Simon Peyton Jones pushed to branch wip/T24464 at Glasgow Haskell Compiler / GHC
Commits:
-
02fa9d82
by Simon Peyton Jones at 2026-01-17T23:37:42+00:00
-
726ae4c7
by Simon Peyton Jones at 2026-01-17T23:38:31+00:00
-
7050a884
by Simon Peyton Jones at 2026-01-17T23:39:10+00:00
-
495e99fa
by Simon Peyton Jones at 2026-01-18T00:13:10+00:00
11 changed files:
- compiler/GHC/CoreToStg/AddImplicitBinds.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/Iface/Tidy/StaticPtrTable.hs
- compiler/GHC/Tc/Gen/Bind.hs
- compiler/GHC/Tc/Utils/Env.hs
- compiler/GHC/Types/Id/Make.hs
- testsuite/tests/codeGen/should_run/CgStaticPointers.hs
- testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
- testsuite/tests/warnings/should_fail/CaretDiagnostics1.stderr
Changes:
| ... | ... | @@ -98,7 +98,6 @@ addImplicitBinds pgm_cfg mod_loc tycons binds |
| 98 | 98 | |
| 99 | 99 | mkImplicitBinds :: Bool -> ModLocation -> TyCon -> [CoreBind]
|
| 100 | 100 | -- See Note [Data constructor workers]
|
| 101 | --- c.f. Note [Injecting implicit bindings] in GHC.Iface.Tidy
|
|
| 102 | 101 | mkImplicitBinds gen_debug_info mod_loc tycon
|
| 103 | 102 | = classop_binds ++ datacon_binds
|
| 104 | 103 | where
|
| ... | ... | @@ -180,7 +180,8 @@ ds_val_bind dflags (NonRecursive, hsbinds) body |
| 180 | 180 | ; let rhs' = mkOptTickBox rhs_tick rhs_expr
|
| 181 | 181 | ; let body_ty = exprType body
|
| 182 | 182 | ; let mult = getTcMultAnn mult_ann
|
| 183 | - ; error_expr <- mkErrorAppDs pAT_ERROR_ID body_ty (ppr pat')
|
|
| 183 | + ; error_expr <- mkErrorAppDs pAT_ERROR_ID body_ty (ppr pat)
|
|
| 184 | + -- Show the original user-written `pat` in error msg
|
|
| 184 | 185 | ; matchSimply rhs' PatBindRhs mult pat' body error_expr }
|
| 185 | 186 | -- This is the one place where matchSimply is given a non-ManyTy
|
| 186 | 187 | -- multiplicity argument.
|
| ... | ... | @@ -432,7 +432,7 @@ tidyProgram opts (ModGuts { mg_module = mod |
| 432 | 432 | --
|
| 433 | 433 | -- See Note [Don't attempt to trim data types]
|
| 434 | 434 | final_ids = [ trimId (opt_trim_ids opts) id
|
| 435 | - | id <- bindersOfBinds tidy_binds
|
|
| 435 | + | id <- bindersOfBinds tidy_binds'
|
|
| 436 | 436 | , isExternalName (idName id)
|
| 437 | 437 | , not (isWiredIn id)
|
| 438 | 438 | ] -- See Note [Drop wired-in things]
|
| ... | ... | @@ -443,9 +443,6 @@ tidyProgram opts (ModGuts { mg_module = mod |
| 443 | 443 | tidy_cls_insts = mkFinalClsInsts tidy_type_env $ mkInstEnv cls_insts
|
| 444 | 444 | tidy_rules = tidyRules tidy_env trimmed_rules
|
| 445 | 445 | |
| 446 | - -- See Note [Injecting implicit bindings]
|
|
| 447 | - all_tidy_binds = tidy_binds'
|
|
| 448 | - |
|
| 449 | 446 | -- Get the TyCons to generate code for. Careful! We must use
|
| 450 | 447 | -- the untidied TyCons here, because we need
|
| 451 | 448 | -- (a) implicit TyCons arising from types and classes defined
|
| ... | ... | @@ -458,13 +455,13 @@ tidyProgram opts (ModGuts { mg_module = mod |
| 458 | 455 | |
| 459 | 456 | local_ccs
|
| 460 | 457 | | opt_collect_ccs opts
|
| 461 | - = collectCostCentres mod all_tidy_binds tidy_rules
|
|
| 458 | + = collectCostCentres mod tidy_binds' tidy_rules
|
|
| 462 | 459 | | otherwise
|
| 463 | 460 | = S.empty
|
| 464 | 461 | |
| 465 | 462 | return (CgGuts { cg_module = mod
|
| 466 | 463 | , cg_tycons = alg_tycons
|
| 467 | - , cg_binds = all_tidy_binds
|
|
| 464 | + , cg_binds = tidy_binds'
|
|
| 468 | 465 | , cg_ccs = S.toList local_ccs
|
| 469 | 466 | , cg_foreign = all_foreign_stubs
|
| 470 | 467 | , cg_foreign_files = foreign_files
|
| ... | ... | @@ -80,20 +80,30 @@ Here is a running example: |
| 80 | 80 | static form wouldn't be closed because the Show dictionary would come from
|
| 81 | 81 | g's context instead of coming from the top level.
|
| 82 | 82 | |
| 83 | -(SF4) The desugarer replaces the static form with a top-level binding for
|
|
| 84 | - an application of the function 'makeStatic' (defined in module
|
|
| 83 | +(SF4) The desugarer replaces a nested expression (static e) with a top-level
|
|
| 84 | + binding for an application of the function 'makeStatic' (defined in module
|
|
| 85 | 85 | GHC.StaticPtr.Internal of base). So we get
|
| 86 | 86 | |
| 87 | - s = fromStaticPtr (makeStatic location k)
|
|
| 88 | - f x = ...s...
|
|
| 87 | + s = /\abc. makeStatic location e
|
|
| 88 | + f x = ...(fromStaticPtr s)...
|
|
| 89 | + |
|
| 90 | + The new Id `s` is marked Exported so that it won't be inlined, even though
|
|
| 91 | + it is only mentioned once.
|
|
| 89 | 92 | |
| 90 | 93 | (SF6) The CoreTidy pass, specifically `sptCreateStaticBinds`, replaces all
|
| 91 | 94 | bindings of the form
|
| 92 | - b = /\ ... -> makeStatic location value
|
|
| 95 | + s = /\ ... -> makeStatic location value
|
|
| 93 | 96 | with
|
| 94 | - b = /\ ... -> StaticPtr key (StaticPtrInfo "pkg key" "module" location) value
|
|
| 97 | + s = /\ ... -> StaticPtr key
|
|
| 98 | + (StaticPtrInfo "pkg key" "module" location)
|
|
| 99 | + value
|
|
| 95 | 100 | where a distinct key is generated for each binding.
|
| 96 | 101 | |
| 102 | + We also zap s's unfolding (if any) because we are changing the RHS; and
|
|
| 103 | + we don't particularly want client modules to see s's implementation.
|
|
| 104 | + (That would be possibly, with a little bit more footwork; e.g. maybe
|
|
| 105 | + it'd be better to do this key-generation step in the desugarer.)
|
|
| 106 | + |
|
| 97 | 107 | (SF7) If we are compiling to object code we insert a C stub (generated by
|
| 98 | 108 | `sptModuleInitCode`) into the final object which runs when the module is loaded,
|
| 99 | 109 | inserting the static forms defined by the module into the RTS's static pointer
|
| ... | ... | @@ -154,7 +164,8 @@ data StaticPtrOpts = StaticPtrOpts |
| 154 | 164 | -- pointer table.
|
| 155 | 165 | --
|
| 156 | 166 | -- See (SF6) in Note [Grand plan for static forms]
|
| 157 | -sptCreateStaticBinds :: StaticPtrOpts -> Module -> CoreProgram -> IO ([SptEntry], Maybe CStub, CoreProgram)
|
|
| 167 | +sptCreateStaticBinds :: StaticPtrOpts -> Module -> CoreProgram
|
|
| 168 | + -> IO ([SptEntry], Maybe CStub, CoreProgram)
|
|
| 158 | 169 | sptCreateStaticBinds opts this_mod binds = do
|
| 159 | 170 | (fps, binds') <- evalStateT (go [] [] binds) 0
|
| 160 | 171 | let cstub
|
| ... | ... | @@ -186,7 +197,11 @@ sptCreateStaticBinds opts this_mod binds = do |
| 186 | 197 | Nothing -> return (Nothing, (b, e))
|
| 187 | 198 | Just (_, t, info, arg) -> do
|
| 188 | 199 | (fp, e') <- mkStaticBind t info arg
|
| 189 | - return (Just (SptEntry (idName b) fp), (b, foldr Lam e' tvs))
|
|
| 200 | + let b' = zapIdUnfolding b
|
|
| 201 | + -- zapIdUnfolding: we are changing the RHS!
|
|
| 202 | + -- And we don't particularly want importing clients
|
|
| 203 | + -- to see the unfolding anyway
|
|
| 204 | + return (Just (SptEntry (idName b) fp), (b', foldr Lam e' tvs))
|
|
| 190 | 205 | |
| 191 | 206 | mkStaticBind :: Type -> CoreExpr -> CoreExpr
|
| 192 | 207 | -> StateT Int IO (Fingerprint, CoreExpr)
|
| ... | ... | @@ -1798,7 +1798,9 @@ instance Outputable GeneralisationPlan where |
| 1798 | 1798 | ppr (CheckGen _ s) = text "CheckGen" <+> ppr s
|
| 1799 | 1799 | |
| 1800 | 1800 | decideGeneralisationPlan
|
| 1801 | - :: DynFlags -> TopLevelFlag -> ClosedTypeId -> TcSigFun
|
|
| 1801 | + :: DynFlags -> TopLevelFlag
|
|
| 1802 | + -> ClosedTypeId -- True <=> all the free vars have closed types
|
|
| 1803 | + -> TcSigFun
|
|
| 1802 | 1804 | -> [LHsBind GhcRn] -> GeneralisationPlan
|
| 1803 | 1805 | decideGeneralisationPlan dflags top_lvl closed_type sig_fn lbinds
|
| 1804 | 1806 | | Just (bind, sig) <- one_funbind_with_sig = CheckGen bind sig
|
| ... | ... | @@ -1812,7 +1814,7 @@ decideGeneralisationPlan dflags top_lvl closed_type sig_fn lbinds |
| 1812 | 1814 | -- types (see #25428). So we don't force it.
|
| 1813 | 1815 | -- See (NVP5) in Note [Non-variable pattern bindings aren't linear] in GHC.Tc.Gen.Bind.
|
| 1814 | 1816 | |
| 1815 | - | isTopLevel top_lvl = True
|
|
| 1817 | + | isTopLevel top_lvl = True
|
|
| 1816 | 1818 | -- See Note [Always generalise top-level bindings]
|
| 1817 | 1819 | |
| 1818 | 1820 | | has_mult_anns_and_pats = False
|
| ... | ... | @@ -117,7 +117,7 @@ import GHC.Utils.Misc ( HasDebugCallStack ) |
| 117 | 117 | |
| 118 | 118 | import GHC.Data.FastString
|
| 119 | 119 | import GHC.Data.List.SetOps
|
| 120 | -import GHC.Data.Maybe( MaybeErr(..), maybeToList, fromMaybe )
|
|
| 120 | +import GHC.Data.Maybe( MaybeErr(..), maybeToList, fromMaybe, isNothing )
|
|
| 121 | 121 | |
| 122 | 122 | import GHC.Types.SrcLoc
|
| 123 | 123 | import GHC.Types.Basic hiding( SuccessFlag(..) )
|
| ... | ... | @@ -677,7 +677,8 @@ tcExtendNameTyVarEnv binds thing_inside |
| 677 | 677 | |
| 678 | 678 | isTypeClosedLetBndr :: Id -> Bool
|
| 679 | 679 | -- See Note [Bindings with closed types: ClosedTypeId] in GHC.Tc.Types
|
| 680 | -isTypeClosedLetBndr = noFreeVarsOfType . idType
|
|
| 680 | +isTypeClosedLetBndr id
|
|
| 681 | + = noFreeVarsOfType (idType id)
|
|
| 681 | 682 | |
| 682 | 683 | tcExtendRecIds :: [(Name, TcId)] -> TcM a -> TcM a
|
| 683 | 684 | -- Used for binding the recursive uses of Ids in a binding
|
| ... | ... | @@ -712,11 +713,18 @@ tcExtendLetEnv :: TopLevelFlag -> TcSigFun -> ClosedTypeId |
| 712 | 713 | -- Used for both top-level value bindings and nested let/where-bindings
|
| 713 | 714 | -- Used for a single NonRec or a single Rec
|
| 714 | 715 | -- Adds to the TcBinderStack too
|
| 715 | -tcExtendLetEnv top_lvl _sig_fn closed ids thing_inside
|
|
| 716 | +-- Note (ELE) For Ids that are in `sig_fn` we have /already/ extended the env,
|
|
| 717 | +-- using `tcExtendSigIds`, so no point in doing so again. Moreover, for
|
|
| 718 | +-- those Ids, we want closed-ness to be driven entirely by the signature,
|
|
| 719 | +-- and not by the free vars (which are embodied in `closed`.
|
|
| 720 | +tcExtendLetEnv top_lvl sig_fn closed ids thing_inside
|
|
| 716 | 721 | = tcExtendBinderStack [TcIdBndr id top_lvl | Scaled _ id <- ids] $
|
| 717 | 722 | tc_extend_local_env top_lvl
|
| 718 | - [ (idName id, ATcId { tct_id = id, tct_info = LetBound closed })
|
|
| 719 | - | Scaled _ id <- ids ] $
|
|
| 723 | + [ (id_nm, ATcId { tct_id = id, tct_info = LetBound closed })
|
|
| 724 | + | Scaled _ id <- ids
|
|
| 725 | + , let id_nm = idName id
|
|
| 726 | + , isNothing (sig_fn id_nm) -- See (ELE) above
|
|
| 727 | + ] $
|
|
| 720 | 728 | foldr check_one_usg thing_inside ids
|
| 721 | 729 | where
|
| 722 | 730 | check_one_usg (Scaled mult id) thing_inside
|
| ... | ... | @@ -916,8 +916,8 @@ mkDataConRep dc_bang_opts fam_envs wrap_name data_con |
| 916 | 916 | (rep_tys, rep_strs) = unzip (concat rep_tys_w_strs)
|
| 917 | 917 | |
| 918 | 918 | -- This is True if the data constructor or class dictionary constructor
|
| 919 | - -- needs a wrapper. This wrapper is injected into the program later in the
|
|
| 920 | - -- CoreTidy pass. See Note [Injecting implicit bindings] in GHC.Iface.Tidy,
|
|
| 919 | + -- needs a wrapper. This wrapper is injected into the program later in the CoreTidy
|
|
| 920 | + -- pass. See Note [Injecting implicit bindings] in GHC.CoreToStg.AddImplicitBinds
|
|
| 921 | 921 | -- along with the accompanying implementation in getTyConImplicitBinds.
|
| 922 | 922 | wrapper_reqd
|
| 923 | 923 | | isTypeDataTyCon tycon
|
| ... | ... | @@ -15,9 +15,9 @@ main = do |
| 15 | 15 | print $ deRefStaticPtr (static g)
|
| 16 | 16 | print $ deRefStaticPtr p0 'a'
|
| 17 | 17 | print $ deRefStaticPtr (static t_field) $ T 'b'
|
| 18 | - where
|
|
| 19 | - g :: String
|
|
| 20 | - g = "found"
|
|
| 18 | + |
|
| 19 | +g :: String
|
|
| 20 | +g = "found"
|
|
| 21 | 21 | |
| 22 | 22 | lookupKey :: StaticPtr a -> IO a
|
| 23 | 23 | lookupKey p = unsafeLookupStaticPtr (staticKey p) >>= \case
|
| 1 | - |
|
| 2 | 1 | RnStaticPointersFail01.hs:5:7: error: [GHC-88431]
|
| 3 | - • ‘x’ is used in a static form but it is not closed because it
|
|
| 4 | - is not let-bound.
|
|
| 5 | - • In the expression: static x
|
|
| 6 | - In an equation for ‘f’: f x = static x |
|
| 2 | + ‘x’ is used in a static form but it is not defined at top level
|
|
| 3 | + |
| 1 | - |
|
| 2 | 1 | RnStaticPointersFail03.hs:8:7: error: [GHC-88431]
|
| 3 | - • ‘x’ is used in a static form but it is not closed because it
|
|
| 4 | - is not let-bound.
|
|
| 5 | - • In the expression: static (x . id)
|
|
| 6 | - In an equation for ‘f’: f x = static (x . id)
|
|
| 2 | + ‘x’ is used in a static form but it is not defined at top level
|
|
| 7 | 3 | |
| 8 | 4 | RnStaticPointersFail03.hs:10:8: error: [GHC-88431]
|
| 9 | - • ‘k’ is used in a static form but it is not closed because it
|
|
| 10 | - uses ‘x’ which is not let-bound.
|
|
| 11 | - • In the expression: static (k . id)
|
|
| 12 | - In an equation for ‘f0’:
|
|
| 13 | - f0 x
|
|
| 14 | - = static (k . id)
|
|
| 15 | - where
|
|
| 16 | - k = const (const () x)
|
|
| 5 | + ‘k’ is used in a static form but it is not defined at top level
|
|
| 6 | + |
|
| 7 | +RnStaticPointersFail03.hs:14:8: error: [GHC-88431]
|
|
| 8 | + ‘k’ is used in a static form but it is not defined at top level
|
|
| 17 | 9 | |
| 18 | 10 | RnStaticPointersFail03.hs:19:15: error: [GHC-88431]
|
| 19 | - • ‘g’ is used in a static form but it is not closed because it
|
|
| 20 | - uses ‘h’ which has a non-closed type because it contains the
|
|
| 21 | - type variables: ‘a’
|
|
| 22 | - • In the first argument of ‘const’, namely ‘(static (g undefined))’
|
|
| 23 | - In the expression: const (static (g undefined)) (h x)
|
|
| 24 | - In an equation for ‘f2’:
|
|
| 25 | - f2 x
|
|
| 26 | - = const (static (g undefined)) (h x)
|
|
| 27 | - where
|
|
| 28 | - g = h
|
|
| 29 | - h = typeOf |
|
| 11 | + ‘g’ is used in a static form but it is not defined at top level
|
|
| 12 | + |
| 1 | 1 | CaretDiagnostics1.hs:7:8-15: error: [GHC-83865]
|
| 2 | - • Couldn't match expected type ‘IO a0’ with actual type ‘Int’
|
|
| 2 | + • Couldn't match expected type ‘IO a1’ with actual type ‘Int’
|
|
| 3 | 3 | • In the second argument of ‘(+)’, namely ‘(3 :: Int)’
|
| 4 | 4 | In a stmt of a 'do' block:
|
| 5 | 5 | 10000000000000000000000000000000000000 + 2 + (3 :: Int)
|
| ... | ... | @@ -23,9 +23,9 @@ CaretDiagnostics1.hs:8:9-27: error: [GHC-83865] |
| 23 | 23 | | ^^^^^^^^^^^^^^^^^^^
|
| 24 | 24 | |
| 25 | 25 | CaretDiagnostics1.hs:13:7-11: error: [GHC-83865]
|
| 26 | - • Couldn't match type: a1 -> a1
|
|
| 26 | + • Couldn't match type: a0 -> a0
|
|
| 27 | 27 | with: [Char]
|
| 28 | - Expected: a1 -> a1
|
|
| 28 | + Expected: a0 -> a0
|
|
| 29 | 29 | Actual: String
|
| 30 | 30 | • In the pattern: "γηξ"
|
| 31 | 31 | In a case alternative: "γηξ" -> () '0'
|