Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
4 changed files:
- + changelog.d/T27374
- compiler/GHC/Core/Coercion/Opt.hs
- + testsuite/tests/corelint/T27374.hs
- testsuite/tests/corelint/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +issues: #27374
|
|
| 3 | +mrs: !16207
|
|
| 4 | +synopsis:
|
|
| 5 | + Fix optimisation of InstCo coercions
|
|
| 6 | +description:
|
|
| 7 | + Fixes a bug in which the coercion optimiser would incorrectly optimise certain
|
|
| 8 | + InstCo coercions, incorrectly changing their kinds.
|
|
| 9 | + |
| ... | ... | @@ -274,10 +274,11 @@ opt_co4, opt_co4' :: LiftingContext -> SwapFlag -> ReprFlag |
| 274 | 274 | -- Precondition: In every call (opt_co4 lc sym rep role co)
|
| 275 | 275 | -- we should have role = coercionRole co
|
| 276 | 276 | -- Precondition: role is not Phantom
|
| 277 | --- Postcondition: The resulting coercion is equivalant to
|
|
| 278 | --- wrapsub (wrapsym (mksub co)
|
|
| 279 | --- where wrapsym is SymCo if sym=True
|
|
| 280 | --- wrapsub is SubCo if rep=True
|
|
| 277 | +-- Postcondition: The resulting coercion is equivalent to
|
|
| 278 | +-- wrapSub (wrapSym (substCo co))
|
|
| 279 | +-- where substCo applies the LiftingContext substitution
|
|
| 280 | +-- wrapSym wraps in SymCo when the ambient Sym is IsSwapped
|
|
| 281 | +-- wrapSub wraps in SubCo when rep=True
|
|
| 281 | 282 | |
| 282 | 283 | -- opt_co4 is there just to support tracing, when debugging
|
| 283 | 284 | -- Usually it just goes straight to opt_co4'
|
| ... | ... | @@ -327,7 +328,10 @@ opt_co4' env sym rep r (GRefl _r ty (MCo kco)) |
| 327 | 328 | text "Type:" <+> ppr ty) $
|
| 328 | 329 | if isReflKindCo kco || isReflKindCo kco'
|
| 329 | 330 | then wrapSym sym ty_co
|
| 330 | - else wrapSym sym $ mk_coherence_right_co r' (coercionRKind ty_co) kco' ty_co
|
|
| 331 | + else
|
|
| 332 | + -- Keep 'sym' on the outside instead of trying to push it in, to avoid
|
|
| 333 | + -- duplicating 'k_co' in 'GRefl r (ty |> kco) (MCo (sym kco))'
|
|
| 334 | + wrapSym sym $ mk_coherence_right_co r' (coercionRKind ty_co) kco' ty_co
|
|
| 331 | 335 | -- ty :: k1
|
| 332 | 336 | -- kco :: k1 ~ k2
|
| 333 | 337 | -- Desired result coercion: ty ~ ty |> co
|
| ... | ... | @@ -534,25 +538,36 @@ opt_co4' env sym rep r (InstCo fun_co arg_co) |
| 534 | 538 | , let s2' = coercionRKind arg_co'
|
| 535 | 539 | tv_co = mk_coherence_right_co Nominal s2' (mkSymCo k_co') arg_co'
|
| 536 | 540 | env' = extendLiftingContext (zapLiftingContext env) tv' tv_co
|
| 537 | - = opt_co4 env' NotSwapped False r' body_co'
|
|
| 541 | + = opt_co4 env' sym False r' body_co'
|
|
| 538 | 542 | |
| 539 | 543 | -- See Note [Forall over coercion]
|
| 540 | 544 | | Just (cv', _visL, _visR, _kind_co', body_co') <- splitForAllCo_co_maybe fun_co'
|
| 541 | 545 | , CoercionTy h1' <- coercionLKind arg_co'
|
| 542 | 546 | , let env' = extendLiftingContextCvSubst (zapLiftingContext env) cv' h1'
|
| 543 | - = opt_co4 env' NotSwapped False r' body_co'
|
|
| 547 | + = opt_co4 env' sym False r' body_co'
|
|
| 544 | 548 | |
| 545 | 549 | -- Those cases didn't work either, so rebuild the InstCo
|
| 546 | - -- Push Sym into /both/ function /and/ arg_coument
|
|
| 547 | - | otherwise = InstCo fun_co' arg_co'
|
|
| 550 | + | otherwise = InstCo sym_fun_co' sym_arg_co'
|
|
| 548 | 551 | |
| 549 | 552 | where
|
| 550 | - -- fun_co' arg_co' are both optimised, /and/ we have pushed `sym` into both
|
|
| 551 | - -- So no more sym'ing on th results of fun_co' arg_co'
|
|
| 552 | - fun_co' = opt_co4 env sym rep r fun_co
|
|
| 553 | - arg_co' = opt_co4 env sym False Nominal arg_co
|
|
| 554 | 553 | r' = chooseRole rep r
|
| 555 | 554 | |
| 555 | + -- Optimised versions of fun_co & arg_co.
|
|
| 556 | + -- NB: we do /not/ push in `sym` (hence using `NotSwappped`),
|
|
| 557 | + -- in order to respect (LC2) in Note [The LiftingContext in optCoercion].
|
|
| 558 | + fun_co' = opt_co4 env NotSwapped rep r fun_co
|
|
| 559 | + arg_co' = opt_co4 env NotSwapped False Nominal arg_co
|
|
| 560 | + |
|
| 561 | + -- Like fun_co'/arg_co', except we /have/ pushed in `sym`.
|
|
| 562 | + -- We use 'mkDeepSymCo' to push in 'sym' without re-optimising.
|
|
| 563 | + -- See Note [Pushing Sym without re-optimising]
|
|
| 564 | + sym_fun_co'
|
|
| 565 | + | isSwapped sym = mkDeepSymCo fun_co'
|
|
| 566 | + | otherwise = fun_co'
|
|
| 567 | + sym_arg_co'
|
|
| 568 | + | isSwapped sym = mkDeepSymCo arg_co'
|
|
| 569 | + | otherwise = arg_co'
|
|
| 570 | + |
|
| 556 | 571 | opt_co4' env sym _rep r (KindCo co)
|
| 557 | 572 | = assert (r == Nominal) $
|
| 558 | 573 | let kco' = promoteCoercion co in
|
| ... | ... | @@ -575,6 +590,83 @@ We do so here in optCoercion, not in mkCoVarCo; see Note [mkCoVarCo] |
| 575 | 590 | in GHC.Core.Coercion.
|
| 576 | 591 | -}
|
| 577 | 592 | |
| 593 | +{- Note [Pushing Sym without re-optimising]
|
|
| 594 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 595 | +To optimise (InstCo fun_co arg_co) we must first optimise fun_co and arg_co
|
|
| 596 | +/without/ the ambient Sym, as required by (LC2) of
|
|
| 597 | +Note [The LiftingContext in optCoercion].
|
|
| 598 | + |
|
| 599 | +But in the fallback case (when the optimised fun_co is not a ForAllCo), we need
|
|
| 600 | +to push the ambient Sym into both components when rebuilding the InstCo.
|
|
| 601 | + |
|
| 602 | + Re-running the optimiser with sym=IsSwapped would optimise each component twice.
|
|
| 603 | + As the components can themselves contain 'InstCo's, this has the potential to
|
|
| 604 | + trigger exponential behaviour.
|
|
| 605 | + |
|
| 606 | + Simply wrapping 'sym' on the outside would fail to push 'sym' deeply into the
|
|
| 607 | + coercion, which would be in tension with the rest of the coercion optimiser
|
|
| 608 | + which relies on 'sym' being pushed into the leaves to expose cancellation
|
|
| 609 | + opportunities.
|
|
| 610 | + |
|
| 611 | +To solve this, we define 'mkDeepSymCo': it pushes a Sym into an already
|
|
| 612 | +optimised coercion. This is much simpler than full coercion optimisation, as it
|
|
| 613 | +doesn't need to do coercion lifting nor downgrade roles.
|
|
| 614 | +-}
|
|
| 615 | + |
|
| 616 | +-- | Push 'Sym' deeply into an already-optimised coercion.
|
|
| 617 | +--
|
|
| 618 | +-- Morally the same as re-optimising the coercion with @sym=IsSwapped@, but
|
|
| 619 | +-- more efficient.
|
|
| 620 | +--
|
|
| 621 | +-- See Note [Pushing Sym without re-optimising]
|
|
| 622 | +mkDeepSymCo :: NormalCo -> NormalCo
|
|
| 623 | +mkDeepSymCo = go
|
|
| 624 | + where
|
|
| 625 | + go :: NormalCo -> NormalCo
|
|
| 626 | + -- Straightforward cases
|
|
| 627 | + go (SymCo co) = co
|
|
| 628 | + go co@(UnivCo { uco_lty = t1, uco_rty = t2 }) = co { uco_lty = t2, uco_rty = t1 }
|
|
| 629 | + go (TyConAppCo r tc cos) = TyConAppCo r tc $ map go cos
|
|
| 630 | + go (AppCo co1 co2) = AppCo (go co1) (go co2)
|
|
| 631 | + go (FunCo r afl afr cow co1 co2) = FunCo r afr afl (go cow) (go co1) (go co2)
|
|
| 632 | + go (TransCo co1 co2) = TransCo (go co2) (go co1)
|
|
| 633 | + go (SelCo cs co) = SelCo cs $ go co
|
|
| 634 | + go (LRCo lr co) = LRCo lr $ go co
|
|
| 635 | + go (InstCo fun_co arg_co) = InstCo (go fun_co) (go arg_co)
|
|
| 636 | + go (KindCo co) = KindCo $ go co
|
|
| 637 | + go (SubCo co) = SubCo $ go co
|
|
| 638 | + go co@(CoVarCo {}) = SymCo co
|
|
| 639 | + go co@(Refl {}) = co
|
|
| 640 | + go co@(GRefl _ _ MRefl) = co
|
|
| 641 | + go co@(GRefl _ _ (MCo {})) = SymCo co
|
|
| 642 | + -- keep the sym outside, like the GRefl case of opt_co4' does, instead of
|
|
| 643 | + -- GRefl r (ty |> kco) (MCo (sym kco))
|
|
| 644 | + -- as that duplicates 'kco'
|
|
| 645 | + go co@(AxiomCo {}) = SymCo co
|
|
| 646 | + -- Same as in opt_co4': do *not* push sym inside top-level axioms.
|
|
| 647 | + |
|
| 648 | + go co@(ForAllCo { fco_tcv = tcv, fco_visL = visL, fco_visR = visR
|
|
| 649 | + , fco_kind = k_mco, fco_body = body_co })
|
|
| 650 | + = case k_mco of
|
|
| 651 | + MRefl -> ForAllCo tcv visR visL k_mco (go body_co)
|
|
| 652 | + MCo {} ->
|
|
| 653 | + -- Pushing 'sym' into the kind coercion would require threading a
|
|
| 654 | + -- substitution through, as per Note [Optimising ForAllCo].
|
|
| 655 | + -- This wouldn't be difficult (see commented out code below), but
|
|
| 656 | + -- for now we prefer to keep 'mkDeepSymCo' as simple as possible.
|
|
| 657 | + SymCo co
|
|
| 658 | + |
|
| 659 | + -- Pushing 'sym' into the kind coercion, threading 'Subst' through:
|
|
| 660 | + --
|
|
| 661 | + -- = ForAllCo tcv' visR visL k_mco' (go subst' body_co)
|
|
| 662 | + -- where
|
|
| 663 | + -- k_mco' = case k_mco of
|
|
| 664 | + -- MRefl -> MRefl
|
|
| 665 | + -- MCo co -> MCo (go subst co)
|
|
| 666 | + -- (subst', tcv') = forAllCoBndrSubst IsSwapped tcv k_mco' subst
|
|
| 667 | + |
|
| 668 | + go (HoleCo h) = pprPanic "mkDeepSymCo: HoleCo" (ppr h)
|
|
| 669 | + |
|
| 578 | 670 | -------------
|
| 579 | 671 | -- | Optimize a phantom coercion. The input coercion may not necessarily
|
| 580 | 672 | -- be a phantom, but the output sure will be.
|
| ... | ... | @@ -1450,6 +1542,9 @@ But if sym=Swapped, things are trickier. Here is an identity that helps: |
| 1450 | 1542 | of tv:k1 in bodyco by (tv:k2 |> Sym kco)
|
| 1451 | 1543 | This mirrors what happens in the typing rule for ForAllCo
|
| 1452 | 1544 | See Note [ForAllCo] in GHC.Core.TyCo.Rep
|
| 1545 | + NB: doing so inlines 'kco' at all occurrences of tv, duplicating it. This is
|
|
| 1546 | + inconsistent with how we optimise GRefl, where we keep the 'Sym' on the
|
|
| 1547 | + outside to avoid duplicating the kind coercion.
|
|
| 1453 | 1548 | |
| 1454 | 1549 | -}
|
| 1455 | 1550 | optForAllCoBndr :: LiftingContext -> SwapFlag
|
| ... | ... | @@ -1464,13 +1559,20 @@ optForAllCoBndr env sym tcv k_mco |
| 1464 | 1559 | MRefl -> MRefl
|
| 1465 | 1560 | MCo co -> MCo (opt_co4 env sym False Nominal co)
|
| 1466 | 1561 | |
| 1467 | - (env', tcv') = updateLCSubst env upd_subst
|
|
| 1468 | - |
|
| 1469 | - upd_subst :: Subst -> (Subst, TyCoVar)
|
|
| 1470 | - upd_subst subst
|
|
| 1471 | - | isTyVar tcv = upd_subst_tv subst
|
|
| 1472 | - | otherwise = upd_subst_cv subst
|
|
| 1473 | - |
|
| 1562 | + (env', tcv') = updateLCSubst env (forAllCoBndrSubst sym tcv k_mco')
|
|
| 1563 | + |
|
| 1564 | +-- | Substitute a 'ForAllCo' binder, returning the body substitution.
|
|
| 1565 | +--
|
|
| 1566 | +-- See Note [Optimising ForAllCo].
|
|
| 1567 | +forAllCoBndrSubst
|
|
| 1568 | + :: SwapFlag
|
|
| 1569 | + -> TyCoVar -- ^ the ForAllCo binder
|
|
| 1570 | + -> MCoercionN -- ^ its kind coercion, with the ambient Sym already pushed into it
|
|
| 1571 | + -> Subst -> (Subst, TyCoVar)
|
|
| 1572 | +forAllCoBndrSubst sym tcv k_mco'
|
|
| 1573 | + | isTyVar tcv = upd_subst_tv
|
|
| 1574 | + | otherwise = upd_subst_cv
|
|
| 1575 | + where
|
|
| 1474 | 1576 | upd_subst_tv subst
|
| 1475 | 1577 | = case k_mco' of
|
| 1476 | 1578 | MCo k_co' | isSwapped sym -> (subst2, tv2)
|
| 1 | +{-# LANGUAGE BlockArguments #-}
|
|
| 2 | + |
|
| 3 | +-- | Regression test for #27374:
|
|
| 4 | +--
|
|
| 5 | +-- - manually construct some coercions that are not InstCo but become InstCo
|
|
| 6 | +-- after optimisation
|
|
| 7 | +-- - check that the coercion optimiser properly optimises these by running
|
|
| 8 | +-- Core Lint on the output
|
|
| 9 | + |
|
| 10 | +module Main (main) where
|
|
| 11 | + |
|
| 12 | +-- base
|
|
| 13 | +import Control.Monad.IO.Class
|
|
| 14 | + ( liftIO )
|
|
| 15 | +import Data.Foldable
|
|
| 16 | + ( for_ )
|
|
| 17 | +import System.Environment
|
|
| 18 | + ( getArgs )
|
|
| 19 | + |
|
| 20 | +-- ghc
|
|
| 21 | +import GHC
|
|
| 22 | + ( runGhc, getSessionDynFlags, getLogger )
|
|
| 23 | +import GHC.Builtin.Types
|
|
| 24 | + ( maybeTyCon, tupleTyCon, mkBoxedTupleTy )
|
|
| 25 | +import GHC.Core
|
|
| 26 | + ( Expr(Coercion) )
|
|
| 27 | +import GHC.Core.Coercion
|
|
| 28 | + ( Coercion, CoVar, MCoercion(..)
|
|
| 29 | + , Role(..), CoSel(..), FunSel(..)
|
|
| 30 | + , mkCoercionType
|
|
| 31 | + , mkCoVar, mkCoVarCo, mkForAllCo, mkInstCo, mkReflCo, mkNomReflCo
|
|
| 32 | + , mkSelCo, mkSymCo, mkTransCo, mkTyConAppCo
|
|
| 33 | + , tyCoVarsOfCo
|
|
| 34 | + )
|
|
| 35 | +import GHC.Core.Coercion.Opt
|
|
| 36 | + ( OptCoercionOpts(..), optCoercion )
|
|
| 37 | +import GHC.Core.Lint
|
|
| 38 | + ( lintExpr )
|
|
| 39 | +import GHC.Core.Predicate
|
|
| 40 | + ( mkNomEqPred )
|
|
| 41 | +import GHC.Core.TyCo.FVs
|
|
| 42 | + ( tyCoVarsOfCoList )
|
|
| 43 | +import GHC.Core.TyCo.Rep
|
|
| 44 | + ( Type(CoercionTy) )
|
|
| 45 | +import GHC.Core.Type
|
|
| 46 | + |
|
| 47 | +import GHC.Data.FastString
|
|
| 48 | + ( fsLit )
|
|
| 49 | + |
|
| 50 | +import GHC.Driver.Config.Core.Lint
|
|
| 51 | + ( initLintConfig )
|
|
| 52 | + |
|
| 53 | +import GHC.Types.Basic
|
|
| 54 | + ( Boxity(Boxed) )
|
|
| 55 | +import GHC.Types.Var
|
|
| 56 | + ( mkTyVar, coreTyLamForAllTyFlag )
|
|
| 57 | +import GHC.Types.Var.Env
|
|
| 58 | + ( mkInScopeSet )
|
|
| 59 | +import GHC.Types.Name
|
|
| 60 | + ( mkInternalName )
|
|
| 61 | +import GHC.Types.Name.Occurrence
|
|
| 62 | + ( mkTyVarOccFS, mkVarOccFS )
|
|
| 63 | +import GHC.Types.SrcLoc
|
|
| 64 | + ( noSrcSpan )
|
|
| 65 | +import GHC.Types.Unique
|
|
| 66 | + ( mkUniqueGrimily )
|
|
| 67 | + |
|
| 68 | +import GHC.Utils.Error
|
|
| 69 | + ( pprMessageBag, putMsg )
|
|
| 70 | +import GHC.Utils.Outputable
|
|
| 71 | + ( (<+>), text, vcat )
|
|
| 72 | + |
|
| 73 | +--------------------------------------------------------------------------------
|
|
| 74 | +-- Helpers for building fresh variables
|
|
| 75 | +--------------------------------------------------------------------------------
|
|
| 76 | + |
|
| 77 | +mkTv :: Int -> String -> Kind -> TyVar
|
|
| 78 | +mkTv i s =
|
|
| 79 | + mkTyVar $
|
|
| 80 | + mkInternalName
|
|
| 81 | + ( mkUniqueGrimily (fromIntegral i) )
|
|
| 82 | + ( mkTyVarOccFS (fsLit s) )
|
|
| 83 | + noSrcSpan
|
|
| 84 | + |
|
| 85 | +mkCv :: Int -> String -> Type -> CoVar
|
|
| 86 | +mkCv i s =
|
|
| 87 | + mkCoVar $
|
|
| 88 | + mkInternalName
|
|
| 89 | + ( mkUniqueGrimily (fromIntegral i) )
|
|
| 90 | + ( mkVarOccFS (fsLit s) )
|
|
| 91 | + noSrcSpan
|
|
| 92 | + |
|
| 93 | +--------------------------------------------------------------------------------
|
|
| 94 | +-- ForAllCo-over-type
|
|
| 95 | +--------------------------------------------------------------------------------
|
|
| 96 | + |
|
| 97 | +co1 :: Coercion
|
|
| 98 | +co1 =
|
|
| 99 | + -- Use mkTransCo to get a coercion that is not InstCo but optimises to InstCo
|
|
| 100 | + lhs `mkTransCo` rhs
|
|
| 101 | + where
|
|
| 102 | + p = mkTv 21 "p" liftedTypeKind
|
|
| 103 | + q = mkTv 22 "q" liftedTypeKind
|
|
| 104 | + a = mkTv 23 "a" liftedTypeKind
|
|
| 105 | + b = mkTv 24 "b" liftedTypeKind
|
|
| 106 | + |
|
| 107 | + tup2 = tupleTyCon Boxed 2
|
|
| 108 | + |
|
| 109 | + -- cv :: p ~# q
|
|
| 110 | + cv = mkCoVarCo $
|
|
| 111 | + mkCv 25 "cv" $
|
|
| 112 | + mkCoercionType Nominal (mkTyVarTy p) (mkTyVarTy q)
|
|
| 113 | + |
|
| 114 | + -- arg :: Maybe q ~ Maybe p
|
|
| 115 | + arg = mkSymCo (mkTyConAppCo Nominal maybeTyCon [cv])
|
|
| 116 | + |
|
| 117 | + -- forallCo = <forall a b. (a, b) -> a>_N
|
|
| 118 | + forallCo =
|
|
| 119 | + mkReflCo Nominal $
|
|
| 120 | + mkSpecForAllTys [a, b] $
|
|
| 121 | + mkVisFunTyMany
|
|
| 122 | + (mkBoxedTupleTy [mkTyVarTy a, mkTyVarTy b])
|
|
| 123 | + (mkTyVarTy a)
|
|
| 124 | + |
|
| 125 | + -- forallCo @arg @arg
|
|
| 126 | + inst_co = mkInstCo (mkInstCo forallCo arg) arg
|
|
| 127 | + |
|
| 128 | + rhs = mkSymCo (mkSelCo (SelFun SelArg) inst_co)
|
|
| 129 | + lhs = mkTyConAppCo Nominal tup2 [arg, arg]
|
|
| 130 | + |
|
| 131 | +--------------------------------------------------------------------------------
|
|
| 132 | +-- ForAllCo-over-coercion
|
|
| 133 | +--------------------------------------------------------------------------------
|
|
| 134 | + |
|
| 135 | +co2 :: Coercion
|
|
| 136 | +co2 =
|
|
| 137 | + -- This outer 'sym' was necessary to trigger the specific bug
|
|
| 138 | + mkSymCo $
|
|
| 139 | + mkInstCo ( mkSymCo g ) arg
|
|
| 140 | + where
|
|
| 141 | + k1 = mkTyVarTy $ mkTv 11 "k1" liftedTypeKind
|
|
| 142 | + k2 = mkTyVarTy $ mkTv 12 "k2" liftedTypeKind
|
|
| 143 | + |
|
| 144 | + x = mkTv 13 "x" k1
|
|
| 145 | + |
|
| 146 | + -- cv :: k1 ~# Type
|
|
| 147 | + cv_ty = mkNomEqPred k1 liftedTypeKind
|
|
| 148 | + cv = mkCv 14 "cv" cv_ty
|
|
| 149 | + |
|
| 150 | + -- hk :: (k1 ~# Type) ~# (k2 ~# Type)
|
|
| 151 | + hk = mkCoVarCo (mkCv 15 "hk" (mkNomEqPred cv_ty (mkNomEqPred k2 liftedTypeKind)))
|
|
| 152 | + |
|
| 153 | + -- body :: (x |> cv) ~# (x |> cv)
|
|
| 154 | + body = mkNomReflCo (mkCastTy (mkTyVarTy x) (mkCoVarCo cv))
|
|
| 155 | + |
|
| 156 | + -- g :: (forall (cv :: k1 ~# Type). x |> cv)
|
|
| 157 | + -- ~# (forall (cv' :: k2 ~# Type). x |> (sel 2 hk ; cv' ; sym (sel 3 hk)))
|
|
| 158 | + g = mkForAllCo cv vis vis (MCo hk) body
|
|
| 159 | + vis = coreTyLamForAllTyFlag
|
|
| 160 | + |
|
| 161 | + -- two distinct coercions to instantiate at
|
|
| 162 | + coL = mkCoVarCo (mkCv 16 "coL" (mkNomEqPred k1 liftedTypeKind))
|
|
| 163 | + coR = mkCoVarCo (mkCv 17 "coR" (mkNomEqPred k2 liftedTypeKind))
|
|
| 164 | + arg = mkCoVarCo (mkCv 18 "arg" (mkNomEqPred (CoercionTy coL) (CoercionTy coR)))
|
|
| 165 | + |
|
| 166 | +--------------------------------------------------------------------------------
|
|
| 167 | +-- Test runner
|
|
| 168 | +--------------------------------------------------------------------------------
|
|
| 169 | + |
|
| 170 | +test_cos :: [ ( String, Coercion ) ]
|
|
| 171 | +test_cos =
|
|
| 172 | + [ ( "InstCo (TyVar)", co1 )
|
|
| 173 | + , ( "InstCo (CoVar)", co2 )
|
|
| 174 | + ]
|
|
| 175 | + |
|
| 176 | +opt_co :: Coercion -> Coercion
|
|
| 177 | +opt_co co =
|
|
| 178 | + let in_scope = mkInScopeSet $ tyCoVarsOfCo co
|
|
| 179 | + in
|
|
| 180 | + optCoercion
|
|
| 181 | + ( OptCoercionOpts { optCoercionEnabled = True } )
|
|
| 182 | + ( mkEmptySubst in_scope )
|
|
| 183 | + co
|
|
| 184 | + |
|
| 185 | +main :: IO ()
|
|
| 186 | +main = do
|
|
| 187 | + [libdir] <- getArgs
|
|
| 188 | + runGhc ( Just libdir ) do
|
|
| 189 | + dflags <- getSessionDynFlags
|
|
| 190 | + logger <- getLogger
|
|
| 191 | + liftIO $ for_ test_cos \ ( name, co ) -> do
|
|
| 192 | + -- Optimise each test coercion and run the result through Core Lint.
|
|
| 193 | + let
|
|
| 194 | + co' = opt_co co
|
|
| 195 | + in_scope = tyCoVarsOfCoList co'
|
|
| 196 | + lint_cfg = initLintConfig dflags in_scope
|
|
| 197 | + for_ ( lintExpr lint_cfg ( Coercion co' ) ) \ errs ->
|
|
| 198 | + putMsg logger $
|
|
| 199 | + vcat [ text "Core Lint error for" <+> text name
|
|
| 200 | + , pprMessageBag errs
|
|
| 201 | + ] |
| ... | ... | @@ -9,5 +9,6 @@ setTestOpts(extra_hc_opts('-package ghc')) |
| 9 | 9 | setTestOpts(extra_run_opts('"' + config.libdir + '"'))
|
| 10 | 10 | |
| 11 | 11 | test('LintEtaExpand', normal, compile_and_run, [''])
|
| 12 | +test('T27374', normal, compile_and_run, [''])
|
|
| 12 | 13 | ## These tests use the GHC API.
|
| 13 | 14 | ## Test cases which don't use the GHC API should be added nearer the top. |