Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
c673ecf0
by Simon Peyton Jones at 2026-09-05T07:22:59-04:00
9 changed files:
- + changelog.d/T27764
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Tc/Gen/Expr.hs
- testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
- testsuite/tests/rename/should_fail/T26545.stderr
- + testsuite/tests/typecheck/should_compile/T27664.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +synopsis: Fix bug in ``static`` forms
|
|
| 3 | +issues: #27664
|
|
| 4 | +mrs: !16624
|
|
| 5 | +description: A ``static`` form should have no free *term* variables, but it
|
|
| 6 | + can have free *type* variables. Alas, the renamer does not really know what
|
|
| 7 | + is a term variable and what is a type variable, because of required type
|
|
| 8 | + arguments. This patch moves the test to the typechecker, which does know. |
| ... | ... | @@ -39,6 +39,7 @@ import GHC.Tc.Types.ErrCtxt |
| 39 | 39 | import GHC.Types.Id.Info ( RecSelParent )
|
| 40 | 40 | import GHC.Types.Name
|
| 41 | 41 | import GHC.Types.Name.Reader
|
| 42 | +import GHC.Types.Name.Set( FreeNames )
|
|
| 42 | 43 | import GHC.Types.Basic
|
| 43 | 44 | import GHC.Types.Fixity
|
| 44 | 45 | import GHC.Types.SourceText
|
| ... | ... | @@ -363,7 +364,9 @@ type instance XArithSeq GhcTc = PostTcExpr |
| 363 | 364 | type instance XProc (GhcPass _) = (EpToken "proc", TokRarrow)
|
| 364 | 365 | |
| 365 | 366 | type instance XStatic GhcPs = EpToken "static"
|
| 366 | -type instance XStatic GhcRn = NoExtField
|
|
| 367 | +type instance XStatic GhcRn = FreeNames
|
|
| 368 | + -- Free variables of the body; we can't tell if they are
|
|
| 369 | + -- type or term variables until we are typechecking
|
|
| 367 | 370 | type instance XStatic GhcTc = (Type, HsExpr GhcTc)
|
| 368 | 371 | -- Type of expression, and the (fromStaticPtr function)
|
| 369 | 372 | -- These are stored for convenience as the wiring in
|
| ... | ... | @@ -667,18 +667,7 @@ rnExpr e@(HsStatic _ expr) |
| 667 | 667 | -- Rename the payload
|
| 668 | 668 | ; (expr',fvs) <- rnLExpr expr
|
| 669 | 669 | |
| 670 | - -- Check that the free variables of the static form are top-level defined
|
|
| 671 | - -- It's OK to use nonDetEltsUniqSet here as the only side effects of
|
|
| 672 | - -- checkClosedInStaticForm are error messages.
|
|
| 673 | - -- See (SF2) Note [Grand plan for static forms] in GHC.Iface.Tidy.StaticPtrTable
|
|
| 674 | - ; mapM_ check_fv (nonDetEltsUniqSet fvs)
|
|
| 675 | - |
|
| 676 | - ; return (HsStatic noExtField expr', fvs) }
|
|
| 677 | - where
|
|
| 678 | - check_fv :: Name -> RnM ()
|
|
| 679 | - -- Check for free vars not defined at top level
|
|
| 680 | - check_fv n = unless (isExternalName n) $
|
|
| 681 | - addErrTc (TcRnStaticFormNotClosed n)
|
|
| 670 | + ; return (HsStatic fvs expr', fvs) }
|
|
| 682 | 671 | |
| 683 | 672 | {-
|
| 684 | 673 | ************************************************************************
|
| ... | ... | @@ -602,13 +602,19 @@ tcExpr (HsProc x pat cmd) res_ty |
| 602 | 602 | -- and wrap (static e) in a call to
|
| 603 | 603 | -- fromStaticPtr :: IsStatic p => StaticPtr a -> p a
|
| 604 | 604 | |
| 605 | -tcExpr (HsStatic _ expr) res_ty
|
|
| 605 | +tcExpr (HsStatic free_names expr) res_ty
|
|
| 606 | 606 | = do { res_ty <- expTypeToType res_ty
|
| 607 | 607 | ; (co, (p_ty, expr_ty)) <- matchExpectedAppTy res_ty
|
| 608 | 608 | ; (expr', lie) <- captureConstraints $
|
| 609 | 609 | addErrCtxt (StaticFormCtxt expr) $
|
| 610 | 610 | tcCheckPolyExprNC expr expr_ty
|
| 611 | 611 | |
| 612 | + -- Check that the free variables of the static form are top-level defined
|
|
| 613 | + -- It's OK to use nonDetEltsUniqSet here as the only side effects of
|
|
| 614 | + -- checkClosedInStaticForm are error messages.
|
|
| 615 | + -- See (SF2) Note [Grand plan for static forms] in GHC.Iface.Tidy.StaticPtrTable
|
|
| 616 | + ; mapM_ check_free_name (nonDetEltsUniqSet free_names)
|
|
| 617 | + |
|
| 612 | 618 | -- Emit an implication that captures the constraints of `expr`,
|
| 613 | 619 | -- but with a `ic_info` of StaticFormSkol
|
| 614 | 620 | -- See #13499 for an explanation of why this is the right thing to do:
|
| ... | ... | @@ -637,6 +643,24 @@ tcExpr (HsStatic _ expr) res_ty |
| 637 | 643 | HsStatic (static_expr_ty, mkHsWrap wrap fromStaticPtr)
|
| 638 | 644 | expr''
|
| 639 | 645 | }
|
| 646 | + where
|
|
| 647 | + check_free_name :: Name -> TcM ()
|
|
| 648 | + -- Check for free /term/ vars not defined at top level
|
|
| 649 | + -- We use isExternalName as a proxy for top-level-defined
|
|
| 650 | + check_free_name n
|
|
| 651 | + = do { mb_thing <- tcLookupLcl_maybe n
|
|
| 652 | + ; case mb_thing of
|
|
| 653 | + Nothing -> return () -- Imports, tycons, classes allowed
|
|
| 654 | + Just (ATcId {}) -> unless (isExternalName n) $
|
|
| 655 | + addErrTc (TcRnStaticFormNotClosed n)
|
|
| 656 | + |
|
| 657 | + Just (ATyVar {}) -> return () -- Free type variables are allowed
|
|
| 658 | + |
|
| 659 | + -- Not really expecting these, but we'll get an error from
|
|
| 660 | + -- elsewhere, so don't produce an error here
|
|
| 661 | + Just (ATcTyCon {}) -> return ()
|
|
| 662 | + Just (APromotionErr {}) -> return ()
|
|
| 663 | + Just (AGlobal {}) -> return () }
|
|
| 640 | 664 | |
| 641 | 665 | tcExpr (HsEmbTy _ _) _ = failWith (TcRnIllegalTypeExpr TypeKeywordSyntax)
|
| 642 | 666 | tcExpr (HsQual _ _ _) _ = failWith (TcRnIllegalTypeExpr ContextArrowSyntax)
|
| 1 | 1 | RnStaticPointersFail01.hs:5:7: error: [GHC-88431]
|
| 2 | - ‘x’ is used in a static form but it is not defined at top level
|
|
| 2 | + • ‘x’ is used in a static form but it is not defined at top level
|
|
| 3 | + • In the expression: static x
|
|
| 4 | + In an equation for ‘f’: f x = static x
|
|
| 3 | 5 |
| 1 | 1 | RnStaticPointersFail03.hs:8:7: error: [GHC-88431]
|
| 2 | - ‘x’ is used in a static form but it is not defined at top level
|
|
| 2 | + • ‘x’ is used in a static form but it is not defined at top level
|
|
| 3 | + • In the expression: static (x . id)
|
|
| 4 | + In an equation for ‘f’: f x = static (x . id)
|
|
| 3 | 5 | |
| 4 | 6 | RnStaticPointersFail03.hs:10:8: error: [GHC-88431]
|
| 5 | - ‘k’ is used in a static form but it is not defined at top level
|
|
| 7 | + • ‘k’ is used in a static form but it is not defined at top level
|
|
| 8 | + • In the expression: static (k . id)
|
|
| 9 | + In an equation for ‘f0’:
|
|
| 10 | + f0 x
|
|
| 11 | + = static (k . id)
|
|
| 12 | + where
|
|
| 13 | + k = const (const () x)
|
|
| 6 | 14 | |
| 7 | 15 | RnStaticPointersFail03.hs:14:8: error: [GHC-88431]
|
| 8 | - ‘k’ is used in a static form but it is not defined at top level
|
|
| 16 | + • ‘k’ is used in a static form but it is not defined at top level
|
|
| 17 | + • In the expression: static (k . id)
|
|
| 18 | + In an equation for ‘f1’:
|
|
| 19 | + f1 x
|
|
| 20 | + = static (k . id)
|
|
| 21 | + where
|
|
| 22 | + k = id
|
|
| 9 | 23 | |
| 10 | 24 | RnStaticPointersFail03.hs:19:15: error: [GHC-88431]
|
| 11 | - ‘g’ is used in a static form but it is not defined at top level
|
|
| 25 | + • ‘g’ is used in a static form but it is not defined at top level
|
|
| 26 | + • In the first argument of ‘const’, namely ‘(static (g undefined))’
|
|
| 27 | + In the expression: const (static (g undefined)) (h x)
|
|
| 28 | + In an equation for ‘f2’:
|
|
| 29 | + f2 x
|
|
| 30 | + = const (static (g undefined)) (h x)
|
|
| 31 | + where
|
|
| 32 | + g = h
|
|
| 33 | + h = typeOf
|
|
| 12 | 34 |
| 1 | 1 | T26545.hs:12:23: error: [GHC-88431]
|
| 2 | - ‘v’ is used in a static form but it is not defined at top level
|
|
| 2 | + • ‘v’ is used in a static form but it is not defined at top level
|
|
| 3 | + • In the expression: static (I# (v +# 1#))
|
|
| 4 | + In the expression: let v = f 3# in static (I# (v +# 1#))
|
|
| 5 | + In an equation for ‘h’: h x = let v = f 3# in static (I# (v +# 1#))
|
|
| 3 | 6 |
| 1 | +{-# LANGUAGE StaticPointers, ScopedTypeVariables #-}
|
|
| 2 | +module Repro where
|
|
| 3 | + |
|
| 4 | +import Data.Typeable
|
|
| 5 | +import GHC.StaticPtr
|
|
| 6 | + |
|
| 7 | +f1 :: forall a. Typeable a => StaticPtr (a -> a)
|
|
| 8 | +f1 = static (id :: a -> a)
|
|
| 9 | + |
|
| 10 | +f2 :: forall a. Typeable a => StaticPtr (a -> a)
|
|
| 11 | +f2 = static (id) :: StaticPtr (a->a) |
| ... | ... | @@ -969,3 +969,4 @@ test('ExpansionQLIm', normal, compile, ['']) |
| 969 | 969 | test('T23135', normal, compile, [''])
|
| 970 | 970 | test('LazyFieldAnnotations', normal, compile, [''])
|
| 971 | 971 | test('T27557', normal, compile, [''])
|
| 972 | +test('T27664', normal, compile, ['']) |