Apoorv Ingle pushed to branch wip/spj-apporv-Oct24 at Glasgow Haskell Compiler / GHC
Commits:
-
abc37a34
by Apoorv Ingle at 2026-03-30T21:29:37-05:00
6 changed files:
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/App.hs-boot
- compiler/GHC/Tc/Gen/Do.hs
- compiler/GHC/Tc/Gen/Head.hs
- compiler/GHC/Tc/Types/LclEnv.hs
- compiler/GHC/Tc/Utils/Unify.hs
Changes:
| ... | ... | @@ -171,14 +171,90 @@ Note [Instantiation variables are short lived] |
| 171 | 171 | * *
|
| 172 | 172 | ********************************************************************* -}
|
| 173 | 173 | |
| 174 | +{- Note [splitHsApps, XExpr and tcExprSigma]
|
|
| 175 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 176 | + |
|
| 177 | +This implementation is WIP and is subject to change once MR!15811 is figured out
|
|
| 178 | + |
|
| 179 | +To simplify the implementation of `splitHsApps`, we do not look through
|
|
| 180 | +XExpr's, however, we still need to deal with cases such as:
|
|
| 181 | + |
|
| 182 | + (XExpr (ExpandedThingRn f1 (f `HsApp` e1))) `HsApp` e2 `HsApp` e3
|
|
| 183 | + |
|
| 184 | +Otherwise stuff like overloaded labels (#19154) won't work.
|
|
| 185 | + |
|
| 186 | +How do we do it?
|
|
| 187 | + |
|
| 188 | +`splitHsApps` peals off the arguments until it hits an XExpr
|
|
| 189 | +From above example,
|
|
| 190 | + |
|
| 191 | + splitHsApps ((XExpr (ExpandedThingRn f1 (f `HsApp` e1))) `HsApp` e2 `HsApp` e3)
|
|
| 192 | + = { head = XExpr (ExpandedThingRn f1 (f `HsApp` e1))
|
|
| 193 | + , args = [e3, e2] -- NB: arguments are in the reverse order
|
|
| 194 | + }
|
|
| 195 | + |
|
| 196 | +Now, we infer the type of head using tcInferAppHead/tcInferAppHead_maybe.
|
|
| 197 | +Which calls `tcExprSigma` on the XExpr. It performs a mini-`tcApp`
|
|
| 198 | +where it uses the CtOrigin obtained from f1, splits the application chain: f `HsApp` e1.
|
|
| 199 | +and finally returns an uninstantiated sigma type and a typechecked expression
|
|
| 200 | + |
|
| 201 | +It is crucial for tcExprSigma to return an uninstantiated type so that visible type
|
|
| 202 | +applications with rebindable syntax works fine. Eg. T19167
|
|
| 203 | + |
|
| 204 | + |
|
| 205 | + fromListN :: Int -> [elt] -> (forall list. (IsList list, elt ~ Item list) => list)
|
|
| 206 | + fromListN n l = Predule.fromListN n l
|
|
| 207 | + |
|
| 208 | + shouldBeANonEmpty = ['x', 'y', 'z'] @(NonEmpty Char)
|
|
| 209 | + |
|
| 210 | +here the RHS of `shouldBeNonEmpty` is expanded to
|
|
| 211 | + (XExpr (ExpandedThingRn (['x', 'y', 'z']) (fromListN 3 ['x', 'y', 'z']) `HsTypeApp` (NonEmpty Char)
|
|
| 212 | + |
|
| 213 | +Now, if we were to instantiate the head of the expression, we will
|
|
| 214 | +fail to typecheck the expression as the type `NonEmpty Char`.
|
|
| 215 | + |
|
| 216 | + |
|
| 217 | +Wrinkle [DeepSubsumption Flag and Multiplicity]
|
|
| 218 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 219 | + |
|
| 220 | +Consider the expression:
|
|
| 221 | + |
|
| 222 | + (1 :) $ [2, 3]
|
|
| 223 | + |
|
| 224 | +Here, the head of the expression is ($) and it is applied to two arguments
|
|
| 225 | + Arg1 = (1 :)
|
|
| 226 | + Arg2 = [2, 3]
|
|
| 227 | + |
|
| 228 | +Arg1 is an expanded expression as it is a left section wrapped with parenthesis
|
|
| 229 | + |
|
| 230 | + Arg1 = HsPar (XExpr (ExpandedThingRn (HSE (1 :) ((:) 1))))
|
|
| 231 | + |
|
| 232 | +As `($)` is the head of the application chain, we perform QuickLook on the arguments
|
|
| 233 | +in `tcInstFun`. See Note [Quick Look for particular Ids] and Note [tcApp: typechecking applications].
|
|
| 234 | + |
|
| 235 | +Thus, Arg1 will be transformed into
|
|
| 236 | + |
|
| 237 | + EValArgQL { eaql_tc_head = XExpr (ExpandedThingRn (HSE { hs_ctxt = 1 : , hs_expr = ((:) 1))))
|
|
| 238 | + , eaql_arg_ty = [alpha] %1 -> [beta]
|
|
| 239 | + , eqql_args = [EPar] }
|
|
| 240 | + |
|
| 241 | +Now, in `tcValArg` Arg1 is expected to have type [Int] -> [Int],
|
|
| 242 | +and according to Note [Typechecking data constructors], we ought to be able to
|
|
| 243 | +coerce the type [alpha] %1 -> [beta] into type [Int] -> [Int] in `checkResultTy`
|
|
| 244 | +because the "actual" head of Arg1 is (:), thus we need to traverse eaql_tc_head.
|
|
| 245 | + |
|
| 246 | +The hope is that future refactoring simplifies this delicate and complicated process.
|
|
| 247 | + |
|
| 248 | +-}
|
|
| 174 | 249 | -- Very similar to tcApp, but returns a sigma (uninstantiated) type
|
| 175 | 250 | -- CAUTION: Any changes to tcApp should be reflected here
|
| 176 | 251 | -- cf. T19167. the head is an expanded expression applied to a type
|
| 177 | 252 | -- Caution: Currently we assume that the expression is compiler generated/expanded
|
| 178 | 253 | -- Because that is what T19167 test case expects.
|
| 179 | 254 | -- This function should go away after MR!15778 lands
|
| 180 | -tcExprSigma :: Bool -> CtOrigin -> HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType)
|
|
| 181 | -tcExprSigma inst fun_orig rn_expr
|
|
| 255 | +-- See Note [splitHsApps, XExpr and tcExprSigma]
|
|
| 256 | +tcExprSigma :: CtOrigin -> HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType)
|
|
| 257 | +tcExprSigma fun_orig rn_expr
|
|
| 182 | 258 | = do { (fun@(rn_fun,fun_lspan), rn_args) <- splitHsApps rn_expr
|
| 183 | 259 | ; do_ql <- wantQuickLook rn_fun
|
| 184 | 260 | ; (tc_fun, fun_sigma) <- tcInferAppHead fun
|
| ... | ... | @@ -186,7 +262,7 @@ tcExprSigma inst fun_orig rn_expr |
| 186 | 262 | ; traceTc "tcExprSigma" (vcat [ text "rn_expr:" <+> ppr rn_expr
|
| 187 | 263 | , text "tc_fun" <+> ppr tc_fun
|
| 188 | 264 | , text "inGeneratedCode:" <+> ppr inGenCode])
|
| 189 | - ; (inst_args, app_res_sigma) <- tcInstFun do_ql inst (fun_orig, rn_fun, fun_lspan)
|
|
| 265 | + ; (inst_args, app_res_sigma) <- tcInstFun do_ql False (fun_orig, rn_fun, fun_lspan)
|
|
| 190 | 266 | tc_fun fun_sigma rn_args
|
| 191 | 267 | ; tc_args <- tcValArgs do_ql (rn_fun, fun_lspan) inst_args
|
| 192 | 268 | ; let tc_expr = rebuildHsApps (tc_fun, fun_lspan) tc_args
|
| ... | ... | @@ -7,6 +7,4 @@ import GHC.Tc.Utils.TcType ( TcSigmaType ) |
| 7 | 7 | import GHC.Hs.Extension ( GhcRn, GhcTc )
|
| 8 | 8 | |
| 9 | 9 | |
| 10 | -import GHC.Prelude (Bool)
|
|
| 11 | - |
|
| 12 | -tcExprSigma :: Bool -> CtOrigin -> HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) |
|
| 10 | +tcExprSigma :: CtOrigin -> HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) |
| ... | ... | @@ -383,7 +383,7 @@ The `fail`-block wrapping is done by `GHC.Tc.Gen.Do.mk_failable_expr`. |
| 383 | 383 | * _Wrinkle 2_: The call to `fail` will give rise to a `MonadFail` constraint. What `CtOrigin` do we
|
| 384 | 384 | attach to that constraint? When the `MonadFail` constraint can't be solved, it'll show up in error
|
| 385 | 385 | messages and it needs to be a good location. Ideally, it should identify the
|
| 386 | - pattern `p`. Hence, we wrap the `fail` alternative expression with a `ExpandedPat`
|
|
| 386 | + pattern `p`. Hence, we wrap the `fail` alternative expression with a `ExpandedPatRn`
|
|
| 387 | 387 | that tags the fail expression with the failable pattern. (See testcase MonadFailErrors.hs)
|
| 388 | 388 | |
| 389 | 389 | Part 2. Generate warnings for discarded body statement results
|
| ... | ... | @@ -412,7 +412,7 @@ Part 3. Blaming Offending Source Code and Generating Appropriate Error Messages |
| 412 | 412 | To ensure we correctly track source of the offending user written source code,
|
| 413 | 413 | in this case the `do`-statement, we need to keep track of
|
| 414 | 414 | which source statement's expansion the typechecker is currently typechecking.
|
| 415 | -For this purpose we use the `XXExprGhcRn.ExpansionRn`.
|
|
| 415 | +For this purpose we use the `XXExprGhcRn.ExpandedThingRn`.
|
|
| 416 | 416 | It stores the original statement (with location) and the expanded expression
|
| 417 | 417 | |
| 418 | 418 | A. Expanding Body Statements
|
| ... | ... | @@ -453,7 +453,7 @@ It stores the original statement (with location) and the expanded expression |
| 453 | 453 | This popping is implicitly done when we push the error context message for the next statment.
|
| 454 | 454 | See `LclEnv.setLclCtxtHsCtxt`
|
| 455 | 455 | |
| 456 | - Sans the popping business for error context stack,
|
|
| 456 | + Sans the implicit overwriting business for error context stack,
|
|
| 457 | 457 | if there were to be a type error in `e2`, we would get a spurious and confusing error message
|
| 458 | 458 | which mentions "In the stmt of a do block e1" along with the message
|
| 459 | 459 | "In the stmt of a do block e2".
|
| ... | ... | @@ -144,7 +144,7 @@ takes apart either an HsApp, or an infix OpApp, returning |
| 144 | 144 | innermost un-expanded head as the "error head".
|
| 145 | 145 | |
| 146 | 146 | * A list of HsExprArg, the arguments
|
| 147 | -* We do not look through expanded expressions (except PopErrCtxt.)
|
|
| 147 | +* We do not look through expanded expressions (`XExpr`s)
|
|
| 148 | 148 | -}
|
| 149 | 149 | |
| 150 | 150 | data TcPass = TcpRn -- Arguments decomposed
|
| ... | ... | @@ -349,29 +349,6 @@ That makes it possible to typecheck something like |
| 349 | 349 | where
|
| 350 | 350 | f :: forall a. t1 -> forall b. t2 -> t3
|
| 351 | 351 | |
| 352 | -Note [Looking through ExpandedThingRn]
|
|
| 353 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 354 | -When creating an application chain in splitHsApps, we must deal with
|
|
| 355 | - ExpandedThingRn f1 (f `HsApp` e1) `HsApp` e2 `HsApp` e3
|
|
| 356 | - |
|
| 357 | -as a single application chain `f e1 e2 e3`. Otherwise stuff like overloaded
|
|
| 358 | -labels (#19154) won't work.
|
|
| 359 | - |
|
| 360 | -It's easy to achieve this: `splitHsApps` unwraps `ExpandedThingRn`.
|
|
| 361 | - |
|
| 362 | -In order to be able to more accurately reconstruct the original `SrcSpan`s
|
|
| 363 | -from the renamer in `rebuildHsApps`, we also have to track the `SrcSpan`
|
|
| 364 | -of the current application in `VAExpansion` when unwrapping `ExpandedThingRn`
|
|
| 365 | -in `splitHsApps`, just as we track it in a non-expanded expression.
|
|
| 366 | - |
|
| 367 | -Previously, `rebuildHsApps` substituted the location of the original
|
|
| 368 | -expression as given by `splitHsApps` for this. As a result, the application
|
|
| 369 | -head in expanded expressions, e.g. the call to `fromListN`, would either
|
|
| 370 | -have `noSrcSpan` set as its location post-typecheck, or get the location
|
|
| 371 | -of the original expression, depending on whether the `XExpr` given to
|
|
| 372 | -`splitHsApps` is in the outermost layer. The span it got in the renamer
|
|
| 373 | -would always be discarded, causing #23120.
|
|
| 374 | - |
|
| 375 | 352 | Note [Looking through Template Haskell splices in splitHsApps]
|
| 376 | 353 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 377 | 354 | When typechecking an application, we must look through untyped TH splices in
|
| ... | ... | @@ -467,7 +444,7 @@ tcInferAppHead_maybe fun = case fun of |
| 467 | 444 | -> Just <$> tcInferRecSelId f
|
| 468 | 445 | XExpr (ExpandedThingRn (HSE o (L loc e)))
|
| 469 | 446 | -> setSrcSpan (locA loc) $ Just <$>
|
| 470 | - do { (e', ty) <- tcExprSigma False (hsCtxtCtOrigin o) e
|
|
| 447 | + do { (e', ty) <- tcExprSigma (hsCtxtCtOrigin o) e
|
|
| 471 | 448 | ; return (mkExpandedTc o (L loc e'), ty) }
|
| 472 | 449 | -- We do not want to instantiate the type of the head as there may be
|
| 473 | 450 | -- visible type applications in the argument.
|
| ... | ... | @@ -173,6 +173,7 @@ setLclEnvHsCtxt ec = modifyLclCtxt (setLclCtxtHsCtxt ec) |
| 173 | 173 | setLclCtxtHsCtxt :: HsCtxt -> TcLclCtxt -> TcLclCtxt
|
| 174 | 174 | setLclCtxtHsCtxt ec lclCtxt
|
| 175 | 175 | -- Never stack 2 do statement error messages on top of each other
|
| 176 | + -- See Part 3 A of Note [Expanding HsDo with XXExprGhcRn] in `GHC.Tc.Gen.Do`
|
|
| 176 | 177 | | StmtErrCtxt{} : ecs <- tcl_err_ctxt lclCtxt
|
| 177 | 178 | , StmtErrCtxt{} <- ec
|
| 178 | 179 | = lclCtxt { tcl_err_ctxt = ec : ecs }
|
| ... | ... | @@ -2078,6 +2078,9 @@ getDeepSubsumptionFlag_DataConHead app_head = |
| 2078 | 2078 | -> go app_head
|
| 2079 | 2079 | }
|
| 2080 | 2080 | where
|
| 2081 | + -- Why do we look through ExpandedThingTc and HsApps?
|
|
| 2082 | + -- See Wrinkle [DeepSubsumption Flag and Multiplicity] in
|
|
| 2083 | + -- Note [splitHsApps, XExpr and tcExprSigma]
|
|
| 2081 | 2084 | go :: HsExpr GhcTc -> DeepSubsumptionFlag
|
| 2082 | 2085 | go (XExpr (ConLikeTc (RealDataCon {}))) = Deep TopSub
|
| 2083 | 2086 | go (XExpr (ExpandedThingTc (HSE _ (L _ f)))) = go f
|