[Git][ghc/ghc][wip/ani/better-expansion] Do expansions properly
Apoorv Ingle pushed to branch wip/ani/better-expansion at Glasgow Haskell Compiler / GHC Commits: a091fcbb by Apoorv Ingle at 2026-04-01T09:43:04-05:00 Do expansions properly - move splitHsTypes out of tcApp - splitHsApps now looks through HsExpansions - create a new file for expansions Co-authored-by: simonpj <simon.peytonjones@gmail.com> - - - - - 11 changed files: - compiler/GHC/Tc/Gen/App.hs - − compiler/GHC/Tc/Gen/App.hs-boot - + 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/Tc/Gen/Match.hs - compiler/GHC/Tc/Utils/TcMType.hs - compiler/GHC/Tc/Utils/Unify.hs - compiler/ghc.cabal.in - testsuite/tests/partial-sigs/should_compile/SplicesUsed.stderr Changes: ===================================== compiler/GHC/Tc/Gen/App.hs ===================================== @@ -11,7 +11,6 @@ module GHC.Tc.Gen.App ( tcApp - , tcExprSigma , tcExprPrag ) where import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcPolyExpr ) @@ -165,34 +164,6 @@ Note [Instantiation variables are short lived] -} -{- ********************************************************************* -* * - tcInferSigma -* * -********************************************************************* -} - --- Very similar to tcApp, but returns a sigma (uninstantiated) type --- CAUTION: Any changes to tcApp should be reflected here --- cf. T19167. the head is an expanded expression applied to a type --- Caution: Currently we assume that the expression is compiler generated/expanded --- Because that is what T19167 test case expects. --- This function should go away after MR!15778 lands -tcExprSigma :: Bool -> CtOrigin -> HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) -tcExprSigma inst fun_orig rn_expr - = do { (fun@(rn_fun,fun_lspan), rn_args) <- splitHsApps rn_expr - ; do_ql <- wantQuickLook rn_fun - ; (tc_fun, fun_sigma) <- tcInferAppHead fun - ; inGenCode <- inGeneratedCode - ; traceTc "tcExprSigma" (vcat [ text "rn_expr:" <+> ppr rn_expr - , text "tc_fun" <+> ppr tc_fun - , text "inGeneratedCode:" <+> ppr inGenCode]) - ; (inst_args, app_res_sigma) <- tcInstFun do_ql inst (fun_orig, rn_fun, fun_lspan) - tc_fun fun_sigma rn_args - ; tc_args <- tcValArgs do_ql (rn_fun, fun_lspan) inst_args - ; let tc_expr = rebuildHsApps (tc_fun, fun_lspan) tc_args - ; return (tc_expr, app_res_sigma) } - - {- ********************************************************************* * * Typechecking n-ary applications @@ -379,24 +350,22 @@ Unify result type /before/ typechecking the args The latter is much better. That is why we call `checkResultTy` before tcValArgs. -} --- CAUTION: Any changes to tcApp should be reflected in tcExprSigma -tcApp :: HsExpr GhcRn + +-------------------- +tcApp :: HsExpr GhcRn -- The whole application + -> HsExpr GhcRn -> [HsExprArg 'TcpRn] -- Function and arguments -> ExpRhoType -- When checking, -XDeepSubsumption <=> deeply skolemised -> TcM (HsExpr GhcTc) -- See Note [tcApp: typechecking applications] -tcApp rn_expr exp_res_ty - = do { -- Step 1: Split the application chain - (fun@(rn_fun, fun_lspan), rn_args) <- splitHsApps rn_expr - ; inGenCode <- inGeneratedCode +tcApp rn_expr rn_fun rn_args exp_res_ty + = do { fun_lspan <- getFunSrcSpan rn_args ; traceTc "tcApp {" $ - vcat [ text "generated? " <+> ppr inGenCode - , text "rn_expr:" <+> ppr rn_expr - , text "rn_fun:" <+> ppr rn_fun + vcat [ text "rn_fun:" <+> ppr rn_fun , text "fun_lspan:" <+> ppr fun_lspan , text "rn_args:" <+> ppr rn_args ] -- Step 2: Infer the type of `fun`, the head of the application - ; (tc_fun, fun_sigma) <- tcInferAppHead fun + ; (tc_fun, fun_sigma) <- tcInferAppHead (rn_fun, fun_lspan) ; let tc_head = (tc_fun, fun_lspan) -- inst_final: top-instantiate the result type of the application, -- EXCEPT if we are trying to infer a sigma-type @@ -411,22 +380,12 @@ tcApp rn_expr exp_res_ty -- Step 3.1: Instantiate the function type (taking a quick look at args) ; do_ql <- wantQuickLook rn_fun - -- Setp 3.2 Set the correct origin to blame for the error message - -- What should be the origin for this function call? - -- If the head of the function is user written - -- then it can be used in the error message - -- If it is generated code location span, blame it on the - -- origin that can be retrived from the top of the error ctxt stack. - -- See Note [Error contexts in generated code] - ; fun_orig <- mk_origin fun_lspan rn_fun - ; traceTc "tcApp:inferAppHead" $ vcat [ text "tc_fun:" <+> ppr tc_fun , text "fun_sigma:" <+> ppr fun_sigma - , text "fun_origin" <+> ppr fun_orig , text "do_ql:" <+> ppr do_ql] ; (inst_args, app_res_rho) - <- tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_args + <- tcInstFun do_ql inst_final (rn_fun, fun_lspan) tc_fun fun_sigma rn_args -- See (TCAPP1) and (TCAPP2) in -- Note [tcApp: typechecking applications] @@ -440,7 +399,7 @@ tcApp rn_expr exp_res_ty -- Step 4.2: typecheck the arguments ; tc_args <- tcValArgs NoQL (rn_fun, fun_lspan) inst_args -- Step 4.3: wrap up - ; finishApp tc_head tc_args app_res_rho res_wrap } + ; finishApp tc_fun tc_args app_res_rho res_wrap } DoQL -> do { traceTc "tcApp:DoQL" (ppr rn_fun $$ ppr app_res_rho) @@ -458,7 +417,7 @@ tcApp rn_expr exp_res_ty ; res_wrap <- checkResultTy rn_expr tc_head inst_args app_res_rho exp_res_ty -- Step 5.5: wrap up - ; finishApp tc_head tc_args app_res_rho res_wrap } } + ; finishApp tc_fun tc_args app_res_rho res_wrap } } quickLookResultType :: TcRhoType -> ExpRhoType -> TcM () -- This function implements the shaded bit of rule APP-Downarrow in @@ -466,16 +425,16 @@ quickLookResultType :: TcRhoType -> ExpRhoType -> TcM () quickLookResultType app_res_rho (Check exp_rho) = qlUnify app_res_rho exp_rho quickLookResultType _ _ = return () -finishApp :: (HsExpr GhcTc, SrcSpan) -> [HsExprArg 'TcpTc] +finishApp :: HsExpr GhcTc -> [HsExprArg 'TcpTc] -> TcRhoType -> HsWrapper -> TcM (HsExpr GhcTc) -- Do final checks and wrap up the result -finishApp tc_head@(tc_fun,_) tc_args app_res_rho res_wrap +finishApp tc_fun tc_args app_res_rho res_wrap = do { -- Reconstruct, with a horrible special case for tagToEnum#. res_expr <- if isTagToEnum tc_fun - then tcTagToEnum tc_head tc_args app_res_rho - else return (rebuildHsApps tc_head tc_args) + then tcTagToEnum tc_fun tc_args app_res_rho + else return (rebuildHsApps tc_fun tc_args) ; traceTc "End tcApp }" (ppr tc_fun) ; return (mkHsWrap res_wrap res_expr) } @@ -488,11 +447,12 @@ checkResultTy :: HsExpr GhcRn -- expose foralls, but maybe not /deeply/ instantiated -> ExpRhoType -- Expected type; this is deeply skolemised -> TcM HsWrapper -checkResultTy rn_expr (tc_fun, _) _ app_res_rho (Infer inf_res) +checkResultTy rn_expr (tc_fun,_) _ app_res_rho (Infer inf_res) = do { ds_flag <- getDeepSubsumptionFlag_DataConHead tc_fun + -- Why the "DataConHead" bit? See (IIR5) in + -- Note [Instantiation of InferResult] in GHC.Tc.Utils.Unify. ; fillInferResult ds_flag (exprCtOrigin rn_expr) app_res_rho inf_res } - checkResultTy rn_expr (tc_fun, fun_loc) inst_args app_res_rho (Check res_ty) -- Unify with expected type from the context -- See Note [Unify with expected type before typechecking arguments] @@ -561,7 +521,7 @@ tcValArgs do_ql (fun, fun_lspan) args = go do_ql 0 args | EValArgQL{} <- arg = pos + 1 | ETypeArg{ ea_loc_span = l } <- arg - , not (isGeneratedSrcSpan l) + , not (isGeneratedSrcSpan (locA l)) = pos + 1 | otherwise = pos @@ -618,7 +578,7 @@ tcValArg _ pos (fun, fun_lspan) (EValArgQL { , eaql_loc_span = lspan , eaql_arg_ty = sc_arg_ty , eaql_larg = larg@(L arg_loc rn_expr) - , eaql_tc_fun = tc_head + , eaql_tc_fun = tc_head@(tc_fun,_) , eaql_rn_fun = rn_fun , eaql_fun_ue = head_ue , eaql_args = inst_args @@ -636,7 +596,8 @@ tcValArg _ pos (fun, fun_lspan) (EValArgQL { , text "app_lspan" <+> ppr lspan , text "head_lspan" <+> ppr fun_lspan , text "tc_head" <+> ppr tc_head]) - ; ds_flag <- getDeepSubsumptionFlag_DataConHead (fst tc_head) + ; ds_flag <- getDeepSubsumptionFlag + -- NB: whether to do deep /skolemisation/ is independent of data constructors ; (wrap, arg') <- tcScalingUsage mult $ tcSkolemise ds_flag GenSigCtxt exp_arg_ty $ \ exp_arg_rho -> @@ -656,7 +617,7 @@ tcValArg _ pos (fun, fun_lspan) (EValArgQL { ; app_res_rho <- liftZonkM $ zonkTcType app_res_rho ; res_wrap <- checkResultTy rn_expr tc_head inst_args app_res_rho (mkCheckExpType exp_arg_rho) - ; finishApp tc_head tc_args app_res_rho res_wrap } + ; finishApp tc_fun tc_args app_res_rho res_wrap } ; traceTc "tcEValArgQL }" $ vcat [ text "app_res_rho:" <+> ppr app_res_rho ] @@ -690,26 +651,48 @@ tcInstFun :: QLFlag -- always return a rho-type (but not a deep-rho type) -- Generally speaking we pass in True; in Fig 5 of the paper -- |-inst returns a rho-type - -> (CtOrigin, HsExpr GhcRn, SrcSpan) + -> (HsExpr GhcRn, SrcSpan) -> HsExpr GhcTc -> TcSigmaType -> [HsExprArg 'TcpRn] -> TcM ( [HsExprArg 'TcpInst] , TcSigmaType ) -- Does not instantiate trailing invisible foralls --- This crucial function implements the |-inst judgement in Fig 4, plus the --- modification in Fig 5, of the QL paper: +-- This crucial function implements the |-inst judgement in Fig 4, +-- plus the modification in Fig 5, of the QL paper: -- "A quick look at impredicativity" (ICFP'20). -tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_args - = do { traceTc "tcInstFun" (vcat [ text "origin" <+> ppr fun_orig - , text "tc_fun" <+> ppr tc_fun +tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args + = do { traceTc "tcInstFun" (vcat [ text "tc_fun" <+> ppr tc_fun + , text "rn_fun" <+> ppr rn_head , text "fun_sigma" <+> ppr fun_sigma , text "args:" <+> ppr rn_args - , text "do_ql" <+> ppr do_ql - , text "ctx" <+> ppr fun_lspan]) - ; res@(_, fun_ty) <- go 1 [] fun_sigma rn_args + , text "do_ql" <+> ppr do_ql]) + ; fun_origin <- mk_origin rn_head + ; res@(_, fun_ty) <- go fun_origin 1 [] fun_sigma rn_args ; traceTc "tcInstFun:ret" (ppr fun_ty) ; return res } where + -- What should be the origin for this function call? + -- If the head of the function is user written + -- then it can be used in the error message + -- If it is generated code location span, blame it on the + -- origin that can be retrived from the top of the error ctxt stack. + -- See Note [Error contexts in generated code] + mk_origin :: (HsExpr GhcRn, SrcSpan) -- The head of the application chain and its location + -> TcM CtOrigin + mk_origin (rn_fun, fun_lspan) + | not (isGeneratedSrcSpan fun_lspan) + = return $ exprCtOrigin rn_fun + + | otherwise -- If the location is generated, the best we can do is to + -- approximate by looking on top of the error message stack + = do { err_ctxt_stack <- getErrCtxt + ; let hs_ctxt = case err_ctxt_stack of + (c:_) -> c + [] -> pprPanic "mk_origin" (ppr rn_fun) + ; traceTc "mk_origin" (pprHsCtxt hs_ctxt) + ; return $ hsCtxtCtOrigin hs_ctxt + } + -- These are the type variables which must be instantiated to concrete -- types. See Note [Representation-polymorphic Ids with no binding] -- in GHC.Tc.Utils.Concrete @@ -741,34 +724,35 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg inst_fun _ = isInferredForAllTyFlag ----------- - go, go1 :: Int -- Value-argument position of next arg + go, go1 :: CtOrigin -- Of the function + -> Int -- Value-argument position of next arg -> [HsExprArg 'TcpInst] -- Accumulator, reversed -> TcSigmaType -> [HsExprArg 'TcpRn] -> TcM ([HsExprArg 'TcpInst], TcSigmaType) -- go: If fun_ty=kappa, look it up in Theta - go pos acc fun_ty args + go fun_orig pos acc fun_ty args | Just kappa <- getTyVar_maybe fun_ty , isQLInstTyVar kappa = do { cts <- readMetaTyVar kappa ; case cts of - Indirect fun_ty' -> go pos acc fun_ty' args - Flexi -> go1 pos acc fun_ty args } + Indirect fun_ty' -> go fun_orig pos acc fun_ty' args + Flexi -> go1 fun_orig pos acc fun_ty args } | otherwise - = go1 pos acc fun_ty args + = go1 fun_orig pos acc fun_ty args -- go1: fun_ty is not filled-in instantiation variable -- ('go' dealt with that case) -- Handle out-of-scope functions gracefully - go1 pos acc fun_ty (arg : rest_args) + go1 fun_orig pos acc fun_ty (arg : rest_args) | fun_is_out_of_scope, looks_like_type_arg arg -- See Note [VTA for out-of-scope functions] - = go pos acc fun_ty rest_args + = go fun_orig pos acc fun_ty rest_args -- Rule IALL from Fig 4 of the QL paper; applies even if args = [] -- Instantiate invisible foralls and dictionaries. -- c.f. GHC.Tc.Utils.Instantiate.topInstantiate - go1 pos acc fun_ty args + go1 fun_orig pos acc fun_ty args | (tvs, body1) <- tcSplitSomeForAllTyVars (inst_fun args) fun_ty , (theta, body2) <- if inst_fun args Inferred then tcSplitPhiTy body1 @@ -797,12 +781,12 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg -- argument of (#,#) to @LiftedRep, but want to rule out the -- second instantiation @r. - ; go pos (addArgWrap wrap acc) fun_rho args } + ; go fun_orig pos (addArgWrap wrap acc) fun_rho args } -- Going around again means we deal easily with -- nested forall a. Eq a => forall b. Show b => blah -- Rule IRESULT from Fig 4 of the QL paper; no more arguments - go1 _pos acc fun_ty [] + go1 _fun_orig _pos acc fun_ty [] | XExpr (ConLikeTc (RealDataCon dc)) <- tc_fun , isNewDataCon dc , [Scaled _ orig_arg_ty] <- dataConOrigArgTys dc @@ -822,30 +806,30 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg = return (reverse acc, fun_ty) -- Rule ITVDQ from the GHC Proposal #281 - go1 pos acc fun_ty ((EValArg { ea_arg = arg }) : rest_args) + go1 fun_orig pos acc fun_ty ((EValArg { ea_arg = arg }) : rest_args) | Just (tvb, body) <- tcSplitForAllTyVarBinder_maybe fun_ty = assertPpr (binderFlag tvb == Required) (ppr fun_ty $$ ppr arg) $ -- Any invisible binders have been instantiated by IALL above, -- so this forall must be visible (i.e. Required) do { (ty_arg, inst_body) <- tcVDQ fun_conc_tvs (tvb, body) arg ; let wrap = mkWpTyApps [ty_arg] - ; go (pos+1) (addArgWrap wrap acc) inst_body rest_args } + ; go fun_orig (pos+1) (addArgWrap wrap acc) inst_body rest_args } - go1 pos acc fun_ty (EWrap w : args) - = go1 pos (EWrap w : acc) fun_ty args + go1 fun_orig pos acc fun_ty (EWrap w : args) + = go1 fun_orig pos (EWrap w : acc) fun_ty args - go1 pos acc fun_ty (EPrag sp prag : args) - = go1 pos (EPrag sp prag : acc) fun_ty args + go1 fun_orig pos acc fun_ty (EPrag sp prag : args) + = go1 fun_orig pos (EPrag sp prag : acc) fun_ty args -- Rule ITYARG from Fig 4 of the QL paper - go1 pos acc fun_ty ( ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty } - : rest_args ) + go1 fun_orig pos acc fun_ty ( ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty } + : rest_args ) = do { (ty_arg, inst_ty) <- tcVTA fun_conc_tvs fun_ty hs_ty ; let arg' = ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty, ea_ty_arg = ty_arg } - ; go pos (arg' : acc) inst_ty rest_args } + ; go fun_orig pos (arg' : acc) inst_ty rest_args } -- Rule IVAR from Fig 4 of the QL paper: - go1 pos acc fun_ty args@(EValArg {} : _) + go1 fun_orig pos acc fun_ty args@(EValArg {} : _) | Just kappa <- getTyVar_maybe fun_ty , isQLInstTyVar kappa = -- Function type was of form f :: forall a b. t1 -> t2 -> b @@ -861,7 +845,7 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg -- - We must be sure to actually update the variable right now, -- not defer in any way, because this is a QL instantiation variable. -- It's easier just to do the job directly here. - do { arg_tys <- zipWithM new_arg_ty (leadingValArgs args) [pos..] + do { arg_tys <- zipWithM (new_arg_ty fun_orig) (leadingValArgs args) [pos..] ; res_ty <- newOpenFlexiTyVarTyQL do_ql TauTv ; let fun_ty' = mkScaledFunTys arg_tys res_ty @@ -877,12 +861,12 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg -- Then fun_ty :: kk, fun_ty' :: Type, kind_co :: Type ~ kk -- co_wrap :: (fun_ty' |> kind_co) ~ fun_ty' - ; go pos acc' fun_ty' args } + ; go fun_orig pos acc' fun_ty' args } -- Rule IARG from Fig 4 of the QL paper: - go1 pos acc fun_ty + go1 fun_orig pos acc fun_ty (EValArg { ea_arg = arg, ea_loc_span = ctxt } : rest_args) - = do { let herald = mk_herald tc_fun (unLoc arg) + = do { let herald = mk_herald fun_orig tc_fun (unLoc arg) ; (fun_co, arg_ty, res_ty) <- -- NB: matchActualFunTy does the rep-poly check. -- For example, suppose we have f :: forall r (a::TYPE r). a -> Int @@ -894,16 +878,15 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg matchActualFunTy herald (Just $ HsExprTcThing tc_fun) (n_val_args, fun_sigma) fun_ty - ; ds_flag <- getDeepSubsumptionFlag_DataConHead tc_fun - ; arg' <- quickLookArg ds_flag do_ql pos ctxt (rn_fun, fun_lspan) arg arg_ty + ; arg' <- quickLookArg do_ql pos ctxt rn_head arg arg_ty ; let acc' = arg' : addArgWrap (mkWpCastN fun_co) acc - ; go (pos+1) acc' res_ty rest_args } + ; go fun_orig (pos+1) acc' res_ty rest_args } - new_arg_ty :: LHsExpr GhcRn -> Int -> TcM (Scaled TcType) + new_arg_ty :: CtOrigin -> LHsExpr GhcRn -> Int -> TcM (Scaled TcType) -- Make a fresh nus for each argument in rule IVAR - new_arg_ty (L _ arg) i + new_arg_ty fun_orig (L _ arg) i = do { arg_nu <- newArgTyVarTyQL do_ql $ - FRRExpectedFunTy (mk_herald tc_fun arg) i + FRRExpectedFunTy (mk_herald fun_orig tc_fun arg) i -- Following matchActualFunTy, we create nu_i :: TYPE kappa_i[conc], -- thereby ensuring that the arguments have concrete runtime representations @@ -913,12 +896,13 @@ tcInstFun do_ql inst_final (fun_orig, rn_fun, fun_lspan) tc_fun fun_sigma rn_arg ; return (mkScaled mult_ty arg_nu) } - mk_herald :: HsExpr GhcTc -> HsExpr GhcRn -> ExpectedFunTyCtxt - mk_herald tc_fun arg + mk_herald :: CtOrigin -> HsExpr GhcTc -> HsExpr GhcRn -> ExpectedFunTyCtxt + mk_herald fun_orig tc_fun arg = case fun_orig of DoStmtOrigin -> ExpectedFunTySyntaxOp DoStmtOrigin tc_fun _ -> ExpectedFunTyArg (HsExprTcThing tc_fun) arg + -- Is the argument supposed to instantiate a forall? -- -- In other words, given a function application `fn arg`, @@ -1883,23 +1867,23 @@ This turned out to be more subtle than I expected. Wrinkles: -} -quickLookArg :: DeepSubsumptionFlag -> QLFlag -> Int - -> SrcSpan -- ^ location span of the whole application +quickLookArg :: QLFlag -> Int + -> HsExprLoc -- ^ location span of the whole application -> (HsExpr GhcRn, SrcSpan) -- ^ Head of the application chain and its source span -> LHsExpr GhcRn -- ^ Argument -> Scaled TcSigmaTypeFRR -- ^ Type expected by the function -> TcM (HsExprArg 'TcpInst) -- See Note [Quick Look at value arguments] -quickLookArg _ NoQL _ app_lspan _ larg orig_arg_ty +quickLookArg NoQL _ app_lspan _ larg orig_arg_ty = skipQuickLook app_lspan larg orig_arg_ty -quickLookArg ds_flag DoQL pos app_lspan fun_and_lspan larg orig_arg_ty - = do { is_rho <- tcIsDeepRho ds_flag (scaledThing orig_arg_ty) +quickLookArg DoQL pos app_lspan fun_and_lspan larg orig_arg_ty + = do { is_rho <- qlArgHasRhoType (scaledThing orig_arg_ty) ; traceTc "qla" (ppr orig_arg_ty $$ ppr is_rho) ; if not is_rho then skipQuickLook app_lspan larg orig_arg_ty else quickLookArg1 pos app_lspan fun_and_lspan larg orig_arg_ty } -skipQuickLook :: SrcSpan -> LHsExpr GhcRn -> Scaled TcRhoType +skipQuickLook :: HsExprLoc -> LHsExpr GhcRn -> Scaled TcRhoType -> TcM (HsExprArg 'TcpInst) skipQuickLook app_lspan larg arg_ty = return (EValArg { ea_loc_span = app_lspan @@ -1910,13 +1894,26 @@ whenQL :: QLFlag -> ZonkM () -> TcM () whenQL DoQL thing_inside = liftZonkM thing_inside whenQL NoQL _ = return () -tcIsDeepRho :: DeepSubsumptionFlag -> TcType -> TcM Bool --- This top-level zonk step, which is the reason we need a local 'go' loop, --- is subtle. See Section 9 of the QL paper +qlArgHasRhoType :: TcType -> TcM Bool +-- `qlArgHasRhoType` checks that the expected argument type in rule +-- App-lightning-bolt (Fig 5 in the paper) is indeed a rho-type. +-- +-- It must apply the current QL substitution, so it any QLInstTyVar that it +-- comes across. Why? See Section 5.7 in the paper; argument order matters. +-- +-- What if we find an /un-filled/ QLInstVar? We treat this as a rho-type +-- even though a later argument might force it to be sigma-type. See +-- Section 9 in the paper. +-- +-- With -XDeepSubsunption we need a /deep/ rho-type. +-- (We don't need getDeepSubsumptionFlag_DataConHead here because this +-- is only about QuickLook.) -tcIsDeepRho ds_flag = go +qlArgHasRhoType ty + = do { ds_flag <- getDeepSubsumptionFlag + ; go ds_flag ty } where - go ty + go ds_flag ty | isSigmaTy ty = return False @@ -1924,12 +1921,12 @@ tcIsDeepRho ds_flag = go , isQLInstTyVar kappa = do { info <- readMetaTyVar kappa ; case info of - Indirect arg_ty' -> go arg_ty' + Indirect arg_ty' -> go ds_flag arg_ty' Flexi -> return True } | Deep {} <- ds_flag , Just (_, res_ty) <- tcSplitFunTy_maybe ty - = go res_ty + = go ds_flag res_ty | otherwise = return True @@ -1940,14 +1937,20 @@ isGuardedTy ty | Just {} <- tcSplitAppTy_maybe ty = True | otherwise = False -quickLookArg1 :: Int -> SrcSpan -> (HsExpr GhcRn, SrcSpan) -> LHsExpr GhcRn +quickLookArg1 :: Int -> HsExprLoc -> (HsExpr GhcRn, SrcSpan) -> LHsExpr GhcRn -> Scaled TcRhoType -- Deeply skolemised -> TcM (HsExprArg 'TcpInst) -- quickLookArg1 implements the "QL Argument" judgement in Fig 5 of the paper quickLookArg1 pos app_lspan (fun, fun_lspan) larg@(L _ arg) sc_arg_ty@(Scaled _ orig_arg_rho) = addArgCtxt pos (fun, fun_lspan) larg $ -- Context needed for constraints - -- generated by calls in arg - do { ((rn_fun_arg, fun_lspan_arg), rn_args) <- splitHsApps arg + -- generated by calls in arg + do { traceTc "qla1" (ppr arg) + + ; (rn_fun_arg, rn_args) <- splitHsApps arg + + ; traceTc "qla2" (ppr arg) + + ; fun_lspan_arg <- getFunSrcSpan rn_args -- Step 1: get the type of the head of the argument ; (fun_ue, mb_fun_ty) <- tcCollectingUsage $ tcInferAppHead_maybe rn_fun_arg @@ -1970,17 +1973,15 @@ quickLookArg1 pos app_lspan (fun, fun_lspan) larg@(L _ arg) sc_arg_ty@(Scaled _ do { let arg_tc_head = (tc_fun_arg_head, fun_lspan_arg) ; do_ql <- wantQuickLook rn_fun_arg - ; arg_orig <- mk_origin fun_lspan_arg rn_fun_arg ; ((inst_args, app_res_rho), wanted) <- captureConstraints $ - tcInstFun do_ql True (arg_orig, rn_fun_arg, fun_lspan_arg) tc_fun_arg_head fun_sigma_arg_head rn_args + tcInstFun do_ql True (rn_fun_arg, fun_lspan_arg) tc_fun_arg_head fun_sigma_arg_head rn_args -- We must capture type-class and equality constraints here, but -- not usage information. See (QLA6) in Note [Quick Look at -- value arguments] ; traceTc "quickLookArg 2" $ vcat [ text "arg:" <+> ppr arg - , text "orig:" <+> ppr arg_orig , text "orig_arg_rho:" <+> ppr orig_arg_rho , text "app_res_rho:" <+> ppr app_res_rho ] @@ -2018,24 +2019,6 @@ quickLookArg1 pos app_lspan (fun, fun_lspan) larg@(L _ arg) sc_arg_ty@(Scaled _ , eaql_res_rho = app_res_rho }) }}} -mk_origin :: SrcSpan -- SrcSpan of the function - -> HsExpr GhcRn -- The head of the expression application chain - -> TcM CtOrigin -mk_origin fun_lspan rn_fun - | not (isGeneratedSrcSpan fun_lspan) - = return $ exprCtOrigin rn_fun - - | otherwise -- If the location is generated, the best we can do is to - -- approximate by looking on top of the error message stack - = do { err_ctxt_stack <- getErrCtxt - ; let hs_ctxt = case err_ctxt_stack of - (c:_) -> c - [] -> pprPanic "mk_origin" (ppr rn_fun) - ; traceTc "mk_origin" (pprHsCtxt hs_ctxt) - ; return $ hsCtxtCtOrigin hs_ctxt - } - - {- ********************************************************************* * * Folding over instantiation variables @@ -2437,12 +2420,11 @@ isTagToEnum :: HsExpr GhcTc -> Bool isTagToEnum (HsVar _ (L _ fun_id)) = fun_id `hasKey` tagToEnumKey isTagToEnum _ = False -tcTagToEnum :: (HsExpr GhcTc, SrcSpan) -> [HsExprArg 'TcpTc] - -> TcRhoType +tcTagToEnum :: HsExpr GhcTc -> [HsExprArg 'TcpTc] -> TcRhoType -> TcM (HsExpr GhcTc) -- tagToEnum# :: forall a. Int# -> a -- See Note [tagToEnum#] Urgh! -tcTagToEnum (tc_fun, fun_lspan) tc_args res_ty +tcTagToEnum tc_fun tc_args res_ty | [val_arg] <- dropWhile (not . isHsValArg) tc_args = do { res_ty <- liftZonkM $ zonkTcType res_ty @@ -2464,14 +2446,14 @@ tcTagToEnum (tc_fun, fun_lspan) tc_args res_ty ; let rep_ty = mkTyConApp rep_tc rep_args tc_fun' = mkHsWrap (WpTyApp rep_ty) tc_fun df_wrap = mkWpCastR (mkSymCo coi) - tc_expr = rebuildHsApps (tc_fun', fun_lspan) [val_arg] + tc_expr = rebuildHsApps tc_fun' [val_arg] ; return (mkHsWrap df_wrap tc_expr) }}}}} | otherwise = failWithTc TcRnTagToEnumMissingValArg where - vanilla_result = return (rebuildHsApps (tc_fun, fun_lspan) tc_args) + vanilla_result = return (rebuildHsApps tc_fun tc_args) check_enumeration ty' tc | -- isTypeDataTyCon: see wrinkle (W1) in ===================================== compiler/GHC/Tc/Gen/App.hs-boot deleted ===================================== @@ -1,12 +0,0 @@ -module GHC.Tc.Gen.App where - -import GHC.Hs ( HsExpr ) -import GHC.Tc.Types ( TcM ) -import GHC.Tc.Types.Origin ( CtOrigin ) -import GHC.Tc.Utils.TcType ( TcSigmaType ) -import GHC.Hs.Extension ( GhcRn, GhcTc ) - - -import GHC.Prelude (Bool) - -tcExprSigma :: Bool -> CtOrigin -> HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) ===================================== compiler/GHC/Tc/Gen/Expand.hs ===================================== @@ -0,0 +1,107 @@ +{-# LANGUAGE TypeFamilies #-} + +{- +(c) The University of Glasgow 2006 +(c) The GRASP/AQUA Project, Glasgow University, 1992-1998 +-} + +module GHC.Tc.Gen.Expand( tcExpand ) where + +import GHC.Prelude + +import {-# SOURCE #-} GHC.Tc.Gen.Splice( getUntypedSpliceBody ) + +import GHC.Hs + +import GHC.Tc.Utils.Monad +import GHC.Tc.Types.ErrCtxt + +import GHC.Rename.Utils + +{- 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 + +Example: Typechecking the do expression. The typechecker looks (somewhat) like this: + + tcExpr e@(HsDo _ stmts) rho = do { hse <- expandDoStmts stmts + ; tcHsExpansion hse rho } + +The `expandDoStmts` replaces the HsDo { x <- e1; return x } +with something like + HSE { hse_ctxt = ExprCtxt e + , hse_exp = e1 >>= \ x -> x } +and we then typecheck the expression `e1 >>= \ x -> x` + +See also Note [Handling overloaded and rebindable constructs] + and Note [Doing XXExprGhcRn in the Renamer vs Typechecker] + +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 expansion process typically takes a user written thing + L lspan ue + and returns + L lspan (XExpr (ExpandedThingRn (HSE { hse_ctxt = ue + , hse_exp = ee } )) + where `ee` is the expansion of the user written thing `ue` + +* The type checker context has 3 key fields that describe the context: + TcLclCtxt { tcl_loc :: RealSrcSpan + , tcl_in_gen_code :: Bool + , tcl_err_ctxt :: ErrCtxtStack + , ... } + 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 second argument of `$` namely 'r { x=2 }'" + + The `tcl_in_gen_code` is a boolean that keeps track of whether + the current expression being typechecked is compiler generated + or user generated. + + INVARIANT: `tcl_loc` and `tcl_in_gen_code` are modified only in `setSrcSpan`. + +* Now, when + tcMonoLExpr :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc) + gets a located expression, it does 3 things: + (a) Calls `setSrcSpanA` to set the ambient source-code location + (b) Calls `addExprCtxt` to push a suitable `HsCtxt` on top of the `tcl_err_ctxt`. + (c) Calls `tcExpr` to typecheck the expression. + +* In these calls, if the `span` is generated (see `isGeneratedSrcSpan`), then + - `setSrcSpanA` sets `tcl_in_gen_code` to `True`, and leaves `tcl_loc` unchanged + - `addExprCtxt` is a no-op if `tcl_in_gen_code` is True + The result is that `tcl_loc` has the span from the innermost /user/ tree node; + and the ErrCtxtStack in `tcl_err_ctxt` only has contexts arisign from user code. + +* Note that inside an expansion we have sub-expressions from the original program. + As soon as we enter one of those, identified by a /user/ span, `setSrcSpanA` will + sets the `tcl_loc` to reflect that span, and switch off `tcl_in_gen_code`. Nice! +-} + +--------------- +tcExpand :: HsExpr GhcRn -> TcM (Maybe (HsExpansion GhcRn)) +tcExpand e@(OpApp _ arg1 op arg2) + = return $ Just $ + HSE { hse_ctxt = ExprCtxt e + , hse_exp = foldl ap op [arg1,arg2] } + where + ap f a = wrapGenSpan (HsApp noExtField f a) + +tcExpand (XExpr (ExpandedThingRn hse)) + = return (Just hse) + +tcExpand e@(HsUntypedSplice splice_res _) +-- See Note [Looking through Template Haskell splices in splitHsApps] + = do { fun <- getUntypedSpliceBody splice_res + ; return $ Just $ + HSE { hse_ctxt = ExprCtxt e + , hse_exp = wrapGenSpan fun } } + +tcExpand _ = return Nothing ===================================== compiler/GHC/Tc/Gen/Expr.hs ===================================== @@ -13,7 +13,7 @@ module GHC.Tc.Gen.Expr ( tcCheckPolyExpr, tcCheckPolyExprNC, tcCheckMonoExpr, tcCheckMonoExprNC, - tcInferExpr, tcInferSigma, + tcInferExpr, tcInferSigma, tcInferExprSigma, tcInferRho, tcInferRhoNC, tcMonoLExpr, tcMonoLExprNC, tcInferRhoFRR, tcInferRhoFRRNC, @@ -30,10 +30,10 @@ import {-# SOURCE #-} GHC.Tc.Gen.Splice import GHC.Hs import GHC.Hs.Syn.Type - import GHC.Rename.Utils import GHC.Rename.Env ( addUsedGRE, getUpdFieldLbls ) +import GHC.Tc.Gen.Expand( tcExpand ) import GHC.Tc.Gen.App import GHC.Tc.Gen.Head import GHC.Tc.Gen.Do @@ -237,6 +237,9 @@ tcPolyExprCheck expr res_ty tcInferSigma :: LHsExpr GhcRn -> TcM (LHsExpr GhcTc, TcSigmaType) tcInferSigma = tcInferExpr IIF_Sigma +tcInferExprSigma :: HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) +tcInferExprSigma e = runInfer IIF_Sigma IFRR_Any (tcExpr e) + tcInferRho, tcInferRhoNC :: LHsExpr GhcRn -> TcM (LHsExpr GhcTc, TcRhoType) -- Infer a *rho*-type. The return type is always instantiated. tcInferRho = tcInferExpr IIF_DeepRho @@ -291,6 +294,12 @@ tcMonoLExprNC (L loc expr) res_ty do { expr' <- tcExpr expr res_ty ; return (L loc expr') } +--------------- +tcCollectApp :: HsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc) +tcCollectApp the_app res_ty + = do { (fun, args) <- splitHsApps the_app + ; tcApp the_app fun args res_ty } + --------------- tcExpr :: HsExpr GhcRn -> ExpRhoType -- DeepSubsumption <=> when checking, this type @@ -312,19 +321,11 @@ tcExpr :: HsExpr GhcRn -- - ones taken apart by GHC.Tc.Gen.Head.splitHsApps -- - ones understood by GHC.Tc.Gen.Head.tcInferAppHead_maybe -- See Note [Application chains and heads] in GHC.Tc.Gen.App -tcExpr e@(HsVar {}) res_ty = tcApp e res_ty -tcExpr e@(HsApp {}) res_ty = tcApp e res_ty -tcExpr e@(OpApp {}) res_ty = tcApp e res_ty -tcExpr e@(HsAppType {}) res_ty = tcApp e res_ty -tcExpr e@(ExprWithTySig {}) res_ty = tcApp e res_ty -tcExpr e@(XExpr (HsRecSelRn{})) res_ty = tcApp e res_ty - --- Renamer expanded expressions (eg. Right/Left sections) --- or tcExpr expanded expressions (eg. Do statements and Record updates) --- are type checked using tcHsExpansion. --- See Note [Typechecking by expansion: overview] -tcExpr (XExpr (ExpandedThingRn hse)) res_ty = tcHsExpansion hse res_ty - +tcExpr e@(HsVar {}) res_ty = tcApp e e [] res_ty +tcExpr e@(ExprWithTySig {}) res_ty = tcApp e e [] res_ty +tcExpr e@(XExpr (HsRecSelRn{})) res_ty = tcApp e e [] res_ty +tcExpr e@(HsAppType {}) res_ty = tcCollectApp e res_ty +tcExpr e@(HsApp {}) res_ty = tcCollectApp e res_ty -- Typecheck an occurrence of an unbound Id -- @@ -392,7 +393,7 @@ tcExpr e@(HsOverLit _ lit) res_ty -- See Note [Short cut for overloaded literals] in GHC.Tc.Utils.TcMType ; case mb_res of Just lit' -> return (HsOverLit noExtField lit') - Nothing -> tcApp e res_ty } + Nothing -> tcApp e e [] res_ty } -- Why go via tcApp? See Note [Typechecking overloaded literals] {- Note [Typechecking overloaded literals] @@ -530,8 +531,9 @@ tcExpr (HsCase ctxt scrut matches) res_ty tcExpr (HsIf x pred b1 b2) res_ty = do { pred' <- tcCheckMonoExpr pred boolTy - ; (u1,b1') <- tcCollectingUsage $ tcMonoLExpr b1 res_ty - ; (u2,b2') <- tcCollectingUsage $ tcMonoLExpr b2 res_ty + ; let res_ty' = adjustExpTypeForCaseBranches res_ty [b1,b2] + ; (u1,b1') <- tcCollectingUsage $ tcMonoLExpr b1 res_ty' + ; (u2,b2') <- tcCollectingUsage $ tcMonoLExpr b2 res_ty' ; tcEmitBindingUsage (supUE u1 u2) ; return (HsIf x pred' b1' b2') } @@ -730,19 +732,6 @@ tcExpr e@(RecordUpd { rupd_flds = OverloadedRecUpdFields {}}) _ tcExpr (ArithSeq _ witness seq) res_ty = tcArithSeq witness seq res_ty -{- -************************************************************************ -* * - Record dot syntax -* * -************************************************************************ --} - --- These terms have been replaced by their expanded expressions in the renamer. See --- Note [Overview of record dot syntax]. -tcExpr (HsGetField _ _ _) _ = panic "GHC.Tc.Gen.Expr: tcExpr: HsGetField: Not implemented" -tcExpr (HsProjection _ _) _ = panic "GHC.Tc.Gen.Expr: tcExpr: HsProjection: Not implemented" - {- ************************************************************************ * * @@ -755,17 +744,7 @@ tcExpr (HsProjection _ _) _ = panic "GHC.Tc.Gen.Expr: tcExpr: HsProjection: Not -- See Note [Delaying modFinalizers in untyped splices] in GHC.Rename.Splice. tcExpr (HsTypedSplice ext splice) res_ty = tcTypedSplice ext splice res_ty tcExpr e@(HsTypedBracket _ext body) res_ty = tcTypedBracket e body res_ty - tcExpr e@(HsUntypedBracket ps body) res_ty = tcUntypedBracket e body ps res_ty -tcExpr (HsUntypedSplice splice _) res_ty - -- Since `tcApp` deals with `HsUntypedSplice` (in `splitHsApps`), you might - -- wonder why we don't delegate to `tcApp` as we do for `HsVar`, etc. - -- (See the initial block of equations for `tcExpr`.) But we can't do this - -- for `HsUntypedSplice`; to see why, read Wrinkle (UTS1) in - -- Note [Looking through Template Haskell splices in splitHsApps] in - -- GHC.Tc.Gen.Head. - = do { expr <- getUntypedSpliceBody splice - ; tcExpr expr res_ty } {- ************************************************************************ @@ -775,10 +754,12 @@ 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) - +-- See Note [Typechecking by expansion: overview] +tcExpr e res_ty + = do { mb_hse <- tcExpand e + ; case mb_hse of + Just hse -> tcHsExpansion hse res_ty + Nothing -> pprPanic "tcExpr: unhandled case:" (ppr e) } {- ************************************************************************ @@ -788,73 +769,6 @@ tcExpr (SectionR {}) ty = pprPanic "tcExpr:SectionR" (ppr ty) ************************************************************************ -} -{- 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 - -Example: Typechecking the do expression. The typechecker looks (somewhat) like this: - - tcExpr e@(HsDo _ stmts) rho = do { hse <- expandDoStmts stmts - ; tcHsExpansion hse rho } - -The `expandDoStmts` replaces the HsDo { x <- e1; return x } -with something like - HSE { hse_ctxt = ExprCtxt e - , hse_exp = e1 >>= \ x -> x } -and we then typecheck the expression `e1 >>= \ x -> x` - -See also Note [Handling overloaded and rebindable constructs] - and Note [Doing XXExprGhcRn in the Renamer vs Typechecker] - -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 expansion process typically takes a user written thing - L lspan ue - and returns - L lspan (XExpr (ExpandedThingRn (HSE { hse_ctxt = ue - , hse_exp = ee } )) - where `ee` is the expansion of the user written thing `ue` - -* The type checker context has 3 key fields that describe the context: - TcLclCtxt { tcl_loc :: RealSrcSpan - , tcl_in_gen_code :: Bool - , tcl_err_ctxt :: ErrCtxtStack - , ... } - 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 second argument of `$` namely 'r { x=2 }'" - - The `tcl_in_gen_code` is a boolean that keeps track of whether - the current expression being typechecked is compiler generated - or user generated. - - INVARIANT: `tcl_loc` and `tcl_in_gen_code` are modified only in `setSrcSpan`. - -* Now, when - tcMonoLExpr :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc) - gets a located expression, it does 3 things: - (a) Calls `setSrcSpanA` to set the ambient source-code location - (b) Calls `addExprCtxt` to push a suitable `HsCtxt` on top of the `tcl_err_ctxt`. - (c) Calls `tcExpr` to typecheck the expression. - -* In these calls, if the `span` is generated (see `isGeneratedSrcSpan`), then - - `setSrcSpanA` sets `tcl_in_gen_code` to `True`, and leaves `tcl_loc` unchanged - - `addExprCtxt` is a no-op if `tcl_in_gen_code` is True - The result is that `tcl_loc` has the span from the innermost /user/ tree node; - and the ErrCtxtStack in `tcl_err_ctxt` only has contexts arisign from user code. - -* Note that inside an expansion we have sub-expressions from the original program. - As soon as we enter one of those, identified by a /user/ span, `setSrcSpanA` will - sets the `tcl_loc` to reflect that span, and switch off `tcl_in_gen_code`. Nice! --} - tcHsExpansion :: HsExpansion GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc) tcHsExpansion (HSE { hse_ctxt = o, hse_exp = e }) res_ty = do { e' <- tcMonoLExpr e res_ty ===================================== compiler/GHC/Tc/Gen/Expr.hs-boot ===================================== @@ -35,6 +35,8 @@ tcInferRho, tcInferRhoNC :: tcInferRhoFRR, tcInferRhoFRRNC :: FixedRuntimeRepContext -> LHsExpr GhcRn -> TcM (LHsExpr GhcTc, TcRhoType) +tcInferExprSigma :: HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) + tcInferExpr :: InferInstFlag -> LHsExpr GhcRn -> TcM (LHsExpr GhcTc, TcType) tcSyntaxOp :: CtOrigin ===================================== compiler/GHC/Tc/Gen/Head.hs ===================================== @@ -9,9 +9,9 @@ -} module GHC.Tc.Gen.Head - ( HsExprArg(..), TcPass(..), QLFlag(..), EWrap(..) + ( HsExprArg(..), HsExprLoc, TcPass(..), QLFlag(..), EWrap(..) , splitHsApps, rebuildHsApps - , addArgWrap, isHsValArg + , addArgWrap, isHsValArg, getFunSrcSpan , leadingValArgs, isVisibleArg, getDeepSubsumptionFlag_DataConHead , tcInferAppHead, tcInferAppHead_maybe @@ -22,16 +22,13 @@ module GHC.Tc.Gen.Head , pprArgInst, addFunResCtxt ) where import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcExpr, tcCheckPolyExprNC, tcPolyLExprSig ) -import {-# SOURCE #-} GHC.Tc.Gen.Splice( getUntypedSpliceBody ) -import {-# SOURCE #-} GHC.Tc.Gen.App( tcExprSigma ) import GHC.Prelude import GHC.Hs import GHC.Hs.Syn.Type -import GHC.Rename.Utils (mkExpandedTc, mkExpandedExprTc) - import GHC.Tc.Gen.HsType +import GHC.Tc.Gen.Expand( tcExpand ) import GHC.Tc.Gen.Bind( chooseInferredQuantifiers ) import GHC.Tc.Gen.Sig( tcUserTypeSig, tcInstSig ) import GHC.Tc.TyCl.PatSyn( patSynBuilderOcc ) @@ -86,7 +83,7 @@ import GHC.Data.Maybe The data type HsExprArg :: TcPass -> Type is a very local type, used only within this module and GHC.Tc.Gen.App -* It's really a zipper for an application chain +* It's just a bog-standard zipper for an application chain See Note [Application chains and heads] in GHC.Tc.Gen.App for what an "application chain" is. @@ -147,6 +144,8 @@ takes apart either an HsApp, or an infix OpApp, returning * We do not look through expanded expressions (except PopErrCtxt.) -} +type HsExprLoc = EpAnn AnnListItem -- The location attached to a HsExpr + data TcPass = TcpRn -- Arguments decomposed | TcpInst -- Function instantiated | TcpTc -- Typechecked @@ -154,34 +153,34 @@ data TcPass = TcpRn -- Arguments decomposed data HsExprArg (p :: TcPass) where -- See Note [HsExprArg] -- Data constructor EValArg represents a value argument - EValArg :: { ea_loc_span :: SrcSpan - , ea_arg_ty :: !(XEVAType p) - , ea_arg :: LHsExpr (GhcPass (XPass p)) } + EValArg :: { ea_loc_span :: HsExprLoc + , ea_arg_ty :: !(XEVAType p) + , ea_arg :: LHsExpr (GhcPass (XPass p)) } -> HsExprArg p -- Data constructor EValArgQL represents an argument that has been -- partly-type-checked by Quick Look; see Note [EValArgQL] - EValArgQL :: { eaql_loc_span :: SrcSpan - , eaql_arg_ty :: Scaled TcSigmaType -- Argument type expected by function - , eaql_larg :: LHsExpr GhcRn -- Original application, for - -- location and error msgs - , eaql_rn_fun :: HsExpr GhcRn -- Head of the argument if it is an application - , eaql_tc_fun :: (HsExpr GhcTc, SrcSpan) -- Typechecked head and its location span - , eaql_fun_ue :: UsageEnv -- Usage environment of the typechecked head (QLA5) - , eaql_args :: [HsExprArg 'TcpInst] -- Args: instantiated, not typechecked - , eaql_wanted :: WantedConstraints - , eaql_encl :: Bool -- True <=> we have already qlUnified - -- eaql_arg_ty and eaql_res_rho - , eaql_res_rho :: TcRhoType } -- Result type of the application + EValArgQL :: { eaql_loc_span :: HsExprLoc + , eaql_arg_ty :: Scaled TcSigmaType -- Argument type expected by function + , eaql_larg :: LHsExpr GhcRn -- Original application, for + -- location and error msgs + , eaql_rn_fun :: HsExpr GhcRn -- Head of the argument if it is an application + , eaql_tc_fun :: (HsExpr GhcTc, SrcSpan) -- Typechecked head and its location span + , eaql_fun_ue :: UsageEnv -- Usage environment of the typechecked head (QLA5) + , eaql_args :: [HsExprArg 'TcpInst] -- Args: instantiated, not typechecked + , eaql_wanted :: WantedConstraints + , eaql_encl :: Bool -- True <=> we have already qlUnified + -- eaql_arg_ty and eaql_res_rho + , eaql_res_rho :: TcRhoType } -- Result type of the application -> HsExprArg 'TcpInst -- Only exists in TcpInst phase - ETypeArg :: { ea_loc_span :: SrcSpan - , ea_hs_ty :: LHsWcType GhcRn -- The type arg - , ea_ty_arg :: !(XETAType p) } -- Kind-checked type arg + ETypeArg :: { ea_loc_span :: HsExprLoc + , ea_hs_ty :: LHsWcType GhcRn -- The type arg + , ea_ty_arg :: !(XETAType p) } -- Kind-checked type arg -> HsExprArg p - EPrag :: SrcSpan -> (HsPragE (GhcPass (XPass p))) -> HsExprArg p - EWrap :: EWrap -> HsExprArg p + EPrag :: HsExprLoc -> (HsPragE (GhcPass (XPass p))) -> HsExprArg p + EWrap :: EWrap -> HsExprArg p type family XETAType (p :: TcPass) where -- Type arguments XETAType 'TcpRn = NoExtField @@ -193,8 +192,8 @@ type family XEVAType (p :: TcPass) where -- Value arguments data QLFlag = DoQL | NoQL -data EWrap = EPar SrcSpan - | EExpand (HsExpr GhcRn) +data EWrap = EPar HsExprLoc + | EExpand HsExprLoc HsCtxt | EHsWrap HsWrapper @@ -207,11 +206,11 @@ type family XPass (p :: TcPass) where XPass 'TcpInst = 'Renamed XPass 'TcpTc = 'Typechecked -mkEValArg :: SrcSpan -> LHsExpr GhcRn -> HsExprArg 'TcpRn +mkEValArg :: HsExprLoc -> LHsExpr GhcRn -> HsExprArg 'TcpRn mkEValArg src_loc e = EValArg { ea_arg = e, ea_loc_span = src_loc , ea_arg_ty = noExtField } -mkETypeArg :: SrcSpan -> LHsWcType GhcRn -> HsExprArg 'TcpRn +mkETypeArg :: HsExprLoc -> LHsWcType GhcRn -> HsExprArg 'TcpRn mkETypeArg src_loc hs_ty = ETypeArg { ea_loc_span = src_loc , ea_hs_ty = hs_ty @@ -223,74 +222,17 @@ addArgWrap wrap args | otherwise = EWrap (EHsWrap wrap) : args -splitHsApps :: HsExpr GhcRn - -> TcM ( (HsExpr GhcRn, SrcSpan) -- Head - , [HsExprArg 'TcpRn]) -- Args --- See Note [splitHsApps]. --- --- This uses the TcM monad solely because we must run modFinalizers when looking --- through HsUntypedSplices --- (see Note [Looking through Template Haskell splices in splitHsApps]). -splitHsApps e = go e noSrcSpan [] - where - go :: HsExpr GhcRn -> SrcSpan -> [HsExprArg 'TcpRn] - -> TcM ((HsExpr GhcRn, SrcSpan), [HsExprArg 'TcpRn]) - -- Modify the SrcSpan as we walk inwards, so it describes the next argument - go (HsPar _ (L l fun)) lspan args = go fun (locA l) (EWrap (EPar lspan) : args) - go (HsPragE _ p (L l fun)) lspan args = go fun (locA l) (EPrag lspan p : args) - go (HsAppType _ (L l fun) ty) lspan args = go fun (locA l) (mkETypeArg lspan ty : args) - go (HsApp _ (L l fun) arg) lspan args = go fun (locA l) (mkEValArg lspan arg : args) - - -- See Note [Looking through Template Haskell splices in splitHsApps] - go e@(HsUntypedSplice splice_res splice) _ args - = do { fun <- getUntypedSpliceBody splice_res - ; go fun lspan' (EWrap (EExpand e) : args) } - where - lspan' :: SrcSpan - lspan' = case splice of - HsUntypedSpliceExpr _ (L l _) -> locA l -- l :: SrcAnn AnnListItem - HsQuasiQuote _ _ (L l _) -> locA l -- l :: SrcAnn NoEpAnns - (XUntypedSplice (HsImplicitLiftSplice _ _ _ (L l _))) -> locA l - - -- See Note [Desugar OpApp in the typechecker] - go e@(OpApp _ arg1 (L l op) arg2) _ args - = pure ( (op, locA l) - , mkEValArg noSrcSpan arg1 - : mkEValArg noSrcSpan arg2 - -- noSrcSpan because this the span of the call, - -- and its hard to say exactly what that is - : EWrap (EExpand e) - : args ) - - go e lspan args = pure ((e, lspan), args) - - --- | Rebuild an application: takes a type-checked application head --- expression together with arguments in the form of typechecked 'HsExprArg's --- and returns a typechecked application of the head to the arguments. -rebuildHsApps :: (HsExpr GhcTc, SrcSpan) - -- ^ the function being applied - -> [HsExprArg 'TcpTc] - -- ^ the arguments to the function - -> HsExpr GhcTc -rebuildHsApps (fun, _) [] = fun -rebuildHsApps (fun, sloc) (arg : args) - = case arg of - EValArg { ea_arg = arg, ea_loc_span = sloc' } - -> rebuildHsApps (HsApp noExtField lfun arg, sloc') args - ETypeArg { ea_hs_ty = hs_ty, ea_ty_arg = ty, ea_loc_span = sloc' } - -> rebuildHsApps (HsAppType ty lfun hs_ty, sloc') args - EPrag sloc' p - -> rebuildHsApps (HsPragE noExtField p lfun, sloc') args - EWrap (EPar sloc') - -> rebuildHsApps (gHsPar lfun, sloc') args - EWrap (EExpand o) - -> rebuildHsApps (mkExpandedExprTc o fun, sloc) args - EWrap (EHsWrap wrap) - -> rebuildHsApps (mkHsWrap wrap fun, sloc) args - where - lfun = L (noAnnSrcSpan sloc) fun +-------------------- +getFunSrcSpan :: [HsExprArg 'TcpRn] -> TcM SrcSpan +getFunSrcSpan [] = getSrcSpanM +getFunSrcSpan (ETypeArg { ea_loc_span = l } : _) = return (locA l) +getFunSrcSpan (EValArg { ea_loc_span = l } : _) = return (locA l) +getFunSrcSpan (EPrag l _ : _) = return (locA l) +getFunSrcSpan (EWrap (EPar l) : _) = return (locA l) +getFunSrcSpan (EWrap (EExpand l _) : _) = return (locA l) +getFunSrcSpan (EWrap (EHsWrap {}) : args) = getFunSrcSpan args +-------------------- isHsValArg :: HsExprArg id -> Bool isHsValArg (EValArg {}) = True isHsValArg _ = False @@ -334,13 +276,60 @@ pprArgInst (EValArgQL { eaql_tc_fun = fun, eaql_args = args, eaql_res_rho = ty}) 2 (vcat [ vcat (map pprArgInst args), text "ea_ql_ty:" <+> ppr ty ]) instance Outputable EWrap where - ppr (EPar _) = text "EPar" - ppr (EHsWrap w) = text "EHsWrap" <+> ppr w - ppr (EExpand orig) = text "EExpand" <+> ppr orig + ppr (EPar _) = text "EPar" + ppr (EHsWrap w) = text "EHsWrap" <+> ppr w + ppr (EExpand _ _) = text "EExpand" -- No Outputable instance for HsCtxt yet + + + +{- ********************************************************************* +* * + Splitting and rebuilding +* * +********************************************************************* -} + +splitHsApps :: HsExpr GhcRn -> TcM (HsExpr GhcRn, [HsExprArg 'TcpRn]) +splitHsApps e = go e [] + where + go (HsPar _ (L l fun)) args = go fun (EWrap (EPar l) : args) + go (HsPragE _ p (L l fun)) args = go fun (EPrag l p : args) + go (HsAppType _ (L l fun) ty) args = go fun (mkETypeArg l ty : args) + go (HsApp _ (L l fun) arg) args = go fun (mkEValArg l arg : args) + go fun args = do { mb_hse <- tcExpand fun + ; case mb_hse of + Just (HSE { hse_ctxt = orig, hse_exp = L l fun' }) + -> go fun' (EWrap (EExpand l orig) : args) + Nothing + -> return (fun, args) } + +-- | Rebuild an application: takes a type-checked application head +-- expression together with arguments in the form of typechecked 'HsExprArg's +-- and returns a typechecked application of the head to the arguments. +rebuildHsApps :: HsExpr GhcTc + -- ^ the function being applied + -> [HsExprArg 'TcpTc] + -- ^ the arguments to the function + -> HsExpr GhcTc +rebuildHsApps fun [] = fun +rebuildHsApps fun (arg : args) + = case arg of + EValArg { ea_arg = arg, ea_loc_span = l } + -> rebuildHsApps (HsApp noExtField (L l fun) arg) args + ETypeArg { ea_hs_ty = hs_ty, ea_ty_arg = ty, ea_loc_span = l } + -> rebuildHsApps (HsAppType ty (L l fun) hs_ty) args + EPrag l p + -> rebuildHsApps (HsPragE noExtField p (L l fun)) args + EWrap (EPar l) + -> rebuildHsApps (HsPar noExtField (L l fun)) args + EWrap (EExpand l o) + -> rebuildHsApps (XExpr (ExpandedThingTc (HSE o (L l fun)))) args + EWrap (EHsWrap wrap) + -> rebuildHsApps (mkHsWrap wrap fun) args + {- Note [Desugar OpApp in the typechecker] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Operator sections are desugared in the renamer; see GHC.Rename.Expr +pOperator sections are desugared in the renamer; see GHC.Rename.Expr Note [Handling overloaded and rebindable constructs]. But for reasons explained there, we rename OpApp to OpApp. Then, here in the typechecker, we desugar it to a use of ExpandedThingRn. @@ -401,6 +390,8 @@ handling splices and quasiquotes has already been performed by the renamer by the time we get to `splitHsApps`. Wrinkle (UTS1): +*** TODO *** put this somewhere else + `tcExpr` has a separate case for `HsUntypedSplice`s that do /not/ occur at the head of an application. This is important to handle programs like this one: @@ -446,9 +437,7 @@ tcInferAppHead (fun,fun_lspan) do { mb_tc_fun <- tcInferAppHead_maybe fun ; case mb_tc_fun of Just (fun', fun_sigma) -> return (fun', fun_sigma) - Nothing -> runInferRho (tcExpr fun) - - } + Nothing -> runInferRho (tcExpr fun) } tcInferAppHead_maybe :: HsExpr GhcRn -> TcM (Maybe (HsExpr GhcTc, TcSigmaType)) @@ -457,23 +446,11 @@ tcInferAppHead_maybe :: HsExpr GhcRn -- XExpr's although complicated needs to be looked through, useful for QL things when -- the argument is an XExpr tcInferAppHead_maybe fun = case fun of - HsVar _ nm - -> Just <$> tcInferId nm - ExprWithTySig _ e hs_ty - -> Just <$>tcExprWithSig e hs_ty - HsOverLit _ lit - -> Just <$> tcInferOverLit lit - XExpr (HsRecSelRn f) - -> Just <$> tcInferRecSelId f - XExpr (ExpandedThingRn (HSE o (L loc e))) - -> setSrcSpan (locA loc) $ Just <$> - do { (e', ty) <- tcExprSigma False (hsCtxtCtOrigin o) e - ; return (mkExpandedTc o (L loc e'), ty) } - -- We do not want to instantiate the type of the head as there may be - -- visible type applications in the argument. - -- c.f. T19167 - _ - -> return Nothing + HsVar _ nm -> Just <$> tcInferId nm + ExprWithTySig _ e hs_ty -> Just <$> tcExprWithSig e hs_ty + HsOverLit _ lit -> Just <$> tcInferOverLit lit + XExpr (HsRecSelRn f) -> Just <$> tcInferRecSelId f + _ -> return Nothing {- ********************************************************************* * * ===================================== compiler/GHC/Tc/Gen/Match.hs ===================================== @@ -219,10 +219,10 @@ tcMatches :: (AnnoBody body, Outputable (body GhcTc)) -> MatchGroup GhcRn (LocatedA (body GhcRn)) -> TcM (MatchGroup GhcTc (LocatedA (body GhcTc))) -tcMatches ctxt tc_body pat_tys rhs_ty (MG { mg_alts = L l matches +tcMatches ctxt tc_body pat_tys exp_ty (MG { mg_alts = L l matches , mg_ext = origin }) | null matches -- Deal with case e of {} - -- Since there are no branches, no one else will fill in rhs_ty + -- Since there are no branches, no one else will fill in exp_ty -- when in inference mode, so we must do it ourselves, -- here, using expTypeToType = do { tcEmitBindingUsage bottomUE @@ -233,17 +233,19 @@ tcMatches ctxt tc_body pat_tys rhs_ty (MG { mg_alts = L l matches [ExpForAllPatTy tvb] -> failWithTc $ TcRnEmptyCase ctxt (EmptyCaseForall tvb) [] -> panic "tcMatches: no arguments in EmptyCase" _t1:(_t2:_ts) -> panic "tcMatches: multiple arguments in EmptyCase" - ; rhs_ty <- expTypeToType rhs_ty + ; rhs_ty <- expTypeToType exp_ty ; return (MG { mg_alts = L l [] , mg_ext = MatchGroupTc [pat_ty] rhs_ty origin }) } | otherwise - = do { umatches <- mapM (tcCollectingUsage . tcMatch tc_body pat_tys rhs_ty) matches - ; let (usages, matches') = unzip umatches + = do { let exp_ty' = adjustExpTypeForCaseBranches exp_ty matches + tc_match match = tcCollectingUsage $ + tcMatch tc_body pat_tys exp_ty' match + ; (usages, matches') <- mapAndUnzipM tc_match matches ; tcEmitBindingUsage $ supUEs usages ; pat_tys <- mapM readScaledExpType (filter_out_forall_pat_tys pat_tys) - ; rhs_ty <- readExpType rhs_ty + ; rhs_ty <- readExpType exp_ty ; traceTc "tcMatches" (ppr matches' $$ ppr pat_tys $$ ppr rhs_ty) ; return (MG { mg_alts = L l matches' , mg_ext = MatchGroupTc pat_tys rhs_ty origin ===================================== compiler/GHC/Tc/Utils/TcMType.hs ===================================== @@ -63,7 +63,7 @@ module GHC.Tc.Utils.TcMType ( mkCheckExpType, newInferExpType, newInferExpTypeFRR, runInfer, runInferRho, runInferSigma, runInferKind, runInferRhoFRR, runInferSigmaFRR, readExpType, readExpType_maybe, readScaledExpType, - expTypeToType, scaledExpTypeToType, + expTypeToType, scaledExpTypeToType, adjustExpTypeForCaseBranches, checkingExpType_maybe, checkingExpType, inferResultToType, ensureMonoType, promoteTcType, @@ -499,6 +499,17 @@ inferResultToType (IR { ir_uniq = u, ir_lvl = tc_lvl ; let conc_orig = ConcreteFRR $ FixedRuntimeRepOrigin tau frr ; return tau } +adjustExpTypeForCaseBranches :: ExpRhoType -> [branch] -> ExpRhoType +-- See Note [fillInferResult: multiple branches] +adjustExpTypeForCaseBranches exp_ty branches + = case exp_ty of + Infer ir | IR { ir_inst = IIF_Sigma } <- ir + , branches `lengthAtLeast` 2 + -> Infer (ir { ir_inst = IIF_DeepRho }) + | otherwise + -> exp_ty + Check {} -> exp_ty + {- Note [inferResultToType] ~~~~~~~~~~~~~~~~~~~~~~~~~~~ expTypeToType and inferResultType convert an InferResult to a monotype. ===================================== compiler/GHC/Tc/Utils/Unify.hs ===================================== @@ -99,13 +99,12 @@ import qualified GHC.LanguageExtensions as LangExt import GHC.Builtin.Types import GHC.Types.Name -import GHC.Types.Id( idType, isDataConId ) +import GHC.Types.Id( idType ) import GHC.Types.Var as Var import GHC.Types.Var.Set import GHC.Types.Var.Env import GHC.Types.Basic import GHC.Types.Unique.Set (nonDetEltsUniqSet) -import GHC.Types.SrcLoc (unLoc, GenLocated (..)) import GHC.Utils.Misc import GHC.Utils.Outputable as Outputable @@ -426,7 +425,7 @@ Some examples: tcSkolemiseGeneral :: HasDebugCallStack - => DeepSubsumptionFlag + => DeepSubsumptionFlag -- Ignores the DeepSubsumptionDepth -> UserTypeCtxt -> TcType -> TcType -- top_ty and expected_ty -- Here, top_ty is the type we started to skolemise; used only in SigSkol @@ -1169,7 +1168,7 @@ fillInferResultNoInst act_res_ty (IR { ir_uniq = u ; return final_co } } -fillInferResult :: DeepSubsumptionFlag -> CtOrigin -> TcType -> InferResult -> TcM HsWrapper +fillInferResult :: DeepSubsumptionFlag -> CtOrigin -> TcSigmaType -> InferResult -> TcM HsWrapper -- See Note [Instantiation of InferResult] fillInferResult ds_flag ct_orig res_ty ires@(IR { ir_inst = iif }) = case iif of @@ -1203,7 +1202,7 @@ There are two things to worry about: T1 -> e1 T2 -> e2 -Our typing rules are: +In general our typing rules are: * The RHS of a existential or GADT alternative must always be a monotype, regardless of the number of alternatives. @@ -1218,17 +1217,13 @@ Our typing rules are: We use choice (2) in that Section. (GHC 8.10 and earlier used choice (1).) - But note that - case e of - True -> hr - False -> \x -> hr x - will fail, because we still /infer/ both branches, so the \x will get - a (monotype) unification variable, which will fail to unify with - (forall a. a->a) +Note [fillInferResult: GADTs and existentials] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We can detect the GADT/existential situation, case (1) of Note [fillInferResult], +by seeing that the current TcLevel is greater than that stored in ir_lvl of the +Infer ExpType. We bump the level whenever we go past a GADT/existential match. -For (1) we can detect the GADT/existential situation by seeing that -the current TcLevel is greater than that stored in ir_lvl of the Infer -ExpType. We bump the level whenever we go past a GADT/existential match. +We insist that the RHS has a monotype, regardless of the number of alternatives. Then, before filling the hole use promoteTcType to promote the type to the outer ir_lvl. promoteTcType does this @@ -1239,11 +1234,6 @@ That forces the type to be a monotype (since unification variables can only unify with monotypes); and catches skolem-escapes because the alpha is untouchable until the equality floats out. -For (2), we simply look to see if the hole is filled already. - - if not, we promote (as above) and fill the hole - - if it is filled, we simply unify with the type that is - already there - (FIR1) There is one wrinkle. Suppose we have case e of T1 -> e1 :: (forall a. a->a) -> Int @@ -1258,7 +1248,47 @@ For (2), we simply look to see if the hole is filled already. So if we check G2 second, we still want to emit a constraint that restricts the RHS to be a monotype. This is done by ensureMonoType, and it works by simply generating a constraint (alpha ~ ty), where alpha is a fresh -unification variable. We discard the evidence. + unification variable. We discard the evidence. + +Note [fillInferResult: multiple branches] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If there are multiple case branches, case (2) of Note [fillInferResult] +we simply look to see if the hole is filled already. + - if not, we promote (as above) and fill the hole + - if it is filled, we simply unify with the type that is already there + +But consider + case x of + True -> True + False -> undefined +and suppose we call `tcInferSigma` on this expression, so that the `ir_inst` +field of the expected result type is `IIF_Sigma`. The danger is that we'll +fill the hole with `Bool` (from the `True`) and then reject when we try to +unify that with `forall a. a->a`, from the call to `undefined`. + +Another example: + case x of + True -> (e1 :: forall a b. a->b) + False -> (e3 :: forall b a. a->b) + +To avoid this, we never infer a sigma-type from a multi-branch `case`. Instead +we just zap the `IIF_Sigma` to `IIF_DeepRho` when walking inside the branches +of multi-arm case-expression, or an if-expression. See calls to +`adjustExpTypeForCaseBranches`. + +This does mean that this would work: + (let x = 77+55 in h x x) @Int +where + h :: Int -> Int -> forall a. a->a +The `@Int` would instantiate the `forall a`. + +Note that + case e of + True -> hr + False -> \x -> hr x + where hr :: (forall a. a->a) -> Int +will fail, because we still /infer/ both branches, so the \x will get a +(monotype) unification variable, which will fail to unify with (forall a. a->a) Note [Instantiation of InferResult] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1274,7 +1304,7 @@ Usually this field is `IIF_DeepRho` meaning "return a (possibly deep) rho-type". Why is this the common case? See #17173 for discussion. Here are some examples of why: -1. Consider +(IIR1) Consider f x = (*) We want to instantiate the type of (*) before returning, else we will infer the type @@ -1286,21 +1316,46 @@ of why: instantiating. This could perhaps be worked around, but it may be hard to know even when instantiation should happen. -2. Another reason. Consider +(IIR2) Another reason. Consider f :: (?x :: Int) => a -> a g y = let ?x = 3::Int in f Here want to instantiate f's type so that the ?x::Int constraint gets discharged by the enclosing implicit-parameter binding. -3. Suppose one defines plus = (+). If we instantiate lazily, we will +(IIR3) Suppose one defines plus = (+). If we instantiate lazily, we will infer plus :: forall a. Num a => a -> a -> a. However, the monomorphism restriction compels us to infer plus :: Integer -> Integer -> Integer (or similar monotype). Indeed, the only way to know whether to apply the monomorphism restriction at all is to instantiate -HOWEVER, not always! Here are places where we want `IIF_Sigma` meaning -"return a sigma-type": +(IIR4) When -XDeepSubsumption is on, we /deeply/ instantiate. Why isn't + top-instantiation enough? Answer: to accept the following program (T26225b) with + -XDeepSubsumption, we need to deeply instantiate when inferring in checkResultTy: + + f :: Int -> (forall a. a->a) + g :: Int -> Bool -> Bool + + test b = case b of + True -> f + False -> g + + If we don't deeply instantiate in the branches of the case expression, we will + try to unify the type of `f` with that of `g`, which fails. If we instead + deeply instantiate `f`, we will fill the `InferResult` with `Int -> alpha -> alpha` + which then successfully unifies with the type of `g` when we come to fill the + `InferResult` hole a second time for the second case branch. + +(IIR5) When inferring, even /without/ -XDeepSubsumption, we must deeply instantiate + the types of data constructors. E.g + data T = MkT Int int + f = MkT 3 + We must infer MkT 3 :: Int ->{mu} T (fresh mu) + and not MkT 3 :: Int ->{one} T + See Note [Typechecking data constructors] in GHC.Tc.Gen.Head + Hence the use of `getDeepSubsumptionFlag_DataConHead` in `checkResultTy`. + +HOWEVER, `ir_inst` is not always `IIF_DeepRho`! Here are places when it isn't: * IIF_Sigma: In GHC.Tc.Module.tcRnExpr, which implements GHCi's :type command, we want to return a completely uninstantiated type. @@ -1316,23 +1371,6 @@ HOWEVER, not always! Here are places where we want `IIF_Sigma` meaning but /not/ deeply instantiate (#26331). See Note [View patterns and polymorphism] in GHC.Tc.Gen.Pat. This the only place we use IIF_ShallowRho. -Why do we want to deeply instantiate, ever? Why isn't top-instantiation enough? -Answer: to accept the following program (T26225b) with -XDeepSubsumption, we -need to deeply instantiate when inferring in checkResultTy: - - f :: Int -> (forall a. a->a) - g :: Int -> Bool -> Bool - - test b = - case b of - True -> f - False -> g - -If we don't deeply instantiate in the branches of the case expression, we will -try to unify the type of 'f' with that of 'g', which fails. If we instead -deeply instantiate 'f', we will fill the 'InferResult' with 'Int -> alpha -> alpha' -which then successfully unifies with the type of 'g' when we come to fill the -'InferResult' hole a second time for the second case branch. -} {- @@ -2068,24 +2106,14 @@ getDeepSubsumptionFlag = -- | Variant of 'getDeepSubsumptionFlag' which enables a top-level subsumption -- in order to implement the plan of Note [Typechecking data constructors]. getDeepSubsumptionFlag_DataConHead :: HsExpr GhcTc -> TcM DeepSubsumptionFlag -getDeepSubsumptionFlag_DataConHead app_head = - do { user_ds <- xoptM LangExt.DeepSubsumption - ; traceTc "getDeepSubsumptionFlag_DataConHead" (ppr app_head) - ; return $ - if | user_ds - -> Deep DeepSub - | otherwise - -> go app_head - } +getDeepSubsumptionFlag_DataConHead app_head + = do { user_ds <- xoptM LangExt.DeepSubsumption + ; return $ if | user_ds -> Deep DeepSub + | dc_head app_head -> Deep TopSub + | otherwise -> Shallow } where - go :: HsExpr GhcTc -> DeepSubsumptionFlag - go (XExpr (ConLikeTc (RealDataCon {}))) = Deep TopSub - go (XExpr (ExpandedThingTc (HSE _ (L _ f)))) = go f - go (XExpr (WrapExpr _ f)) = go f - go (HsApp _ f _) = go (unLoc f) - go (HsAppType _ f _) = go (unLoc f) - go _ = Shallow - + dc_head (XExpr (ConLikeTc (RealDataCon {}))) = True + dc_head _ = False -- | 'tc_sub_type_deep' is where the actual work happens for deep subsumption. -- ===================================== compiler/ghc.cabal.in ===================================== @@ -832,6 +832,7 @@ Library GHC.Tc.Gen.Bind GHC.Tc.Gen.Default GHC.Tc.Gen.Do + GHC.Tc.Gen.Expand GHC.Tc.Gen.Export GHC.Tc.Gen.Expr GHC.Tc.Gen.Foreign ===================================== testsuite/tests/partial-sigs/should_compile/SplicesUsed.stderr ===================================== @@ -1,6 +1,5 @@ [1 of 2] Compiling Splices ( Splices.hs, Splices.o ) [2 of 2] Compiling SplicesUsed ( SplicesUsed.hs, SplicesUsed.o ) - SplicesUsed.hs:7:15: warning: [GHC-88464] [-Wpartial-type-signatures (in -Wdefault)] • Found type wildcard ‘_’ standing for ‘Maybe Bool’ • In the type signature: maybeBool :: _ @@ -21,8 +20,7 @@ SplicesUsed.hs:8:26: warning: [GHC-88464] [-Wpartial-type-signatures (in -Wdefau • Found type wildcard ‘_’ standing for ‘Bool’ • In the first argument of ‘Maybe’, namely ‘_’ In an expression type signature: Maybe _ - In the first argument of ‘id :: _a -> _a’, namely - ‘(Just True :: Maybe _)’ + In the expression: Just True :: Maybe _ • Relevant bindings include maybeBool :: Maybe Bool (bound at SplicesUsed.hs:8:1) @@ -78,3 +76,4 @@ SplicesUsed.hs:18:2: warning: [GHC-88464] [-Wpartial-type-signatures (in -Wdefau the inferred type of bar :: Bool -> w -> (Bool, w) at SplicesUsed.hs:18:2-11 • In the type signature: bar :: _a -> _b -> (_a, _b) + View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a091fcbb975d514542e66e4d456bb99f... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a091fcbb975d514542e66e4d456bb99f... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Apoorv Ingle (@ani)