Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
-
14b72145
by Fendor at 2026-04-17T17:26:31-04:00
-
91aee7ae
by Simon Peyton Jones at 2026-04-17T17:26:32-04:00
-
36a66041
by mangoiv at 2026-04-17T17:26:32-04:00
19 changed files:
- + changelog.d/ghc-pkg-long-path-support
- compiler/GHC/Core/Lint.hs
- + compiler/GHC/Core/Lint/SubstTypeLets.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/WorkWrap/Utils.hs
- compiler/GHC/Core/Subst.hs
- compiler/GHC/Driver/Config/Core/Lint.hs
- compiler/GHC/Unit/State.hs
- compiler/ghc.cabal.in
- libraries/base/tests/perf/all.T
- libraries/ghc-boot/GHC/Unit/Database.hs
- libraries/ghc-boot/ghc-boot.cabal.in
- testsuite/tests/cabal/Makefile
- testsuite/tests/cabal/all.T
- + testsuite/tests/cabal/ghcpkg10.stdout
- testsuite/tests/corelint/LintEtaExpand.stderr
- testsuite/tests/corelint/T21115b.stderr
- utils/ghc-pkg/Main.hs
- utils/ghc-pkg/ghc-pkg.cabal.in
Changes:
| 1 | +section: ghc-pkg
|
|
| 2 | +synopsis: Improve ``ghc-pkg``'s support for long paths on windows.
|
|
| 3 | +issues: #26960
|
|
| 4 | +mrs: !15584
|
|
| 5 | + |
|
| 6 | +description: {
|
|
| 7 | + ``ghc-pkg`` can't handle working with file paths longer than the MAX_PATH
|
|
| 8 | + restrictions on windows as it is not using UNC file paths by default.
|
|
| 9 | + |
|
| 10 | + By using UNC file paths whenever possible, we improve ``ghc-pkg`` on windows.
|
|
| 11 | + Note, this still requires the user to enable the use of long paths in order to opt-in
|
|
| 12 | + this behaviour on older windows machines.
|
|
| 13 | +}
|
|
| 14 | + |
|
| 15 | + |
| ... | ... | @@ -18,7 +18,7 @@ module GHC.Core.Lint ( |
| 18 | 18 | LintConfig (..),
|
| 19 | 19 | WarnsAndErrs,
|
| 20 | 20 | |
| 21 | - lintCoreBindings', lintUnfolding,
|
|
| 21 | + lintCoreBindings, lintUnfolding,
|
|
| 22 | 22 | lintPassResult, lintExpr,
|
| 23 | 23 | lintAnnots, lintAxioms,
|
| 24 | 24 | |
| ... | ... | @@ -46,6 +46,7 @@ import GHC.Core.FVs |
| 46 | 46 | import GHC.Core.Utils
|
| 47 | 47 | import GHC.Core.Stats ( coreBindsStats )
|
| 48 | 48 | import GHC.Core.DataCon
|
| 49 | +import GHC.Core.Lint.SubstTypeLets( substTypeLets )
|
|
| 49 | 50 | import GHC.Core.Ppr
|
| 50 | 51 | import GHC.Core.Coercion
|
| 51 | 52 | import GHC.Core.Type as Type
|
| ... | ... | @@ -178,65 +179,7 @@ Note [Linting function types] |
| 178 | 179 | All saturated applications of funTyCon are represented with the FunTy constructor.
|
| 179 | 180 | See Note [Function type constructors and FunTy] in GHC.Builtin.Types.Prim
|
| 180 | 181 | |
| 181 | - We check this invariant in lintType.
|
|
| 182 | - |
|
| 183 | -Note [Linting type lets]
|
|
| 184 | -~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 185 | -In the desugarer, it's very very convenient to be able to say (in effect)
|
|
| 186 | - let a = Type Bool in
|
|
| 187 | - let x::a = True in <body>
|
|
| 188 | -That is, use a type let. See Note [Core type and coercion invariant] in "GHC.Core".
|
|
| 189 | -One place it is used is in mkWwBodies; see Note [Join points and beta-redexes]
|
|
| 190 | -in GHC.Core.Opt.WorkWrap.Utils. (Maybe there are other "clients" of this feature; I'm not sure).
|
|
| 191 | - |
|
| 192 | -* Hence when linting <body> we need to remember that a=Int, else we
|
|
| 193 | - might reject a correct program. So we carry a type substitution (in
|
|
| 194 | - this example [a -> Bool]) and apply this substitution before
|
|
| 195 | - comparing types. In effect, in Lint, type equality is always
|
|
| 196 | - equality-modulo-le-subst. This is in the le_subst field of
|
|
| 197 | - LintEnv. But nota bene:
|
|
| 198 | - |
|
| 199 | - (SI1) The le_subst substitution is applied to types and coercions only
|
|
| 200 | - |
|
| 201 | - (SI2) The result of that substitution is used only to check for type
|
|
| 202 | - equality, to check well-typed-ness, /but is then discarded/.
|
|
| 203 | - The result of substitution does not outlive the CoreLint pass.
|
|
| 204 | - |
|
| 205 | - (SI3) The InScopeSet of le_subst includes only TyVar and CoVar binders.
|
|
| 206 | - |
|
| 207 | -* The function
|
|
| 208 | - lintInTy :: Type -> LintM (Type, Kind)
|
|
| 209 | - returns a substituted type.
|
|
| 210 | - |
|
| 211 | -* When we encounter a binder (like x::a) we must apply the substitution
|
|
| 212 | - to the type of the binding variable. lintBinders does this.
|
|
| 213 | - |
|
| 214 | -* Clearly we need to clone tyvar binders as we go.
|
|
| 215 | - |
|
| 216 | -* But take care (#17590)! We must also clone CoVar binders:
|
|
| 217 | - let a = TYPE (ty |> cv)
|
|
| 218 | - in \cv -> blah
|
|
| 219 | - blindly substituting for `a` might capture `cv`.
|
|
| 220 | - |
|
| 221 | -* Alas, when cloning a coercion variable we might choose a unique
|
|
| 222 | - that happens to clash with an inner Id, thus
|
|
| 223 | - \cv_66 -> let wild_X7 = blah in blah
|
|
| 224 | - We decide to clone `cv_66` because it's already in scope. Fine,
|
|
| 225 | - choose a new unique. Aha, X7 looks good. So we check the lambda
|
|
| 226 | - body with le_subst of [cv_66 :-> cv_X7]
|
|
| 227 | - |
|
| 228 | - This is all fine, even though we use the same unique as wild_X7.
|
|
| 229 | - As (SI2) says, we do /not/ return a new lambda
|
|
| 230 | - (\cv_X7 -> let wild_X7 = blah in ...)
|
|
| 231 | - We simply use the le_subst substitution in types/coercions only, when
|
|
| 232 | - checking for equality.
|
|
| 233 | - |
|
| 234 | -* We still need to check that Id occurrences are bound by some
|
|
| 235 | - enclosing binding. We do /not/ use the InScopeSet for the le_subst
|
|
| 236 | - for this purpose -- it contains only TyCoVars. Instead we have a separate
|
|
| 237 | - le_ids for the in-scope Id binders.
|
|
| 238 | - |
|
| 239 | -Sigh. We might want to explore getting rid of type-let!
|
|
| 182 | +We check this invariant in lintType.
|
|
| 240 | 183 | |
| 241 | 184 | Note [Bad unsafe coercion]
|
| 242 | 185 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -311,6 +254,7 @@ path does not result in allocation in the hot path. This can be surprisingly |
| 311 | 254 | impactful. Changing `lint_app` reduced allocations for one test program I was
|
| 312 | 255 | looking at by ~4%.
|
| 313 | 256 | |
| 257 | + |
|
| 314 | 258 | ************************************************************************
|
| 315 | 259 | * *
|
| 316 | 260 | Beginning and ending passes
|
| ... | ... | @@ -407,26 +351,37 @@ data LintPassResultConfig = LintPassResultConfig |
| 407 | 351 | , lpr_platform :: !Platform
|
| 408 | 352 | , lpr_makeLintFlags :: !LintFlags
|
| 409 | 353 | , lpr_passPpr :: !SDoc
|
| 354 | + , lpr_preSubst :: !Bool -- True <=> run substTypeLets before linting
|
|
| 355 | + -- See Note [Substituting type-lets]
|
|
| 410 | 356 | , lpr_localsInScope :: ![Var]
|
| 411 | 357 | }
|
| 412 | 358 | |
| 413 | 359 | lintPassResult :: Logger -> LintPassResultConfig
|
| 414 | 360 | -> CoreProgram -> IO ()
|
| 415 | 361 | lintPassResult logger cfg binds
|
| 416 | - = do { let warns_and_errs = lintCoreBindings'
|
|
| 417 | - (LintConfig
|
|
| 362 | + = do { let lint_config = LintConfig
|
|
| 418 | 363 | { l_diagOpts = lpr_diagOpts cfg
|
| 419 | 364 | , l_platform = lpr_platform cfg
|
| 420 | 365 | , l_flags = lpr_makeLintFlags cfg
|
| 421 | 366 | , l_vars = lpr_localsInScope cfg
|
| 422 | - })
|
|
| 423 | - binds
|
|
| 367 | + }
|
|
| 368 | + |
|
| 369 | + -- Do the pre-substitution if necessary
|
|
| 370 | + -- See Note [Substituting type-lets] in GHC.Core.SubstTypeLets
|
|
| 371 | + -- especially wrinkle (STL2)
|
|
| 372 | + ; let binds1 | lpr_preSubst cfg = substTypeLets binds
|
|
| 373 | + | otherwise = binds
|
|
| 374 | + |
|
| 375 | + -- Do the main Lint pass itself
|
|
| 376 | + ; let warns_and_errs = lintCoreBindings lint_config binds1
|
|
| 377 | + |
|
| 378 | + -- Report the results
|
|
| 424 | 379 | ; Err.showPass logger $
|
| 425 | 380 | "Core Linted result of " ++
|
| 426 | 381 | renderWithContext defaultSDocContext (lpr_passPpr cfg)
|
| 427 | 382 | ; displayLintResults logger
|
| 428 | 383 | (lpr_passPpr cfg)
|
| 429 | - (pprCoreBindings binds) warns_and_errs
|
|
| 384 | + (pprCoreBindings binds1) warns_and_errs
|
|
| 430 | 385 | }
|
| 431 | 386 | |
| 432 | 387 | displayLintResults :: Logger
|
| ... | ... | @@ -456,11 +411,11 @@ lint_banner string pass = text "*** Core Lint" <+> text string |
| 456 | 411 | <+> text "***"
|
| 457 | 412 | |
| 458 | 413 | -- | Type-check a 'CoreProgram'. See Note [Core Lint guarantee].
|
| 459 | -lintCoreBindings' :: LintConfig -> CoreProgram -> WarnsAndErrs
|
|
| 414 | +lintCoreBindings :: LintConfig -> CoreProgram -> WarnsAndErrs
|
|
| 460 | 415 | -- Returns (warnings, errors)
|
| 461 | 416 | -- If you edit this function, you may need to update the GHC formalism
|
| 462 | 417 | -- See Note [GHC Formalism]
|
| 463 | -lintCoreBindings' cfg binds
|
|
| 418 | +lintCoreBindings cfg binds
|
|
| 464 | 419 | = initL cfg $
|
| 465 | 420 | addLoc TopLevelBindings $
|
| 466 | 421 | do { -- Check that all top-level binders are distinct
|
| ... | ... | @@ -472,8 +427,7 @@ lintCoreBindings' cfg binds |
| 472 | 427 | ; checkL (null ext_dups) (dupExtVars ext_dups)
|
| 473 | 428 | |
| 474 | 429 | -- Typecheck the bindings
|
| 475 | - ; lintRecBindings TopLevel all_pairs $ \_ ->
|
|
| 476 | - return () }
|
|
| 430 | + ; lintRecBindings TopLevel all_pairs $ return () }
|
|
| 477 | 431 | where
|
| 478 | 432 | all_pairs = flattenBinds binds
|
| 479 | 433 | -- Put all the top-level binders in scope at the start
|
| ... | ... | @@ -555,28 +509,28 @@ Check a core binding, returning the list of variables bound. |
| 555 | 509 | -- Let
|
| 556 | 510 | |
| 557 | 511 | lintRecBindings :: TopLevelFlag -> [(Id, CoreExpr)]
|
| 558 | - -> ([OutId] -> LintM a) -> LintM (a, [UsageEnv])
|
|
| 512 | + -> LintM a -> LintM (a, [UsageEnv])
|
|
| 559 | 513 | lintRecBindings top_lvl pairs thing_inside
|
| 560 | - = lintIdBndrs top_lvl bndrs $ \ bndrs' ->
|
|
| 561 | - do { ues <- zipWithM lint_pair bndrs' rhss
|
|
| 562 | - ; a <- thing_inside bndrs'
|
|
| 514 | + = lintIdBndrs top_lvl bndrs $
|
|
| 515 | + do { ues <- zipWithM lint_pair bndrs rhss
|
|
| 516 | + ; a <- thing_inside
|
|
| 563 | 517 | ; return (a, ues) }
|
| 564 | 518 | where
|
| 565 | 519 | (bndrs, rhss) = unzip pairs
|
| 566 | - lint_pair bndr' rhs
|
|
| 567 | - = addLoc (RhsOf bndr') $
|
|
| 568 | - do { (rhs_ty, ue) <- lintRhs bndr' rhs -- Check the rhs
|
|
| 569 | - ; lintLetBind top_lvl Recursive bndr' rhs rhs_ty
|
|
| 520 | + lint_pair bndr rhs
|
|
| 521 | + = addLoc (RhsOf bndr) $
|
|
| 522 | + do { (rhs_ty, ue) <- lintRhs bndr rhs -- Check the rhs
|
|
| 523 | + ; lintLetBind top_lvl Recursive bndr rhs rhs_ty
|
|
| 570 | 524 | ; return ue }
|
| 571 | 525 | |
| 572 | -lintLetBody :: LintLocInfo -> [OutId] -> CoreExpr -> LintM (OutType, UsageEnv)
|
|
| 526 | +lintLetBody :: LintLocInfo -> [Id] -> CoreExpr -> LintM (Type, UsageEnv)
|
|
| 573 | 527 | lintLetBody loc bndrs body
|
| 574 | 528 | = do { (body_ty, body_ue) <- addLoc loc (lintCoreExpr body)
|
| 575 | 529 | ; mapM_ (lintJoinBndrType body_ty) bndrs
|
| 576 | 530 | ; return (body_ty, body_ue) }
|
| 577 | 531 | |
| 578 | -lintLetBind :: TopLevelFlag -> RecFlag -> OutId
|
|
| 579 | - -> CoreExpr -> OutType -> LintM ()
|
|
| 532 | +lintLetBind :: TopLevelFlag -> RecFlag -> Id
|
|
| 533 | + -> CoreExpr -> Type -> LintM ()
|
|
| 580 | 534 | -- Binder's type, and the RHS, have already been linted
|
| 581 | 535 | -- This function checks other invariants
|
| 582 | 536 | lintLetBind top_lvl rec_flag binder rhs rhs_ty
|
| ... | ... | @@ -651,14 +605,17 @@ lintLetBind top_lvl rec_flag binder rhs rhs_ty |
| 651 | 605 | |
| 652 | 606 | _ -> return ()
|
| 653 | 607 | |
| 654 | - ; addLoc (RuleOf binder) $ mapM_ (lintCoreRule binder binder_ty) (idCoreRules binder)
|
|
| 608 | + -- Lint any RULES
|
|
| 609 | + ; addLoc (RuleOf binder) $
|
|
| 610 | + mapM_ (lintCoreRule binder binder_ty) (idCoreRules binder)
|
|
| 655 | 611 | |
| 612 | + -- Lint the unfolding
|
|
| 613 | + -- Do this here, not in lintIdBinder, so that all the
|
|
| 614 | + -- binders of the letrec group are in scope
|
|
| 656 | 615 | ; addLoc (UnfoldingOf binder) $
|
| 657 | 616 | lintIdUnfolding binder binder_ty (idUnfolding binder)
|
| 658 | - ; return () }
|
|
| 659 | 617 | |
| 660 | - -- We should check the unfolding, if any, but this is tricky because
|
|
| 661 | - -- the unfolding is a SimplifiableCoreExpr. Give up for now.
|
|
| 618 | + ; return () }
|
|
| 662 | 619 | |
| 663 | 620 | -- | Checks the RHS of bindings. It only differs from 'lintCoreExpr'
|
| 664 | 621 | -- in that it doesn't reject occurrences of the function 'makeStatic' when they
|
| ... | ... | @@ -667,7 +624,7 @@ lintLetBind top_lvl rec_flag binder rhs rhs_ty |
| 667 | 624 | -- join point.
|
| 668 | 625 | --
|
| 669 | 626 | -- See Note [Checking StaticPtrs].
|
| 670 | -lintRhs :: Id -> CoreExpr -> LintM (OutType, UsageEnv)
|
|
| 627 | +lintRhs :: Id -> CoreExpr -> LintM (Type, UsageEnv)
|
|
| 671 | 628 | -- NB: the Id can be Linted or not -- it's only used for
|
| 672 | 629 | -- its OccInfo and join-pointer-hood
|
| 673 | 630 | lintRhs bndr rhs
|
| ... | ... | @@ -682,7 +639,7 @@ lintRhs _bndr rhs = fmap lf_check_static_ptrs getLintFlags >>= go |
| 682 | 639 | where
|
| 683 | 640 | -- Allow occurrences of 'makeStatic' at the top-level but produce errors
|
| 684 | 641 | -- otherwise.
|
| 685 | - go :: StaticPtrCheck -> LintM (OutType, UsageEnv)
|
|
| 642 | + go :: StaticPtrCheck -> LintM (Type, UsageEnv)
|
|
| 686 | 643 | go AllowAtTopLevel
|
| 687 | 644 | | (binders0, rhs') <- collectTyBinders rhs
|
| 688 | 645 | , Just (fun, t, info, e) <- collectMakeStaticArgs rhs'
|
| ... | ... | @@ -699,7 +656,7 @@ lintRhs _bndr rhs = fmap lf_check_static_ptrs getLintFlags >>= go |
| 699 | 656 | |
| 700 | 657 | -- | Lint the RHS of a join point with expected join arity of @n@ (see Note
|
| 701 | 658 | -- [Join points] in "GHC.Core").
|
| 702 | -lintJoinLams :: JoinArity -> Maybe Id -> CoreExpr -> LintM (OutType, UsageEnv)
|
|
| 659 | +lintJoinLams :: JoinArity -> Maybe Id -> CoreExpr -> LintM (Type, UsageEnv)
|
|
| 703 | 660 | lintJoinLams join_arity enforce rhs
|
| 704 | 661 | = go join_arity rhs
|
| 705 | 662 | where
|
| ... | ... | @@ -715,17 +672,22 @@ lintIdUnfolding :: Id -> Type -> Unfolding -> LintM () |
| 715 | 672 | lintIdUnfolding bndr bndr_ty uf
|
| 716 | 673 | | isStableUnfolding uf
|
| 717 | 674 | , Just rhs <- maybeUnfoldingTemplate uf
|
| 718 | - = noMultiplicityChecks $ -- Skip linearity checking for unfoldings
|
|
| 719 | - -- See Note [Linting linearity]
|
|
| 720 | - do { ty <- fst <$> (if isCompulsoryUnfolding uf
|
|
| 721 | - then noFixedRuntimeRepChecks $ lintRhs bndr rhs
|
|
| 722 | - -- ^^^^^^^^^^^^^^^^^^^^^^^
|
|
| 723 | - -- See Note [Checking for representation polymorphism]
|
|
| 724 | - else lintRhs bndr rhs)
|
|
| 725 | - ; ensureEqTys bndr_ty ty (mkRhsMsg bndr (text "unfolding") ty) }
|
|
| 726 | -lintIdUnfolding _ _ _
|
|
| 727 | - = return () -- Do not Lint unstable unfoldings, because that leads
|
|
| 728 | - -- to exponential behaviour; c.f. GHC.Core.FVs.idUnfoldingVars
|
|
| 675 | + = suppress_rr_checks $
|
|
| 676 | + noMultiplicityChecks $ -- Skip linearity checking for unfoldings
|
|
| 677 | + -- See Note [Linting linearity]
|
|
| 678 | + do { (unf_ty, _unf_ue) <- lintRhs bndr rhs
|
|
| 679 | + ; ensureEqTys bndr_ty unf_ty (mkRhsMsg bndr (text "unfolding") unf_ty) }
|
|
| 680 | + |
|
| 681 | + | otherwise
|
|
| 682 | + = -- Do not Lint the body of an unstable unfolding, because that leads
|
|
| 683 | + -- to exponential behaviour; c.f. GHC.Core.FVs.idUnfoldingVars
|
|
| 684 | + return ()
|
|
| 685 | + |
|
| 686 | + where
|
|
| 687 | + -- See Note [Checking for representation polymorphism]
|
|
| 688 | + suppress_rr_checks thing_inside
|
|
| 689 | + | isCompulsoryUnfolding uf = noFixedRuntimeRepChecks thing_inside
|
|
| 690 | + | otherwise = thing_inside
|
|
| 729 | 691 | |
| 730 | 692 | {- Note [Checking for INLINE loop breakers]
|
| 731 | 693 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -887,13 +849,8 @@ suspicious and worth investigating if you have a seg-fault or bizarre behaviour. |
| 887 | 849 | ************************************************************************
|
| 888 | 850 | -}
|
| 889 | 851 | |
| 890 | -lintCoreExpr :: InExpr -> LintM (OutType, UsageEnv)
|
|
| 891 | --- The returned type has the substitution from the monad
|
|
| 892 | --- already applied to it:
|
|
| 893 | --- lintCoreExpr e subst = exprType (subst e)
|
|
| 894 | ---
|
|
| 895 | --- The returned "type" can be a kind, if the expression is (Type ty)
|
|
| 896 | - |
|
| 852 | +lintCoreExpr :: CoreExpr -> LintM (Type, UsageEnv)
|
|
| 853 | +-- The returned type is the type of the expression
|
|
| 897 | 854 | -- If you edit this function, you may need to update the GHC formalism
|
| 898 | 855 | -- See Note [GHC Formalism]
|
| 899 | 856 | |
| ... | ... | @@ -920,7 +877,7 @@ lintCoreExpr (Cast expr co) |
| 920 | 877 | |
| 921 | 878 | ; lintCoercion co
|
| 922 | 879 | ; lintRole co Representational (coercionRole co)
|
| 923 | - ; Pair from_ty to_ty <- substCoKindM co
|
|
| 880 | + ; let Pair from_ty to_ty = coercionKind co
|
|
| 924 | 881 | ; checkValueType (typeKind to_ty) $
|
| 925 | 882 | text "target of cast" <+> quotes (ppr co)
|
| 926 | 883 | ; ensureEqTys from_ty expr_ty (mkCastErr expr co from_ty expr_ty)
|
| ... | ... | @@ -934,27 +891,22 @@ lintCoreExpr (Tick tickish expr) |
| 934 | 891 | |
| 935 | 892 | lintCoreExpr (Let (NonRec tv (Type ty)) body)
|
| 936 | 893 | | isTyVar tv
|
| 937 | - = -- See Note [Linting type lets]
|
|
| 938 | - do { ty' <- lintTypeAndSubst ty
|
|
| 939 | - ; lintTyCoBndr tv $ \ tv' ->
|
|
| 940 | - do { addLoc (RhsOf tv) $ lintTyKind tv' ty'
|
|
| 941 | - -- Now extend the substitution so we
|
|
| 942 | - -- take advantage of it in the body
|
|
| 943 | - ; extendTvSubstL tv ty' $
|
|
| 944 | - addLoc (BodyOfLet tv) $
|
|
| 945 | - lintCoreExpr body } }
|
|
| 894 | + = do { lintType ty
|
|
| 895 | + ; lintTyCoBndr tv $
|
|
| 896 | + do { addLoc (RhsOf tv) $ lintTyKind tv ty
|
|
| 897 | + ; addLoc (BodyOfLet tv) $ lintCoreExpr body } }
|
|
| 946 | 898 | |
| 947 | 899 | lintCoreExpr (Let (NonRec bndr rhs) body)
|
| 948 | 900 | | isId bndr
|
| 949 | 901 | = do { -- First Lint the RHS, before bringing the binder into scope
|
| 950 | 902 | (rhs_ty, let_ue) <- lintRhs bndr rhs
|
| 951 | 903 | |
| 952 | - -- See Note [Multiplicity of let binders] in Var
|
|
| 904 | + -- See Note [Multiplicity of let binders] in Var
|
|
| 953 | 905 | -- Now lint the binder
|
| 954 | - ; lintBinder LetBind bndr $ \bndr' ->
|
|
| 955 | - do { lintLetBind NotTopLevel NonRecursive bndr' rhs rhs_ty
|
|
| 956 | - ; addAliasUE bndr' let_ue $
|
|
| 957 | - lintLetBody (BodyOfLet bndr') [bndr'] body } }
|
|
| 906 | + ; lintBinder LetBind bndr $
|
|
| 907 | + do { lintLetBind NotTopLevel NonRecursive bndr rhs rhs_ty
|
|
| 908 | + ; addAliasUE bndr let_ue $
|
|
| 909 | + lintLetBody (BodyOfLet bndr) [bndr] body } }
|
|
| 958 | 910 | |
| 959 | 911 | | otherwise
|
| 960 | 912 | = failWithL (mkLetErr bndr rhs) -- Not quite accurate
|
| ... | ... | @@ -973,8 +925,8 @@ lintCoreExpr e@(Let (Rec pairs) body) |
| 973 | 925 | |
| 974 | 926 | -- See Note [Multiplicity of let binders] in Var
|
| 975 | 927 | ; ((body_type, body_ue), ues) <-
|
| 976 | - lintRecBindings NotTopLevel pairs $ \ bndrs' ->
|
|
| 977 | - lintLetBody (BodyOfLetRec bndrs') bndrs' body
|
|
| 928 | + lintRecBindings NotTopLevel pairs $
|
|
| 929 | + lintLetBody (BodyOfLetRec bndrs) bndrs body
|
|
| 978 | 930 | ; return (body_type, body_ue `addUE` scaleUE ManyTy (foldr1WithDefault zeroUE addUE ues)) }
|
| 979 | 931 | where
|
| 980 | 932 | bndrs = map fst pairs
|
| ... | ... | @@ -986,7 +938,7 @@ lintCoreExpr e@(App _ _) |
| 986 | 938 | -- N.B. we may have an over-saturated application of the form:
|
| 987 | 939 | -- runRW (\s -> \x -> ...) y
|
| 988 | 940 | , ty_arg1 : ty_arg2 : cont_arg : rest <- args
|
| 989 | - = do { let lint_rw_cont :: CoreArg -> Mult -> UsageEnv -> LintM (OutType, UsageEnv)
|
|
| 941 | + = do { let lint_rw_cont :: CoreArg -> Mult -> UsageEnv -> LintM (Type, UsageEnv)
|
|
| 990 | 942 | lint_rw_cont expr@(Lam _ _) mult fun_ue
|
| 991 | 943 | = do { (arg_ty, arg_ue) <- lintJoinLams 1 (Just fun) expr
|
| 992 | 944 | ; let app_ue = addUE fun_ue (scaleUE mult arg_ue)
|
| ... | ... | @@ -1036,74 +988,73 @@ lintCoreExpr (Type ty) |
| 1036 | 988 | lintCoreExpr (Coercion co)
|
| 1037 | 989 | -- See Note [Coercions in terms]
|
| 1038 | 990 | = do { addLoc (InCo co) $ lintCoercion co
|
| 1039 | - ; ty <- substTyM (coercionType co)
|
|
| 991 | + ; let ty = coercionType co
|
|
| 1040 | 992 | ; return (ty, zeroUE) }
|
| 1041 | 993 | |
| 1042 | 994 | ----------------------
|
| 1043 | -lintIdOcc :: InId -> Int -- Number of arguments (type or value) being passed
|
|
| 1044 | - -> LintM (OutType, UsageEnv) -- returns type of the *variable*
|
|
| 1045 | -lintIdOcc in_id nargs
|
|
| 1046 | - = addLoc (OccOf in_id) $
|
|
| 1047 | - do { checkL (isNonCoVarId in_id)
|
|
| 1048 | - (text "Non term variable" <+> ppr in_id)
|
|
| 995 | +lintIdOcc :: Id -> Int -- Number of arguments (type or value) being passed
|
|
| 996 | + -> LintM (Type, UsageEnv) -- returns type of the *variable*
|
|
| 997 | +lintIdOcc id nargs
|
|
| 998 | + = addLoc (OccOf id) $
|
|
| 999 | + do { checkL (isNonCoVarId id)
|
|
| 1000 | + (text "Non term variable" <+> ppr id)
|
|
| 1049 | 1001 | -- See GHC.Core Note [Variable occurrences in Core]
|
| 1050 | 1002 | |
| 1051 | - -- Check that the type of the occurrence is the same
|
|
| 1052 | - -- as the type of the binding site. The inScopeIds are
|
|
| 1053 | - -- /un-substituted/, so this checks that the occurrence type
|
|
| 1054 | - -- is identical to the binder type.
|
|
| 1055 | - -- This makes things much easier for things like:
|
|
| 1056 | - -- /\a. \(x::Maybe a). /\a. ...(x::Maybe a)...
|
|
| 1057 | - -- The "::Maybe a" on the occurrence is referring to the /outer/ a.
|
|
| 1058 | - -- If we compared /substituted/ types we'd risk comparing
|
|
| 1059 | - -- (Maybe a) from the binding site with bogus (Maybe a1) from
|
|
| 1060 | - -- the occurrence site. Comparing un-substituted types finesses
|
|
| 1061 | - -- this altogether
|
|
| 1062 | - ; out_ty <- lintVarOcc in_id
|
|
| 1003 | + ; lintVarOcc id
|
|
| 1063 | 1004 | |
| 1064 | 1005 | -- Check for a nested occurrence of the StaticPtr constructor.
|
| 1065 | 1006 | -- See Note [Checking StaticPtrs].
|
| 1066 | 1007 | ; when (nargs /= 0) $
|
| 1067 | - checkL (idName in_id /= makeStaticName) $
|
|
| 1008 | + checkL (idName id /= makeStaticName) $
|
|
| 1068 | 1009 | text "Found makeStatic nested in an expression"
|
| 1069 | 1010 | |
| 1070 | - ; checkDeadIdOcc in_id
|
|
| 1011 | + ; checkDeadIdOcc id
|
|
| 1071 | 1012 | |
| 1072 | - ; case isDataConId_maybe in_id of
|
|
| 1013 | + ; case isDataConId_maybe id of
|
|
| 1073 | 1014 | Nothing -> return ()
|
| 1074 | 1015 | Just dc -> checkTypeDataConOcc "expression" dc
|
| 1075 | 1016 | |
| 1076 | - ; checkJoinOcc in_id nargs
|
|
| 1077 | - ; usage <- varCallSiteUsage in_id
|
|
| 1078 | - |
|
| 1079 | - ; return (out_ty, usage) }
|
|
| 1017 | + ; checkJoinOcc id nargs
|
|
| 1018 | + ; usage <- varCallSiteUsage id
|
|
| 1080 | 1019 | |
| 1020 | + ; return (idType id, usage) }
|
|
| 1081 | 1021 | |
| 1082 | 1022 | |
| 1023 | +------------------
|
|
| 1083 | 1024 | lintCoreFun :: CoreExpr
|
| 1084 | - -> Int -- Number of arguments (type or val) being passed
|
|
| 1085 | - -> LintM (OutType, UsageEnv) -- Returns type of the *function*
|
|
| 1025 | + -> Int -- Number of arguments (type or val) being passed
|
|
| 1026 | + -> LintM (Type, UsageEnv) -- Returns type of the *function*
|
|
| 1086 | 1027 | lintCoreFun (Var var) nargs
|
| 1087 | 1028 | = lintIdOcc var nargs
|
| 1088 | 1029 | |
| 1089 | 1030 | lintCoreFun (Lam var body) nargs
|
| 1090 | - -- Act like lintCoreExpr of Lam, but *don't* call markAllJoinsBad;
|
|
| 1091 | - -- See Note [Beta redexes]
|
|
| 1031 | + -- Act like lintCoreExpr of Lam, but *don't* necessarily call markAllJoinsBad;
|
|
| 1032 | + -- See Note [Join points and beta-redexes]
|
|
| 1092 | 1033 | | nargs /= 0
|
| 1093 | 1034 | = lintLambda var $ lintCoreFun body (nargs - 1)
|
| 1094 | 1035 | |
| 1095 | 1036 | lintCoreFun expr nargs
|
| 1096 | - = markAllJoinsBadIf (nargs /= 0) $
|
|
| 1097 | - -- See Note [Join points are less general than the paper]
|
|
| 1098 | - lintCoreExpr expr
|
|
| 1037 | + = do { mark_bad_joins
|
|
| 1038 | + <- if nargs == 0
|
|
| 1039 | + then -- Saturated lambda
|
|
| 1040 | + -- See Note [Join points and beta-redexes]
|
|
| 1041 | + do { flags <- getLintFlags
|
|
| 1042 | + ; return (not (lf_allow_beta_joins flags)) }
|
|
| 1043 | + else -- Something else
|
|
| 1044 | + -- See Note [Join points are less general than the paper]
|
|
| 1045 | + return True
|
|
| 1046 | + |
|
| 1047 | + ; markAllJoinsBadIf mark_bad_joins $
|
|
| 1048 | + lintCoreExpr expr }
|
|
| 1049 | + |
|
| 1099 | 1050 | ------------------
|
| 1100 | 1051 | lintLambda :: Var -> LintM (Type, UsageEnv) -> LintM (Type, UsageEnv)
|
| 1101 | 1052 | lintLambda var lintBody =
|
| 1102 | 1053 | addLoc (LambdaBodyOf var) $
|
| 1103 | - lintBinder LambdaBind var $ \ var' ->
|
|
| 1054 | + lintBinder LambdaBind var $
|
|
| 1104 | 1055 | do { (body_ty, ue) <- lintBody
|
| 1105 | - ; ue' <- checkLinearity ue var'
|
|
| 1106 | - ; return (mkLamType var' body_ty, ue') }
|
|
| 1056 | + ; ue' <- checkLinearity ue var
|
|
| 1057 | + ; return (mkLamType var body_ty, ue') }
|
|
| 1107 | 1058 | ------------------
|
| 1108 | 1059 | checkDeadIdOcc :: Id -> LintM ()
|
| 1109 | 1060 | -- Occurrences of an Id should never be dead....
|
| ... | ... | @@ -1117,8 +1068,8 @@ checkDeadIdOcc id |
| 1117 | 1068 | = return ()
|
| 1118 | 1069 | |
| 1119 | 1070 | ------------------
|
| 1120 | -lintJoinBndrType :: OutType -- Type of the body
|
|
| 1121 | - -> OutId -- Possibly a join Id
|
|
| 1071 | +lintJoinBndrType :: Type -- Type of the body
|
|
| 1072 | + -> Id -- Possibly a join Id
|
|
| 1122 | 1073 | -> LintM ()
|
| 1123 | 1074 | -- Checks that the return type of a join Id matches the body
|
| 1124 | 1075 | -- E.g. join j x = rhs in body
|
| ... | ... | @@ -1337,8 +1288,55 @@ checkLinearity body_ue lam_var = |
| 1337 | 1288 | return body_ue'
|
| 1338 | 1289 | Nothing -> return body_ue -- A type variable
|
| 1339 | 1290 | |
| 1340 | -{- Note [Linting join points with casts or ticks]
|
|
| 1341 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1291 | +{- Note [Join points and beta-redexes]
|
|
| 1292 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1293 | +In the worker/wrapper pass, the worker invokes the original function by calling
|
|
| 1294 | +it with arguments, thus producing a beta-redex for the simplifier to munch away:
|
|
| 1295 | + |
|
| 1296 | + \x y z -> e => (\x y z -> e) wx wy wz
|
|
| 1297 | + |
|
| 1298 | +But we need to take care if `e` invokes a join point. For example:
|
|
| 1299 | + |
|
| 1300 | + join j1 x = ...
|
|
| 1301 | + join j2 y = if y == 0 then 0 else j1 y
|
|
| 1302 | +=>
|
|
| 1303 | + join j1 x = ...
|
|
| 1304 | + join $wj2 y# = (\y -> if y == 0 then 0 else jump j1 y) (I# y#)
|
|
| 1305 | + join j2 y = case y of I# y# -> jump $wj2 y#
|
|
| 1306 | + |
|
| 1307 | +Now the jump to `j1` is inside a lambda and inside an application. That is ill-typed
|
|
| 1308 | +from Lint's point of view. And yet, after one round of simplification it'll all be
|
|
| 1309 | +fine.
|
|
| 1310 | + |
|
| 1311 | +You might wonder if we could use a `let` instead of a lambda for the worker:
|
|
| 1312 | + |
|
| 1313 | + join $wj2 y# = let y = I# y#
|
|
| 1314 | + in if y == 0 then 0 else jump j1 y
|
|
| 1315 | + |
|
| 1316 | +That would solve the join-point problem, but it really doesn't work because
|
|
| 1317 | + 1. The lets shadow each other
|
|
| 1318 | + 2. In particular the invariant (NoTypeShadowing) is easily broken.
|
|
| 1319 | + (We might have type lambdas of course.)
|
|
| 1320 | + |
|
| 1321 | +In short, te lambda arguments should not "see" any of the lambda-bound
|
|
| 1322 | +variables.
|
|
| 1323 | + |
|
| 1324 | +So our solution is this:
|
|
| 1325 | + |
|
| 1326 | +* Use straightforward applicaion in the worker-wrapper pass, creating a beta-redex.
|
|
| 1327 | + See the call to `mkApps` in GHC.Core.Opt.WorkWrap.Utils.mkWwBodies.
|
|
| 1328 | + |
|
| 1329 | +* Tell Lint not to complain about a join-point invocation hidden under a
|
|
| 1330 | + saturated beta-redex. The code is rather simple: see `lintCoreFun`.
|
|
| 1331 | + |
|
| 1332 | + We guard this with a Lint flag `lf_allow_beta_joins`.
|
|
| 1333 | + |
|
| 1334 | +* Teach occurrence analysis that `j1` is still a join point, despite its
|
|
| 1335 | + call being nested inside the beta-redex. See Note [occAnal for applications]
|
|
| 1336 | + in GHC.Core.Opt.OccurAnal.
|
|
| 1337 | + |
|
| 1338 | +Note [Linting join points with casts or ticks]
|
|
| 1339 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1342 | 1340 | As per Note [Join points, casts, and ticks] in GHC.Core, we have to be careful
|
| 1343 | 1341 | when a cast or tick occurs in between a join point binding and a corresponding
|
| 1344 | 1342 | join point occurrence.
|
| ... | ... | @@ -1409,33 +1407,6 @@ lose track of why an expression is bottom, so we shouldn't make too |
| 1409 | 1407 | much fuss when that happens.
|
| 1410 | 1408 | |
| 1411 | 1409 | |
| 1412 | -Note [Beta redexes]
|
|
| 1413 | -~~~~~~~~~~~~~~~~~~~
|
|
| 1414 | -Consider:
|
|
| 1415 | - |
|
| 1416 | - join j @x y z = ... in
|
|
| 1417 | - (\@x y z -> jump j @x y z) @t e1 e2
|
|
| 1418 | - |
|
| 1419 | -This is clearly ill-typed, since the jump is inside both an application and a
|
|
| 1420 | -lambda, either of which is enough to disqualify it as a tail call (see Note
|
|
| 1421 | -[Invariants on join points] in GHC.Core). However, strictly from a
|
|
| 1422 | -lambda-calculus perspective, the term doesn't go wrong---after the two beta
|
|
| 1423 | -reductions, the jump *is* a tail call and everything is fine.
|
|
| 1424 | - |
|
| 1425 | -Why would we want to allow this when we have let? One reason is that a compound
|
|
| 1426 | -beta redex (that is, one with more than one argument) has different scoping
|
|
| 1427 | -rules: naively reducing the above example using lets will capture any free
|
|
| 1428 | -occurrence of y in e2. More fundamentally, type lets are tricky; many passes,
|
|
| 1429 | -such as Float Out, tacitly assume that the incoming program's type lets have
|
|
| 1430 | -all been dealt with by the simplifier. Thus we don't want to let-bind any types
|
|
| 1431 | -in, say, GHC.Core.Subst.simpleOptPgm, which in some circumstances can run immediately
|
|
| 1432 | -before Float Out.
|
|
| 1433 | - |
|
| 1434 | -All that said, currently GHC.Core.Subst.simpleOptPgm is the only thing using this
|
|
| 1435 | -loophole, doing so to avoid re-traversing large functions (beta-reducing a type
|
|
| 1436 | -lambda without introducing a type let requires a substitution). TODO: Improve
|
|
| 1437 | -simpleOptPgm so that we can forget all this ever happened.
|
|
| 1438 | - |
|
| 1439 | 1410 | ************************************************************************
|
| 1440 | 1411 | * *
|
| 1441 | 1412 | \subsection[lintCoreArgs]{lintCoreArgs}
|
| ... | ... | @@ -1449,23 +1420,23 @@ subtype of the required type, as one would expect. |
| 1449 | 1420 | -- Takes the functions type and arguments as argument.
|
| 1450 | 1421 | -- Returns the *result* of applying the function to arguments.
|
| 1451 | 1422 | -- e.g. f :: Int -> Bool -> Int would return `Int` as result type.
|
| 1452 | -lintCoreArgs :: (OutType, UsageEnv) -> [InExpr] -> LintM (OutType, UsageEnv)
|
|
| 1423 | +lintCoreArgs :: (Type, UsageEnv) -> [CoreExpr] -> LintM (Type, UsageEnv)
|
|
| 1453 | 1424 | lintCoreArgs (fun_ty, fun_ue) args
|
| 1454 | - = lintApp (text "expression")
|
|
| 1455 | - lintTyArg lintValArg fun_ty args fun_ue
|
|
| 1425 | + = lintApp (text "expression") lintTyArg lintValArg fun_ty args fun_ue
|
|
| 1456 | 1426 | |
| 1457 | -lintTyArg :: InExpr -> LintM OutType
|
|
| 1427 | +lintTyArg :: CoreExpr -> LintM Type
|
|
| 1458 | 1428 | |
| 1459 | 1429 | -- Type argument
|
| 1460 | 1430 | lintTyArg (Type arg_ty)
|
| 1461 | 1431 | = do { checkL (not (isCoercionTy arg_ty))
|
| 1462 | 1432 | (text "Unnecessary coercion-to-type injection:"
|
| 1463 | 1433 | <+> ppr arg_ty)
|
| 1464 | - ; lintTypeAndSubst arg_ty }
|
|
| 1434 | + ; lintType arg_ty
|
|
| 1435 | + ; return arg_ty }
|
|
| 1465 | 1436 | lintTyArg arg
|
| 1466 | 1437 | = failWithL (hang (text "Expected type argument but found") 2 (ppr arg))
|
| 1467 | 1438 | |
| 1468 | -lintValArg :: InExpr -> Mult -> UsageEnv -> LintM (OutType, UsageEnv)
|
|
| 1439 | +lintValArg :: CoreExpr -> Mult -> UsageEnv -> LintM (Type, UsageEnv)
|
|
| 1469 | 1440 | lintValArg arg mult fun_ue
|
| 1470 | 1441 | = do { (arg_ty, arg_ue) <- markAllJoinsBad $ lintCoreExpr arg
|
| 1471 | 1442 | -- See Note [Representation polymorphism invariants] in GHC.Core
|
| ... | ... | @@ -1484,9 +1455,9 @@ lintValArg arg mult fun_ue |
| 1484 | 1455 | |
| 1485 | 1456 | -----------------
|
| 1486 | 1457 | lintAltBinders :: UsageEnv
|
| 1487 | - -> Var -- Case binder
|
|
| 1488 | - -> OutType -- Scrutinee type
|
|
| 1489 | - -> OutType -- Constructor type
|
|
| 1458 | + -> Var -- Case binder
|
|
| 1459 | + -> Type -- Scrutinee type
|
|
| 1460 | + -> Type -- Constructor type
|
|
| 1490 | 1461 | -> [(Mult, OutVar)] -- Binders
|
| 1491 | 1462 | -> LintM UsageEnv
|
| 1492 | 1463 | -- If you edit this function, you may need to update the GHC formalism
|
| ... | ... | @@ -1505,6 +1476,7 @@ lintAltBinders rhs_ue case_bndr scrut_ty con_ty ((var_w, bndr):bndrs) |
| 1505 | 1476 | ; rhs_ue' <- checkCaseLinearity rhs_ue case_bndr var_w bndr
|
| 1506 | 1477 | ; lintAltBinders rhs_ue' case_bndr scrut_ty con_ty' bndrs }
|
| 1507 | 1478 | |
| 1479 | + |
|
| 1508 | 1480 | -- | Implements the case rules for linearity
|
| 1509 | 1481 | checkCaseLinearity :: UsageEnv -> Var -> Mult -> Var -> LintM UsageEnv
|
| 1510 | 1482 | checkCaseLinearity ue case_bndr var_w bndr = do
|
| ... | ... | @@ -1529,7 +1501,7 @@ checkCaseLinearity ue case_bndr var_w bndr = do |
| 1529 | 1501 | |
| 1530 | 1502 | |
| 1531 | 1503 | -----------------
|
| 1532 | -lintTyApp :: OutType -> OutType -> LintM OutType
|
|
| 1504 | +lintTyApp :: Type -> Type -> LintM Type
|
|
| 1533 | 1505 | lintTyApp fun_ty arg_ty
|
| 1534 | 1506 | | Just (tv,body_ty) <- splitForAllTyVar_maybe fun_ty
|
| 1535 | 1507 | = do { lintTyKind tv arg_ty
|
| ... | ... | @@ -1547,8 +1519,8 @@ lintTyApp fun_ty arg_ty |
| 1547 | 1519 | -- | @lintValApp arg fun_ty arg_ty@ lints an application of @fun arg@
|
| 1548 | 1520 | -- where @fun :: fun_ty@ and @arg :: arg_ty@, returning the type of the
|
| 1549 | 1521 | -- application.
|
| 1550 | -lintValApp :: CoreExpr -> OutType -> OutType -> UsageEnv -> UsageEnv
|
|
| 1551 | - -> LintM (OutType, UsageEnv)
|
|
| 1522 | +lintValApp :: CoreExpr -> Type -> Type -> UsageEnv -> UsageEnv
|
|
| 1523 | + -> LintM (Type, UsageEnv)
|
|
| 1552 | 1524 | lintValApp arg fun_ty arg_ty fun_ue arg_ue
|
| 1553 | 1525 | | Just (_, w, arg_ty', res_ty') <- splitFunTy_maybe fun_ty
|
| 1554 | 1526 | = do { ensureEqTys arg_ty' arg_ty (mkAppMsg arg_ty' arg_ty arg)
|
| ... | ... | @@ -1559,9 +1531,7 @@ lintValApp arg fun_ty arg_ty fun_ue arg_ue |
| 1559 | 1531 | where
|
| 1560 | 1532 | err2 = mkNonFunAppMsg fun_ty arg_ty arg
|
| 1561 | 1533 | |
| 1562 | -lintTyKind :: OutTyVar -> OutType -> LintM ()
|
|
| 1563 | --- Both args have had substitution applied
|
|
| 1564 | - |
|
| 1534 | +lintTyKind :: OutTyVar -> Type -> LintM ()
|
|
| 1565 | 1535 | -- If you edit this function, you may need to update the GHC formalism
|
| 1566 | 1536 | -- See Note [GHC Formalism]
|
| 1567 | 1537 | lintTyKind tyvar arg_ty
|
| ... | ... | @@ -1579,36 +1549,36 @@ lintTyKind tyvar arg_ty |
| 1579 | 1549 | ************************************************************************
|
| 1580 | 1550 | -}
|
| 1581 | 1551 | |
| 1582 | -lintCaseExpr :: CoreExpr -> InId -> InType -> [CoreAlt] -> LintM (OutType, UsageEnv)
|
|
| 1552 | +lintCaseExpr :: CoreExpr -> Id -> Type -> [CoreAlt] -> LintM (Type, UsageEnv)
|
|
| 1583 | 1553 | lintCaseExpr scrut case_bndr alt_ty alts
|
| 1584 | 1554 | = do { let e = Case scrut case_bndr alt_ty alts -- Just for error messages
|
| 1585 | 1555 | |
| 1586 | 1556 | -- Check the scrutinee
|
| 1587 | - ; (scrut_ty', scrut_ue) <- markAllJoinsBad $ lintCoreExpr scrut
|
|
| 1557 | + ; (scrut_ty, scrut_ue) <- markAllJoinsBad $ lintCoreExpr scrut
|
|
| 1588 | 1558 | -- See Note [Join points are less general than the paper]
|
| 1589 | 1559 | -- in GHC.Core
|
| 1590 | 1560 | |
| 1591 | - ; alt_ty' <- addLoc (CaseTy scrut) $ lintValueType alt_ty
|
|
| 1561 | + ; addLoc (CaseTy scrut) $ lintValueType alt_ty
|
|
| 1592 | 1562 | |
| 1593 | - ; checkCaseAlts e scrut scrut_ty' alts
|
|
| 1563 | + ; checkCaseAlts e scrut scrut_ty alts
|
|
| 1594 | 1564 | |
| 1595 | 1565 | -- Lint the case-binder. Must do this after linting the scrutinee
|
| 1596 | 1566 | -- because the case-binder isn't in scope in the scrutineex
|
| 1597 | - ; lintBinder CaseBind case_bndr $ \case_bndr' ->
|
|
| 1567 | + ; lintBinder CaseBind case_bndr $
|
|
| 1598 | 1568 | -- Don't use lintIdBndr on case_bndr, because unboxed tuple is legitimate
|
| 1599 | 1569 | |
| 1600 | - do { let case_bndr_ty' = idType case_bndr'
|
|
| 1601 | - scrut_mult = idMult case_bndr'
|
|
| 1570 | + do { let case_bndr_ty = idType case_bndr
|
|
| 1571 | + scrut_mult = idMult case_bndr
|
|
| 1602 | 1572 | |
| 1603 | - ; ensureEqTys case_bndr_ty' scrut_ty' (mkScrutMsg case_bndr case_bndr_ty' scrut_ty')
|
|
| 1573 | + ; ensureEqTys case_bndr_ty scrut_ty (mkScrutMsg case_bndr case_bndr_ty scrut_ty)
|
|
| 1604 | 1574 | -- See GHC.Core Note [Case expression invariants] item (7)
|
| 1605 | 1575 | |
| 1606 | 1576 | ; -- Check the alternatives
|
| 1607 | - ; alt_ues <- mapM (lintCoreAlt case_bndr' scrut_ty' scrut_mult alt_ty') alts
|
|
| 1577 | + ; alt_ues <- mapM (lintCoreAlt case_bndr scrut_ty scrut_mult alt_ty) alts
|
|
| 1608 | 1578 | ; let case_ue = (scaleUE scrut_mult scrut_ue) `addUE` supUEs alt_ues
|
| 1609 | - ; return (alt_ty', case_ue) } }
|
|
| 1579 | + ; return (alt_ty, case_ue) } }
|
|
| 1610 | 1580 | |
| 1611 | -checkCaseAlts :: InExpr -> InExpr -> OutType -> [CoreAlt] -> LintM ()
|
|
| 1581 | +checkCaseAlts :: CoreExpr -> CoreExpr -> Type -> [CoreAlt] -> LintM ()
|
|
| 1612 | 1582 | -- a) Check that the alts are non-empty
|
| 1613 | 1583 | -- b1) Check that the DEFAULT comes first, if it exists
|
| 1614 | 1584 | -- b2) Check that the others are in increasing order
|
| ... | ... | @@ -1683,17 +1653,17 @@ checkCaseAlts e scrut scrut_ty alts |
| 1683 | 1653 | is_lit_alt (Alt (LitAlt _) _ _) = True
|
| 1684 | 1654 | is_lit_alt _ = False
|
| 1685 | 1655 | |
| 1686 | -lintAltExpr :: CoreExpr -> OutType -> LintM UsageEnv
|
|
| 1656 | +lintAltExpr :: CoreExpr -> Type -> LintM UsageEnv
|
|
| 1687 | 1657 | lintAltExpr expr ann_ty
|
| 1688 | 1658 | = do { (actual_ty, ue) <- lintCoreExpr expr
|
| 1689 | 1659 | ; ensureEqTys actual_ty ann_ty (mkCaseAltMsg expr actual_ty ann_ty)
|
| 1690 | 1660 | ; return ue }
|
| 1691 | 1661 | -- See GHC.Core Note [Case expression invariants] item (6)
|
| 1692 | 1662 | |
| 1693 | -lintCoreAlt :: OutId -- Case binder
|
|
| 1694 | - -> OutType -- Type of scrutinee
|
|
| 1663 | +lintCoreAlt :: Id -- Case binder
|
|
| 1664 | + -> Type -- Type of scrutinee
|
|
| 1695 | 1665 | -> Mult -- Multiplicity of scrutinee
|
| 1696 | - -> OutType -- Type of the alternative
|
|
| 1666 | + -> Type -- Type of the alternative
|
|
| 1697 | 1667 | -> CoreAlt
|
| 1698 | 1668 | -> LintM UsageEnv
|
| 1699 | 1669 | -- If you edit this function, you may need to update the GHC formalism
|
| ... | ... | @@ -1738,11 +1708,11 @@ lintCoreAlt case_bndr scrut_ty _scrut_mult alt_ty alt@(Alt (DataAlt con) args rh |
| 1738 | 1708 | ; multiplicities = map binderMult $ fst $ splitPiTys con_payload_ty }
|
| 1739 | 1709 | |
| 1740 | 1710 | -- And now bring the new binders into scope
|
| 1741 | - ; lintBinders CasePatBind args $ \ args' -> do
|
|
| 1711 | + ; lintBinders CasePatBind args $ do
|
|
| 1742 | 1712 | { rhs_ue <- lintAltExpr rhs alt_ty
|
| 1743 | 1713 | ; rhs_ue' <- addLoc (CasePat alt) $
|
| 1744 | 1714 | lintAltBinders rhs_ue case_bndr scrut_ty con_payload_ty
|
| 1745 | - (zipEqual multiplicities args')
|
|
| 1715 | + (zipEqual multiplicities args)
|
|
| 1746 | 1716 | ; return $ deleteUE rhs_ue' case_bndr
|
| 1747 | 1717 | }
|
| 1748 | 1718 | }
|
| ... | ... | @@ -1784,54 +1754,52 @@ lintLinearBinder doc actual_usage described_usage |
| 1784 | 1754 | -}
|
| 1785 | 1755 | |
| 1786 | 1756 | -- When we lint binders, we (one at a time and in order):
|
| 1787 | --- 1. Lint var types or kinds (possibly substituting)
|
|
| 1788 | --- 2. Add the binder to the in scope set, and if its a coercion var,
|
|
| 1789 | --- we may extend the substitution to reflect its (possibly) new kind
|
|
| 1790 | -lintBinders :: HasDebugCallStack => BindingSite -> [InVar] -> ([OutVar] -> LintM a) -> LintM a
|
|
| 1791 | -lintBinders _ [] linterF = linterF []
|
|
| 1792 | -lintBinders site (var:vars) linterF = lintBinder site var $ \var' ->
|
|
| 1793 | - lintBinders site vars $ \ vars' ->
|
|
| 1794 | - linterF (var':vars')
|
|
| 1757 | +-- 1. Lint var types or kinds
|
|
| 1758 | +-- 2. Add the binder to the in scope set
|
|
| 1759 | +lintBinders :: HasDebugCallStack => BindingSite -> [Var] -> LintM a -> LintM a
|
|
| 1760 | +lintBinders _ [] linterF = linterF
|
|
| 1761 | +lintBinders site (var:vars) linterF = lintBinder site var $
|
|
| 1762 | + lintBinders site vars $
|
|
| 1763 | + linterF
|
|
| 1795 | 1764 | |
| 1796 | 1765 | -- If you edit this function, you may need to update the GHC formalism
|
| 1797 | 1766 | -- See Note [GHC Formalism]
|
| 1798 | -lintBinder :: HasDebugCallStack => BindingSite -> InVar -> (OutVar -> LintM a) -> LintM a
|
|
| 1767 | +lintBinder :: HasDebugCallStack => BindingSite -> Var -> LintM a -> LintM a
|
|
| 1799 | 1768 | lintBinder site var linterF
|
| 1800 | 1769 | | isTyCoVar var = lintTyCoBndr var linterF
|
| 1801 | 1770 | | otherwise = lintIdBndr NotTopLevel site var linterF
|
| 1802 | 1771 | |
| 1803 | -lintTyCoBndr :: HasDebugCallStack => TyCoVar -> (OutTyCoVar -> LintM a) -> LintM a
|
|
| 1772 | +lintTyCoBndr :: HasDebugCallStack => TyCoVar -> LintM a -> LintM a
|
|
| 1804 | 1773 | lintTyCoBndr tcv thing_inside
|
| 1805 | - = do { tcv_type' <- lintTypeAndSubst (varType tcv)
|
|
| 1806 | - ; let tcv_kind' = typeKind tcv_type'
|
|
| 1774 | + = do { let tcv_type = varType tcv
|
|
| 1775 | + tcv_kind = typeKind tcv_type
|
|
| 1807 | 1776 | |
| 1777 | + ; lintType (varType tcv)
|
|
| 1808 | 1778 | -- See (FORALL1) and (FORALL2) in GHC.Core.Type
|
| 1809 | 1779 | ; if (isTyVar tcv)
|
| 1810 | 1780 | then -- Check that in (forall (a:ki). blah) we have ki:Type
|
| 1811 | - lintL (isLiftedTypeKind tcv_kind') $
|
|
| 1781 | + lintL (isLiftedTypeKind tcv_kind) $
|
|
| 1812 | 1782 | hang (text "TyVar whose kind does not have kind Type:")
|
| 1813 | - 2 (ppr tcv <+> dcolon <+> ppr tcv_type' <+> dcolon <+> ppr tcv_kind')
|
|
| 1783 | + 2 (ppr tcv <+> dcolon <+> ppr tcv_type <+> dcolon <+> ppr tcv_kind)
|
|
| 1814 | 1784 | else -- Check that in (forall (cv::ty). blah),
|
| 1815 | 1785 | -- then ty looks like (t1 ~# t2)
|
| 1816 | - lintL (isCoVarType tcv_type') $
|
|
| 1786 | + lintL (isCoVarType tcv_type) $
|
|
| 1817 | 1787 | text "CoVar with non-coercion type:" <+> pprTyVar tcv
|
| 1818 | 1788 | |
| 1819 | - ; addInScopeTyCoVar tcv tcv_type' thing_inside }
|
|
| 1789 | + ; addInScopeTyCoVar tcv thing_inside }
|
|
| 1820 | 1790 | |
| 1821 | -lintIdBndrs :: forall a. TopLevelFlag -> [InId] -> ([OutId] -> LintM a) -> LintM a
|
|
| 1791 | +lintIdBndrs :: forall a. TopLevelFlag -> [Id] -> LintM a -> LintM a
|
|
| 1822 | 1792 | lintIdBndrs top_lvl ids thing_inside
|
| 1823 | 1793 | = go ids thing_inside
|
| 1824 | 1794 | where
|
| 1825 | - go :: [Id] -> ([Id] -> LintM a) -> LintM a
|
|
| 1826 | - go [] thing_inside = thing_inside []
|
|
| 1827 | - go (id:ids) thing_inside = lintIdBndr top_lvl LetBind id $ \id' ->
|
|
| 1828 | - go ids $ \ids' ->
|
|
| 1829 | - thing_inside (id' : ids')
|
|
| 1795 | + go :: [Id] -> LintM a -> LintM a
|
|
| 1796 | + go [] thing_inside = thing_inside
|
|
| 1797 | + go (id:ids) thing_inside = lintIdBndr top_lvl LetBind id $
|
|
| 1798 | + go ids $
|
|
| 1799 | + thing_inside
|
|
| 1830 | 1800 | |
| 1831 | 1801 | lintIdBndr :: TopLevelFlag -> BindingSite
|
| 1832 | - -> InVar -> (OutVar -> LintM a) -> LintM a
|
|
| 1833 | --- Do substitution on the type of a binder and add the var with this
|
|
| 1834 | --- new type to the in-scope set of the second argument
|
|
| 1802 | + -> Var -> LintM a -> LintM a
|
|
| 1835 | 1803 | -- ToDo: lint its rules
|
| 1836 | 1804 | lintIdBndr top_lvl bind_site id thing_inside
|
| 1837 | 1805 | = assertPpr (isId id) (ppr id) $
|
| ... | ... | @@ -1864,14 +1832,16 @@ lintIdBndr top_lvl bind_site id thing_inside |
| 1864 | 1832 | ; lintL (not (isCoVarType id_ty))
|
| 1865 | 1833 | (text "Non-CoVar has coercion type" <+> ppr id <+> dcolon <+> ppr id_ty)
|
| 1866 | 1834 | |
| 1867 | - -- Check that the lambda binder has no value or OtherCon unfolding.
|
|
| 1835 | + -- Check that lambda-bound Ids have no unfolding; not even OtherCon
|
|
| 1868 | 1836 | -- See #21496
|
| 1869 | - ; lintL (not (bind_site == LambdaBind && isEvaldUnfolding (idUnfolding id)))
|
|
| 1870 | - (text "Lambda binder with value or OtherCon unfolding.")
|
|
| 1837 | + ; let unf = idUnfolding id
|
|
| 1838 | + ; checkL (not (bind_site == LambdaBind && hasSomeUnfolding unf)) $
|
|
| 1839 | + hang (text "Lambda binder" <+> quotes (ppr id) <+> text "has an unfolding")
|
|
| 1840 | + 2 (ppr unf)
|
|
| 1871 | 1841 | |
| 1872 | - ; out_ty <- addLoc (IdTy id) (lintValueType id_ty)
|
|
| 1842 | + ; addLoc (IdTy id) (lintValueType id_ty)
|
|
| 1873 | 1843 | |
| 1874 | - ; addInScopeId id out_ty thing_inside }
|
|
| 1844 | + ; addInScopeId id thing_inside }
|
|
| 1875 | 1845 | where
|
| 1876 | 1846 | id_ty = idType id
|
| 1877 | 1847 | |
| ... | ... | @@ -1891,62 +1861,44 @@ lintIdBndr top_lvl bind_site id thing_inside |
| 1891 | 1861 | {- Note [Linting types and coercions]
|
| 1892 | 1862 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1893 | 1863 | Notice that
|
| 1894 | - lintType :: InType -> LintM ()
|
|
| 1895 | - lintCoercion :: InCoercion -> LintM ()
|
|
| 1864 | + lintType :: Type -> LintM ()
|
|
| 1865 | + lintCoercion :: Coercion -> LintM ()
|
|
| 1896 | 1866 | Neither returns anything.
|
| 1897 | 1867 | |
| 1898 | -If you need the kind of the type, then do `typeKind` and then apply
|
|
| 1899 | -the ambient substitution using `substTyM`. Note that the substitution
|
|
| 1900 | -empty unless there is shadowing or type-lets; and if the substitution is
|
|
| 1901 | -empty, the `substTyM` is a no-op.
|
|
| 1902 | - |
|
| 1903 | -It is better to take the kind and then substitute, rather than substitute
|
|
| 1904 | -and then take the kind, becaues the kind is usually smaller.
|
|
| 1905 | - |
|
| 1906 | -Note: you might wonder if we should apply the same logic to expressions.
|
|
| 1907 | -Why do we have
|
|
| 1908 | - lintExpr :: InExpr -> LintM OutType
|
|
| 1909 | -Partly inertia; but also taking the type of an expresison involve looking
|
|
| 1910 | -down a deep chain of let's, whereas that is not true of taking the kind
|
|
| 1911 | -of a type. It'd be worth an experiment though.
|
|
| 1912 | - |
|
| 1913 | -Historical note: in the olden days we had
|
|
| 1914 | - lintType :: InType -> LintM OutType
|
|
| 1915 | -but that burned a huge amount of allocation building an OutType that was
|
|
| 1916 | -often discarded, or used only to get its kind.
|
|
| 1917 | - |
|
| 1918 | -I also experimented with
|
|
| 1919 | - lintType :: InType -> LintM OutKind
|
|
| 1920 | -but that too was slower. It is also much simpler to return ()! If we
|
|
| 1921 | -return the kind we have to duplicate the logic in `typeKind`; and it is
|
|
| 1922 | -much worse for coercions.
|
|
| 1868 | +Note: you might wonder why we have
|
|
| 1869 | + lintExpr :: CoreExpr -> LintM Type
|
|
| 1870 | + lintType :: Type -> LintM ()
|
|
| 1871 | + |
|
| 1872 | +That is, linting an expression yields its type, but linting a type does not
|
|
| 1873 | +yield its kind. Partly inertia; but:
|
|
| 1874 | + |
|
| 1875 | +* Taking the type of an expresison involves looking down a deep chain of let's,
|
|
| 1876 | + whereas that is not true of taking the kind of a type. It'd be worth an
|
|
| 1877 | + experiment though.
|
|
| 1878 | + |
|
| 1879 | +* I did experiment with
|
|
| 1880 | + lintType :: Type -> LintM Kind
|
|
| 1881 | + but that too was slower. It is also much simpler to return ()! If we return
|
|
| 1882 | + the kind we have to duplicate the logic in `typeKind`; and it is much worse
|
|
| 1883 | + for coercions.
|
|
| 1923 | 1884 | -}
|
| 1924 | 1885 | |
| 1925 | -lintValueType :: Type -> LintM OutType
|
|
| 1886 | +lintValueType :: Type -> LintM ()
|
|
| 1926 | 1887 | -- Types only, not kinds
|
| 1927 | --- Check the type, and apply the substitution to it
|
|
| 1928 | --- See Note [Linting type lets]
|
|
| 1929 | 1888 | lintValueType ty
|
| 1930 | 1889 | = addLoc (InType ty) $
|
| 1931 | - do { ty' <- lintTypeAndSubst ty
|
|
| 1932 | - ; let sk = typeKind ty'
|
|
| 1890 | + do { lintType ty
|
|
| 1891 | + ; let sk = typeKind ty
|
|
| 1933 | 1892 | ; lintL (isTYPEorCONSTRAINT sk) $
|
| 1934 | 1893 | hang (text "Ill-kinded type:" <+> ppr ty)
|
| 1935 | - 2 (text "has kind:" <+> ppr sk)
|
|
| 1936 | - ; return ty' }
|
|
| 1894 | + 2 (text "has kind:" <+> ppr sk)}
|
|
| 1937 | 1895 | |
| 1938 | 1896 | checkTyCon :: TyCon -> LintM ()
|
| 1939 | 1897 | checkTyCon tc
|
| 1940 | 1898 | = checkL (not (isTcTyCon tc)) (text "Found TcTyCon:" <+> ppr tc)
|
| 1941 | 1899 | |
| 1942 | 1900 | -------------------
|
| 1943 | -lintTypeAndSubst :: InType -> LintM OutType
|
|
| 1944 | -lintTypeAndSubst ty = do { lintType ty; substTyM ty }
|
|
| 1945 | - -- In GHCi we may lint an expression with a free
|
|
| 1946 | - -- type variable. Then it won't be in the
|
|
| 1947 | - -- substitution, but it should be in scope
|
|
| 1948 | - |
|
| 1949 | -lintType :: InType -> LintM ()
|
|
| 1901 | +lintType :: Type -> LintM ()
|
|
| 1950 | 1902 | -- See Note [Linting types and coercions]
|
| 1951 | 1903 | --
|
| 1952 | 1904 | -- If you edit this function, you may need to update the GHC formalism
|
| ... | ... | @@ -1956,8 +1908,7 @@ lintType (TyVarTy tv) |
| 1956 | 1908 | = failWithL (mkBadTyVarMsg tv)
|
| 1957 | 1909 | |
| 1958 | 1910 | | otherwise
|
| 1959 | - = do { _ <- lintVarOcc tv
|
|
| 1960 | - ; return () }
|
|
| 1911 | + = lintVarOcc tv
|
|
| 1961 | 1912 | |
| 1962 | 1913 | lintType ty@(AppTy t1 t2)
|
| 1963 | 1914 | | TyConApp {} <- t1
|
| ... | ... | @@ -1965,7 +1916,7 @@ lintType ty@(AppTy t1 t2) |
| 1965 | 1916 | | otherwise
|
| 1966 | 1917 | = do { let (fun_ty, arg_tys) = collect t1 [t2]
|
| 1967 | 1918 | ; lintType fun_ty
|
| 1968 | - ; fun_kind <- substTyM (typeKind fun_ty)
|
|
| 1919 | + ; let fun_kind = typeKind fun_ty
|
|
| 1969 | 1920 | ; lint_ty_app ty fun_kind arg_tys }
|
| 1970 | 1921 | where
|
| 1971 | 1922 | collect (AppTy f a) as = collect f (a:as)
|
| ... | ... | @@ -1997,21 +1948,21 @@ lintType ty@(FunTy af tw t1 t2) |
| 1997 | 1948 | lintType ty@(ForAllTy {})
|
| 1998 | 1949 | = go [] ty
|
| 1999 | 1950 | where
|
| 2000 | - go :: [OutTyCoVar] -> InType -> LintM ()
|
|
| 1951 | + go :: [OutTyCoVar] -> Type -> LintM ()
|
|
| 2001 | 1952 | -- Loop, collecting the forall-binders
|
| 2002 | 1953 | go tcvs ty@(ForAllTy (Bndr tcv _) body_ty)
|
| 2003 | 1954 | | not (isTyCoVar tcv)
|
| 2004 | 1955 | = failWithL (text "Non-TyVar or Non-CoVar bound in type:" <+> ppr ty)
|
| 2005 | 1956 | |
| 2006 | 1957 | | otherwise
|
| 2007 | - = lintTyCoBndr tcv $ \tcv' ->
|
|
| 1958 | + = lintTyCoBndr tcv $
|
|
| 2008 | 1959 | do { -- See GHC.Core.TyCo.Rep Note [Unused coercion variable in ForAllTy]
|
| 2009 | 1960 | -- Suspicious because it works on InTyCoVar; c.f. ForAllCo
|
| 2010 | 1961 | when (isCoVar tcv) $
|
| 2011 | 1962 | lintL (anyFreeVarsOfType (== tcv) body_ty) $
|
| 2012 | 1963 | text "Covar does not occur in the body:" <+> (ppr tcv $$ ppr body_ty)
|
| 2013 | 1964 | |
| 2014 | - ; go (tcv' : tcvs) body_ty }
|
|
| 1965 | + ; go (tcv : tcvs) body_ty }
|
|
| 2015 | 1966 | |
| 2016 | 1967 | go tcvs body_ty
|
| 2017 | 1968 | = do { lintType body_ty
|
| ... | ... | @@ -2019,7 +1970,7 @@ lintType ty@(ForAllTy {}) |
| 2019 | 1970 | |
| 2020 | 1971 | lintType (CastTy ty co)
|
| 2021 | 1972 | = do { lintType ty
|
| 2022 | - ; ty_kind <- substTyM (typeKind ty)
|
|
| 1973 | + ; let ty_kind = typeKind ty
|
|
| 2023 | 1974 | ; co_lk <- lintStarCoercion co
|
| 2024 | 1975 | ; ensureEqTys ty_kind co_lk (mkCastTyErr ty co ty_kind co_lk) }
|
| 2025 | 1976 | |
| ... | ... | @@ -2027,14 +1978,14 @@ lintType (LitTy l) = lintTyLit l |
| 2027 | 1978 | lintType (CoercionTy co) = lintCoercion co
|
| 2028 | 1979 | |
| 2029 | 1980 | -----------------
|
| 2030 | -lintForAllBody :: [OutTyCoVar] -> InType -> LintM ()
|
|
| 1981 | +lintForAllBody :: [OutTyCoVar] -> Type -> LintM ()
|
|
| 2031 | 1982 | -- Do the checks for the body of a forall-type
|
| 2032 | 1983 | lintForAllBody tcvs body_ty
|
| 2033 | 1984 | = do { -- For type variables, check for skolem escape
|
| 2034 | 1985 | -- See Note [Phantom type variables in kinds] in GHC.Core.Type
|
| 2035 | 1986 | -- The kind of (forall cv. th) is liftedTypeKind, so no
|
| 2036 | 1987 | -- need to check for skolem-escape in the CoVar case
|
| 2037 | - body_kind <- substTyM (typeKind body_ty)
|
|
| 1988 | + let body_kind = typeKind body_ty
|
|
| 2038 | 1989 | ; case occCheckExpand tcvs body_kind of
|
| 2039 | 1990 | Just {} -> return ()
|
| 2040 | 1991 | Nothing -> failWithL $
|
| ... | ... | @@ -2045,7 +1996,7 @@ lintForAllBody tcvs body_ty |
| 2045 | 1996 | ; checkValueType body_kind (text "the body of forall:" <+> ppr body_ty) }
|
| 2046 | 1997 | |
| 2047 | 1998 | -----------------
|
| 2048 | -lintTySynFamApp :: Bool -> InType -> TyCon -> [InType] -> LintM ()
|
|
| 1999 | +lintTySynFamApp :: Bool -> Type -> TyCon -> [Type] -> LintM ()
|
|
| 2049 | 2000 | -- The TyCon is a type synonym or a type family (not a data family)
|
| 2050 | 2001 | -- See Note [Linting type synonym applications]
|
| 2051 | 2002 | -- c.f. GHC.Tc.Validity.check_syn_tc_app
|
| ... | ... | @@ -2071,21 +2022,21 @@ lintTySynFamApp report_unsat ty tc tys |
| 2071 | 2022 | |
| 2072 | 2023 | -----------------
|
| 2073 | 2024 | -- Confirms that a kind is really TYPE r or Constraint
|
| 2074 | -checkValueType :: OutKind -> SDoc -> LintM ()
|
|
| 2025 | +checkValueType :: Kind -> SDoc -> LintM ()
|
|
| 2075 | 2026 | checkValueType kind doc
|
| 2076 | 2027 | = lintL (isTYPEorCONSTRAINT kind)
|
| 2077 | 2028 | (text "Non-Type-like kind when Type-like expected:" <+> ppr kind $$
|
| 2078 | 2029 | text "when checking" <+> doc)
|
| 2079 | 2030 | |
| 2080 | 2031 | -----------------
|
| 2081 | -lintArrow :: SDoc -> FunTyFlag -> InType -> InType -> InType -> LintM ()
|
|
| 2032 | +lintArrow :: SDoc -> FunTyFlag -> Type -> Type -> Type -> LintM ()
|
|
| 2082 | 2033 | -- If you edit this function, you may need to update the GHC formalism
|
| 2083 | 2034 | -- See Note [GHC Formalism]
|
| 2084 | 2035 | lintArrow what af t1 t2 tw -- Eg lintArrow "type or kind `blah'" k1 k2 kw
|
| 2085 | 2036 | -- or lintArrow "coercion `blah'" k1 k2 kw
|
| 2086 | - = do { k1 <- substTyM (typeKind t1)
|
|
| 2087 | - ; k2 <- substTyM (typeKind t2)
|
|
| 2088 | - ; kw <- substTyM (typeKind tw)
|
|
| 2037 | + = do { let k1 = typeKind t1
|
|
| 2038 | + k2 = typeKind t2
|
|
| 2039 | + kw = typeKind tw
|
|
| 2089 | 2040 | ; unless (isTYPEorCONSTRAINT k1) (report (text "argument") t1 k1)
|
| 2090 | 2041 | ; unless (isTYPEorCONSTRAINT k2) (report (text "result") t2 k2)
|
| 2091 | 2042 | ; unless (isMultiplicityTy kw) (report (text "multiplicity") tw kw)
|
| ... | ... | @@ -2111,34 +2062,34 @@ lintTyLit (StrTyLit _) = return () |
| 2111 | 2062 | lintTyLit (CharTyLit _) = return ()
|
| 2112 | 2063 | |
| 2113 | 2064 | -----------------
|
| 2114 | -lint_ty_app :: InType -> OutKind -> [InType] -> LintM ()
|
|
| 2065 | +lint_ty_app :: Type -> Kind -> [Type] -> LintM ()
|
|
| 2115 | 2066 | lint_ty_app ty = lint_tyco_app (text "type" <+> quotes (ppr ty))
|
| 2116 | 2067 | |
| 2117 | -lint_co_app :: HasDebugCallStack => Coercion -> OutKind -> [InType] -> LintM ()
|
|
| 2068 | +lint_co_app :: HasDebugCallStack => Coercion -> Kind -> [Type] -> LintM ()
|
|
| 2118 | 2069 | lint_co_app co = lint_tyco_app (text "coercion" <+> quotes (ppr co))
|
| 2119 | 2070 | |
| 2120 | -lint_tyco_app :: SDoc -> OutKind -> [InType] -> LintM ()
|
|
| 2071 | +lint_tyco_app :: SDoc -> Kind -> [Type] -> LintM ()
|
|
| 2121 | 2072 | lint_tyco_app msg fun_kind arg_tys
|
| 2122 | 2073 | -- See Note [Avoiding compiler perf traps when constructing error messages.]
|
| 2123 | - = do { _ <- lintApp msg (\ty -> do { lintType ty; substTyM ty })
|
|
| 2124 | - (\ty _ _ -> do { lintType ty; ki <- substTyM (typeKind ty); return (ki,()) })
|
|
| 2125 | - fun_kind arg_tys ()
|
|
| 2074 | + = do { _ <- lintApp msg (\ty -> do { lintType ty; return ty })
|
|
| 2075 | + (\ty _ _ -> do { lintType ty; return (typeKind ty,()) })
|
|
| 2076 | + fun_kind arg_tys ()
|
|
| 2126 | 2077 | ; return () }
|
| 2127 | 2078 | |
| 2128 | 2079 | ----------------
|
| 2129 | -lintApp :: forall in_a acc. Outputable in_a =>
|
|
| 2080 | +lintApp :: forall a acc. Outputable a =>
|
|
| 2130 | 2081 | SDoc
|
| 2131 | - -> (in_a -> LintM OutType) -- Lint the thing and return its value
|
|
| 2132 | - -> (in_a -> Mult -> acc -> LintM (OutKind, acc)) -- Lint the thing and return its type
|
|
| 2133 | - -> OutType
|
|
| 2134 | - -> [in_a] -- The arguments, always "In" things
|
|
| 2135 | - -> acc -- Used (only) for UsageEnv in /term/ applications
|
|
| 2136 | - -> LintM (OutType,acc)
|
|
| 2082 | + -> (a -> LintM Type) -- Lint the thing and return its value
|
|
| 2083 | + -> (a -> Mult -> acc -> LintM (Kind, acc)) -- Lint the thing and return its type
|
|
| 2084 | + -> Type
|
|
| 2085 | + -> [a] -- The arguments
|
|
| 2086 | + -> acc -- Used (only) for UsageEnv in /term/ applications
|
|
| 2087 | + -> LintM (Type,acc)
|
|
| 2137 | 2088 | -- lintApp is a performance-critical function, which deals with multiple
|
| 2138 | 2089 | -- applications such as (/\a./\b./\c. expr) @ta @tb @tc
|
| 2139 | 2090 | -- When returning the type of this expression we want to avoid substituting a:=ta,
|
| 2140 | 2091 | -- and /then/ substituting b:=tb, etc. That's quadratic, and can be a huge
|
| 2141 | --- perf hole. So we gather all the arguments [in_a], and then gather the
|
|
| 2092 | +-- perf hole. So we gather all the arguments [a], and then gather the
|
|
| 2142 | 2093 | -- substitution incrementally in the `go` loop.
|
| 2143 | 2094 | --
|
| 2144 | 2095 | -- lintApp is used:
|
| ... | ... | @@ -2158,7 +2109,7 @@ lintApp msg lint_forall_arg lint_arrow_arg !orig_fun_ty all_args acc |
| 2158 | 2109 | |
| 2159 | 2110 | ; let init_subst = mkEmptySubst in_scope
|
| 2160 | 2111 | |
| 2161 | - go :: Subst -> OutType -> acc -> [in_a] -> LintM (OutType, acc)
|
|
| 2112 | + go :: Subst -> Type -> acc -> [a] -> LintM (Type, acc)
|
|
| 2162 | 2113 | -- The Subst applies (only) to the fun_ty
|
| 2163 | 2114 | -- c.f. GHC.Core.Type.piResultTys, which has a similar loop
|
| 2164 | 2115 | |
| ... | ... | @@ -2202,7 +2153,7 @@ lintApp msg lint_forall_arg lint_arrow_arg !orig_fun_ty all_args acc |
| 2202 | 2153 | -- explicitly and don't capture them as free variables. Otherwise this binder might
|
| 2203 | 2154 | -- become a thunk that get's allocated in the hot code path.
|
| 2204 | 2155 | -- See Note [Avoiding compiler perf traps when constructing error messages.]
|
| 2205 | -lint_app_fail_msg :: (Outputable a2) => SDoc -> OutType -> a2 -> SDoc -> SDoc
|
|
| 2156 | +lint_app_fail_msg :: (Outputable a2) => SDoc -> Type -> a2 -> SDoc -> SDoc
|
|
| 2206 | 2157 | lint_app_fail_msg msg kfn arg_tys extra
|
| 2207 | 2158 | = vcat [ hang (text "Application error in") 2 msg
|
| 2208 | 2159 | , nest 2 (text "Function type =" <+> ppr kfn)
|
| ... | ... | @@ -2215,7 +2166,7 @@ lint_app_fail_msg msg kfn arg_tys extra |
| 2215 | 2166 | * *
|
| 2216 | 2167 | ********************************************************************* -}
|
| 2217 | 2168 | |
| 2218 | -lintCoreRule :: OutVar -> OutType -> CoreRule -> LintM ()
|
|
| 2169 | +lintCoreRule :: OutVar -> Type -> CoreRule -> LintM ()
|
|
| 2219 | 2170 | lintCoreRule _ _ (BuiltinRule {})
|
| 2220 | 2171 | = return () -- Don't bother
|
| 2221 | 2172 | |
| ... | ... | @@ -2223,7 +2174,7 @@ lintCoreRule fun fun_ty rule@(Rule { ru_name = name, ru_bndrs = bndrs |
| 2223 | 2174 | , ru_args = args, ru_rhs = rhs })
|
| 2224 | 2175 | = noMultiplicityChecks $ -- Skip linearity checking for rules
|
| 2225 | 2176 | -- See Note [Linting linearity]
|
| 2226 | - lintBinders LambdaBind bndrs $ \ _ ->
|
|
| 2177 | + lintBinders LambdaBind bndrs $
|
|
| 2227 | 2178 | do { (lhs_ty, _) <- lintCoreArgs (fun_ty, zeroUE) args
|
| 2228 | 2179 | ; (rhs_ty, _) <- case idJoinPointHood fun of
|
| 2229 | 2180 | JoinPoint join_arity
|
| ... | ... | @@ -2311,10 +2262,10 @@ Note [Join points and unfoldings/rules] in "GHC.Core.Opt.OccurAnal" for further |
| 2311 | 2262 | |
| 2312 | 2263 | {- Note [Asymptotic efficiency]
|
| 2313 | 2264 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 2314 | -When linting coercions (and types actually) we return a linted
|
|
| 2315 | -(substituted) coercion. Then we often have to take the coercionKind of
|
|
| 2316 | -that returned coercion. If we get long chains, that can be asymptotically
|
|
| 2317 | -inefficient, notably in
|
|
| 2265 | +When linting coercions we traverse the coercion. Then we often have to take the
|
|
| 2266 | +coercionKind of that returned coercion. If we get long chains, that can be
|
|
| 2267 | +asymptotically inefficient, notably in
|
|
| 2268 | + |
|
| 2318 | 2269 | * TransCo
|
| 2319 | 2270 | * InstCo
|
| 2320 | 2271 | * SelCo (cf #9233)
|
| ... | ... | @@ -2326,30 +2277,23 @@ the bad perf bites us in practice. |
| 2326 | 2277 | A solution would be to return the kind and role of the coercion,
|
| 2327 | 2278 | as well as the linted coercion. Or perhaps even *only* the kind and role,
|
| 2328 | 2279 | which is what used to happen. But that proved tricky and error prone
|
| 2329 | -(#17923), so now we return the coercion.
|
|
| 2280 | +(#17923).
|
|
| 2330 | 2281 | -}
|
| 2331 | 2282 | |
| 2332 | 2283 | |
| 2333 | 2284 | -- lintStarCoercion lints a coercion, confirming that its lh kind and
|
| 2334 | 2285 | -- its rh kind are both *; also ensures that the role is Nominal
|
| 2335 | 2286 | -- Returns the lh kind
|
| 2336 | -lintStarCoercion :: InCoercion -> LintM OutType
|
|
| 2287 | +lintStarCoercion :: Coercion -> LintM Type
|
|
| 2337 | 2288 | lintStarCoercion g
|
| 2338 | 2289 | = do { lintCoercion g
|
| 2339 | - ; Pair t1 t2 <- substCoKindM g
|
|
| 2290 | + ; let Pair t1 t2 = coercionKind g
|
|
| 2340 | 2291 | ; checkValueType (typeKind t1) (text "the kind of the left type in" <+> ppr g)
|
| 2341 | 2292 | ; checkValueType (typeKind t2) (text "the kind of the right type in" <+> ppr g)
|
| 2342 | 2293 | ; lintRole g Nominal (coercionRole g)
|
| 2343 | 2294 | ; return t1 }
|
| 2344 | 2295 | |
| 2345 | -substCoKindM :: InCoercion -> LintM (Pair OutType)
|
|
| 2346 | -substCoKindM co
|
|
| 2347 | - = do { let !(Pair lk rk) = coercionKind co
|
|
| 2348 | - ; lk' <- substTyM lk
|
|
| 2349 | - ; rk' <- substTyM rk
|
|
| 2350 | - ; return (Pair lk' rk') }
|
|
| 2351 | - |
|
| 2352 | -lintCoercion :: HasDebugCallStack => InCoercion -> LintM ()
|
|
| 2296 | +lintCoercion :: HasDebugCallStack => Coercion -> LintM ()
|
|
| 2353 | 2297 | -- See Note [Linting types and coercions]
|
| 2354 | 2298 | --
|
| 2355 | 2299 | -- If you edit this function, you may need to update the GHC formalism
|
| ... | ... | @@ -2361,7 +2305,7 @@ lintCoercion (CoVarCo cv) |
| 2361 | 2305 | 2 (text "With offending type:" <+> ppr (varType cv)))
|
| 2362 | 2306 | |
| 2363 | 2307 | | otherwise -- C.f. lintType (TyVarTy tv), which has better docs
|
| 2364 | - = do { _ <- lintVarOcc cv; return () }
|
|
| 2308 | + = lintVarOcc cv
|
|
| 2365 | 2309 | |
| 2366 | 2310 | lintCoercion (Refl ty) = lintType ty
|
| 2367 | 2311 | lintCoercion (GRefl _r ty MRefl) = lintType ty
|
| ... | ... | @@ -2369,8 +2313,8 @@ lintCoercion (GRefl _r ty MRefl) = lintType ty |
| 2369 | 2313 | lintCoercion (GRefl _r ty (MCo co))
|
| 2370 | 2314 | = do { lintType ty
|
| 2371 | 2315 | ; lintCoercion co
|
| 2372 | - ; tk <- substTyM (typeKind ty)
|
|
| 2373 | - ; tl <- substTyM (coercionLKind co)
|
|
| 2316 | + ; let tk = typeKind ty
|
|
| 2317 | + tl = coercionLKind co
|
|
| 2374 | 2318 | ; ensureEqTys tk tl $
|
| 2375 | 2319 | hang (text "GRefl coercion kind mis-match:" <+> ppr co)
|
| 2376 | 2320 | 2 (vcat [ppr ty, ppr tk, ppr tl])
|
| ... | ... | @@ -2403,8 +2347,8 @@ lintCoercion co@(AppCo co1 co2) |
| 2403 | 2347 | = do { lintCoercion co1
|
| 2404 | 2348 | ; lintCoercion co2
|
| 2405 | 2349 | ; let !(Pair lt1 rt1) = coercionKind co1
|
| 2406 | - ; lk1 <- substTyM (typeKind lt1)
|
|
| 2407 | - ; rk1 <- substTyM (typeKind rt1)
|
|
| 2350 | + lk1 = typeKind lt1
|
|
| 2351 | + rk1 = typeKind rt1
|
|
| 2408 | 2352 | ; lint_co_app co lk1 [coercionLKind co2]
|
| 2409 | 2353 | ; lint_co_app co rk1 [coercionRKind co2]
|
| 2410 | 2354 | |
| ... | ... | @@ -2421,7 +2365,7 @@ lintCoercion co@(ForAllCo {}) |
| 2421 | 2365 | = do { _ <- go [] co; return () }
|
| 2422 | 2366 | where
|
| 2423 | 2367 | go :: [OutTyCoVar] -- Binders in reverse order
|
| 2424 | - -> InCoercion -> LintM Role
|
|
| 2368 | + -> Coercion -> LintM Role
|
|
| 2425 | 2369 | go tcvs co@(ForAllCo { fco_tcv = tcv, fco_visL = visL, fco_visR = visR
|
| 2426 | 2370 | , fco_kind = kind_mco, fco_body = body_co })
|
| 2427 | 2371 | | not (isTyCoVar tcv)
|
| ... | ... | @@ -2431,15 +2375,15 @@ lintCoercion co@(ForAllCo {}) |
| 2431 | 2375 | = do { mb_lk <- case kind_mco of
|
| 2432 | 2376 | MRefl -> return Nothing
|
| 2433 | 2377 | MCo kind_co -> Just <$> lintStarCoercion kind_co
|
| 2434 | - ; lintTyCoBndr tcv $ \tcv' ->
|
|
| 2378 | + ; lintTyCoBndr tcv $
|
|
| 2435 | 2379 | do { case mb_lk of
|
| 2436 | 2380 | Nothing -> return ()
|
| 2437 | - Just lk -> ensureEqTys (varType tcv') lk $
|
|
| 2381 | + Just lk -> ensureEqTys (varType tcv) lk $
|
|
| 2438 | 2382 | text "Kind mis-match in ForallCo" <+> ppr co
|
| 2439 | 2383 | |
| 2440 | 2384 | -- I'm not very sure about this part, because it traverses body_co
|
| 2441 | 2385 | -- but at least it's on a cold path (a ForallCo for a CoVar)
|
| 2442 | - -- Also it works on InTyCoVar and InCoercion, which is suspect
|
|
| 2386 | + -- Also it works on InTyCoVar and Coercion, which is suspect
|
|
| 2443 | 2387 | ; when (isCoVar tcv) $
|
| 2444 | 2388 | do { lintL (visL == coreTyLamForAllTyFlag && visR == coreTyLamForAllTyFlag) $
|
| 2445 | 2389 | text "Invalid visibility flags in CoVar ForAllCo" <+> ppr co
|
| ... | ... | @@ -2448,7 +2392,7 @@ lintCoercion co@(ForAllCo {}) |
| 2448 | 2392 | text "Covar can only appear in Refl and GRefl: " <+> ppr co }
|
| 2449 | 2393 | -- See (FC6) in Note [ForAllCo] in GHC.Core.TyCo.Rep
|
| 2450 | 2394 | |
| 2451 | - ; role <- go (tcv':tcvs) body_co
|
|
| 2395 | + ; role <- go (tcv:tcvs) body_co
|
|
| 2452 | 2396 | |
| 2453 | 2397 | ; when (role == Nominal) $
|
| 2454 | 2398 | lintL (visL `eqForAllVis` visR) $
|
| ... | ... | @@ -2505,8 +2449,8 @@ lintCoercion co@(UnivCo { uco_role = r, uco_prov = prov |
| 2505 | 2449 | -- Check the to and from types
|
| 2506 | 2450 | ; lintType ty1
|
| 2507 | 2451 | ; lintType ty2
|
| 2508 | - ; tk1 <- substTyM (typeKind ty1)
|
|
| 2509 | - ; tk2 <- substTyM (typeKind ty2)
|
|
| 2452 | + ; let tk1 = typeKind ty1
|
|
| 2453 | + tk2 = typeKind ty2
|
|
| 2510 | 2454 | |
| 2511 | 2455 | ; when (r /= Phantom && isTYPEorCONSTRAINT tk1 && isTYPEorCONSTRAINT tk2)
|
| 2512 | 2456 | (checkTypes ty1 ty2)
|
| ... | ... | @@ -2560,8 +2504,8 @@ lintCoercion (SymCo co) = lintCoercion co |
| 2560 | 2504 | lintCoercion co@(TransCo co1 co2)
|
| 2561 | 2505 | = do { lintCoercion co1
|
| 2562 | 2506 | ; lintCoercion co2
|
| 2563 | - ; rk1 <- substTyM (coercionRKind co1)
|
|
| 2564 | - ; lk2 <- substTyM (coercionLKind co2)
|
|
| 2507 | + ; let rk1 = coercionRKind co1
|
|
| 2508 | + lk2 = coercionLKind co2
|
|
| 2565 | 2509 | ; ensureEqTys rk1 lk2
|
| 2566 | 2510 | (hang (text "Trans coercion mis-match:" <+> ppr co)
|
| 2567 | 2511 | 2 (vcat [ppr (coercionKind co1), ppr (coercionKind co2)]))
|
| ... | ... | @@ -2569,7 +2513,7 @@ lintCoercion co@(TransCo co1 co2) |
| 2569 | 2513 | |
| 2570 | 2514 | lintCoercion the_co@(SelCo cs co)
|
| 2571 | 2515 | = do { lintCoercion co
|
| 2572 | - ; Pair s t <- substCoKindM co
|
|
| 2516 | + ; let Pair s t = coercionKind co
|
|
| 2573 | 2517 | |
| 2574 | 2518 | ; if -- forall (both TyVar and CoVar)
|
| 2575 | 2519 | | Just _ <- splitForAllTyCoVar_maybe s
|
| ... | ... | @@ -2604,7 +2548,7 @@ lintCoercion the_co@(SelCo cs co) |
| 2604 | 2548 | |
| 2605 | 2549 | lintCoercion the_co@(LRCo _lr co)
|
| 2606 | 2550 | = do { lintCoercion co
|
| 2607 | - ; Pair s t <- substCoKindM co
|
|
| 2551 | + ; let Pair s t = coercionKind co
|
|
| 2608 | 2552 | ; lintRole co Nominal (coercionRole co)
|
| 2609 | 2553 | ; case (splitAppTy_maybe s, splitAppTy_maybe t) of
|
| 2610 | 2554 | (Just {}, Just {}) -> return ()
|
| ... | ... | @@ -2618,14 +2562,12 @@ lintCoercion orig_co@(InstCo co arg) |
| 2618 | 2562 | go (InstCo co arg) args = do { lintCoercion arg; go co (arg:args) }
|
| 2619 | 2563 | go co args = do { lintCoercion co
|
| 2620 | 2564 | ; let Pair lty rty = coercionKind co
|
| 2621 | - ; lty' <- substTyM lty
|
|
| 2622 | - ; rty' <- substTyM rty
|
|
| 2623 | 2565 | ; in_scope <- getInScope
|
| 2624 | 2566 | ; let subst = mkEmptySubst in_scope
|
| 2625 | - ; go_args (subst, lty') (subst,rty') args }
|
|
| 2567 | + ; go_args (subst, lty) (subst,rty) args }
|
|
| 2626 | 2568 | |
| 2627 | 2569 | -------------
|
| 2628 | - go_args :: (Subst, OutType) -> (Subst,OutType) -> [InCoercion]
|
|
| 2570 | + go_args :: (Subst, Type) -> (Subst,Type) -> [Coercion]
|
|
| 2629 | 2571 | -> LintM ()
|
| 2630 | 2572 | go_args _ _ []
|
| 2631 | 2573 | = return ()
|
| ... | ... | @@ -2634,11 +2576,11 @@ lintCoercion orig_co@(InstCo co arg) |
| 2634 | 2576 | ; go_args lty1 rty1 args }
|
| 2635 | 2577 | |
| 2636 | 2578 | -------------
|
| 2637 | - go_arg :: (Subst, OutType) -> (Subst,OutType) -> InCoercion
|
|
| 2638 | - -> LintM ((Subst,OutType), (Subst,OutType))
|
|
| 2579 | + go_arg :: (Subst, Type) -> (Subst,Type) -> Coercion
|
|
| 2580 | + -> LintM ((Subst,Type), (Subst,Type))
|
|
| 2639 | 2581 | go_arg (lsubst,lty) (rsubst,rty) arg
|
| 2640 | 2582 | = do { lintRole arg Nominal (coercionRole arg)
|
| 2641 | - ; Pair arg_lty arg_rty <- substCoKindM arg
|
|
| 2583 | + ; let Pair arg_lty arg_rty = coercionKind arg
|
|
| 2642 | 2584 | |
| 2643 | 2585 | ; case (splitForAllTyCoVar_maybe lty, splitForAllTyCoVar_maybe rty) of
|
| 2644 | 2586 | -- forall over tvar
|
| ... | ... | @@ -2662,11 +2604,11 @@ lintCoercion orig_co@(InstCo co arg) |
| 2662 | 2604 | lintCoercion this_co@(AxiomCo ax cos)
|
| 2663 | 2605 | = do { mapM_ lintCoercion cos
|
| 2664 | 2606 | ; lint_roles 0 (coAxiomRuleArgRoles ax) cos
|
| 2665 | - ; prs <- mapM substCoKindM cos
|
|
| 2607 | + ; let prs = map coercionKind cos
|
|
| 2666 | 2608 | ; lint_ax ax prs }
|
| 2667 | 2609 | |
| 2668 | 2610 | where
|
| 2669 | - lint_ax :: CoAxiomRule -> [Pair OutType] -> LintM ()
|
|
| 2611 | + lint_ax :: CoAxiomRule -> [Pair Type] -> LintM ()
|
|
| 2670 | 2612 | lint_ax (BuiltInFamRew bif) prs
|
| 2671 | 2613 | = checkL (isJust (bifrw_proves bif prs)) bad_bif
|
| 2672 | 2614 | lint_ax (BuiltInFamInj bif) prs
|
| ... | ... | @@ -2754,8 +2696,8 @@ lintBranch this_co fam_tc branch arg_kinds |
| 2754 | 2696 | = do { checkL (arg_kinds `equalLength` (ktvs ++ cvs)) $
|
| 2755 | 2697 | (bad_ax this_co (text "lengths"))
|
| 2756 | 2698 | |
| 2757 | - ; subst <- getSubst
|
|
| 2758 | - ; let empty_subst = zapSubst subst
|
|
| 2699 | + ; in_scope <- getInScope
|
|
| 2700 | + ; let empty_subst = mkEmptySubst in_scope
|
|
| 2759 | 2701 | ; _ <- foldlM check_ki (empty_subst, empty_subst)
|
| 2760 | 2702 | (zip (ktvs ++ cvs) arg_kinds)
|
| 2761 | 2703 | |
| ... | ... | @@ -2880,12 +2822,12 @@ lint_axiom ax@(CoAxiom { co_ax_tc = tc, co_ax_branches = branches |
| 2880 | 2822 | lint_branch :: TyCon -> CoAxBranch -> LintM ()
|
| 2881 | 2823 | lint_branch ax_tc (CoAxBranch { cab_tvs = tvs, cab_cvs = cvs
|
| 2882 | 2824 | , cab_lhs = lhs_args, cab_rhs = rhs })
|
| 2883 | - = lintBinders LambdaBind (tvs ++ cvs) $ \_ ->
|
|
| 2825 | + = lintBinders LambdaBind (tvs ++ cvs) $
|
|
| 2884 | 2826 | do { let lhs = mkTyConApp ax_tc lhs_args
|
| 2885 | 2827 | ; lintType lhs
|
| 2886 | 2828 | ; lintType rhs
|
| 2887 | - ; lhs_kind <- substTyM (typeKind lhs)
|
|
| 2888 | - ; rhs_kind <- substTyM (typeKind rhs)
|
|
| 2829 | + ; let lhs_kind = typeKind lhs
|
|
| 2830 | + rhs_kind = typeKind rhs
|
|
| 2889 | 2831 | ; lintL (not (lhs_kind `typesAreApart` rhs_kind)) $
|
| 2890 | 2832 | hang (text "Inhomogeneous axiom")
|
| 2891 | 2833 | 2 (text "lhs:" <+> ppr lhs <+> dcolon <+> ppr lhs_kind $$
|
| ... | ... | @@ -2969,35 +2911,26 @@ type LintLevel = Int |
| 2969 | 2911 | -- If you edit this type, you may need to update the GHC formalism
|
| 2970 | 2912 | -- See Note [GHC Formalism]
|
| 2971 | 2913 | data LintEnv
|
| 2972 | - = LE { le_flags :: LintFlags -- Linting the result of this pass
|
|
| 2973 | - , le_loc :: [LintLocInfo] -- Locations
|
|
| 2974 | - |
|
| 2975 | - , le_subst :: Subst
|
|
| 2976 | - -- Current substitution, for TyCoVars only.
|
|
| 2977 | - -- Non-CoVar Ids don't appear in here, not even in the InScopeSet
|
|
| 2978 | - -- Used for (a) cloning to avoid shadowing of TyCoVars,
|
|
| 2979 | - -- so that eqType works ok
|
|
| 2980 | - -- (b) substituting for let-bound tyvars, when we have
|
|
| 2981 | - -- (let @a = Int -> Int in ...)
|
|
| 2982 | - |
|
| 2983 | - , le_level :: LintLevel
|
|
| 2984 | - , le_in_vars :: VarEnv (InVar, OutType, LintLevel)
|
|
| 2985 | - -- Maps an InVar (i.e. its unique) to its binding InVar
|
|
| 2986 | - -- and to its OutType
|
|
| 2987 | - -- /All/ in-scope variables are here (term variables,
|
|
| 2988 | - -- type variables, and coercion variables)
|
|
| 2989 | - -- Used at an occurrence of the InVar
|
|
| 2914 | + = LE { le_flags :: LintFlags -- Linting the result of this pass
|
|
| 2915 | + , le_loc :: [LintLocInfo] -- Locations
|
|
| 2916 | + , le_level :: LintLevel
|
|
| 2917 | + , le_in_scope :: InScopeSet
|
|
| 2918 | + |
|
| 2919 | + , le_vars :: VarEnv (Var, LintLevel)
|
|
| 2920 | + -- Maps a Var (i.e. its unique) to its binding Var and level
|
|
| 2921 | + -- /All/ in-scope variables are here (term variables,
|
|
| 2922 | + -- type variables, and coercion variables)
|
|
| 2923 | + -- So the domain is the same as the le_in_scope in-scope set
|
|
| 2924 | + -- Used at an occurrence of the Var
|
|
| 2990 | 2925 | |
| 2991 | 2926 | , le_joins :: UniqMap Id JoinOcc
|
| 2992 | 2927 | -- ^ Join points in scope that are valid
|
| 2993 | - -- A subset of the InScopeSet in le_subst
|
|
| 2994 | 2928 | -- See Note [Join points]
|
| 2995 | 2929 | |
| 2996 | 2930 | , le_ue_aliases :: NameEnv UsageEnv
|
| 2997 | 2931 | -- See Note [Linting linearity]
|
| 2998 | 2932 | -- Assigns usage environments to the alias-like binders,
|
| 2999 | 2933 | -- as found in non-recursive lets.
|
| 3000 | - -- Domain is OutIds
|
|
| 3001 | 2934 | |
| 3002 | 2935 | , le_platform :: Platform -- ^ Target platform
|
| 3003 | 2936 | , le_diagOpts :: DiagOpts -- ^ Target platform
|
| ... | ... | @@ -3011,7 +2944,8 @@ data LintFlags |
| 3011 | 2944 | , lf_check_linearity :: Bool -- ^ See Note [Linting linearity]
|
| 3012 | 2945 | , lf_check_fixed_rep :: Bool -- ^ See Note [Checking for representation polymorphism]
|
| 3013 | 2946 | , lf_check_rubbish_lits :: Bool -- ^ See Note [Checking for rubbish literals]
|
| 3014 | - , lf_allow_weak_joins :: Bool -- ^ See Note [Linting join points with casts or ticks]
|
|
| 2947 | + , lf_allow_weak_joins :: Bool -- ^ See Note [Linting join points with casts or ticks]
|
|
| 2948 | + , lf_allow_beta_joins :: Bool -- ^ See Note [Join points and beta-redexes]
|
|
| 3015 | 2949 | }
|
| 3016 | 2950 | |
| 3017 | 2951 | -- See Note [Checking StaticPtrs]
|
| ... | ... | @@ -3078,20 +3012,6 @@ top-level bindings. See SimplCore Note [Grand plan for static forms]. |
| 3078 | 3012 | |
| 3079 | 3013 | The linter checks that no occurrence or `makeStatic` occurs nested.
|
| 3080 | 3014 | |
| 3081 | -Note [Type substitution]
|
|
| 3082 | -~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 3083 | -Why do we need a type substitution? Consider
|
|
| 3084 | - /\(a:*). \(x:a). /\(a:*). id a x
|
|
| 3085 | -This is ill typed, because (renaming variables) it is really
|
|
| 3086 | - /\(a:*). \(x:a). /\(b:*). id b x
|
|
| 3087 | -Hence, when checking an application, we can't naively compare x's type
|
|
| 3088 | -(at its binding site) with its expected type (at a use site). So we
|
|
| 3089 | -rename type binders as we go, maintaining a substitution.
|
|
| 3090 | - |
|
| 3091 | -The same substitution also supports let-type, current expressed as
|
|
| 3092 | - (/\(a:*). body) ty
|
|
| 3093 | -Here we substitute 'ty' for 'a' in 'body', on the fly.
|
|
| 3094 | - |
|
| 3095 | 3015 | Note [Linting type synonym applications]
|
| 3096 | 3016 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 3097 | 3017 | When linting a type-synonym, or type-family, application
|
| ... | ... | @@ -3353,12 +3273,12 @@ initL cfg m |
| 3353 | 3273 | where
|
| 3354 | 3274 | vars = l_vars cfg
|
| 3355 | 3275 | init_level = 0
|
| 3356 | - env = LE { le_flags = l_flags cfg
|
|
| 3357 | - , le_subst = mkEmptySubst (mkInScopeSetList vars)
|
|
| 3358 | - , le_level = init_level
|
|
| 3359 | - , le_in_vars = mkVarEnv [ (v,(v, varType v, init_level)) | v <- vars ]
|
|
| 3360 | - , le_joins = emptyUniqMap
|
|
| 3361 | - , le_loc = []
|
|
| 3276 | + env = LE { le_flags = l_flags cfg
|
|
| 3277 | + , le_level = init_level
|
|
| 3278 | + , le_vars = mkVarEnv [ (v,(v, init_level)) | v <- vars ]
|
|
| 3279 | + , le_in_scope = mkInScopeSetList vars
|
|
| 3280 | + , le_joins = emptyUniqMap
|
|
| 3281 | + , le_loc = []
|
|
| 3362 | 3282 | , le_ue_aliases = emptyNameEnv
|
| 3363 | 3283 | , le_platform = l_platform cfg
|
| 3364 | 3284 | , le_diagOpts = l_diagOpts cfg
|
| ... | ... | @@ -3421,8 +3341,7 @@ addMsg show_context env msgs msg |
| 3421 | 3341 | loc_msgs :: [(SrcLoc, SDoc)] -- Innermost first
|
| 3422 | 3342 | loc_msgs = map dumpLoc (le_loc env)
|
| 3423 | 3343 | |
| 3424 | - cxt_doc = vcat [ vcat $ reverse $ map snd loc_msgs
|
|
| 3425 | - , text "Substitution:" <+> ppr (le_subst env) ]
|
|
| 3344 | + cxt_doc = vcat $ reverse $ map snd loc_msgs
|
|
| 3426 | 3345 | |
| 3427 | 3346 | context | show_context = cxt_doc
|
| 3428 | 3347 | | otherwise = whenPprDebug cxt_doc
|
| ... | ... | @@ -3449,72 +3368,44 @@ inCasePat = LintM $ \ env errs -> fromBoxedLResult (Just (is_case_pat env), errs |
| 3449 | 3368 | is_case_pat (LE { le_loc = CasePat {} : _ }) = True
|
| 3450 | 3369 | is_case_pat _other = False
|
| 3451 | 3370 | |
| 3452 | -addInScopeId :: InId -> OutType -> (OutId -> LintM a) -> LintM a
|
|
| 3371 | +addInScopeId :: Id -> LintM a -> LintM a
|
|
| 3453 | 3372 | -- Unlike addInScopeTyCoVar, this function does no cloning; Ids never get cloned
|
| 3454 | -addInScopeId in_id out_ty thing_inside
|
|
| 3373 | +addInScopeId id thing_inside
|
|
| 3455 | 3374 | = LintM $ \ env errs ->
|
| 3456 | - let !(out_id, env') = add env
|
|
| 3457 | - in unLintM (thing_inside out_id) env' errs
|
|
| 3458 | - |
|
| 3375 | + unLintM thing_inside (add env) errs
|
|
| 3459 | 3376 | where
|
| 3460 | - add env@(LE { le_level = level, le_in_vars = id_vars, le_joins = valid_joins
|
|
| 3461 | - , le_ue_aliases = aliases, le_subst = subst })
|
|
| 3462 | - = (out_id, env1)
|
|
| 3377 | + add env@(LE { le_level = level, le_vars = id_vars, le_joins = valid_joins
|
|
| 3378 | + , le_ue_aliases = aliases, le_in_scope = in_scope })
|
|
| 3379 | + = env { le_level = level1, le_vars = in_vars'
|
|
| 3380 | + , le_in_scope = in_scope `extendInScopeSet` id
|
|
| 3381 | + , le_joins = valid_joins', le_ue_aliases = aliases' }
|
|
| 3463 | 3382 | where
|
| 3464 | 3383 | level1 = level + 1
|
| 3465 | - env1 = env { le_level = level1, le_in_vars = in_vars'
|
|
| 3466 | - , le_joins = valid_joins', le_ue_aliases = aliases' }
|
|
| 3467 | 3384 | |
| 3468 | - in_vars' = extendVarEnv id_vars in_id (in_id, out_ty, level1)
|
|
| 3469 | - aliases' = delFromNameEnv aliases (idName in_id)
|
|
| 3385 | + in_vars' = extendVarEnv id_vars id (id, level1)
|
|
| 3386 | + aliases' = delFromNameEnv aliases (idName id)
|
|
| 3470 | 3387 | -- aliases': when shadowing an alias, we need to make sure the
|
| 3471 | 3388 | -- Id is no longer classified as such. E.g.
|
| 3472 | 3389 | -- let x = <e1> in case x of x { _DEFAULT -> <e2> }
|
| 3473 | 3390 | -- Occurrences of 'x' in e2 shouldn't count as occurrences of e1.
|
| 3474 | 3391 | |
| 3475 | - -- A very tiny optimisation, not sure if it's really worth it
|
|
| 3476 | - -- Short-cut when the substitution is a no-op
|
|
| 3477 | - out_id | isEmptyTCvSubst subst = in_id
|
|
| 3478 | - | otherwise = setIdType in_id out_ty
|
|
| 3479 | - |
|
| 3480 | 3392 | valid_joins'
|
| 3481 | - | isJoinId out_id = addToUniqMap valid_joins in_id NormalJoinOcc -- Overwrite with new arity
|
|
| 3482 | - | otherwise = delFromUniqMap valid_joins in_id -- Remove any existing binding
|
|
| 3393 | + | isJoinId id = addToUniqMap valid_joins id NormalJoinOcc -- Overwrite with new arity
|
|
| 3394 | + | otherwise = delFromUniqMap valid_joins id -- Remove any existing binding
|
|
| 3483 | 3395 | |
| 3484 | -addInScopeTyCoVar :: InTyCoVar -> OutType -> (OutTyCoVar -> LintM a) -> LintM a
|
|
| 3396 | +addInScopeTyCoVar :: TyCoVar -> LintM a -> LintM a
|
|
| 3485 | 3397 | -- This function clones to avoid shadowing of TyCoVars
|
| 3486 | -addInScopeTyCoVar tcv tcv_type thing_inside
|
|
| 3487 | - = LintM $ \ env@(LE { le_level = level, le_in_vars = in_vars, le_subst = subst }) errs ->
|
|
| 3488 | - let (tcv', subst') = subst_bndr subst
|
|
| 3489 | - level' = level + 1
|
|
| 3398 | +addInScopeTyCoVar tcv thing_inside
|
|
| 3399 | + = LintM $ \ env@(LE { le_level = level, le_vars = in_vars
|
|
| 3400 | + , le_in_scope = in_scope }) errs ->
|
|
| 3401 | + let level' = level + 1
|
|
| 3490 | 3402 | env' = env { le_level = level'
|
| 3491 | - , le_in_vars = extendVarEnv in_vars tcv (tcv, tcv_type, level')
|
|
| 3492 | - , le_subst = subst' }
|
|
| 3493 | - in unLintM (thing_inside tcv') env' errs
|
|
| 3494 | - where
|
|
| 3495 | - subst_bndr subst
|
|
| 3496 | - | isEmptyTCvSubst subst -- No change in kind
|
|
| 3497 | - , not (tcv `elemInScopeSet` in_scope) -- Not already in scope
|
|
| 3498 | - = -- Do not extend the substitution, just the in-scope set
|
|
| 3499 | - (if (varType tcv `eqType` tcv_type) then (\x->x) else
|
|
| 3500 | - pprTrace "addInScopeTyCoVar" (
|
|
| 3501 | - vcat [ text "tcv" <+> ppr tcv <+> dcolon <+> ppr (varType tcv)
|
|
| 3502 | - , text "tcv_type" <+> ppr tcv_type ])) $
|
|
| 3503 | - (tcv, subst `extendSubstInScope` tcv)
|
|
| 3504 | - |
|
| 3505 | - -- Clone, and extend the substitution
|
|
| 3506 | - | let tcv' = uniqAway in_scope (setVarType tcv tcv_type)
|
|
| 3507 | - = (tcv', extendTCvSubstWithClone subst tcv tcv')
|
|
| 3508 | - where
|
|
| 3509 | - in_scope = substInScopeSet subst
|
|
| 3510 | - |
|
| 3511 | -getInVarEnv :: LintM (VarEnv (InId, OutType, LintLevel))
|
|
| 3512 | -getInVarEnv = LintM (\env errs -> fromBoxedLResult (Just (le_in_vars env), errs))
|
|
| 3403 | + , le_in_scope = in_scope `extendInScopeSet` tcv
|
|
| 3404 | + , le_vars = extendVarEnv in_vars tcv (tcv, level') }
|
|
| 3405 | + in unLintM thing_inside env' errs
|
|
| 3513 | 3406 | |
| 3514 | -extendTvSubstL :: TyVar -> Type -> LintM a -> LintM a
|
|
| 3515 | -extendTvSubstL tv ty m
|
|
| 3516 | - = LintM $ \ env errs ->
|
|
| 3517 | - unLintM m (env { le_subst = Type.extendTvSubst (le_subst env) tv ty }) errs
|
|
| 3407 | +getInVarEnv :: LintM (VarEnv (Id, LintLevel))
|
|
| 3408 | +getInVarEnv = LintM (\env errs -> fromBoxedLResult (Just (le_vars env), errs))
|
|
| 3518 | 3409 | |
| 3519 | 3410 | markAllJoinsBad :: LintM a -> LintM a
|
| 3520 | 3411 | markAllJoinsBad m
|
| ... | ... | @@ -3549,54 +3440,42 @@ markAllJoinsBadIf False m = m |
| 3549 | 3440 | getValidJoins :: LintM (UniqMap Id JoinOcc)
|
| 3550 | 3441 | getValidJoins = LintM (\ env errs -> fromBoxedLResult (Just (le_joins env), errs))
|
| 3551 | 3442 | |
| 3552 | -getSubst :: LintM Subst
|
|
| 3553 | -getSubst = LintM (\ env errs -> fromBoxedLResult (Just (le_subst env), errs))
|
|
| 3554 | - |
|
| 3555 | -substTyM :: InType -> LintM OutType
|
|
| 3556 | --- Apply the substitution to the type
|
|
| 3557 | --- The substitution is often empty, in which case it is a no-op
|
|
| 3558 | -substTyM ty
|
|
| 3559 | - = do { subst <- getSubst
|
|
| 3560 | - ; return (substTy subst ty) }
|
|
| 3561 | - |
|
| 3562 | 3443 | getUEAliases :: LintM (NameEnv UsageEnv)
|
| 3563 | 3444 | getUEAliases = LintM (\ env errs -> fromBoxedLResult (Just (le_ue_aliases env), errs))
|
| 3564 | 3445 | |
| 3565 | 3446 | getInScope :: LintM InScopeSet
|
| 3566 | -getInScope = LintM (\ env errs -> fromBoxedLResult (Just (substInScopeSet $ le_subst env), errs))
|
|
| 3447 | +getInScope = LintM (\ env errs -> fromBoxedLResult (Just (le_in_scope env), errs))
|
|
| 3567 | 3448 | |
| 3568 | -lintVarOcc :: InVar -> LintM OutType
|
|
| 3449 | +lintVarOcc :: Var -> LintM ()
|
|
| 3569 | 3450 | -- Used at an occurrence of a variable: term variables, type variables, and coercion variables
|
| 3570 | 3451 | -- Checks
|
| 3571 | 3452 | -- - that it is in scope
|
| 3572 | 3453 | -- - that it is not a GlobalId bound by a LocalId
|
| 3573 | --- - that the InType at the ocurrence matches the InType at the binding site
|
|
| 3454 | +-- - that the Type at the ocurrence matches the Type at the binding site
|
|
| 3574 | 3455 | -- - that the variables free in its type are not shadowed at the occurrence site
|
| 3575 | 3456 | lintVarOcc v_occ
|
| 3576 | 3457 | | isGlobalId v_occ
|
| 3577 | - = return (idType v_occ)
|
|
| 3458 | + = return ()
|
|
| 3578 | 3459 | | otherwise
|
| 3579 | 3460 | = do { in_var_env <- getInVarEnv
|
| 3580 | 3461 | ; case lookupVarEnv in_var_env v_occ of
|
| 3581 | 3462 | Nothing -> failWithL (text pp_what <+> quotes (ppr v_occ)
|
| 3582 | 3463 | <+> text "is out of scope")
|
| 3583 | - Just (v_bndr, out_ty, bind_level)
|
|
| 3464 | + Just (v_bndr, bind_level)
|
|
| 3584 | 3465 | -> do { let bndr_ty = idType v_bndr
|
| 3585 | 3466 | ; check_bad_global v_bndr
|
| 3586 | 3467 | ; check_occ_type_match bndr_ty
|
| 3587 | - ; check_occ_type_scope in_var_env bndr_ty bind_level
|
|
| 3588 | - ; return out_ty }
|
|
| 3589 | - |
|
| 3468 | + ; check_occ_type_scope in_var_env bndr_ty bind_level }
|
|
| 3590 | 3469 | }
|
| 3591 | 3470 | where
|
| 3592 | - occ_ty :: InType
|
|
| 3471 | + occ_ty :: Type
|
|
| 3593 | 3472 | occ_ty = idType v_occ
|
| 3594 | 3473 | |
| 3595 | 3474 | pp_what | isTyVar v_occ = "The type variable"
|
| 3596 | 3475 | | isCoVar v_occ = "The coercion variable"
|
| 3597 | 3476 | | otherwise = "The value variable"
|
| 3598 | 3477 | |
| 3599 | - check_bad_global :: InVar -> LintM ()
|
|
| 3478 | + check_bad_global :: Var -> LintM ()
|
|
| 3600 | 3479 | -- 'check_bad_global' checks for the case where an /occurrence/ is
|
| 3601 | 3480 | -- a GlobalId, but there is an enclosing binding for a LocalId.
|
| 3602 | 3481 | -- NB: the in-scope variables are mostly LocalIds, checked by lintIdBndr,
|
| ... | ... | @@ -3616,26 +3495,26 @@ lintVarOcc v_occ |
| 3616 | 3495 | | otherwise
|
| 3617 | 3496 | = return ()
|
| 3618 | 3497 | |
| 3619 | - check_occ_type_match :: InType -> LintM ()
|
|
| 3498 | + check_occ_type_match :: Type -> LintM ()
|
|
| 3620 | 3499 | -- Check that the type in /binder/ and the type in the /occurrence/ are the same
|
| 3621 | 3500 | check_occ_type_match bndr_ty
|
| 3622 | - = ensureEqTys bndr_ty occ_ty $ -- Compares InTypes
|
|
| 3501 | + = ensureEqTys bndr_ty occ_ty $ -- Compares Types
|
|
| 3623 | 3502 | mkBndrOccTypeMismatchMsg v_occ bndr_ty occ_ty
|
| 3624 | 3503 | |
| 3625 | - check_occ_type_scope :: VarEnv (InVar,OutType,LintLevel) -> InType -> LintLevel -> LintM ()
|
|
| 3504 | + check_occ_type_scope :: VarEnv (Var,LintLevel) -> Type -> LintLevel -> LintM ()
|
|
| 3626 | 3505 | -- Check that the free vars of the binder's type
|
| 3627 | 3506 | -- are not shadowed at the occurrence site
|
| 3628 | 3507 | check_occ_type_scope in_var_env bndr_ty bind_level
|
| 3629 | 3508 | = checkL (null bad_fvs) $
|
| 3630 | 3509 | mkBndrOccFreeVarMsg v_occ occ_ty bad_fvs
|
| 3631 | 3510 | where
|
| 3632 | - bad_fvs :: [InVar]
|
|
| 3511 | + bad_fvs :: [Var]
|
|
| 3633 | 3512 | bad_fvs = filter is_bad (tyCoVarsOfTypeList bndr_ty)
|
| 3634 | 3513 | |
| 3635 | - is_bad :: InVar -> Bool
|
|
| 3514 | + is_bad :: Var -> Bool
|
|
| 3636 | 3515 | -- True of a variable bound inside bind_level
|
| 3637 | 3516 | is_bad v = case lookupVarEnv in_var_env v of
|
| 3638 | - Just (_, _, v_level) -> v_level > bind_level
|
|
| 3517 | + Just (_, v_level) -> v_level > bind_level
|
|
| 3639 | 3518 | Nothing -> True
|
| 3640 | 3519 | |
| 3641 | 3520 | lookupJoinId :: Id -> LintM (Maybe (JoinArity, JoinOcc))
|
| ... | ... | @@ -3647,21 +3526,21 @@ lookupJoinId id |
| 3647 | 3526 | Just join_occ -> return $ Just (idJoinArity id, join_occ)
|
| 3648 | 3527 | Nothing -> return Nothing }
|
| 3649 | 3528 | |
| 3650 | -addAliasUE :: OutId -> UsageEnv -> LintM a -> LintM a
|
|
| 3529 | +addAliasUE :: Id -> UsageEnv -> LintM a -> LintM a
|
|
| 3651 | 3530 | addAliasUE id ue thing_inside = LintM $ \ env errs ->
|
| 3652 | 3531 | let new_ue_aliases =
|
| 3653 | 3532 | extendNameEnv (le_ue_aliases env) (getName id) ue
|
| 3654 | 3533 | in
|
| 3655 | 3534 | unLintM thing_inside (env { le_ue_aliases = new_ue_aliases }) errs
|
| 3656 | 3535 | |
| 3657 | -varCallSiteUsage :: OutId -> LintM UsageEnv
|
|
| 3536 | +varCallSiteUsage :: Id -> LintM UsageEnv
|
|
| 3658 | 3537 | varCallSiteUsage id =
|
| 3659 | 3538 | do m <- getUEAliases
|
| 3660 | 3539 | return $ case lookupNameEnv m (getName id) of
|
| 3661 | 3540 | Nothing -> singleUsageUE id
|
| 3662 | 3541 | Just id_ue -> id_ue
|
| 3663 | 3542 | |
| 3664 | -ensureEqTys :: OutType -> OutType -> SDoc -> LintM ()
|
|
| 3543 | +ensureEqTys :: Type -> Type -> SDoc -> LintM ()
|
|
| 3665 | 3544 | -- check ty2 is subtype of ty1 (ie, has same structure but usage
|
| 3666 | 3545 | -- annotations need only be consistent, not equal)
|
| 3667 | 3546 | -- Assumes ty1,ty2 are have already had the substitution applied
|
| ... | ... | @@ -3885,7 +3764,7 @@ mkLetErr bndr rhs |
| 3885 | 3764 | hang (text "Rhs:")
|
| 3886 | 3765 | 4 (ppr rhs)]
|
| 3887 | 3766 | |
| 3888 | -mkTyAppMsg :: OutType -> Type -> SDoc
|
|
| 3767 | +mkTyAppMsg :: Type -> Type -> SDoc
|
|
| 3889 | 3768 | mkTyAppMsg ty arg_ty
|
| 3890 | 3769 | = vcat [text "Illegal type application:",
|
| 3891 | 3770 | hang (text "Function type:")
|
| ... | ... | @@ -4006,13 +3885,13 @@ mkJoinBndrOccMismatchMsg bndr join_arity_bndr join_arity_occ |
| 4006 | 3885 | , text "Arity at binding site:" <+> ppr join_arity_bndr
|
| 4007 | 3886 | , text "Arity at occurrence: " <+> ppr join_arity_occ ]
|
| 4008 | 3887 | |
| 4009 | -mkBndrOccTypeMismatchMsg :: InVar -> InType -> InType -> SDoc
|
|
| 3888 | +mkBndrOccTypeMismatchMsg :: Var -> Type -> Type -> SDoc
|
|
| 4010 | 3889 | mkBndrOccTypeMismatchMsg var bndr_ty occ_ty
|
| 4011 | 3890 | = vcat [ text "Mismatch in type between binder and occurrence"
|
| 4012 | 3891 | , text "Binder: " <+> ppr var <+> dcolon <+> ppr bndr_ty
|
| 4013 | 3892 | , text "Occurrence:" <+> ppr var <+> dcolon <+> ppr occ_ty ]
|
| 4014 | 3893 | |
| 4015 | -mkBndrOccFreeVarMsg :: InVar -> InType -> [TyCoVar] -> SDoc
|
|
| 3894 | +mkBndrOccFreeVarMsg :: Var -> Type -> [TyCoVar] -> SDoc
|
|
| 4016 | 3895 | mkBndrOccFreeVarMsg var occ_ty bad_tvs
|
| 4017 | 3896 | = vcat [ text "Free vars of type are shadowed:" <+> ppr bad_tvs
|
| 4018 | 3897 | , text "Occurrence:" <+> ppr var <+> dcolon <+> ppr occ_ty ]
|
| 1 | +{-
|
|
| 2 | +(c) The University of Glasgow 2006
|
|
| 3 | +(c) The GRASP/AQUA Project, Glasgow University, 1993-1998
|
|
| 4 | +-}
|
|
| 5 | + |
|
| 6 | +module GHC.Core.Lint.SubstTypeLets(
|
|
| 7 | + substTypeLets
|
|
| 8 | + ) where
|
|
| 9 | + |
|
| 10 | +import GHC.Prelude
|
|
| 11 | + |
|
| 12 | +import GHC.Core
|
|
| 13 | +import GHC.Core.Subst
|
|
| 14 | +import GHC.Core.Utils( mkInScopeSetBndrs )
|
|
| 15 | + |
|
| 16 | +import GHC.Types.Var
|
|
| 17 | + |
|
| 18 | +import GHC.Utils.Misc( mapSnd )
|
|
| 19 | +import GHC.Utils.Outputable
|
|
| 20 | +import GHC.Utils.Panic
|
|
| 21 | + |
|
| 22 | +{- Note [Substituting type-lets]
|
|
| 23 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 24 | +When desugaring pattern matching we really, really need non-Lint-acceptable type-lets.
|
|
| 25 | +Suppose we have
|
|
| 26 | + f (MkT a (Just a (x::a)) (y::a)) = rhs1
|
|
| 27 | + f (MkT b (Nothing b) (z::b)) = rhs2
|
|
| 28 | +where
|
|
| 29 | + MkT :: ∀ a. Maybe a -> a -> T
|
|
| 30 | + |
|
| 31 | +We desugar this to
|
|
| 32 | + f x = case x of
|
|
| 33 | + MkT w (v :: Maybe w) (p:w)
|
|
| 34 | + -> let { a=w, b=w }
|
|
| 35 | + in let { y:a=p, z:b=p }
|
|
| 36 | + in case v of
|
|
| 37 | + Just a (x:a) -> rhs1 [y::a]
|
|
| 38 | + Nothing b -> rhs2 [z::b]
|
|
| 39 | + |
|
| 40 | +Look at those type-lets { a=w, b=w }. They make the type variables in the
|
|
| 41 | +/two/ separately-typechecked clauses for `f` line up with the /single/ pattern
|
|
| 42 | +match on `x`, which binds the type variable `w`.
|
|
| 43 | + |
|
| 44 | +Key point: the body of the let is only type-correct /after/ substituting
|
|
| 45 | +a:=w, b:=w. Even the next let, { y:a=p } isn't type-correct without that
|
|
| 46 | +substitution, because (p:w).
|
|
| 47 | + |
|
| 48 | +So the `substTypeLets` pass does this:
|
|
| 49 | + - It runs as part of Lint, as a pre-pass before the main Lint
|
|
| 50 | + - It runs only when we are Linting the output of the desugarer
|
|
| 51 | + - The result of substTypeLets is discarded after linting
|
|
| 52 | + |
|
| 53 | +When it finds a nested type-let
|
|
| 54 | + let @a = ty in body
|
|
| 55 | +it substitutes a:=ty in `body`
|
|
| 56 | + |
|
| 57 | +Wrinkles
|
|
| 58 | + |
|
| 59 | +(STL1) It only substitutes /nested/ type-lets, not top level.
|
|
| 60 | + |
|
| 61 | +(STL2) You might think that we'd run it unconditionally, after desugaring. But actually,
|
|
| 62 | + the Simplifier (or SimpleOpt) will deal with these type-lets, so it is just Lint
|
|
| 63 | + that we must placate. We don't want to incur the cost of this pass except when
|
|
| 64 | + we are Linting.
|
|
| 65 | + |
|
| 66 | + TL;DR: we do substTypeLets as a pre-pass to the Lint pass that immediately follows
|
|
| 67 | + desugaring. See `GHC.Core.lintPassResult`, and the `lpr_preSubst` field in
|
|
| 68 | + `LintPassResultConfig`.
|
|
| 69 | + |
|
| 70 | +(STL3) Should `substTypeLets` process (stable) unfoldings? It does not need to
|
|
| 71 | + because all unfoldings have `simpleOptExpr` applied to them, so the tricky
|
|
| 72 | + type-lets will already be substituted.
|
|
| 73 | + |
|
| 74 | + Of course we stil need to apply the current substitution, but that is done
|
|
| 75 | + automatically by `substBndr`.
|
|
| 76 | +-}
|
|
| 77 | + |
|
| 78 | +substTypeLets :: CoreProgram -> CoreProgram
|
|
| 79 | +substTypeLets binds = map stl_top binds
|
|
| 80 | + where
|
|
| 81 | + stl_top (NonRec b r) = NonRec b (stlExpr empty_subst r)
|
|
| 82 | + stl_top (Rec prs) = Rec (mapSnd (stlExpr empty_subst) prs)
|
|
| 83 | + |
|
| 84 | + empty_subst = mkEmptySubst $
|
|
| 85 | + mkInScopeSetBndrs binds
|
|
| 86 | + |
|
| 87 | +----------------------
|
|
| 88 | +stlBind :: Subst -> CoreBind -> (Subst, CoreBind)
|
|
| 89 | +stlBind subst (Rec prs)
|
|
| 90 | + = assertPpr (not (any isTyVar bndrs)) (ppr prs) $
|
|
| 91 | + (subst', Rec prs')
|
|
| 92 | + where
|
|
| 93 | + (bndrs,rhss) = unzip prs
|
|
| 94 | + (subst', bndrs') = substRecBndrs subst bndrs
|
|
| 95 | + -- substRecBndrs: see (STL3) in Note [Substituting type-lets]
|
|
| 96 | + rhss' = map (stlExpr subst') rhss
|
|
| 97 | + prs' = bndrs' `zip` rhss'
|
|
| 98 | + |
|
| 99 | +stlBind subst (NonRec bndr rhs)
|
|
| 100 | + = (subst', NonRec bndr' (stlExpr subst rhs))
|
|
| 101 | + where
|
|
| 102 | + (subst', bndr') = substBndr subst bndr
|
|
| 103 | + -- substBndr: see (STL3) in Note [Substituting type-lets]
|
|
| 104 | + |
|
| 105 | +----------------------
|
|
| 106 | +stlExpr :: Subst -> CoreExpr -> CoreExpr
|
|
| 107 | + |
|
| 108 | +stlExpr subst (Let (NonRec tv (Type ty)) body)
|
|
| 109 | + = -- This equation is the main payload of the entire pass!
|
|
| 110 | + stlExpr (extendTvSubst subst tv (substTy subst ty)) body
|
|
| 111 | + |
|
| 112 | +stlExpr subst (Let bind body)
|
|
| 113 | + = Let bind' (stlExpr subst' body)
|
|
| 114 | + where
|
|
| 115 | + (subst', bind') = stlBind subst bind
|
|
| 116 | + |
|
| 117 | +stlExpr subst (Lam bndr body)
|
|
| 118 | + = Lam bndr' (stlExpr subst' body)
|
|
| 119 | + where
|
|
| 120 | + (subst', bndr') = substBndr subst bndr
|
|
| 121 | + |
|
| 122 | +stlExpr subst (Case scrut bndr ty alts)
|
|
| 123 | + = Case (stlExpr subst scrut) bndr' (substTy subst ty)
|
|
| 124 | + (map stl_alt alts)
|
|
| 125 | + where
|
|
| 126 | + (subst', bndr') = substBndr subst bndr
|
|
| 127 | + |
|
| 128 | + stl_alt (Alt con bndrs rhs)
|
|
| 129 | + = Alt con bndrs' (stlExpr subst'' rhs)
|
|
| 130 | + where
|
|
| 131 | + (subst'', bndrs') = substBndrs subst' bndrs
|
|
| 132 | + |
|
| 133 | +-- Simple cases
|
|
| 134 | +stlExpr _ (Lit l) = Lit l
|
|
| 135 | +stlExpr subst (Var v) = lookupIdSubst subst v
|
|
| 136 | +stlExpr subst (App e1 e2) = App (stlExpr subst e1) (stlExpr subst e2)
|
|
| 137 | +stlExpr subst (Type ty) = Type (substTy subst ty)
|
|
| 138 | +stlExpr subst (Tick t e) = Tick (substTickish subst t) (stlExpr subst e)
|
|
| 139 | +stlExpr subst (Cast e co) = Cast (stlExpr subst e) (substCo subst co)
|
|
| 140 | +stlExpr subst (Coercion co) = Coercion (substCo subst co) |
| ... | ... | @@ -2676,6 +2676,8 @@ occAnalArgs :: OccEnv -> CoreExpr -> [CoreExpr] |
| 2676 | 2676 | -> WithUsageDetails CoreExpr
|
| 2677 | 2677 | -- The `fun` argument is just an accumulating parameter,
|
| 2678 | 2678 | -- the base for building the application we return
|
| 2679 | +--
|
|
| 2680 | +-- We have applied markAllNonTail to the returned usage-details
|
|
| 2679 | 2681 | occAnalArgs env fun args one_shots
|
| 2680 | 2682 | = go emptyDetails fun args one_shots
|
| 2681 | 2683 | where
|
| ... | ... | @@ -2686,7 +2688,9 @@ occAnalArgs env fun args one_shots |
| 2686 | 2688 | encl | Var f <- fun, isDeadEndSig (idDmdSig f) = OccScrut
|
| 2687 | 2689 | | otherwise = OccVanilla
|
| 2688 | 2690 | |
| 2689 | - go uds fun [] _ = WUD uds fun
|
|
| 2691 | + go uds fun [] _ = WUD (markAllNonTail uds) fun
|
|
| 2692 | + -- markAllNonTail: calls in arguments are not tail calls!
|
|
| 2693 | + |
|
| 2690 | 2694 | go uds fun (arg:args) one_shots
|
| 2691 | 2695 | = go (uds `andUDs` arg_uds) (fun `App` arg') args one_shots'
|
| 2692 | 2696 | where
|
| ... | ... | @@ -2778,8 +2782,7 @@ occAnalApp env (Var fun_id, args, ticks) |
| 2778 | 2782 | |
| 2779 | 2783 | all_uds = fun_uds `andUDs` final_args_uds
|
| 2780 | 2784 | |
| 2781 | - !final_args_uds = markAllNonTail $
|
|
| 2782 | - markAllInsideLamIf (isRhsEnv env && is_exp) $
|
|
| 2785 | + !final_args_uds = markAllInsideLamIf (isRhsEnv env && is_exp) $
|
|
| 2783 | 2786 | -- isRhsEnv: see Note [OccEncl]
|
| 2784 | 2787 | args_uds
|
| 2785 | 2788 | -- We mark the free vars of the argument of a constructor or PAP
|
| ... | ... | @@ -2809,20 +2812,27 @@ occAnalApp env (Var fun_id, args, ticks) |
| 2809 | 2812 | -- See Note [Sources of one-shot information], bullet point A']
|
| 2810 | 2813 | |
| 2811 | 2814 | occAnalApp env (fun, args, ticks)
|
| 2812 | - = let app_out = mkTicks ticks app'
|
|
| 2813 | - in WUD (markAllNonTail (fun_uds `andUDs` args_uds)) app_out
|
|
| 2814 | - |
|
| 2815 | + = WUD (fun_uds `andUDs` args_uds) (mkTicks ticks app')
|
|
| 2815 | 2816 | where
|
| 2816 | 2817 | !(WUD args_uds app') = occAnalArgs env fun' args []
|
| 2817 | - !(WUD fun_uds fun') = occAnal (addAppCtxt env args) fun
|
|
| 2818 | - -- The addAppCtxt is a bit cunning. One iteration of the simplifier
|
|
| 2819 | - -- often leaves behind beta redexes like
|
|
| 2820 | - -- (\x y -> e) a1 a2
|
|
| 2821 | - -- Here we would like to mark x,y as one-shot, and treat the whole
|
|
| 2822 | - -- thing much like a let. We do this by pushing some OneShotLam items
|
|
| 2823 | - -- onto the context stack.
|
|
| 2818 | + !(WUD fun_uds fun') = go_fun env fun args
|
|
| 2819 | + |
|
| 2820 | + -- See (A2) in Note [occAnal for applications]
|
|
| 2821 | + go_fun env (Lam bndr body) (_ : args)
|
|
| 2822 | + = addInScopeOne env bndr $ \ env' ->
|
|
| 2823 | + let !(WUD body_uds body') = go_fun env' body args
|
|
| 2824 | + !bndr' = tagLamBinder body_uds bndr
|
|
| 2825 | + in WUD body_uds (Lam bndr' body')
|
|
| 2826 | + go_fun env fun args
|
|
| 2827 | + | null args
|
|
| 2828 | + = occAnal env fun
|
|
| 2829 | + | otherwise
|
|
| 2830 | + = let !env' = addAppCtxt env args
|
|
| 2831 | + !(WUD fun_uds fun') = occAnal env' fun
|
|
| 2832 | + in WUD (markAllNonTail fun_uds) fun'
|
|
| 2824 | 2833 | |
| 2825 | 2834 | addAppCtxt :: OccEnv -> [Arg CoreBndr] -> OccEnv
|
| 2835 | +-- See (A3) in Note [occAnal for applications]
|
|
| 2826 | 2836 | addAppCtxt env@(OccEnv { occ_one_shots = ctxt }) args
|
| 2827 | 2837 | | n_val_args > 0
|
| 2828 | 2838 | = env { occ_one_shots = replicate n_val_args OneShotLam ++ ctxt
|
| ... | ... | @@ -2834,8 +2844,40 @@ addAppCtxt env@(OccEnv { occ_one_shots = ctxt }) args |
| 2834 | 2844 | where
|
| 2835 | 2845 | n_val_args = valArgCount args
|
| 2836 | 2846 | |
| 2847 | +{- Note [occAnal for applications]
|
|
| 2848 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 2849 | +One iteration of the simplifier sometimes leaves behind beta redexes like
|
|
| 2850 | + (\x y -> e) a1 a2
|
|
| 2851 | +This happens particularly in worker/wrapper; see Note [Join points and beta-redexes]
|
|
| 2852 | +in GHC.Core.Lint. In these cases there are three things we want to take care of
|
|
| 2853 | +in the occurrence analyser:
|
|
| 2854 | + |
|
| 2855 | +(A1) We don't want to mark variables inside `e` as `InsideLam`; that would just
|
|
| 2856 | + delay inlining them for another iteration of the Simplifier.
|
|
| 2857 | + |
|
| 2858 | +(A2) If there is a join-point invocation inside `e`, we don't want to complain about
|
|
| 2859 | + lost join points. See Note [Join points and beta-redexes] in GHC.Core.Lint for
|
|
| 2860 | + more detail.
|
|
| 2861 | + |
|
| 2862 | +(A3) Suppose we have something like
|
|
| 2863 | + (case e of (a,b) -> (\x.blah) |> co) arg
|
|
| 2864 | + which can happen during 'gentle' simplification when we don't do case-of-case,
|
|
| 2865 | + not push arguments into cases. Then we'd still like to mark that lambda
|
|
| 2866 | + as one-shot, so that things can get inlined inside it. We can to this
|
|
| 2867 | + by pushing OneShotLam items onto the context stack.
|
|
| 2868 | + |
|
| 2869 | + Live example: `read_tup4` in test CoOpt_Read.
|
|
| 2870 | + |
|
| 2871 | +How we address these:
|
|
| 2872 | + |
|
| 2873 | +* (A2): we focus narrowly on visible beta-redexes ((\x.e) arg), since that
|
|
| 2874 | + is what is needed for Note [Join points and beta-redexes]. We do this
|
|
| 2875 | + via the `go_fun` loop in `occAnalApp`.
|
|
| 2876 | + |
|
| 2877 | +* (A1) and (A3): for visible beta-redexes, the `go_fun` loop does the job.
|
|
| 2878 | + But for less-visible ones, like in (A3) we push `OneShotLam` items onto
|
|
| 2879 | + the context stack, in `addAppCtxt`.
|
|
| 2837 | 2880 | |
| 2838 | -{-
|
|
| 2839 | 2881 | Note [Sources of one-shot information]
|
| 2840 | 2882 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 2841 | 2883 | The occurrence analyser obtains one-shot-lambda information from two sources:
|
| ... | ... | @@ -241,10 +241,10 @@ mkWwBodies opts fun_id ww_arity arg_vars res_ty demands res_cpr |
| 241 | 241 | = (work_args, work_args, work_marks)
|
| 242 | 242 | |
| 243 | 243 | call_work work_fn = mkVarApps (Var work_fn) work_call_args
|
| 244 | - call_rhs fn_rhs = mkAppsBeta fn_rhs fn_args
|
|
| 245 | - -- See Note [Join points and beta-redexes]
|
|
| 244 | + call_rhs fn_rhs = mkApps fn_rhs fn_args
|
|
| 245 | + -- See Note [Join points and beta-redexes] in GHC.Core.Lint
|
|
| 246 | 246 | wrapper_body = mkLams cloned_arg_vars . wrap_fn_cpr . wrap_fn_str . call_work
|
| 247 | - -- See Note [Call-by-value for worker args]
|
|
| 247 | + -- See Note [Call-by-value for worker args]
|
|
| 248 | 248 | work_seq_str_flds = mkStrictFieldSeqs (zip work_lam_args work_call_str)
|
| 249 | 249 | worker_body = mkLams work_lam_args . work_seq_str_flds . work_fn_cpr . call_rhs
|
| 250 | 250 | worker_args_dmds= [ idDemandInfo v | v <- work_call_args, isId v]
|
| ... | ... | @@ -280,14 +280,6 @@ mkWwBodies opts fun_id ww_arity arg_vars res_ty demands res_cpr |
| 280 | 280 | arity_ok | isJoinId fun_id = ww_arity <= n_dmds
|
| 281 | 281 | | otherwise = ww_arity == n_dmds
|
| 282 | 282 | |
| 283 | --- | Version of 'GHC.Core.mkApps' that does beta reduction on-the-fly.
|
|
| 284 | --- PRECONDITION: The arg expressions are not free in any of the lambdas binders.
|
|
| 285 | -mkAppsBeta :: CoreExpr -> [CoreArg] -> CoreExpr
|
|
| 286 | --- The precondition holds for our call site in mkWwBodies, because all the FVs
|
|
| 287 | --- of as are either cloned_arg_vars (and thus fresh) or fresh worker args.
|
|
| 288 | -mkAppsBeta (Lam b body) (a:as) = bindNonRec b a $! mkAppsBeta body as
|
|
| 289 | -mkAppsBeta f as = mkApps f as
|
|
| 290 | - |
|
| 291 | 283 | -- See Note [Limit w/w arity]
|
| 292 | 284 | isWorkerSmallEnough :: Int -> Int -> [Var] -> Bool
|
| 293 | 285 | isWorkerSmallEnough max_worker_args old_n_args vars
|
| ... | ... | @@ -525,36 +517,6 @@ Solution is simple: put the void argument /last/: |
| 525 | 517 | |
| 526 | 518 | c.f Note [SpecConstr void argument insertion] in GHC.Core.Opt.SpecConstr
|
| 527 | 519 | |
| 528 | -Note [Join points and beta-redexes]
|
|
| 529 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 530 | -Originally, the worker would invoke the original function by calling it with
|
|
| 531 | -arguments, thus producing a beta-redex for the simplifier to munch away:
|
|
| 532 | - |
|
| 533 | - \x y z -> e => (\x y z -> e) wx wy wz
|
|
| 534 | - |
|
| 535 | -Now that we have special rules about join points, however, this is Not Good if
|
|
| 536 | -the original function is itself a join point, as then it may contain invocations
|
|
| 537 | -of other join points:
|
|
| 538 | - |
|
| 539 | - join j1 x = ...
|
|
| 540 | - join j2 y = if y == 0 then 0 else j1 y
|
|
| 541 | - |
|
| 542 | - =>
|
|
| 543 | - |
|
| 544 | - join j1 x = ...
|
|
| 545 | - join $wj2 y# = let wy = I# y# in (\y -> if y == 0 then 0 else jump j1 y) wy
|
|
| 546 | - join j2 y = case y of I# y# -> jump $wj2 y#
|
|
| 547 | - |
|
| 548 | -There can't be an intervening lambda between a join point's declaration and its
|
|
| 549 | -occurrences, so $wj2 here is wrong. But of course, this is easy enough to fix:
|
|
| 550 | - |
|
| 551 | - ...
|
|
| 552 | - let join $wj2 y# = let wy = I# y# in let y = wy in if y == 0 then 0 else j1 y
|
|
| 553 | - ...
|
|
| 554 | - |
|
| 555 | -Hence we simply do the beta-reduction here. (This would be harder if we had to
|
|
| 556 | -worry about hygiene, but luckily wy is freshly generated.)
|
|
| 557 | - |
|
| 558 | 520 | Note [Freshen WW arguments]
|
| 559 | 521 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 560 | 522 | When we do a worker/wrapper split, we must freshen the arg vars of the original
|
| ... | ... | @@ -13,7 +13,8 @@ module GHC.Core.Subst ( |
| 13 | 13 | |
| 14 | 14 | -- ** Substituting into expressions and related types
|
| 15 | 15 | deShadowBinds, substRuleInfo, substRulesForImportedIds,
|
| 16 | - substTyUnchecked, substCo, substExpr, substExprSC, substBind, substBindSC,
|
|
| 16 | + substTy, substTyUnchecked, substCo,
|
|
| 17 | + substExpr, substExprSC, substBind, substBindSC,
|
|
| 17 | 18 | substUnfolding, substUnfoldingSC,
|
| 18 | 19 | lookupIdSubst, lookupIdSubst_maybe, substIdType, substIdOcc,
|
| 19 | 20 | substTickish, substDVarSet, substIdInfo,
|
| ... | ... | @@ -42,8 +43,7 @@ import GHC.Core.FVs |
| 42 | 43 | import GHC.Core.Seq
|
| 43 | 44 | import GHC.Core.Utils
|
| 44 | 45 | |
| 45 | - -- We are defining local versions
|
|
| 46 | -import GHC.Core.Type hiding ( substTy )
|
|
| 46 | +import GHC.Core.Type
|
|
| 47 | 47 | import GHC.Core.Coercion( mkCoVarCo, substCoVarBndr )
|
| 48 | 48 | import GHC.Core.TyCo.FVs
|
| 49 | 49 |
| 1 | 1 | module GHC.Driver.Config.Core.Lint
|
| 2 | 2 | ( endPass
|
| 3 | 3 | , endPassHscEnvIO
|
| 4 | - , lintCoreBindings
|
|
| 5 | 4 | , initEndPassConfig
|
| 6 | 5 | , initLintPassResultConfig
|
| 7 | 6 | , initLintConfig
|
| ... | ... | @@ -50,16 +49,6 @@ endPassHscEnvIO hsc_env name_ppr_ctx pass binds rules |
| 50 | 49 | binds rules
|
| 51 | 50 | }
|
| 52 | 51 | |
| 53 | --- | Type-check a 'CoreProgram'. See Note [Core Lint guarantee].
|
|
| 54 | -lintCoreBindings :: DynFlags -> CoreToDo -> [Var] -> CoreProgram -> WarnsAndErrs
|
|
| 55 | -lintCoreBindings dflags coreToDo vars -- binds
|
|
| 56 | - = lintCoreBindings' $ LintConfig
|
|
| 57 | - { l_diagOpts = initDiagOpts dflags
|
|
| 58 | - , l_platform = targetPlatform dflags
|
|
| 59 | - , l_flags = perPassFlags dflags coreToDo
|
|
| 60 | - , l_vars = vars
|
|
| 61 | - }
|
|
| 62 | - |
|
| 63 | 52 | initEndPassConfig :: DynFlags -> [Var] -> NamePprCtx -> CoreToDo -> EndPassConfig
|
| 64 | 53 | initEndPassConfig dflags extra_vars name_ppr_ctx pass = EndPassConfig
|
| 65 | 54 | { ep_dumpCoreSizes = not (gopt Opt_SuppressCoreSizes dflags)
|
| ... | ... | @@ -104,10 +93,17 @@ initLintPassResultConfig dflags extra_vars pass = LintPassResultConfig |
| 104 | 93 | { lpr_diagOpts = initDiagOpts dflags
|
| 105 | 94 | , lpr_platform = targetPlatform dflags
|
| 106 | 95 | , lpr_makeLintFlags = perPassFlags dflags pass
|
| 107 | - , lpr_passPpr = ppr pass
|
|
| 96 | + , lpr_passPpr = ppr pass
|
|
| 97 | + , lpr_preSubst = doPreSubst pass
|
|
| 108 | 98 | , lpr_localsInScope = extra_vars
|
| 109 | 99 | }
|
| 110 | 100 | |
| 101 | +doPreSubst :: CoreToDo -> Bool
|
|
| 102 | +doPreSubst CoreDesugar = True -- Output of desugarer, /before/ running any optimisation,
|
|
| 103 | + -- not even simpleOpt. See Note Note [Substituting type-lets]
|
|
| 104 | + -- in GHC.Core.SubstTypeLets
|
|
| 105 | +doPreSubst _ = False
|
|
| 106 | + |
|
| 111 | 107 | perPassFlags :: DynFlags -> CoreToDo -> LintFlags
|
| 112 | 108 | perPassFlags dflags pass
|
| 113 | 109 | = (defaultLintFlags dflags)
|
| ... | ... | @@ -116,7 +112,8 @@ perPassFlags dflags pass |
| 116 | 112 | , lf_check_static_ptrs = check_static_ptrs
|
| 117 | 113 | , lf_check_linearity = check_linearity
|
| 118 | 114 | , lf_check_rubbish_lits = check_rubbish
|
| 119 | - , lf_allow_weak_joins = allow_weak_joins }
|
|
| 115 | + , lf_allow_weak_joins = allow_weak_joins
|
|
| 116 | + , lf_allow_beta_joins = allow_beta_joins }
|
|
| 120 | 117 | where
|
| 121 | 118 | -- See Note [Checking for global Ids]
|
| 122 | 119 | check_globals = case pass of
|
| ... | ... | @@ -158,6 +155,11 @@ perPassFlags dflags pass |
| 158 | 155 | CorePrep -> True
|
| 159 | 156 | _ -> False
|
| 160 | 157 | |
| 158 | + -- See Note [Join points and beta-redexes] in GHC.Core.Lint
|
|
| 159 | + allow_beta_joins = case pass of
|
|
| 160 | + CoreDoWorkerWrapper -> True
|
|
| 161 | + _ -> False
|
|
| 162 | + |
|
| 161 | 163 | initLintConfig :: DynFlags -> [Var] -> LintConfig
|
| 162 | 164 | initLintConfig dflags vars =LintConfig
|
| 163 | 165 | { l_diagOpts = initDiagOpts dflags
|
| ... | ... | @@ -175,4 +177,5 @@ defaultLintFlags dflags = LF { lf_check_global_ids = False |
| 175 | 177 | , lf_check_fixed_rep = True
|
| 176 | 178 | , lf_check_rubbish_lits = True
|
| 177 | 179 | , lf_allow_weak_joins = False
|
| 180 | + , lf_allow_beta_joins = False
|
|
| 178 | 181 | } |
| ... | ... | @@ -802,7 +802,7 @@ readUnitDatabase logger cfg conf_file = do |
| 802 | 802 | if cache_exists
|
| 803 | 803 | then do
|
| 804 | 804 | debugTraceMsg logger 2 $ text "Using binary package database:" <+> ppr filename
|
| 805 | - readPackageDbForGhc (OsPath.unsafeDecodeUtf filename)
|
|
| 805 | + readPackageDbForGhc filename
|
|
| 806 | 806 | else do
|
| 807 | 807 | -- If there is no package.cache file, we check if the database is not
|
| 808 | 808 | -- empty by inspecting if the directory contains any .conf file. If it
|
| ... | ... | @@ -361,6 +361,7 @@ Library |
| 361 | 361 | GHC.Core.InstEnv
|
| 362 | 362 | GHC.Core.Lint
|
| 363 | 363 | GHC.Core.Lint.Interactive
|
| 364 | + GHC.Core.Lint.SubstTypeLets
|
|
| 364 | 365 | GHC.Core.LateCC
|
| 365 | 366 | GHC.Core.LateCC.Types
|
| 366 | 367 | GHC.Core.LateCC.TopLevelBinds
|
| ... | ... | @@ -5,15 +5,13 @@ setTestOpts(js_skip) |
| 5 | 5 | # Check optimization of `elem`
|
| 6 | 6 | #--------------------------------------
|
| 7 | 7 | |
| 8 | -elemCoreFilter = "sed -En '/^(is|fusion|noFusion)[A-Za-z]*($| )/,/^$/p'"
|
|
| 9 | - |
|
| 10 | 8 | def elemCoreTest(test_name, module_name, opt):
|
| 11 | 9 | test(test_name,
|
| 12 | 10 | [only_ways(['normal']), extra_files([module_name + '.hs'])],
|
| 13 | 11 | multimod_compile_filter,
|
| 14 | 12 | [module_name,
|
| 15 | 13 | f'{opt} -ddump-simpl -dsuppress-all -dsuppress-uniques -dno-typeable-binds',
|
| 16 | - elemCoreFilter])
|
|
| 14 | + "sed -En '/^(is|fusion|noFusion)[A-Za-z]*($| )/,/^$/p'"])
|
|
| 17 | 15 | |
| 18 | 16 | elemCoreTest('T17752_O1', 'T17752', '-O1')
|
| 19 | 17 | elemCoreTest('T17752_O2', 'T17752', '-O2')
|
| ... | ... | @@ -68,6 +68,8 @@ module GHC.Unit.Database |
| 68 | 68 | -- * Misc
|
| 69 | 69 | , mkMungePathUrl
|
| 70 | 70 | , mungeUnitInfoPaths
|
| 71 | + , writeFileAtomic
|
|
| 72 | + , unsafeDecodeUtf
|
|
| 71 | 73 | )
|
| 72 | 74 | where
|
| 73 | 75 | |
| ... | ... | @@ -86,18 +88,23 @@ import Data.Binary.Get as Bin |
| 86 | 88 | import Data.List (intersperse)
|
| 87 | 89 | import Control.Exception as Exception
|
| 88 | 90 | import Control.Monad (when)
|
| 89 | -import System.FilePath as FilePath
|
|
| 91 | +import qualified System.FilePath as FilePath
|
|
| 90 | 92 | #if !defined(mingw32_HOST_OS)
|
| 91 | 93 | import Data.Bits ((.|.))
|
| 92 | -import System.Posix.Files
|
|
| 94 | +import System.Posix.Files.PosixString
|
|
| 93 | 95 | import System.Posix.Types (FileMode)
|
| 96 | +import System.OsString.Internal.Types (getOsString)
|
|
| 94 | 97 | #endif
|
| 95 | 98 | import System.IO
|
| 96 | 99 | import System.IO.Error
|
| 97 | 100 | import GHC.IO.Exception (IOErrorType(InappropriateType))
|
| 98 | 101 | import qualified GHC.Data.ShortText as ST
|
| 99 | 102 | import GHC.IO.Handle.Lock
|
| 100 | -import System.Directory
|
|
| 103 | +import GHC.Stack.Types (HasCallStack)
|
|
| 104 | +import System.OsPath
|
|
| 105 | +import qualified System.Directory.OsPath as OsPath
|
|
| 106 | +import qualified System.Directory.Internal as OsPath.Internal
|
|
| 107 | +import qualified System.File.OsPath as FileIO
|
|
| 101 | 108 | |
| 102 | 109 | -- | @ghc-boot@'s UnitInfo, serialized to the database.
|
| 103 | 110 | type DbUnitInfo = GenericUnitInfo BS.ByteString BS.ByteString BS.ByteString BS.ByteString DbModule
|
| ... | ... | @@ -314,13 +321,13 @@ data DbInstUnitId |
| 314 | 321 | newtype PackageDbLock = PackageDbLock Handle
|
| 315 | 322 | |
| 316 | 323 | -- | Acquire an exclusive lock related to package DB under given location.
|
| 317 | -lockPackageDb :: FilePath -> IO PackageDbLock
|
|
| 324 | +lockPackageDb :: OsPath -> IO PackageDbLock
|
|
| 318 | 325 | |
| 319 | 326 | -- | Release the lock related to package DB.
|
| 320 | 327 | unlockPackageDb :: PackageDbLock -> IO ()
|
| 321 | 328 | |
| 322 | 329 | -- | Acquire a lock of given type related to package DB under given location.
|
| 323 | -lockPackageDbWith :: LockMode -> FilePath -> IO PackageDbLock
|
|
| 330 | +lockPackageDbWith :: LockMode -> OsPath -> IO PackageDbLock
|
|
| 324 | 331 | lockPackageDbWith mode file = do
|
| 325 | 332 | -- We are trying to open the lock file and then lock it. Thus the lock file
|
| 326 | 333 | -- needs to either exist or we need to be able to create it. Ideally we
|
| ... | ... | @@ -350,10 +357,10 @@ lockPackageDbWith mode file = do |
| 350 | 357 | (lockFileOpenIn ReadWriteMode)
|
| 351 | 358 | (const $ lockFileOpenIn ReadMode)
|
| 352 | 359 | where
|
| 353 | - lock = file <.> "lock"
|
|
| 360 | + lock = file <.> OsPath.Internal.os "lock"
|
|
| 354 | 361 | |
| 355 | 362 | lockFileOpenIn io_mode = bracketOnError
|
| 356 | - (openBinaryFile lock io_mode)
|
|
| 363 | + (FileIO.openBinaryFile lock io_mode)
|
|
| 357 | 364 | hClose
|
| 358 | 365 | -- If file locking support is not available, ignore the error and proceed
|
| 359 | 366 | -- normally. Without it the only thing we lose on non-Windows platforms is
|
| ... | ... | @@ -387,7 +394,7 @@ isDbOpenReadMode = \case |
| 387 | 394 | |
| 388 | 395 | -- | Read the part of the package DB that GHC is interested in.
|
| 389 | 396 | --
|
| 390 | -readPackageDbForGhc :: FilePath -> IO [DbUnitInfo]
|
|
| 397 | +readPackageDbForGhc :: OsPath -> IO [DbUnitInfo]
|
|
| 391 | 398 | readPackageDbForGhc file =
|
| 392 | 399 | decodeFromFile file DbOpenReadOnly getDbForGhc >>= \case
|
| 393 | 400 | (pkgs, DbOpenReadOnly) -> return pkgs
|
| ... | ... | @@ -409,7 +416,7 @@ readPackageDbForGhc file = |
| 409 | 416 | -- we additionally receive a PackageDbLock that represents a lock on the
|
| 410 | 417 | -- database, so that we can safely update it later.
|
| 411 | 418 | --
|
| 412 | -readPackageDbForGhcPkg :: Binary pkgs => FilePath -> DbOpenMode mode t ->
|
|
| 419 | +readPackageDbForGhcPkg :: Binary pkgs => OsPath -> DbOpenMode mode t ->
|
|
| 413 | 420 | IO (pkgs, DbOpenMode mode PackageDbLock)
|
| 414 | 421 | readPackageDbForGhcPkg file mode =
|
| 415 | 422 | decodeFromFile file mode getDbForGhcPkg
|
| ... | ... | @@ -425,7 +432,7 @@ readPackageDbForGhcPkg file mode = |
| 425 | 432 | |
| 426 | 433 | -- | Write the whole of the package DB, both parts.
|
| 427 | 434 | --
|
| 428 | -writePackageDb :: Binary pkgs => FilePath -> [DbUnitInfo] -> pkgs -> IO ()
|
|
| 435 | +writePackageDb :: Binary pkgs => OsPath -> [DbUnitInfo] -> pkgs -> IO ()
|
|
| 429 | 436 | writePackageDb file ghcPkgs ghcPkgPart = do
|
| 430 | 437 | writeFileAtomic file (runPut putDbForGhcPkg)
|
| 431 | 438 | #if !defined(mingw32_HOST_OS)
|
| ... | ... | @@ -446,10 +453,10 @@ writePackageDb file ghcPkgs ghcPkgPart = do |
| 446 | 453 | ghcPart = encode ghcPkgs
|
| 447 | 454 | |
| 448 | 455 | #if !defined(mingw32_HOST_OS)
|
| 449 | -addFileMode :: FilePath -> FileMode -> IO ()
|
|
| 456 | +addFileMode :: OsPath -> FileMode -> IO ()
|
|
| 450 | 457 | addFileMode file m = do
|
| 451 | - o <- fileMode <$> getFileStatus file
|
|
| 452 | - setFileMode file (m .|. o)
|
|
| 458 | + o <- fileMode <$> getFileStatus (getOsString file)
|
|
| 459 | + setFileMode (getOsString file) (m .|. o)
|
|
| 453 | 460 | #endif
|
| 454 | 461 | |
| 455 | 462 | getHeader :: Get (Word32, Word32)
|
| ... | ... | @@ -496,7 +503,7 @@ headerMagic = BS.Char8.pack "\0ghcpkg\0" |
| 496 | 503 | |
| 497 | 504 | -- | Feed a 'Get' decoder with data chunks from a file.
|
| 498 | 505 | --
|
| 499 | -decodeFromFile :: FilePath -> DbOpenMode mode t -> Get pkgs ->
|
|
| 506 | +decodeFromFile :: OsPath -> DbOpenMode mode t -> Get pkgs ->
|
|
| 500 | 507 | IO (pkgs, DbOpenMode mode PackageDbLock)
|
| 501 | 508 | decodeFromFile file mode decoder = case mode of
|
| 502 | 509 | DbOpenReadOnly -> do
|
| ... | ... | @@ -517,7 +524,7 @@ decodeFromFile file mode decoder = case mode of |
| 517 | 524 | bracketOnError (lockPackageDb file) unlockPackageDb $ \lock -> do
|
| 518 | 525 | (, DbOpenReadWrite lock) <$> decodeFileContents
|
| 519 | 526 | where
|
| 520 | - decodeFileContents = withBinaryFile file ReadMode $ \hnd ->
|
|
| 527 | + decodeFileContents = FileIO.withBinaryFile file ReadMode $ \hnd ->
|
|
| 521 | 528 | feed hnd (runGetIncremental decoder)
|
| 522 | 529 | |
| 523 | 530 | feed hnd (Partial k) = do chunk <- BS.hGet hnd BS.Lazy.defaultChunkSize
|
| ... | ... | @@ -527,21 +534,21 @@ decodeFromFile file mode decoder = case mode of |
| 527 | 534 | feed _ (Done _ _ res) = return res
|
| 528 | 535 | feed _ (Fail _ _ msg) = ioError err
|
| 529 | 536 | where
|
| 530 | - err = mkIOError InappropriateType loc Nothing (Just file)
|
|
| 537 | + err = mkIOError InappropriateType loc Nothing (Just $ unsafeDecodeUtf file)
|
|
| 531 | 538 | `ioeSetErrorString` msg
|
| 532 | 539 | loc = "GHC.Unit.Database.readPackageDb"
|
| 533 | 540 | |
| 534 | 541 | -- Copied from Cabal's Distribution.Simple.Utils.
|
| 535 | -writeFileAtomic :: FilePath -> BS.Lazy.ByteString -> IO ()
|
|
| 542 | +writeFileAtomic :: OsPath -> BS.Lazy.ByteString -> IO ()
|
|
| 536 | 543 | writeFileAtomic targetPath content = do
|
| 537 | 544 | let (targetDir, targetFile) = splitFileName targetPath
|
| 538 | 545 | Exception.bracketOnError
|
| 539 | - (openBinaryTempFileWithDefaultPermissions targetDir $ targetFile <.> "tmp")
|
|
| 540 | - (\(tmpPath, handle) -> hClose handle >> removeFile tmpPath)
|
|
| 546 | + (FileIO.openBinaryTempFileWithDefaultPermissions targetDir $ targetFile <.> OsPath.Internal.os "tmp")
|
|
| 547 | + (\(tmpPath, handle) -> hClose handle >> OsPath.removeFile tmpPath)
|
|
| 541 | 548 | (\(tmpPath, handle) -> do
|
| 542 | 549 | BS.Lazy.hPut handle content
|
| 543 | 550 | hClose handle
|
| 544 | - renameFile tmpPath targetPath)
|
|
| 551 | + OsPath.renameFile tmpPath targetPath)
|
|
| 545 | 552 | |
| 546 | 553 | instance Binary DbUnitInfo where
|
| 547 | 554 | put (GenericUnitInfo
|
| ... | ... | @@ -711,7 +718,7 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url) |
| 711 | 718 | -- rather than letting FilePath change it to use \ as the separator
|
| 712 | 719 | stripVarPrefix var path = case ST.stripPrefix var path of
|
| 713 | 720 | Just "" -> Just ""
|
| 714 | - Just cs | isPathSeparator (ST.head cs) -> Just cs
|
|
| 721 | + Just cs | FilePath.isPathSeparator (ST.head cs) -> Just cs
|
|
| 715 | 722 | _ -> Nothing
|
| 716 | 723 | |
| 717 | 724 | |
| ... | ... | @@ -742,3 +749,8 @@ mungeUnitInfoPaths top_dir pkgroot pkg = |
| 742 | 749 | munge_paths = map munge_path
|
| 743 | 750 | munge_urls = map munge_url
|
| 744 | 751 | (munge_path,munge_url) = mkMungePathUrl top_dir pkgroot
|
| 752 | + |
|
| 753 | +-- | Decode an 'OsPath' to 'FilePath', throwing an 'error' if decoding failed.
|
|
| 754 | +-- Prefer 'decodeUtf' and gracious error handling.
|
|
| 755 | +unsafeDecodeUtf :: HasCallStack => OsPath -> FilePath
|
|
| 756 | +unsafeDecodeUtf = OsPath.Internal.so |
| ... | ... | @@ -82,6 +82,8 @@ Library |
| 82 | 82 | containers >= 0.5 && < 0.9,
|
| 83 | 83 | directory >= 1.2 && < 1.4,
|
| 84 | 84 | filepath >= 1.3 && < 1.6,
|
| 85 | + file-io >= 0.1.6 && < 0.3,
|
|
| 86 | + os-string >= 2.0.1 && < 2.1,
|
|
| 85 | 87 | deepseq >= 1.4 && < 1.6,
|
| 86 | 88 | ghc-platform >= 0.1,
|
| 87 | 89 | ghc-toolchain >= 0.1
|
| ... | ... | @@ -79,6 +79,25 @@ ghcpkg04 : |
| 79 | 79 | @: # testpkg-1.2.3.4 and newtestpkg-2.0 are both exposed now
|
| 80 | 80 | '$(TEST_HC)' $(TEST_HC_OPTS) -package-db $(PKGCONF04) -c ghcpkg04.hs || true
|
| 81 | 81 | |
| 82 | +PKGCONF20=local20.package.conf
|
|
| 83 | +LOCAL_GHC_PKG20 = '$(GHC_PKG)' --no-user-package-db
|
|
| 84 | + |
|
| 85 | +DIR1=asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf
|
|
| 86 | +DIR2=zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv
|
|
| 87 | +DIR3=uiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiop
|
|
| 88 | +DIR4=qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwer
|
|
| 89 | +WDIR=$(DIR1)/$(DIR2)/$(DIR3)/$(DIR4)
|
|
| 90 | +.PHONY: ghcpkg10
|
|
| 91 | +ghcpkg10 :
|
|
| 92 | + @mkdir -p $(WDIR)
|
|
| 93 | + @rm -rf $(WDIR)/$(PKGCONF20)
|
|
| 94 | + $(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) init $(WDIR)/$(PKGCONF20)
|
|
| 95 | + $(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) list
|
|
| 96 | + $(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) register --force test.pkg 2>/dev/null
|
|
| 97 | + $(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) describe testpkg | $(STRIP_PKGROOT)
|
|
| 98 | + $(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) describe testpkg-1.2.3.4 | $(STRIP_PKGROOT)
|
|
| 99 | + $(LOCAL_GHC_PKG20) -f $(WDIR)/$(PKGCONF20) field testpkg-1.2.3.4 import-dirs
|
|
| 100 | + |
|
| 82 | 101 | # Test stacking of package.confs (also #2441)
|
| 83 | 102 | PKGCONF05a=local05a.package.conf
|
| 84 | 103 | PKGCONF05b=local05b.package.conf
|
| ... | ... | @@ -5,6 +5,7 @@ def ignore_warnings(str): |
| 5 | 5 | return re.sub(r'Warning:.*\n', '', str)
|
| 6 | 6 | |
| 7 | 7 | test('ghcpkg01', [extra_files(['test.pkg', 'test2.pkg', 'test3.pkg'])], makefile_test, [])
|
| 8 | +test('ghcpkg10', [extra_files(['test.pkg', 'test2.pkg', 'test3.pkg'])], makefile_test, [])
|
|
| 8 | 9 | |
| 9 | 10 | # Use ignore_stderr to prevent (when HADDOCK_DOCS=NO):
|
| 10 | 11 | # warning: haddock-interfaces .. doesn't exist or isn't a file
|
| 1 | +asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf/zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv/uiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiopuiop/qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwer/local20.package.conf
|
|
| 2 | + (no packages)
|
|
| 3 | +Reading package info from "test.pkg" ... done.
|
|
| 4 | +name: testpkg
|
|
| 5 | +version: 1.2.3.4
|
|
| 6 | +visibility: public
|
|
| 7 | +id: testpkg-1.2.3.4-XXX
|
|
| 8 | +key: testpkg-1.2.3.4-XXX
|
|
| 9 | +license: BSD3
|
|
| 10 | +copyright: (c) The Univsersity of Glasgow 2004
|
|
| 11 | +maintainer: glasgow-haskell-users@haskell.org
|
|
| 12 | +author: simonmar@microsoft.com
|
|
| 13 | +stability: stable
|
|
| 14 | +homepage: http://www.haskell.org/ghc
|
|
| 15 | +package-url: http://www.haskell.org/ghc
|
|
| 16 | +description: A Test Package
|
|
| 17 | +category: none
|
|
| 18 | +exposed: True
|
|
| 19 | +exposed-modules: A
|
|
| 20 | +hidden-modules: B C.D
|
|
| 21 | +import-dirs: /usr/local/lib/testpkg "c:/Program Files/testpkg"
|
|
| 22 | +library-dirs: /usr/local/lib/testpkg "c:/Program Files/testpkg"
|
|
| 23 | +hs-libraries: testpkg-1.2.3.4-XXX
|
|
| 24 | +include-dirs: /usr/local/include/testpkg "c:/Program Files/testpkg"
|
|
| 25 | +pkgroot:
|
|
| 26 | + |
|
| 27 | +name: testpkg
|
|
| 28 | +version: 1.2.3.4
|
|
| 29 | +visibility: public
|
|
| 30 | +id: testpkg-1.2.3.4-XXX
|
|
| 31 | +key: testpkg-1.2.3.4-XXX
|
|
| 32 | +license: BSD3
|
|
| 33 | +copyright: (c) The Univsersity of Glasgow 2004
|
|
| 34 | +maintainer: glasgow-haskell-users@haskell.org
|
|
| 35 | +author: simonmar@microsoft.com
|
|
| 36 | +stability: stable
|
|
| 37 | +homepage: http://www.haskell.org/ghc
|
|
| 38 | +package-url: http://www.haskell.org/ghc
|
|
| 39 | +description: A Test Package
|
|
| 40 | +category: none
|
|
| 41 | +exposed: True
|
|
| 42 | +exposed-modules: A
|
|
| 43 | +hidden-modules: B C.D
|
|
| 44 | +import-dirs: /usr/local/lib/testpkg "c:/Program Files/testpkg"
|
|
| 45 | +library-dirs: /usr/local/lib/testpkg "c:/Program Files/testpkg"
|
|
| 46 | +hs-libraries: testpkg-1.2.3.4-XXX
|
|
| 47 | +include-dirs: /usr/local/include/testpkg "c:/Program Files/testpkg"
|
|
| 48 | +pkgroot:
|
|
| 49 | + |
|
| 50 | +import-dirs: /usr/local/lib/testpkg "c:/Program Files/testpkg" |
| 1 | 1 | <no location info>: warning:
|
| 2 | 2 | • The first argument of ‘coerce’ does not have a fixed runtime representation:
|
| 3 | 3 | a :: TYPE k
|
| 4 | - Substitution: <InScope = {a q}
|
|
| 5 | - IdSubst = []
|
|
| 6 | - TvSubst = []
|
|
| 7 | - CvSubst = []>
|
|
| 8 | 4 | in coerce BAD 1
|
| 9 | 5 | <no location info>: warning:
|
| 10 | 6 | • The first argument of ‘coerce’ does not have a fixed runtime representation:
|
| 11 | 7 | ‘q’ is not concrete.
|
| 12 | - Substitution: <InScope = {a q}
|
|
| 13 | - IdSubst = []
|
|
| 14 | - TvSubst = []
|
|
| 15 | - CvSubst = []>
|
|
| 16 | 8 | in coerce BAD 2
|
| 17 | 9 | <no location info>: warning:
|
| 18 | 10 | • The result of the first argument of the primop ‘catch#’ does not have a fixed runtime representation:
|
| 19 | 11 | a :: TYPE q
|
| 20 | - Substitution: <InScope = {a q}
|
|
| 21 | - IdSubst = []
|
|
| 22 | - TvSubst = []
|
|
| 23 | - CvSubst = []>
|
|
| 24 | 12 | in catch# BAD 1
|
| 25 | 13 | <no location info>: warning:
|
| 26 | 14 | • The result of the first argument of the primop ‘catch#’ does not have a fixed runtime representation:
|
| 27 | 15 | ‘q’ is not concrete.
|
| 28 | - Substitution: <InScope = {a q}
|
|
| 29 | - IdSubst = []
|
|
| 30 | - TvSubst = []
|
|
| 31 | - CvSubst = []>
|
|
| 32 | 16 | in catch# BAD 2 |
| ... | ... | @@ -6,10 +6,6 @@ T21115b.hs:9:1: warning: |
| 6 | 6 | In the body of lambda with binder ds :: Double#
|
| 7 | 7 | In the body of a let with binder fail :: (# #) -> Int#
|
| 8 | 8 | In the body of a let with binder fail :: (# #) -> Int#
|
| 9 | - Substitution: <InScope = {}
|
|
| 10 | - IdSubst = []
|
|
| 11 | - TvSubst = []
|
|
| 12 | - CvSubst = []>
|
|
| 13 | 9 | *** Offending Program ***
|
| 14 | 10 | Rec {
|
| 15 | 11 | $trModule = Module (TrNameS "main"#) (TrNameS "T21115b"#)
|
| ... | ... | @@ -47,12 +47,19 @@ import Distribution.Types.UnqualComponentName |
| 47 | 47 | import Distribution.Types.LibraryName
|
| 48 | 48 | import Distribution.Types.MungedPackageName
|
| 49 | 49 | import Distribution.Types.MungedPackageId
|
| 50 | -import Distribution.Simple.Utils (toUTF8BS, writeUTF8File, readUTF8File)
|
|
| 50 | +import Distribution.Simple.Utils (ignoreBOM, toUTF8BS, toUTF8LBS, fromUTF8LBS)
|
|
| 51 | 51 | import qualified Data.Version as Version
|
| 52 | -import System.FilePath as FilePath
|
|
| 52 | +import System.OsPath as OsPath
|
|
| 53 | +import qualified System.FilePath as FilePath
|
|
| 53 | 54 | import qualified System.FilePath.Posix as FilePath.Posix
|
| 54 | -import System.Directory ( getXdgDirectory, createDirectoryIfMissing, getAppUserDataDirectory,
|
|
| 55 | - getModificationTime, XdgDirectory ( XdgData ) )
|
|
| 55 | +import System.Directory.OsPath
|
|
| 56 | + ( getXdgDirectory, createDirectoryIfMissing, getAppUserDataDirectory,
|
|
| 57 | + getModificationTime, XdgDirectory ( XdgData ),
|
|
| 58 | + doesDirectoryExist, getDirectoryContents,
|
|
| 59 | + doesFileExist, removeFile,
|
|
| 60 | + getCurrentDirectory )
|
|
| 61 | +import System.Directory.Internal (os)
|
|
| 62 | +import qualified System.File.OsPath as FileIO
|
|
| 56 | 63 | import Text.Printf
|
| 57 | 64 | |
| 58 | 65 | import Prelude hiding (Foldable(..))
|
| ... | ... | @@ -65,15 +72,13 @@ import Data.Bifunctor |
| 65 | 72 | |
| 66 | 73 | import Data.Char ( toLower )
|
| 67 | 74 | import Control.Monad
|
| 68 | -import System.Directory ( doesDirectoryExist, getDirectoryContents,
|
|
| 69 | - doesFileExist, removeFile,
|
|
| 70 | - getCurrentDirectory )
|
|
| 71 | 75 | import System.Exit ( exitWith, ExitCode(..) )
|
| 72 | 76 | import System.Environment ( getArgs, getProgName, getEnv )
|
| 73 | 77 | import System.IO
|
| 74 | 78 | import System.IO.Error
|
| 75 | -import GHC.IO ( catchException )
|
|
| 79 | +import GHC.IO ( catchException, unsafePerformIO )
|
|
| 76 | 80 | import GHC.IO.Exception (IOErrorType(InappropriateType))
|
| 81 | +import GHC.Stack.Types (HasCallStack)
|
|
| 77 | 82 | import Data.List ( group, sort, sortBy, nub, partition, find
|
| 78 | 83 | , intercalate, intersperse, unfoldr
|
| 79 | 84 | , isInfixOf, isSuffixOf, isPrefixOf, stripPrefix )
|
| ... | ... | @@ -429,8 +434,9 @@ runit verbosity cli nonopts = do |
| 429 | 434 | print filename
|
| 430 | 435 | glob filename >>= print
|
| 431 | 436 | #endif
|
| 432 | - ["init", filename] ->
|
|
| 433 | - initPackageDB filename verbosity cli
|
|
| 437 | + ["init", filename] -> do
|
|
| 438 | + filenameOs <- encodeFS filename
|
|
| 439 | + initPackageDB filenameOs verbosity cli
|
|
| 434 | 440 | ["register", filename] ->
|
| 435 | 441 | registerPackage filename verbosity cli
|
| 436 | 442 | multi_instance
|
| ... | ... | @@ -538,7 +544,7 @@ readPackageArg AsDefault str = Id <$> readGlobPkgId str |
| 538 | 544 | |
| 539 | 545 | data PackageDB (mode :: GhcPkg.DbMode)
|
| 540 | 546 | = PackageDB {
|
| 541 | - location, locationAbsolute :: !FilePath,
|
|
| 547 | + location, locationAbsolute :: !OsPath,
|
|
| 542 | 548 | -- We need both possibly-relative and definitely-absolute package
|
| 543 | 549 | -- db locations. This is because the relative location is used as
|
| 544 | 550 | -- an identifier for the db, so it is important we do not modify it.
|
| ... | ... | @@ -570,14 +576,14 @@ allPackagesInStack = concatMap packages |
| 570 | 576 | -- specified package DB can depend on, since dependencies can only extend
|
| 571 | 577 | -- down the stack, not up (e.g. global packages cannot depend on user
|
| 572 | 578 | -- packages).
|
| 573 | -stackUpTo :: FilePath -> PackageDBStack -> PackageDBStack
|
|
| 579 | +stackUpTo :: OsPath -> PackageDBStack -> PackageDBStack
|
|
| 574 | 580 | stackUpTo to_modify = dropWhile ((/= to_modify) . location)
|
| 575 | 581 | |
| 576 | -readFromSettingsFile :: FilePath
|
|
| 577 | - -> (FilePath -> RawSettings -> Either String b)
|
|
| 582 | +readFromSettingsFile :: OsPath
|
|
| 583 | + -> (OsPath -> RawSettings -> Either String b)
|
|
| 578 | 584 | -> IO (Either String b)
|
| 579 | 585 | readFromSettingsFile settingsFile f = do
|
| 580 | - settingsStr <- readFile settingsFile
|
|
| 586 | + settingsStr <- readUtf8File settingsFile
|
|
| 581 | 587 | pure $ do
|
| 582 | 588 | mySettings <- case maybeReadFuzzy settingsStr of
|
| 583 | 589 | Just s -> pure $ Map.fromList s
|
| ... | ... | @@ -586,11 +592,11 @@ readFromSettingsFile settingsFile f = do |
| 586 | 592 | Nothing -> Left $ "Can't parse settings file " ++ show settingsFile
|
| 587 | 593 | f settingsFile mySettings
|
| 588 | 594 | |
| 589 | -readFromTargetFile :: FilePath
|
|
| 595 | +readFromTargetFile :: OsPath
|
|
| 590 | 596 | -> (Target -> b)
|
| 591 | 597 | -> IO (Either String b)
|
| 592 | 598 | readFromTargetFile targetFile f = do
|
| 593 | - targetStr <- readFile targetFile
|
|
| 599 | + targetStr <- readUtf8File targetFile
|
|
| 594 | 600 | pure $ do
|
| 595 | 601 | target <- case maybeReadFuzzy targetStr of
|
| 596 | 602 | Just t -> Right t
|
| ... | ... | @@ -626,33 +632,35 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 626 | 632 | case [ f | FlagGlobalConfig f <- my_flags ] of
|
| 627 | 633 | -- See Note [Base Dir] for more information on the base dir / top dir.
|
| 628 | 634 | [] -> do mb_dir <- getBaseDir
|
| 629 | - case mb_dir of
|
|
| 635 | + mb_dir_os <- traverse encodeFS mb_dir
|
|
| 636 | + case mb_dir_os of
|
|
| 630 | 637 | Nothing -> die err_msg
|
| 631 | 638 | Just dir -> do
|
| 632 | 639 | -- Look for where it is given in the settings file, if marked there.
|
| 633 | 640 | -- See Note [Settings file] about this file, and why we need GHC to share it with us.
|
| 634 | - let settingsFile = dir </> "settings"
|
|
| 641 | + let settingsFile = dir </> os "settings"
|
|
| 635 | 642 | exists_settings_file <- doesFileExist settingsFile
|
| 636 | 643 | erel_db <-
|
| 637 | 644 | if exists_settings_file
|
| 638 | - then readFromSettingsFile settingsFile getGlobalPackageDb
|
|
| 639 | - else pure (Left ("Settings file doesn't exist: " ++ settingsFile))
|
|
| 645 | + then do
|
|
| 646 | + readFromSettingsFile settingsFile (\ settings -> getGlobalPackageDb (unsafeDecodeUtf settings))
|
|
| 647 | + else pure (Left ("Settings file doesn't exist: " ++ showOsPath settingsFile))
|
|
| 640 | 648 | |
| 641 | 649 | case erel_db of
|
| 642 | - Right rel_db -> return (dir, dir </> rel_db)
|
|
| 650 | + Right rel_db -> return (dir, dir </> unsafeEncodeUtf rel_db)
|
|
| 643 | 651 | -- If the version of GHC doesn't have this field or the settings file
|
| 644 | 652 | -- doesn't exist for some reason, look in the libdir.
|
| 645 | 653 | Left err -> do
|
| 646 | 654 | r <- lookForPackageDBIn dir
|
| 647 | 655 | case r of
|
| 648 | - Nothing -> die (unlines [err, ("Fallback: Can't find package database in " ++ dir)])
|
|
| 656 | + Nothing -> die (unlines [err, ("Fallback: Can't find package database in " ++ showOsPath dir)])
|
|
| 649 | 657 | Just path -> return (dir, path)
|
| 650 | 658 | fs -> do
|
| 651 | 659 | -- The value of the $topdir variable used in some package descriptions
|
| 652 | 660 | -- Note that the way we calculate this is slightly different to how it
|
| 653 | 661 | -- is done in ghc itself. We rely on the convention that the global
|
| 654 | 662 | -- package db lives in ghc's libdir.
|
| 655 | - let pkg_db = last fs
|
|
| 663 | + let pkg_db = unsafeEncodeUtf $ last fs
|
|
| 656 | 664 | top_dir <- absolutePath (takeDirectory pkg_db)
|
| 657 | 665 | return (top_dir, pkg_db)
|
| 658 | 666 | |
| ... | ... | @@ -662,10 +670,10 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 662 | 670 | -- getXdgDirectory can fail (e.g. if $HOME isn't set)
|
| 663 | 671 | |
| 664 | 672 | mb_user_conf <-
|
| 665 | - case [ f | FlagUserConfig f <- my_flags ] of
|
|
| 673 | + case [ unsafeEncodeUtf f | FlagUserConfig f <- my_flags ] of
|
|
| 666 | 674 | _ | no_user_db -> return Nothing
|
| 667 | 675 | [] -> do
|
| 668 | - let targetFile = top_dir </> "targets" </> "default.target"
|
|
| 676 | + let targetFile = top_dir </> os "targets" </> os "default.target"
|
|
| 669 | 677 | exists_settings_file <- doesFileExist targetFile
|
| 670 | 678 | targetArchOS <- case exists_settings_file of
|
| 671 | 679 | False -> do
|
| ... | ... | @@ -694,15 +702,15 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 694 | 702 | -- otherwise we use $XDG_DATA_HOME/$UNIQUE_SUBDIR
|
| 695 | 703 | --
|
| 696 | 704 | -- UNIQUE_SUBDIR is typically a combination of the target platform and GHC version
|
| 697 | - m_appdir <- getFirstSuccess $ map (fmap (</> subdir))
|
|
| 698 | - [ getAppUserDataDirectory "ghc" -- this is ~/.ghc/
|
|
| 699 | - , getXdgDirectory XdgData "ghc" -- this is $XDG_DATA_HOME/
|
|
| 705 | + m_appdir <- getFirstSuccess $ map (fmap (</> unsafeEncodeUtf subdir))
|
|
| 706 | + [ getAppUserDataDirectory $ os "ghc" -- this is ~/.ghc/
|
|
| 707 | + , getXdgDirectory XdgData $ os "ghc" -- this is $XDG_DATA_HOME/
|
|
| 700 | 708 | ]
|
| 701 | 709 | case m_appdir of
|
| 702 | 710 | Nothing -> return Nothing
|
| 703 | 711 | Just dir -> do
|
| 704 | 712 | lookForPackageDBIn dir >>= \case
|
| 705 | - Nothing -> return (Just (dir </> "package.conf.d", False))
|
|
| 713 | + Nothing -> return (Just (dir </> os "package.conf.d", False))
|
|
| 706 | 714 | Just f -> return (Just (f, True))
|
| 707 | 715 | fs -> return (Just (last fs, True))
|
| 708 | 716 | |
| ... | ... | @@ -716,11 +724,11 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 716 | 724 | |
| 717 | 725 | e_pkg_path <- tryIO (System.Environment.getEnv "GHC_PACKAGE_PATH")
|
| 718 | 726 | let env_stack =
|
| 719 | - case e_pkg_path of
|
|
| 727 | + case fmap unsafeEncodeUtf e_pkg_path of
|
|
| 720 | 728 | Left _ -> sys_databases
|
| 721 | 729 | Right path
|
| 722 | - | not (null path) && isSearchPathSeparator (last path)
|
|
| 723 | - -> splitSearchPath (init path) ++ sys_databases
|
|
| 730 | + | hasTrailingPathSeparator path
|
|
| 731 | + -> splitSearchPath (dropTrailingPathSeparator path) <> sys_databases
|
|
| 724 | 732 | | otherwise
|
| 725 | 733 | -> splitSearchPath path
|
| 726 | 734 | |
| ... | ... | @@ -733,7 +741,7 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 733 | 741 | | Just (user_conf, _user_exists) <- mb_user_conf
|
| 734 | 742 | = Just user_conf
|
| 735 | 743 | is_db_flag FlagGlobal = Just virt_global_conf
|
| 736 | - is_db_flag (FlagConfig f) = Just f
|
|
| 744 | + is_db_flag (FlagConfig f) = Just $ unsafeEncodeUtf f
|
|
| 737 | 745 | is_db_flag _ = Nothing
|
| 738 | 746 | |
| 739 | 747 | let flag_db_names | null db_flags = env_stack
|
| ... | ... | @@ -748,7 +756,7 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 748 | 756 | -- stack, unless any of them are present in the stack
|
| 749 | 757 | -- already.
|
| 750 | 758 | let final_stack = filter (`notElem` env_stack)
|
| 751 | - [ f | FlagConfig f <- reverse my_flags ]
|
|
| 759 | + [ unsafeEncodeUtf f | FlagConfig f <- reverse my_flags ]
|
|
| 752 | 760 | ++ env_stack
|
| 753 | 761 | |
| 754 | 762 | top_db = if null db_flags
|
| ... | ... | @@ -764,7 +772,7 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 764 | 772 | when (verbosity > Normal) $ do
|
| 765 | 773 | infoLn ("db stack: " ++ show (map location db_stack))
|
| 766 | 774 | F.forM_ db_to_operate_on $ \db ->
|
| 767 | - infoLn ("modifying: " ++ (location db))
|
|
| 775 | + infoLn ("modifying: " ++ showOsPath (location db))
|
|
| 768 | 776 | infoLn ("flag db stack: " ++ show (map location flag_db_stack))
|
| 769 | 777 | |
| 770 | 778 | return (db_stack, db_to_operate_on, flag_db_stack)
|
| ... | ... | @@ -843,17 +851,19 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 843 | 851 | |
| 844 | 852 | return (db_stack, GhcPkg.DbOpenReadWrite to_modify)
|
| 845 | 853 | where
|
| 846 | - couldntOpenDbForModification :: FilePath -> IOError -> IO a
|
|
| 854 | + couldntOpenDbForModification :: OsPath -> IOError -> IO a
|
|
| 847 | 855 | couldntOpenDbForModification db_path e = die $ "Couldn't open database "
|
| 848 | - ++ db_path ++ " for modification: " ++ show e
|
|
| 856 | + ++ showOsPath db_path ++ " for modification: " ++ show e
|
|
| 849 | 857 | |
| 850 | 858 | -- Parse package db in read-only mode.
|
| 851 | - readDatabase :: FilePath -> IO (PackageDB 'GhcPkg.DbReadOnly)
|
|
| 859 | + readDatabase :: OsPath -> IO (PackageDB 'GhcPkg.DbReadOnly)
|
|
| 852 | 860 | readDatabase db_path = do
|
| 853 | 861 | db <- readParseDatabase verbosity mb_user_conf
|
| 854 | 862 | GhcPkg.DbOpenReadOnly use_cache db_path
|
| 855 | 863 | if expand_vars
|
| 856 | - then return $ mungePackageDBPaths top_dir db
|
|
| 864 | + then do
|
|
| 865 | + top_dir_filepath <- decodeFS top_dir
|
|
| 866 | + return $ mungePackageDBPaths top_dir_filepath db
|
|
| 857 | 867 | else return db
|
| 858 | 868 | |
| 859 | 869 | stateSequence :: Monad m => s -> [s -> m (a, s)] -> m ([a], s)
|
| ... | ... | @@ -863,20 +873,20 @@ getPkgDatabases verbosity mode use_user use_cache expand_vars my_flags = do |
| 863 | 873 | (as, s'') <- stateSequence s' ms
|
| 864 | 874 | return (a : as, s'')
|
| 865 | 875 | |
| 866 | -lookForPackageDBIn :: FilePath -> IO (Maybe FilePath)
|
|
| 876 | +lookForPackageDBIn :: OsPath -> IO (Maybe OsPath)
|
|
| 867 | 877 | lookForPackageDBIn dir = do
|
| 868 | - let path_dir = dir </> "package.conf.d"
|
|
| 878 | + let path_dir = dir </> os "package.conf.d"
|
|
| 869 | 879 | exists_dir <- doesDirectoryExist path_dir
|
| 870 | 880 | if exists_dir then return (Just path_dir) else do
|
| 871 | - let path_file = dir </> "package.conf"
|
|
| 881 | + let path_file = dir </> os "package.conf"
|
|
| 872 | 882 | exists_file <- doesFileExist path_file
|
| 873 | 883 | if exists_file then return (Just path_file) else return Nothing
|
| 874 | 884 | |
| 875 | 885 | readParseDatabase :: forall mode t. Verbosity
|
| 876 | - -> Maybe (FilePath,Bool)
|
|
| 886 | + -> Maybe (OsPath,Bool)
|
|
| 877 | 887 | -> GhcPkg.DbOpenMode mode t
|
| 878 | 888 | -> Bool -- use cache
|
| 879 | - -> FilePath
|
|
| 889 | + -> OsPath
|
|
| 880 | 890 | -> IO (PackageDB mode)
|
| 881 | 891 | readParseDatabase verbosity mb_user_conf mode use_cache path
|
| 882 | 892 | -- the user database (only) is allowed to be non-existent
|
| ... | ... | @@ -898,7 +908,7 @@ readParseDatabase verbosity mb_user_conf mode use_cache path |
| 898 | 908 | Just db -> return db
|
| 899 | 909 | Nothing ->
|
| 900 | 910 | die $ "ghc no longer supports single-file style package "
|
| 901 | - ++ "databases (" ++ path ++ ") use 'ghc-pkg init'"
|
|
| 911 | + ++ "databases (" ++ showOsPath path ++ ") use 'ghc-pkg init'"
|
|
| 902 | 912 | ++ "to create the database with the correct format."
|
| 903 | 913 | |
| 904 | 914 | | otherwise -> ioError err
|
| ... | ... | @@ -914,7 +924,7 @@ readParseDatabase verbosity mb_user_conf mode use_cache path |
| 914 | 924 | -- It's fine if the cache is not there as long as the
|
| 915 | 925 | -- database is empty.
|
| 916 | 926 | when (not $ null confs) $ do
|
| 917 | - warn ("WARNING: cache does not exist: " ++ cache)
|
|
| 927 | + warn ("WARNING: cache does not exist: " ++ showOsPath cache)
|
|
| 918 | 928 | warn ("ghc will fail to read this package db. " ++
|
| 919 | 929 | recacheAdvice)
|
| 920 | 930 | else do
|
| ... | ... | @@ -923,7 +933,7 @@ readParseDatabase verbosity mb_user_conf mode use_cache path |
| 923 | 933 | ignore_cache (const $ return ())
|
| 924 | 934 | Right tcache -> do
|
| 925 | 935 | when (verbosity >= Verbose) $ do
|
| 926 | - warn ("Timestamp " ++ show tcache ++ " for " ++ cache)
|
|
| 936 | + warn ("Timestamp " ++ show tcache ++ " for " ++ showOsPath cache)
|
|
| 927 | 937 | -- If any of the .conf files is newer than package.cache, we
|
| 928 | 938 | -- assume that cache is out of date.
|
| 929 | 939 | cache_outdated <- (`anyM` confs) $ \conf ->
|
| ... | ... | @@ -931,12 +941,12 @@ readParseDatabase verbosity mb_user_conf mode use_cache path |
| 931 | 941 | if not cache_outdated
|
| 932 | 942 | then do
|
| 933 | 943 | when (verbosity > Normal) $
|
| 934 | - infoLn ("using cache: " ++ cache)
|
|
| 944 | + infoLn ("using cache: " ++ showOsPath cache)
|
|
| 935 | 945 | GhcPkg.readPackageDbForGhcPkg cache mode
|
| 936 | 946 | >>= uncurry mkPackageDB
|
| 937 | 947 | else do
|
| 938 | 948 | whenReportCacheErrors $ do
|
| 939 | - warn ("WARNING: cache is out of date: " ++ cache)
|
|
| 949 | + warn ("WARNING: cache is out of date: " ++ showOsPath cache)
|
|
| 940 | 950 | warn ("ghc will see an old view of this " ++
|
| 941 | 951 | "package db. " ++ recacheAdvice)
|
| 942 | 952 | ignore_cache $ \file -> do
|
| ... | ... | @@ -947,11 +957,11 @@ readParseDatabase verbosity mb_user_conf mode use_cache path |
| 947 | 957 | GT -> " (older than cache)"
|
| 948 | 958 | EQ -> " (same as cache)"
|
| 949 | 959 | warn ("Timestamp " ++ show tFile
|
| 950 | - ++ " for " ++ file ++ rel)
|
|
| 960 | + ++ " for " ++ showOsPath file ++ rel)
|
|
| 951 | 961 | where
|
| 952 | - confs = map (path </>) $ filter (".conf" `isSuffixOf`) fs
|
|
| 962 | + confs = map (path </>) $ filter (os ".conf" `OsPath.isExtensionOf`) fs
|
|
| 953 | 963 | |
| 954 | - ignore_cache :: (FilePath -> IO ()) -> IO (PackageDB mode)
|
|
| 964 | + ignore_cache :: (OsPath -> IO ()) -> IO (PackageDB mode)
|
|
| 955 | 965 | ignore_cache checkTime = do
|
| 956 | 966 | -- If we're opening for modification, we need to acquire a
|
| 957 | 967 | -- lock even if we don't open the cache now, because we are
|
| ... | ... | @@ -987,17 +997,18 @@ readParseDatabase verbosity mb_user_conf mode use_cache path |
| 987 | 997 | packages = pkgs
|
| 988 | 998 | }
|
| 989 | 999 | |
| 990 | -parseSingletonPackageConf :: Verbosity -> FilePath -> IO InstalledPackageInfo
|
|
| 1000 | +parseSingletonPackageConf :: Verbosity -> OsPath -> IO InstalledPackageInfo
|
|
| 991 | 1001 | parseSingletonPackageConf verbosity file = do
|
| 992 | - when (verbosity > Normal) $ infoLn ("reading package config: " ++ file)
|
|
| 993 | - BS.readFile file >>= fmap fst . parsePackageInfo
|
|
| 1002 | + when (verbosity > Normal) $ infoLn ("reading package config: " ++ showOsPath file)
|
|
| 1003 | + FileIO.readFile file >>= fmap fst . parsePackageInfo . BS.toStrict
|
|
| 1004 | + |
|
| 994 | 1005 | |
| 995 | -cachefilename :: FilePath
|
|
| 996 | -cachefilename = "package.cache"
|
|
| 1006 | +cachefilename :: OsPath
|
|
| 1007 | +cachefilename = os "package.cache"
|
|
| 997 | 1008 | |
| 998 | 1009 | mungePackageDBPaths :: FilePath -> PackageDB mode -> PackageDB mode
|
| 999 | 1010 | mungePackageDBPaths top_dir db@PackageDB { packages = pkgs } =
|
| 1000 | - db { packages = map (mungePackagePaths top_dir pkgroot) pkgs }
|
|
| 1011 | + db { packages = map (mungePackagePaths top_dir (unsafeDecodeUtf pkgroot)) pkgs }
|
|
| 1001 | 1012 | where
|
| 1002 | 1013 | pkgroot = takeDirectory $ dropTrailingPathSeparator (locationAbsolute db)
|
| 1003 | 1014 | -- It so happens that for both styles of package db ("package.conf"
|
| ... | ... | @@ -1044,12 +1055,13 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url) |
| 1044 | 1055 | | Just p' <- stripVarPrefix "$httptopdir" p = toUrlPath top_dir p'
|
| 1045 | 1056 | | otherwise = p
|
| 1046 | 1057 | |
| 1058 | + toUrlPath :: FilePath -> FilePath -> FilePath
|
|
| 1047 | 1059 | toUrlPath r p = "file:///"
|
| 1048 | 1060 | -- URLs always use posix style '/' separators:
|
| 1049 | 1061 | ++ FilePath.Posix.joinPath
|
| 1050 | 1062 | (r : -- We need to drop a leading "/" or "\\"
|
| 1051 | 1063 | -- if there is one:
|
| 1052 | - dropWhile (all isPathSeparator)
|
|
| 1064 | + dropWhile (all FilePath.isPathSeparator)
|
|
| 1053 | 1065 | (FilePath.splitDirectories p))
|
| 1054 | 1066 | |
| 1055 | 1067 | -- We could drop the separator here, and then use </> above. However,
|
| ... | ... | @@ -1057,7 +1069,7 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url) |
| 1057 | 1069 | -- rather than letting FilePath change it to use \ as the separator
|
| 1058 | 1070 | stripVarPrefix var path = case stripPrefix var path of
|
| 1059 | 1071 | Just [] -> Just []
|
| 1060 | - Just cs@(c : _) | isPathSeparator c -> Just cs
|
|
| 1072 | + Just cs@(c : _) | FilePath.isPathSeparator c -> Just cs
|
|
| 1061 | 1073 | _ -> Nothing
|
| 1062 | 1074 | |
| 1063 | 1075 | -- -----------------------------------------------------------------------------
|
| ... | ... | @@ -1074,18 +1086,18 @@ mkMungePathUrl top_dir pkgroot = (munge_path, munge_url) |
| 1074 | 1086 | |
| 1075 | 1087 | -- ghc itself also cooperates in this workaround
|
| 1076 | 1088 | |
| 1077 | -tryReadParseOldFileStyleDatabase :: Verbosity -> Maybe (FilePath, Bool)
|
|
| 1078 | - -> GhcPkg.DbOpenMode mode t -> Bool -> FilePath
|
|
| 1089 | +tryReadParseOldFileStyleDatabase :: Verbosity -> Maybe (OsPath, Bool)
|
|
| 1090 | + -> GhcPkg.DbOpenMode mode t -> Bool -> OsPath
|
|
| 1079 | 1091 | -> IO (Maybe (PackageDB mode))
|
| 1080 | 1092 | tryReadParseOldFileStyleDatabase verbosity mb_user_conf
|
| 1081 | 1093 | mode use_cache path = do
|
| 1082 | 1094 | -- assumes we've already established that path exists and is not a dir
|
| 1083 | - content <- readFile path `catchIO` \_ -> return ""
|
|
| 1095 | + content <- readUtf8File path `catchIO` \_ -> return ""
|
|
| 1084 | 1096 | if take 2 content == "[]"
|
| 1085 | 1097 | then do
|
| 1086 | 1098 | path_abs <- absolutePath path
|
| 1087 | 1099 | let path_dir = adjustOldDatabasePath path
|
| 1088 | - warn $ "Warning: ignoring old file-style db and trying " ++ path_dir
|
|
| 1100 | + warn $ "Warning: ignoring old file-style db and trying " ++ showOsPath path_dir
|
|
| 1089 | 1101 | direxists <- doesDirectoryExist path_dir
|
| 1090 | 1102 | if direxists
|
| 1091 | 1103 | then do
|
| ... | ... | @@ -1112,7 +1124,7 @@ tryReadParseOldFileStyleDatabase verbosity mb_user_conf |
| 1112 | 1124 | adjustOldFileStylePackageDB :: PackageDB mode -> IO (PackageDB mode)
|
| 1113 | 1125 | adjustOldFileStylePackageDB db = do
|
| 1114 | 1126 | -- assumes we have not yet established if it's an old style or not
|
| 1115 | - mcontent <- liftM Just (readFile (location db)) `catchIO` \_ -> return Nothing
|
|
| 1127 | + mcontent <- liftM Just (readUtf8File (location db)) `catchIO` \_ -> return Nothing
|
|
| 1116 | 1128 | case fmap (take 2) mcontent of
|
| 1117 | 1129 | -- it is an old style and empty db, so look for a dir kind in location.d/
|
| 1118 | 1130 | Just "[]" -> return db {
|
| ... | ... | @@ -1121,20 +1133,20 @@ adjustOldFileStylePackageDB db = do |
| 1121 | 1133 | }
|
| 1122 | 1134 | -- it is old style but not empty, we have to bail
|
| 1123 | 1135 | Just _ -> die $ "ghc no longer supports single-file style package "
|
| 1124 | - ++ "databases (" ++ location db ++ ") use 'ghc-pkg init'"
|
|
| 1136 | + ++ "databases (" ++ showOsPath (location db) ++ ") use 'ghc-pkg init'"
|
|
| 1125 | 1137 | ++ "to create the database with the correct format."
|
| 1126 | 1138 | -- probably not old style, carry on as normal
|
| 1127 | 1139 | Nothing -> return db
|
| 1128 | 1140 | |
| 1129 | -adjustOldDatabasePath :: FilePath -> FilePath
|
|
| 1130 | -adjustOldDatabasePath = (<.> "d")
|
|
| 1141 | +adjustOldDatabasePath :: OsPath -> OsPath
|
|
| 1142 | +adjustOldDatabasePath = (<.> os "d")
|
|
| 1131 | 1143 | |
| 1132 | 1144 | -- -----------------------------------------------------------------------------
|
| 1133 | 1145 | -- Creating a new package DB
|
| 1134 | 1146 | |
| 1135 | -initPackageDB :: FilePath -> Verbosity -> [Flag] -> IO ()
|
|
| 1147 | +initPackageDB :: OsPath -> Verbosity -> [Flag] -> IO ()
|
|
| 1136 | 1148 | initPackageDB filename verbosity _flags = do
|
| 1137 | - let eexist = die ("cannot create: " ++ filename ++ " already exists")
|
|
| 1149 | + let eexist = die ("cannot create: " ++ showOsPath filename ++ " already exists")
|
|
| 1138 | 1150 | b1 <- doesFileExist filename
|
| 1139 | 1151 | when b1 eexist
|
| 1140 | 1152 | b2 <- doesDirectoryExist filename
|
| ... | ... | @@ -1183,7 +1195,8 @@ registerPackage input verbosity my_flags multi_instance |
| 1183 | 1195 | f -> do
|
| 1184 | 1196 | when (verbosity >= Normal) $
|
| 1185 | 1197 | info ("Reading package info from " ++ show f ++ " ... ")
|
| 1186 | - readUTF8File f
|
|
| 1198 | + fs <- encodeFS f
|
|
| 1199 | + readUtf8File fs
|
|
| 1187 | 1200 | |
| 1188 | 1201 | expanded <- if expand_env_vars then expandEnvVars s force
|
| 1189 | 1202 | else return s
|
| ... | ... | @@ -1199,7 +1212,11 @@ registerPackage input verbosity my_flags multi_instance |
| 1199 | 1212 | -- validate the expanded pkg, but register the unexpanded
|
| 1200 | 1213 | pkgroot <- absolutePath (takeDirectory to_modify)
|
| 1201 | 1214 | let top_dir = takeDirectory (location (last db_stack))
|
| 1202 | - pkg_expanded = mungePackagePaths top_dir pkgroot pkg
|
|
| 1215 | + |
|
| 1216 | + top_dir_filepath <- decodeFS top_dir
|
|
| 1217 | + pkgroot_filepath <- decodeFS pkgroot
|
|
| 1218 | + let
|
|
| 1219 | + pkg_expanded = mungePackagePaths top_dir_filepath pkgroot_filepath pkg
|
|
| 1203 | 1220 | |
| 1204 | 1221 | let truncated_stack = stackUpTo to_modify db_stack
|
| 1205 | 1222 | -- truncate the stack for validation, because we don't allow
|
| ... | ... | @@ -1274,13 +1291,13 @@ changeDBDir verbosity cmds db db_stack = do |
| 1274 | 1291 | updateDBCache verbosity db db_stack
|
| 1275 | 1292 | where
|
| 1276 | 1293 | do_cmd (RemovePackage p) = do
|
| 1277 | - let file = location db </> display (installedUnitId p) <.> "conf"
|
|
| 1278 | - when (verbosity > Normal) $ infoLn ("removing " ++ file)
|
|
| 1294 | + let file = location db </> unsafeEncodeUtf (display (installedUnitId p)) <.> os "conf"
|
|
| 1295 | + when (verbosity > Normal) $ infoLn ("removing " ++ showOsPath file)
|
|
| 1279 | 1296 | removeFileSafe file
|
| 1280 | 1297 | do_cmd (AddPackage p) = do
|
| 1281 | - let file = location db </> display (installedUnitId p) <.> "conf"
|
|
| 1282 | - when (verbosity > Normal) $ infoLn ("writing " ++ file)
|
|
| 1283 | - writeUTF8File file (showInstalledPackageInfo p)
|
|
| 1298 | + let file = location db </> unsafeEncodeUtf (display (installedUnitId p)) <.> os "conf"
|
|
| 1299 | + when (verbosity > Normal) $ infoLn ("writing " ++ showOsPath file)
|
|
| 1300 | + writeUtf8File file (showInstalledPackageInfo p)
|
|
| 1284 | 1301 | do_cmd (ModifyPackage p) =
|
| 1285 | 1302 | do_cmd (AddPackage p)
|
| 1286 | 1303 | |
| ... | ... | @@ -1338,13 +1355,13 @@ updateDBCache verbosity db db_stack = do |
| 1338 | 1355 | warn $ " " ++ pkg
|
| 1339 | 1356 | |
| 1340 | 1357 | when (verbosity > Normal) $
|
| 1341 | - infoLn ("writing cache " ++ filename)
|
|
| 1358 | + infoLn ("writing cache " ++ showOsPath filename)
|
|
| 1342 | 1359 | |
| 1343 | 1360 | let d = fmap (fromPackageCacheFormat . fst) pkgsGhcCacheFormat
|
| 1344 | 1361 | GhcPkg.writePackageDb filename d pkgsCabalFormat
|
| 1345 | 1362 | `catchIO` \e ->
|
| 1346 | 1363 | if isPermissionError e
|
| 1347 | - then die $ filename ++ ": you don't have permission to modify this file"
|
|
| 1364 | + then die $ showOsPath filename ++ ": you don't have permission to modify this file"
|
|
| 1348 | 1365 | else ioError e
|
| 1349 | 1366 | |
| 1350 | 1367 | case packageDbLock db of
|
| ... | ... | @@ -1583,7 +1600,7 @@ listPackages verbosity my_flags mPackageName mModuleName = do |
| 1583 | 1600 | broken = map installedUnitId (brokenPackages pkg_map)
|
| 1584 | 1601 | |
| 1585 | 1602 | show_normal PackageDB{ location = db_name, packages = pkg_confs } =
|
| 1586 | - do hPutStrLn stdout db_name
|
|
| 1603 | + do hPutStrLn stdout (showOsPath db_name)
|
|
| 1587 | 1604 | if null pkg_confs
|
| 1588 | 1605 | then hPutStrLn stdout " (no packages)"
|
| 1589 | 1606 | else hPutStrLn stdout $ unlines (map (" " ++) (map pp_pkg pkg_confs))
|
| ... | ... | @@ -1610,7 +1627,7 @@ listPackages verbosity my_flags mPackageName mModuleName = do |
| 1610 | 1627 | #else
|
| 1611 | 1628 | let
|
| 1612 | 1629 | show_colour PackageDB{ location = db_name, packages = pkg_confs } =
|
| 1613 | - do hPutStrLn stdout db_name
|
|
| 1630 | + do hPutStrLn stdout (showOsPath db_name)
|
|
| 1614 | 1631 | if null pkg_confs
|
| 1615 | 1632 | then hPutStrLn stdout " (no packages)"
|
| 1616 | 1633 | else hPutStrLn stdout $ unlines (map (" " ++) (map pp_pkg pkg_confs))
|
| ... | ... | @@ -1698,7 +1715,7 @@ dumpUnits verbosity my_flags expand_pkgroot = do |
| 1698 | 1715 | doDump expand_pkgroot [ (pkg, locationAbsolute db)
|
| 1699 | 1716 | | db <- flag_db_stack, pkg <- packages db ]
|
| 1700 | 1717 | |
| 1701 | -doDump :: Bool -> [(InstalledPackageInfo, FilePath)] -> IO ()
|
|
| 1718 | +doDump :: Bool -> [(InstalledPackageInfo, OsPath)] -> IO ()
|
|
| 1702 | 1719 | doDump expand_pkgroot pkgs = do
|
| 1703 | 1720 | -- fix the encoding to UTF-8, since this is an interchange format
|
| 1704 | 1721 | hSetEncoding stdout utf8
|
| ... | ... | @@ -1731,7 +1748,7 @@ findPackagesByDB db_stack pkgarg |
| 1731 | 1748 | |
| 1732 | 1749 | cannotFindPackage :: PackageArg -> Maybe (PackageDB mode) -> IO a
|
| 1733 | 1750 | cannotFindPackage pkgarg mdb = die $ "cannot find package " ++ pkg_msg pkgarg
|
| 1734 | - ++ maybe "" (\db -> " in " ++ location db) mdb
|
|
| 1751 | + ++ maybe "" (\db -> " in " ++ showOsPath (location db)) mdb
|
|
| 1735 | 1752 | where
|
| 1736 | 1753 | pkg_msg (Id pkgid) = displayGlobPkgId pkgid
|
| 1737 | 1754 | pkg_msg (IUId ipid) = display ipid
|
| ... | ... | @@ -1944,7 +1961,7 @@ checkPackageConfig pkg verbosity db_stack |
| 1944 | 1961 | checkExposedModules db_stack pkg
|
| 1945 | 1962 | checkOtherModules pkg
|
| 1946 | 1963 | let has_code = Set.null (openModuleSubstFreeHoles (Map.fromList (instantiatedWith pkg)))
|
| 1947 | - when has_code $ mapM_ (checkHSLib verbosity (libraryDirs pkg ++ libraryDynDirs pkg)) (hsLibraries pkg)
|
|
| 1964 | + when has_code $ mapM_ (checkHSLib verbosity (fmap unsafeEncodeUtf $ libraryDirs pkg ++ libraryDynDirs pkg)) (hsLibraries pkg)
|
|
| 1948 | 1965 | -- ToDo: check these somehow?
|
| 1949 | 1966 | -- extra_libraries :: [String],
|
| 1950 | 1967 | -- c_includes :: [String],
|
| ... | ... | @@ -2011,20 +2028,20 @@ checkPath url_ok is_dir warn_only thisfield d |
| 2011 | 2028 | || "https://" `isPrefixOf` d) = return ()
|
| 2012 | 2029 | |
| 2013 | 2030 | | url_ok
|
| 2014 | - , Just d' <- stripPrefix "file://" d
|
|
| 2015 | - = checkPath False is_dir warn_only thisfield d'
|
|
| 2031 | + , Just f <- stripPrefix "file://" d
|
|
| 2032 | + = checkPath False is_dir warn_only thisfield f
|
|
| 2016 | 2033 | |
| 2017 | 2034 | -- Note: we don't check for $topdir/${pkgroot} here. We rely on these
|
| 2018 | 2035 | -- variables having been expanded already, see mungePackagePaths.
|
| 2019 | 2036 | |
| 2020 | - | isRelative d = verror ForceFiles $
|
|
| 2037 | + | isRelative d' = verror ForceFiles $
|
|
| 2021 | 2038 | thisfield ++ ": " ++ d ++ " is a relative path which "
|
| 2022 | 2039 | ++ "makes no sense (as there is nothing for it to be "
|
| 2023 | 2040 | ++ "relative to). You can make paths relative to the "
|
| 2024 | 2041 | ++ "package database itself by using ${pkgroot}."
|
| 2025 | 2042 | -- relative paths don't make any sense; #4134
|
| 2026 | 2043 | | otherwise = do
|
| 2027 | - there <- liftIO $ if is_dir then doesDirectoryExist d else doesFileExist d
|
|
| 2044 | + there <- liftIO $ if is_dir then doesDirectoryExist d' else doesFileExist d'
|
|
| 2028 | 2045 | when (not there) $
|
| 2029 | 2046 | let msg = thisfield ++ ": " ++ d ++ " doesn't exist or isn't a "
|
| 2030 | 2047 | ++ if is_dir then "directory" else "file"
|
| ... | ... | @@ -2032,6 +2049,8 @@ checkPath url_ok is_dir warn_only thisfield d |
| 2032 | 2049 | if warn_only
|
| 2033 | 2050 | then vwarn msg
|
| 2034 | 2051 | else verror ForceFiles msg
|
| 2052 | + where
|
|
| 2053 | + d' = unsafeEncodeUtf d
|
|
| 2035 | 2054 | |
| 2036 | 2055 | checkDep :: PackageDBStack -> UnitId -> Validate ()
|
| 2037 | 2056 | checkDep db_stack pkgid
|
| ... | ... | @@ -2050,24 +2069,25 @@ checkDuplicateDepends deps |
| 2050 | 2069 | where
|
| 2051 | 2070 | dups = [ p | (p:_:_) <- group (sort deps) ]
|
| 2052 | 2071 | |
| 2053 | -checkHSLib :: Verbosity -> [String] -> String -> Validate ()
|
|
| 2072 | +checkHSLib :: Verbosity -> [OsPath] -> String -> Validate ()
|
|
| 2054 | 2073 | checkHSLib _verbosity dirs lib = do
|
| 2055 | - let filenames = ["lib" ++ lib ++ ".a",
|
|
| 2056 | - "lib" ++ lib ++ "_p.a",
|
|
| 2057 | - "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so",
|
|
| 2058 | - "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so",
|
|
| 2059 | - "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib",
|
|
| 2060 | - "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib",
|
|
| 2061 | - lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll",
|
|
| 2062 | - lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll",
|
|
| 2063 | - lib ++ ".bytecodelib"
|
|
| 2064 | - ]
|
|
| 2074 | + let filenames = fmap OsPath.unsafeEncodeUtf
|
|
| 2075 | + [ "lib" ++ lib ++ ".a"
|
|
| 2076 | + , "lib" ++ lib ++ "_p.a"
|
|
| 2077 | + , "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so"
|
|
| 2078 | + , "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".so"
|
|
| 2079 | + , "lib" ++ lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib"
|
|
| 2080 | + , "lib" ++ lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dylib"
|
|
| 2081 | + , lib ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll"
|
|
| 2082 | + , lib ++ "_p" ++ "-ghc" ++ GHC.Version.cProjectVersion ++ ".dll"
|
|
| 2083 | + , lib ++ ".bytecodelib"
|
|
| 2084 | + ]
|
|
| 2065 | 2085 | b <- liftIO $ doesFileExistOnPath filenames dirs
|
| 2066 | 2086 | when (not b) $
|
| 2067 | 2087 | verror ForceFiles ("cannot find any of " ++ show filenames ++
|
| 2068 | 2088 | " on library path")
|
| 2069 | 2089 | |
| 2070 | -doesFileExistOnPath :: [FilePath] -> [FilePath] -> IO Bool
|
|
| 2090 | +doesFileExistOnPath :: [OsPath] -> [OsPath] -> IO Bool
|
|
| 2071 | 2091 | doesFileExistOnPath filenames paths = anyM doesFileExist fullFilenames
|
| 2072 | 2092 | where fullFilenames = [ path </> filename
|
| 2073 | 2093 | | filename <- filenames
|
| ... | ... | @@ -2096,9 +2116,9 @@ checkModuleFile :: InstalledPackageInfo -> ModuleName -> Validate () |
| 2096 | 2116 | checkModuleFile pkg modl =
|
| 2097 | 2117 | -- there's no interface file for GHC.Prim
|
| 2098 | 2118 | unless (modl == ModuleName.fromString "GHC.Prim") $ do
|
| 2099 | - let files = [ ModuleName.toFilePath modl <.> extension
|
|
| 2100 | - | extension <- ["hi", "p_hi", "dyn_hi", "p_dyn_hi"] ]
|
|
| 2101 | - b <- liftIO $ doesFileExistOnPath files (importDirs pkg)
|
|
| 2119 | + let files = [ unsafeEncodeUtf (ModuleName.toFilePath modl) <.> extension
|
|
| 2120 | + | extension <- fmap os ["hi", "p_hi", "dyn_hi", "p_dyn_hi"] ]
|
|
| 2121 | + b <- liftIO $ doesFileExistOnPath files (fmap unsafeEncodeUtf $ importDirs pkg)
|
|
| 2102 | 2122 | when (not b) $
|
| 2103 | 2123 | verror ForceFiles ("cannot find any of " ++ show files)
|
| 2104 | 2124 | |
| ... | ... | @@ -2273,19 +2293,45 @@ installSignalHandlers = do |
| 2273 | 2293 | return ()
|
| 2274 | 2294 | #endif
|
| 2275 | 2295 | |
| 2296 | +-- ------------------------------------------------
|
|
| 2297 | +-- OsPath Utils
|
|
| 2298 | + |
|
| 2299 | +-- | Show an 'OsPath', throwing an exception if we fail to decode it.
|
|
| 2300 | +showOsPath :: HasCallStack => OsPath -> FilePath
|
|
| 2301 | +showOsPath = unsafePerformIO . decodeFS
|
|
| 2302 | + |
|
| 2303 | +-- | Turn a path relative to the current directory into a (normalised)
|
|
| 2304 | +-- absolute path.
|
|
| 2305 | +absolutePath :: OsPath -> IO OsPath
|
|
| 2306 | +absolutePath path = return . normalise . (</> path) =<< getCurrentDirectory
|
|
| 2307 | + |
|
| 2308 | +-- ------------------------------------------------
|
|
| 2309 | + |
|
| 2276 | 2310 | catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a
|
| 2277 | 2311 | catchIO = catchException
|
| 2278 | 2312 | |
| 2279 | 2313 | tryIO :: IO a -> IO (Either Exception.IOException a)
|
| 2280 | 2314 | tryIO = Exception.try
|
| 2281 | 2315 | |
| 2282 | --- removeFileSave doesn't throw an exceptions, if the file is already deleted
|
|
| 2283 | -removeFileSafe :: FilePath -> IO ()
|
|
| 2316 | +-----------------------------------------
|
|
| 2317 | +-- Adapted from ghc/compiler/utils/Panic
|
|
| 2318 | + |
|
| 2319 | +-- | 'removeFileSave' doesn't throw an exceptions, if the file is already deleted
|
|
| 2320 | +removeFileSafe :: OsPath -> IO ()
|
|
| 2284 | 2321 | removeFileSafe fn =
|
| 2285 | 2322 | removeFile fn `catchIO` \ e ->
|
| 2286 | 2323 | when (not $ isDoesNotExistError e) $ ioError e
|
| 2287 | 2324 | |
| 2288 | --- | Turn a path relative to the current directory into a (normalised)
|
|
| 2289 | --- absolute path.
|
|
| 2290 | -absolutePath :: FilePath -> IO FilePath
|
|
| 2291 | -absolutePath path = return . normalise . (</> path) =<< getCurrentDirectory |
|
| 2325 | +-- | Read a file using UTF-8 encoding
|
|
| 2326 | +--
|
|
| 2327 | +-- Taken from https://github.com/haskell/cabal/blob/cea1d8ff1a80df3c3b3148d1556bd3edf656da93/Cabal-syntax/src/Distribution/Utils/Generic.hs#L326
|
|
| 2328 | +-- and adapted to 'OsPath'.
|
|
| 2329 | +writeUtf8File :: OsPath -> String -> IO ()
|
|
| 2330 | +writeUtf8File file contents = writeFileAtomic file (toUTF8LBS contents)
|
|
| 2331 | + |
|
| 2332 | +-- | Read a file and interpret its content to be UTF-8 encoded.
|
|
| 2333 | +--
|
|
| 2334 | +-- Taken from https://github.com/haskell/cabal/blob/cea1d8ff1a80df3c3b3148d1556bd3edf656da93/Cabal-syntax/src/Distribution/Utils/Generic.hs#L309
|
|
| 2335 | +-- and adapted to 'OsPath'.
|
|
| 2336 | +readUtf8File :: OsPath -> IO String
|
|
| 2337 | +readUtf8File file = (ignoreBOM . fromUTF8LBS) <$> FileIO.readFile file |
| ... | ... | @@ -25,6 +25,7 @@ Executable ghc-pkg |
| 25 | 25 | process >= 1 && < 1.7,
|
| 26 | 26 | containers,
|
| 27 | 27 | filepath,
|
| 28 | + file-io,
|
|
| 28 | 29 | Cabal,
|
| 29 | 30 | Cabal-syntax,
|
| 30 | 31 | binary,
|