Apoorv Ingle pushed to branch wip/spj-apporv-Oct24 at Glasgow Haskell Compiler / GHC

Commits:

6 changed files:

Changes:

  • compiler/GHC/Tc/Gen/App.hs
    ... ... @@ -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
    

  • compiler/GHC/Tc/Gen/App.hs-boot
    ... ... @@ -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)

  • compiler/GHC/Tc/Gen/Do.hs
    ... ... @@ -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".
    

  • compiler/GHC/Tc/Gen/Head.hs
    ... ... @@ -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.
    

  • compiler/GHC/Tc/Types/LclEnv.hs
    ... ... @@ -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 }
    

  • compiler/GHC/Tc/Utils/Unify.hs
    ... ... @@ -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