{- |
(c) The GRASP/AQUA Project, Glasgow University, 1993-1998

A lint pass to check basic STG invariants:

- Variables should be defined before used.

- Let bindings should not have unboxed types (unboxed bindings should only
  appear in case), except when they're join points (see Note [Core let-can-float
  invariant] and #14117).

- If linting after unarisation, invariants listed in Note [Post-unarisation
  invariants].

Because we don't have types and coercions in STG we can't really check types
here.

Some history:

StgLint used to check types, but it never worked and so it was disabled in 2000
with this note:

    WARNING:
    ~~~~~~~~

    This module has suffered bit-rot; it is likely to yield lint errors
    for Stg code that is currently perfectly acceptable for code
    generation.  Solution: don't use it!  (KSW 2000-05).

Since then there were some attempts at enabling it again, as summarised in #14787.
It's finally decided that we remove all type checking and only look for
basic properties listed above.
-}

{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies,
  DeriveFunctor #-}

module GHC.Stg.Lint ( lintStgTopBindings ) where

import GHC.Prelude

import GHC.Stg.Syntax
import GHC.Stg.Utils

import GHC.Core.Lint        ( interactiveInScope )
import GHC.Core.DataCon
import GHC.Core             ( AltCon(..) )
import GHC.Core.Type

import GHC.Types.Basic      ( TopLevelFlag(..), isTopLevel, isMarkedCbv )
import GHC.Types.CostCentre ( isCurrentCCS )
import GHC.Types.Error      ( DiagnosticReason(WarningWithoutFlag) )
import GHC.Types.Id
import GHC.Types.Var.Set
import GHC.Types.Name       ( getSrcLoc, nameIsLocalOrFrom )
import GHC.Types.RepType
import GHC.Types.SrcLoc

import GHC.Utils.Logger
import GHC.Utils.Outputable
import GHC.Utils.Error      ( mkLocMessage, DiagOpts )
import qualified GHC.Utils.Error as Err

import GHC.Unit.Module            ( Module )
import GHC.Runtime.Context        ( InteractiveContext )

import GHC.Data.Bag         ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )

import Control.Applicative ((<|>))
import Control.Monad
import Data.Maybe
import GHC.Utils.Misc

lintStgTopBindings :: forall a . (OutputablePass a, BinderP a ~ Id)
                   => Logger
                   -> DiagOpts
                   -> StgPprOpts
                   -> InteractiveContext
                   -> Module -- ^ module being compiled
                   -> Bool   -- ^ have we run Unarise yet?
                   -> String -- ^ who produced the STG?
                   -> [GenStgTopBinding a]
                   -> IO ()

lintStgTopBindings :: Logger
-> DiagOpts
-> StgPprOpts
-> InteractiveContext
-> Module
-> Bool
-> String
-> [GenStgTopBinding a]
-> IO ()
lintStgTopBindings Logger
logger DiagOpts
diag_opts StgPprOpts
opts InteractiveContext
ictxt Module
this_mod Bool
unarised String
whodunnit [GenStgTopBinding a]
binds
  = {-# SCC "StgLint" #-}
    case DiagOpts
-> Module -> Bool -> StgPprOpts -> IdSet -> LintM () -> Maybe SDoc
forall a.
DiagOpts
-> Module -> Bool -> StgPprOpts -> IdSet -> LintM a -> Maybe SDoc
initL DiagOpts
diag_opts Module
this_mod Bool
unarised StgPprOpts
opts IdSet
top_level_binds ([GenStgTopBinding a] -> LintM ()
lint_binds [GenStgTopBinding a]
binds) of
      Maybe SDoc
Nothing  ->
        () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Just SDoc
msg -> do
        Logger -> MessageClass -> SrcSpan -> SDoc -> IO ()
logMsg Logger
logger MessageClass
Err.MCDump SrcSpan
noSrcSpan
          (SDoc -> IO ()) -> SDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ PprStyle -> SDoc -> SDoc
withPprStyle PprStyle
defaultDumpStyle
          ([SDoc] -> SDoc
vcat [ String -> SDoc
text String
"*** Stg Lint ErrMsgs: in" SDoc -> SDoc -> SDoc
<+>
                        String -> SDoc
text String
whodunnit SDoc -> SDoc -> SDoc
<+> String -> SDoc
text String
"***",
                  SDoc
msg,
                  String -> SDoc
text String
"*** Offending Program ***",
                  StgPprOpts -> [GenStgTopBinding a] -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> [GenStgTopBinding pass] -> SDoc
pprGenStgTopBindings StgPprOpts
opts [GenStgTopBinding a]
binds,
                  String -> SDoc
text String
"*** End of Offense ***"])
        Logger -> Int -> IO ()
Err.ghcExit Logger
logger Int
1
  where
    -- Bring all top-level binds into scope because CoreToStg does not generate
    -- bindings in dependency order (so we may see a use before its definition).
    top_level_binds :: IdSet
top_level_binds = IdSet -> [Var] -> IdSet
extendVarSetList ([Var] -> IdSet
mkVarSet ([GenStgTopBinding a] -> [Var]
forall (a :: StgPass).
(BinderP a ~ Var) =>
[GenStgTopBinding a] -> [Var]
bindersOfTopBinds [GenStgTopBinding a]
binds))
                                       (InteractiveContext -> [Var]
interactiveInScope InteractiveContext
ictxt)

    lint_binds :: [GenStgTopBinding a] -> LintM ()

    lint_binds :: [GenStgTopBinding a] -> LintM ()
lint_binds [] = () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    lint_binds (GenStgTopBinding a
bind:[GenStgTopBinding a]
binds) = do
        [Var]
binders <- GenStgTopBinding a -> LintM [Var]
forall (a :: StgPass).
(Outputable (XLet a), Outputable (XLetNoEscape a),
 Outputable (XRhsClosure a), OutputableBndr (BinderP a),
 BinderP a ~ Var) =>
GenStgTopBinding a -> LintM [Var]
lint_bind GenStgTopBinding a
bind
        [Var] -> LintM () -> LintM ()
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [Var]
binders (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
            [GenStgTopBinding a] -> LintM ()
lint_binds [GenStgTopBinding a]
binds

    lint_bind :: GenStgTopBinding a -> LintM [Var]
lint_bind (StgTopLifted GenStgBinding a
bind) = TopLevelFlag -> GenStgBinding a -> LintM [Var]
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
TopLevelFlag -> GenStgBinding a -> LintM [Var]
lintStgBinds TopLevelFlag
TopLevel GenStgBinding a
bind
    lint_bind (StgTopStringLit Var
v ByteString
_) = [Var] -> LintM [Var]
forall (m :: * -> *) a. Monad m => a -> m a
return [Var
v]

lintStgArg :: StgArg -> LintM ()
lintStgArg :: StgArg -> LintM ()
lintStgArg (StgLitArg Literal
_) = () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
lintStgArg (StgVarArg Var
v) = Var -> LintM ()
lintStgVar Var
v

lintStgVar :: Id -> LintM ()
lintStgVar :: Var -> LintM ()
lintStgVar Var
id = Var -> LintM ()
checkInScope Var
id

lintStgBinds
    :: (OutputablePass a, BinderP a ~ Id)
    => TopLevelFlag -> GenStgBinding a -> LintM [Id] -- Returns the binders
lintStgBinds :: TopLevelFlag -> GenStgBinding a -> LintM [Var]
lintStgBinds TopLevelFlag
top_lvl (StgNonRec BinderP a
binder GenStgRhs a
rhs) = do
    TopLevelFlag -> (Var, GenStgRhs a) -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
TopLevelFlag -> (Var, GenStgRhs a) -> LintM ()
lint_binds_help TopLevelFlag
top_lvl (BinderP a
Var
binder,GenStgRhs a
rhs)
    [Var] -> LintM [Var]
forall (m :: * -> *) a. Monad m => a -> m a
return [BinderP a
Var
binder]

lintStgBinds TopLevelFlag
top_lvl (StgRec [(BinderP a, GenStgRhs a)]
pairs)
  = [Var] -> LintM [Var] -> LintM [Var]
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [Var]
binders (LintM [Var] -> LintM [Var]) -> LintM [Var] -> LintM [Var]
forall a b. (a -> b) -> a -> b
$ do
        ((Var, GenStgRhs a) -> LintM ())
-> [(Var, GenStgRhs a)] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (TopLevelFlag -> (Var, GenStgRhs a) -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
TopLevelFlag -> (Var, GenStgRhs a) -> LintM ()
lint_binds_help TopLevelFlag
top_lvl) [(BinderP a, GenStgRhs a)]
[(Var, GenStgRhs a)]
pairs
        [Var] -> LintM [Var]
forall (m :: * -> *) a. Monad m => a -> m a
return [Var]
binders
  where
    binders :: [Var]
binders = [Var
b | (Var
b,GenStgRhs a
_) <- [(BinderP a, GenStgRhs a)]
[(Var, GenStgRhs a)]
pairs]

lint_binds_help
    :: (OutputablePass a, BinderP a ~ Id)
    => TopLevelFlag
    -> (Id, GenStgRhs a)
    -> LintM ()
lint_binds_help :: TopLevelFlag -> (Var, GenStgRhs a) -> LintM ()
lint_binds_help TopLevelFlag
top_lvl (Var
binder, GenStgRhs a
rhs)
  = LintLocInfo -> LintM () -> LintM ()
forall a. LintLocInfo -> LintM a -> LintM a
addLoc (Var -> LintLocInfo
RhsOf Var
binder) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$ do
        Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TopLevelFlag -> Bool
isTopLevel TopLevelFlag
top_lvl) (GenStgRhs a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgRhs a -> LintM ()
checkNoCurrentCCS GenStgRhs a
rhs)
        GenStgRhs a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgRhs a -> LintM ()
lintStgRhs GenStgRhs a
rhs
        StgPprOpts
opts <- LintM StgPprOpts
getStgPprOpts
        -- Check binder doesn't have unlifted type or it's a join point
        Bool -> SDoc -> LintM ()
checkL ( Var -> Bool
isJoinId Var
binder
              Bool -> Bool -> Bool
|| Bool -> Bool
not (HasDebugCallStack => Type -> Bool
Type -> Bool
isUnliftedType (Var -> Type
idType Var
binder))
              Bool -> Bool -> Bool
|| Var -> Bool
isDataConWorkId Var
binder Bool -> Bool -> Bool
|| Var -> Bool
isDataConWrapId Var
binder) -- until #17521 is fixed
          (StgPprOpts -> Var -> GenStgRhs a -> SDoc
forall (a :: StgPass).
OutputablePass a =>
StgPprOpts -> Var -> GenStgRhs a -> SDoc
mkUnliftedTyMsg StgPprOpts
opts Var
binder GenStgRhs a
rhs)

-- | Top-level bindings can't inherit the cost centre stack from their
-- (static) allocation site.
checkNoCurrentCCS
    :: (OutputablePass a, BinderP a ~ Id)
    => GenStgRhs a
    -> LintM ()
checkNoCurrentCCS :: GenStgRhs a -> LintM ()
checkNoCurrentCCS GenStgRhs a
rhs = do
   StgPprOpts
opts <- LintM StgPprOpts
getStgPprOpts
   let rhs' :: SDoc
rhs' = StgPprOpts -> GenStgRhs a -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> GenStgRhs pass -> SDoc
pprStgRhs StgPprOpts
opts GenStgRhs a
rhs
   case GenStgRhs a
rhs of
      StgRhsClosure XRhsClosure a
_ CostCentreStack
ccs UpdateFlag
_ [BinderP a]
_ GenStgExpr a
_
         | CostCentreStack -> Bool
isCurrentCCS CostCentreStack
ccs
         -> SDoc -> LintM ()
addErrL (String -> SDoc
text String
"Top-level StgRhsClosure with CurrentCCS" SDoc -> SDoc -> SDoc
$$ SDoc
rhs')
      StgRhsCon CostCentreStack
ccs DataCon
_ ConstructorNumber
_ [StgTickish]
_ [StgArg]
_
         | CostCentreStack -> Bool
isCurrentCCS CostCentreStack
ccs
         -> SDoc -> LintM ()
addErrL (String -> SDoc
text String
"Top-level StgRhsCon with CurrentCCS" SDoc -> SDoc -> SDoc
$$ SDoc
rhs')
      GenStgRhs a
_ -> () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

lintStgRhs :: (OutputablePass a, BinderP a ~ Id) => GenStgRhs a -> LintM ()

lintStgRhs :: GenStgRhs a -> LintM ()
lintStgRhs (StgRhsClosure XRhsClosure a
_ CostCentreStack
_ UpdateFlag
_ [] GenStgExpr a
expr)
  = GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
expr

lintStgRhs (StgRhsClosure XRhsClosure a
_ CostCentreStack
_ UpdateFlag
_ [BinderP a]
binders GenStgExpr a
expr)
  = LintLocInfo -> LintM () -> LintM ()
forall a. LintLocInfo -> LintM a -> LintM a
addLoc ([Var] -> LintLocInfo
LambdaBodyOf [BinderP a]
[Var]
binders) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
      [Var] -> LintM () -> LintM ()
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [BinderP a]
[Var]
binders (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
        GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
expr

lintStgRhs rhs :: GenStgRhs a
rhs@(StgRhsCon CostCentreStack
_ DataCon
con ConstructorNumber
_ [StgTickish]
_ [StgArg]
args) = do
    StgPprOpts
opts <- LintM StgPprOpts
getStgPprOpts
    Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (DataCon -> Bool
isUnboxedTupleDataCon DataCon
con Bool -> Bool -> Bool
|| DataCon -> Bool
isUnboxedSumDataCon DataCon
con) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$ do
      SDoc -> LintM ()
addErrL (String -> SDoc
text String
"StgRhsCon is an unboxed tuple or sum application" SDoc -> SDoc -> SDoc
$$
               StgPprOpts -> GenStgRhs a -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> GenStgRhs pass -> SDoc
pprStgRhs StgPprOpts
opts GenStgRhs a
rhs)

    DataCon -> [StgArg] -> SDoc -> LintM ()
forall (t :: * -> *) a.
Foldable t =>
DataCon -> t a -> SDoc -> LintM ()
lintConApp DataCon
con [StgArg]
args (StgPprOpts -> GenStgRhs a -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> GenStgRhs pass -> SDoc
pprStgRhs StgPprOpts
opts GenStgRhs a
rhs)

    (StgArg -> LintM ()) -> [StgArg] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ StgArg -> LintM ()
lintStgArg [StgArg]
args
    (StgArg -> LintM ()) -> [StgArg] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ StgArg -> LintM ()
checkPostUnariseConArg [StgArg]
args

lintStgExpr :: (OutputablePass a, BinderP a ~ Id) => GenStgExpr a -> LintM ()

lintStgExpr :: GenStgExpr a -> LintM ()
lintStgExpr (StgLit Literal
_) = () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

lintStgExpr e :: GenStgExpr a
e@(StgApp Var
fun [StgArg]
args) = do
    Var -> LintM ()
lintStgVar Var
fun
    (StgArg -> LintM ()) -> [StgArg] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ StgArg -> LintM ()
lintStgArg [StgArg]
args

    LintFlags
lf <- LintM LintFlags
getLintFlags
    Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LintFlags -> Bool
lf_unarised LintFlags
lf) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$ do
      -- A function which expects a unlifted argument as n'th argument
      -- always needs to be applied to n arguments.
      -- See Note [Strict Worker Ids].
      let marks :: [CbvMark]
marks = [CbvMark] -> Maybe [CbvMark] -> [CbvMark]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [CbvMark] -> [CbvMark]) -> Maybe [CbvMark] -> [CbvMark]
forall a b. (a -> b) -> a -> b
$ Var -> Maybe [CbvMark]
idCbvMarks_maybe Var
fun
      if [CbvMark] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ((CbvMark -> Bool) -> [CbvMark] -> [CbvMark]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEndLE (Bool -> Bool
not (Bool -> Bool) -> (CbvMark -> Bool) -> CbvMark -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CbvMark -> Bool
isMarkedCbv) [CbvMark]
marks) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> [StgArg] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [StgArg]
args
        then SDoc -> LintM ()
addErrL (SDoc -> LintM ()) -> SDoc -> LintM ()
forall a b. (a -> b) -> a -> b
$ SDoc -> Int -> SDoc -> SDoc
hang (String -> SDoc
text String
"Undersatured cbv marked ID in App" SDoc -> SDoc -> SDoc
<+> GenStgExpr a -> SDoc
forall a. Outputable a => a -> SDoc
ppr GenStgExpr a
e ) Int
2 (SDoc -> SDoc) -> SDoc -> SDoc
forall a b. (a -> b) -> a -> b
$
          (String -> SDoc
text String
"marks" SDoc -> SDoc -> SDoc
<> [CbvMark] -> SDoc
forall a. Outputable a => a -> SDoc
ppr [CbvMark]
marks SDoc -> SDoc -> SDoc
$$
          String -> SDoc
text String
"args" SDoc -> SDoc -> SDoc
<> [StgArg] -> SDoc
forall a. Outputable a => a -> SDoc
ppr [StgArg]
args SDoc -> SDoc -> SDoc
$$
          String -> SDoc
text String
"arity" SDoc -> SDoc -> SDoc
<> Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Int
idArity Var
fun) SDoc -> SDoc -> SDoc
$$
          String -> SDoc
text String
"join_arity" SDoc -> SDoc -> SDoc
<> Maybe Int -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Maybe Int
isJoinId_maybe Var
fun))
        else () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

lintStgExpr app :: GenStgExpr a
app@(StgConApp DataCon
con ConstructorNumber
_n [StgArg]
args [Type]
_arg_tys) = do
    -- unboxed sums should vanish during unarise
    LintFlags
lf <- LintM LintFlags
getLintFlags
    let !unarised :: Bool
unarised = LintFlags -> Bool
lf_unarised LintFlags
lf
    Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
unarised Bool -> Bool -> Bool
&& DataCon -> Bool
isUnboxedSumDataCon DataCon
con) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$ do
      StgPprOpts
opts <- LintM StgPprOpts
getStgPprOpts
      SDoc -> LintM ()
addErrL (String -> SDoc
text String
"Unboxed sum after unarise:" SDoc -> SDoc -> SDoc
$$
               StgPprOpts -> GenStgExpr a -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> GenStgExpr pass -> SDoc
pprStgExpr StgPprOpts
opts GenStgExpr a
app)

    StgPprOpts
opts <- LintM StgPprOpts
getStgPprOpts
    DataCon -> [StgArg] -> SDoc -> LintM ()
forall (t :: * -> *) a.
Foldable t =>
DataCon -> t a -> SDoc -> LintM ()
lintConApp DataCon
con [StgArg]
args (StgPprOpts -> GenStgExpr a -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> GenStgExpr pass -> SDoc
pprStgExpr StgPprOpts
opts GenStgExpr a
app)

    (StgArg -> LintM ()) -> [StgArg] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ StgArg -> LintM ()
lintStgArg [StgArg]
args
    (StgArg -> LintM ()) -> [StgArg] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ StgArg -> LintM ()
checkPostUnariseConArg [StgArg]
args

lintStgExpr (StgOpApp StgOp
_ [StgArg]
args Type
_) =
    (StgArg -> LintM ()) -> [StgArg] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ StgArg -> LintM ()
lintStgArg [StgArg]
args

lintStgExpr (StgLet XLet a
_ GenStgBinding a
binds GenStgExpr a
body) = do
    [Var]
binders <- TopLevelFlag -> GenStgBinding a -> LintM [Var]
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
TopLevelFlag -> GenStgBinding a -> LintM [Var]
lintStgBinds TopLevelFlag
NotTopLevel GenStgBinding a
binds
    LintLocInfo -> LintM () -> LintM ()
forall a. LintLocInfo -> LintM a -> LintM a
addLoc ([Var] -> LintLocInfo
BodyOfLetRec [Var]
binders) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
      [Var] -> LintM () -> LintM ()
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [Var]
binders (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
        GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
body

lintStgExpr (StgLetNoEscape XLetNoEscape a
_ GenStgBinding a
binds GenStgExpr a
body) = do
    [Var]
binders <- TopLevelFlag -> GenStgBinding a -> LintM [Var]
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
TopLevelFlag -> GenStgBinding a -> LintM [Var]
lintStgBinds TopLevelFlag
NotTopLevel GenStgBinding a
binds
    LintLocInfo -> LintM () -> LintM ()
forall a. LintLocInfo -> LintM a -> LintM a
addLoc ([Var] -> LintLocInfo
BodyOfLetRec [Var]
binders) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
      [Var] -> LintM () -> LintM ()
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [Var]
binders (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
        GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
body

lintStgExpr (StgTick StgTickish
_ GenStgExpr a
expr) = GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
expr

lintStgExpr (StgCase GenStgExpr a
scrut BinderP a
bndr AltType
alts_type [GenStgAlt a]
alts) = do
    GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
scrut

    LintFlags
lf <- LintM LintFlags
getLintFlags
    let in_scope :: Bool
in_scope = AltType -> Bool -> Bool
stgCaseBndrInScope AltType
alts_type (LintFlags -> Bool
lf_unarised LintFlags
lf)

    [Var] -> LintM () -> LintM ()
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [BinderP a
Var
bndr | Bool
in_scope] ((GenStgAlt a -> LintM ()) -> [GenStgAlt a] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ GenStgAlt a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgAlt a -> LintM ()
lintAlt [GenStgAlt a]
alts)

lintAlt
    :: (OutputablePass a, BinderP a ~ Id)
    => GenStgAlt a -> LintM ()

lintAlt :: GenStgAlt a -> LintM ()
lintAlt GenStgAlt{ alt_con :: forall (pass :: StgPass). GenStgAlt pass -> AltCon
alt_con   = AltCon
DEFAULT
                 , alt_bndrs :: forall (pass :: StgPass). GenStgAlt pass -> [BinderP pass]
alt_bndrs = [BinderP a]
_
                 , alt_rhs :: forall (pass :: StgPass). GenStgAlt pass -> GenStgExpr pass
alt_rhs   = GenStgExpr a
rhs} = GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
rhs

lintAlt GenStgAlt{ alt_con :: forall (pass :: StgPass). GenStgAlt pass -> AltCon
alt_con   = LitAlt Literal
_
                 , alt_bndrs :: forall (pass :: StgPass). GenStgAlt pass -> [BinderP pass]
alt_bndrs = [BinderP a]
_
                 , alt_rhs :: forall (pass :: StgPass). GenStgAlt pass -> GenStgExpr pass
alt_rhs   = GenStgExpr a
rhs} = GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
rhs

lintAlt GenStgAlt{ alt_con :: forall (pass :: StgPass). GenStgAlt pass -> AltCon
alt_con   = DataAlt DataCon
_
                 , alt_bndrs :: forall (pass :: StgPass). GenStgAlt pass -> [BinderP pass]
alt_bndrs = [BinderP a]
bndrs
                 , alt_rhs :: forall (pass :: StgPass). GenStgAlt pass -> GenStgExpr pass
alt_rhs   = GenStgExpr a
rhs} =
  do
    (Var -> LintM ()) -> [Var] -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Var -> LintM ()
checkPostUnariseBndr [BinderP a]
[Var]
bndrs
    [Var] -> LintM () -> LintM ()
forall a. [Var] -> LintM a -> LintM a
addInScopeVars [BinderP a]
[Var]
bndrs (GenStgExpr a -> LintM ()
forall (a :: StgPass).
(OutputablePass a, BinderP a ~ Var) =>
GenStgExpr a -> LintM ()
lintStgExpr GenStgExpr a
rhs)

-- Post unarise check we apply constructors to the right number of args.
-- This can be violated by invalid use of unsafeCoerce as showcased by test
-- T9208
lintConApp :: Foldable t => DataCon -> t a -> SDoc -> LintM ()
lintConApp :: DataCon -> t a -> SDoc -> LintM ()
lintConApp DataCon
con t a
args SDoc
app = do
    Bool
unarised <- LintFlags -> Bool
lf_unarised (LintFlags -> Bool) -> LintM LintFlags -> LintM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> LintM LintFlags
getLintFlags
    Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
unarised Bool -> Bool -> Bool
&&
          Bool -> Bool
not (DataCon -> Bool
isUnboxedTupleDataCon DataCon
con) Bool -> Bool -> Bool
&&
          [StrictnessMark] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (HasDebugCallStack => DataCon -> [StrictnessMark]
DataCon -> [StrictnessMark]
dataConRuntimeRepStrictness DataCon
con) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= t a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length t a
args) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$ do
      SDoc -> LintM ()
addErrL (String -> SDoc
text String
"Constructor applied to incorrect number of arguments:" SDoc -> SDoc -> SDoc
$$
               String -> SDoc
text String
"Application:" SDoc -> SDoc -> SDoc
<> SDoc
app)

{-
************************************************************************
*                                                                      *
The Lint monad
*                                                                      *
************************************************************************
-}

newtype LintM a = LintM
    { LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM :: Module
              -> LintFlags
              -> DiagOpts          -- Diagnostic options
              -> StgPprOpts        -- Pretty-printing options
              -> [LintLocInfo]     -- Locations
              -> IdSet             -- Local vars in scope
              -> Bag SDoc        -- Error messages so far
              -> (a, Bag SDoc)   -- Result and error messages (if any)
    }
    deriving (a -> LintM b -> LintM a
(a -> b) -> LintM a -> LintM b
(forall a b. (a -> b) -> LintM a -> LintM b)
-> (forall a b. a -> LintM b -> LintM a) -> Functor LintM
forall a b. a -> LintM b -> LintM a
forall a b. (a -> b) -> LintM a -> LintM b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> LintM b -> LintM a
$c<$ :: forall a b. a -> LintM b -> LintM a
fmap :: (a -> b) -> LintM a -> LintM b
$cfmap :: forall a b. (a -> b) -> LintM a -> LintM b
Functor)

data LintFlags = LintFlags { LintFlags -> Bool
lf_unarised :: !Bool
                             -- ^ have we run the unariser yet?
                           }

data LintLocInfo
  = RhsOf Id            -- The variable bound
  | LambdaBodyOf [Id]   -- The lambda-binder
  | BodyOfLetRec [Id]   -- One of the binders

dumpLoc :: LintLocInfo -> (SrcSpan, SDoc)
dumpLoc :: LintLocInfo -> (SrcSpan, SDoc)
dumpLoc (RhsOf Var
v) =
  (SrcLoc -> SrcSpan
srcLocSpan (Var -> SrcLoc
forall a. NamedThing a => a -> SrcLoc
getSrcLoc Var
v), String -> SDoc
text String
" [RHS of " SDoc -> SDoc -> SDoc
<> [Var] -> SDoc
pp_binders [Var
v] SDoc -> SDoc -> SDoc
<> Char -> SDoc
char Char
']' )
dumpLoc (LambdaBodyOf [Var]
bs) =
  (SrcLoc -> SrcSpan
srcLocSpan (Var -> SrcLoc
forall a. NamedThing a => a -> SrcLoc
getSrcLoc ([Var] -> Var
forall a. [a] -> a
head [Var]
bs)), String -> SDoc
text String
" [in body of lambda with binders " SDoc -> SDoc -> SDoc
<> [Var] -> SDoc
pp_binders [Var]
bs SDoc -> SDoc -> SDoc
<> Char -> SDoc
char Char
']' )

dumpLoc (BodyOfLetRec [Var]
bs) =
  (SrcLoc -> SrcSpan
srcLocSpan (Var -> SrcLoc
forall a. NamedThing a => a -> SrcLoc
getSrcLoc ([Var] -> Var
forall a. [a] -> a
head [Var]
bs)), String -> SDoc
text String
" [in body of letrec with binders " SDoc -> SDoc -> SDoc
<> [Var] -> SDoc
pp_binders [Var]
bs SDoc -> SDoc -> SDoc
<> Char -> SDoc
char Char
']' )


pp_binders :: [Id] -> SDoc
pp_binders :: [Var] -> SDoc
pp_binders [Var]
bs
  = [SDoc] -> SDoc
sep (SDoc -> [SDoc] -> [SDoc]
punctuate SDoc
comma ((Var -> SDoc) -> [Var] -> [SDoc]
forall a b. (a -> b) -> [a] -> [b]
map Var -> SDoc
pp_binder [Var]
bs))
  where
    pp_binder :: Var -> SDoc
pp_binder Var
b
      = [SDoc] -> SDoc
hsep [Var -> SDoc
forall a. Outputable a => a -> SDoc
ppr Var
b, SDoc
dcolon, Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Type
idType Var
b)]

initL :: DiagOpts -> Module -> Bool -> StgPprOpts -> IdSet -> LintM a -> Maybe SDoc
initL :: DiagOpts
-> Module -> Bool -> StgPprOpts -> IdSet -> LintM a -> Maybe SDoc
initL DiagOpts
diag_opts Module
this_mod Bool
unarised StgPprOpts
opts IdSet
locals (LintM Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
m) = do
  let (a
_, Bag SDoc
errs) = Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
m Module
this_mod (Bool -> LintFlags
LintFlags Bool
unarised) DiagOpts
diag_opts StgPprOpts
opts [] IdSet
locals Bag SDoc
forall a. Bag a
emptyBag
  if Bag SDoc -> Bool
forall a. Bag a -> Bool
isEmptyBag Bag SDoc
errs then
      Maybe SDoc
forall a. Maybe a
Nothing
  else
      SDoc -> Maybe SDoc
forall a. a -> Maybe a
Just ([SDoc] -> SDoc
vcat (SDoc -> [SDoc] -> [SDoc]
punctuate SDoc
blankLine (Bag SDoc -> [SDoc]
forall a. Bag a -> [a]
bagToList Bag SDoc
errs)))

instance Applicative LintM where
      pure :: a -> LintM a
pure a
a = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (a, Bag SDoc))
 -> LintM a)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (a, Bag SDoc))
-> LintM a
forall a b. (a -> b) -> a -> b
$ \Module
_mod LintFlags
_lf DiagOpts
_df StgPprOpts
_opts [LintLocInfo]
_loc IdSet
_scope Bag SDoc
errs -> (a
a, Bag SDoc
errs)
      <*> :: LintM (a -> b) -> LintM a -> LintM b
(<*>) = LintM (a -> b) -> LintM a -> LintM b
forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap
      *> :: LintM a -> LintM b -> LintM b
(*>)  = LintM a -> LintM b -> LintM b
forall a b. LintM a -> LintM b -> LintM b
thenL_

instance Monad LintM where
    >>= :: LintM a -> (a -> LintM b) -> LintM b
(>>=) = LintM a -> (a -> LintM b) -> LintM b
forall a b. LintM a -> (a -> LintM b) -> LintM b
thenL
    >> :: LintM a -> LintM b -> LintM b
(>>)  = LintM a -> LintM b -> LintM b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
(*>)

thenL :: LintM a -> (a -> LintM b) -> LintM b
thenL :: LintM a -> (a -> LintM b) -> LintM b
thenL LintM a
m a -> LintM b
k = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (b, Bag SDoc))
-> LintM b
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (b, Bag SDoc))
 -> LintM b)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (b, Bag SDoc))
-> LintM b
forall a b. (a -> b) -> a -> b
$ \Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs
  -> case LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
forall a.
LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM LintM a
m Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs of
      (a
r, Bag SDoc
errs') -> LintM b
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (b, Bag SDoc)
forall a.
LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM (a -> LintM b
k a
r) Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs'

thenL_ :: LintM a -> LintM b -> LintM b
thenL_ :: LintM a -> LintM b -> LintM b
thenL_ LintM a
m LintM b
k = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (b, Bag SDoc))
-> LintM b
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (b, Bag SDoc))
 -> LintM b)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (b, Bag SDoc))
-> LintM b
forall a b. (a -> b) -> a -> b
$ \Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs
  -> case LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
forall a.
LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM LintM a
m Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs of
      (a
_, Bag SDoc
errs') -> LintM b
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (b, Bag SDoc)
forall a.
LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM LintM b
k Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs'

checkL :: Bool -> SDoc -> LintM ()
checkL :: Bool -> SDoc -> LintM ()
checkL Bool
True  SDoc
_   = () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
checkL Bool
False SDoc
msg = SDoc -> LintM ()
addErrL SDoc
msg

-- Case alts shouldn't have unboxed sum, unboxed tuple, or void binders.
checkPostUnariseBndr :: Id -> LintM ()
checkPostUnariseBndr :: Var -> LintM ()
checkPostUnariseBndr Var
bndr = do
    LintFlags
lf <- LintM LintFlags
getLintFlags
    Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LintFlags -> Bool
lf_unarised LintFlags
lf) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
      Maybe String -> (String -> LintM ()) -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Var -> Maybe String
checkPostUnariseId Var
bndr) ((String -> LintM ()) -> LintM ())
-> (String -> LintM ()) -> LintM ()
forall a b. (a -> b) -> a -> b
$ \String
unexpected ->
        SDoc -> LintM ()
addErrL (SDoc -> LintM ()) -> SDoc -> LintM ()
forall a b. (a -> b) -> a -> b
$
          String -> SDoc
text String
"After unarisation, binder " SDoc -> SDoc -> SDoc
<>
          Var -> SDoc
forall a. Outputable a => a -> SDoc
ppr Var
bndr SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
" has " SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
unexpected SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
" type " SDoc -> SDoc -> SDoc
<>
          Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Type
idType Var
bndr)

-- Arguments shouldn't have sum, tuple, or void types.
checkPostUnariseConArg :: StgArg -> LintM ()
checkPostUnariseConArg :: StgArg -> LintM ()
checkPostUnariseConArg StgArg
arg = case StgArg
arg of
    StgLitArg Literal
_ ->
      () -> LintM ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    StgVarArg Var
id -> do
      LintFlags
lf <- LintM LintFlags
getLintFlags
      Bool -> LintM () -> LintM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LintFlags -> Bool
lf_unarised LintFlags
lf) (LintM () -> LintM ()) -> LintM () -> LintM ()
forall a b. (a -> b) -> a -> b
$
        Maybe String -> (String -> LintM ()) -> LintM ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (Var -> Maybe String
checkPostUnariseId Var
id) ((String -> LintM ()) -> LintM ())
-> (String -> LintM ()) -> LintM ()
forall a b. (a -> b) -> a -> b
$ \String
unexpected ->
          SDoc -> LintM ()
addErrL (SDoc -> LintM ()) -> SDoc -> LintM ()
forall a b. (a -> b) -> a -> b
$
            String -> SDoc
text String
"After unarisation, arg " SDoc -> SDoc -> SDoc
<>
            Var -> SDoc
forall a. Outputable a => a -> SDoc
ppr Var
id SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
" has " SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
unexpected SDoc -> SDoc -> SDoc
<> String -> SDoc
text String
" type " SDoc -> SDoc -> SDoc
<>
            Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Type
idType Var
id)

-- Post-unarisation args and case alt binders should not have unboxed tuple,
-- unboxed sum, or void types. Return what the binder is if it is one of these.
checkPostUnariseId :: Id -> Maybe String
checkPostUnariseId :: Var -> Maybe String
checkPostUnariseId Var
id =
    let
      id_ty :: Type
id_ty = Var -> Type
idType Var
id
      is_sum, is_tuple, is_void :: Maybe String
      is_sum :: Maybe String
is_sum = Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Type -> Bool
isUnboxedSumType Type
id_ty) Maybe () -> Maybe String -> Maybe String
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"unboxed sum"
      is_tuple :: Maybe String
is_tuple = Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Type -> Bool
isUnboxedTupleType Type
id_ty) Maybe () -> Maybe String -> Maybe String
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"unboxed tuple"
      is_void :: Maybe String
is_void = Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (HasDebugCallStack => Type -> Bool
Type -> Bool
isZeroBitTy Type
id_ty) Maybe () -> Maybe String -> Maybe String
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> String -> Maybe String
forall (m :: * -> *) a. Monad m => a -> m a
return String
"void"
    in
      Maybe String
is_sum Maybe String -> Maybe String -> Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe String
is_tuple Maybe String -> Maybe String -> Maybe String
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe String
is_void

addErrL :: SDoc -> LintM ()
addErrL :: SDoc -> LintM ()
addErrL SDoc
msg = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> ((), Bag SDoc))
-> LintM ()
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> ((), Bag SDoc))
 -> LintM ())
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> ((), Bag SDoc))
-> LintM ()
forall a b. (a -> b) -> a -> b
$ \Module
_mod LintFlags
_lf DiagOpts
df StgPprOpts
_opts [LintLocInfo]
loc IdSet
_scope Bag SDoc
errs -> ((), DiagOpts -> Bag SDoc -> SDoc -> [LintLocInfo] -> Bag SDoc
addErr DiagOpts
df Bag SDoc
errs SDoc
msg [LintLocInfo]
loc)

addErr :: DiagOpts -> Bag SDoc -> SDoc -> [LintLocInfo] -> Bag SDoc
addErr :: DiagOpts -> Bag SDoc -> SDoc -> [LintLocInfo] -> Bag SDoc
addErr DiagOpts
diag_opts Bag SDoc
errs_so_far SDoc
msg [LintLocInfo]
locs
  = Bag SDoc
errs_so_far Bag SDoc -> SDoc -> Bag SDoc
forall a. Bag a -> a -> Bag a
`snocBag` [LintLocInfo] -> SDoc
mk_msg [LintLocInfo]
locs
  where
    mk_msg :: [LintLocInfo] -> SDoc
mk_msg (LintLocInfo
loc:[LintLocInfo]
_) = let (SrcSpan
l,SDoc
hdr) = LintLocInfo -> (SrcSpan, SDoc)
dumpLoc LintLocInfo
loc
                     in  MessageClass -> SrcSpan -> SDoc -> SDoc
mkLocMessage (DiagOpts -> DiagnosticReason -> MessageClass
Err.mkMCDiagnostic DiagOpts
diag_opts DiagnosticReason
WarningWithoutFlag)
                                      SrcSpan
l (SDoc
hdr SDoc -> SDoc -> SDoc
$$ SDoc
msg)
    mk_msg []      = SDoc
msg

addLoc :: LintLocInfo -> LintM a -> LintM a
addLoc :: LintLocInfo -> LintM a -> LintM a
addLoc LintLocInfo
extra_loc LintM a
m = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (a, Bag SDoc))
 -> LintM a)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (a, Bag SDoc))
-> LintM a
forall a b. (a -> b) -> a -> b
$ \Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs
   -> LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
forall a.
LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM LintM a
m Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts (LintLocInfo
extra_locLintLocInfo -> [LintLocInfo] -> [LintLocInfo]
forall a. a -> [a] -> [a]
:[LintLocInfo]
loc) IdSet
scope Bag SDoc
errs

addInScopeVars :: [Id] -> LintM a -> LintM a
addInScopeVars :: [Var] -> LintM a -> LintM a
addInScopeVars [Var]
ids LintM a
m = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (a, Bag SDoc))
 -> LintM a)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (a, Bag SDoc))
-> LintM a
forall a b. (a -> b) -> a -> b
$ \Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs
 -> let
        new_set :: IdSet
new_set = [Var] -> IdSet
mkVarSet [Var]
ids
    in LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
forall a.
LintM a
-> Module
-> LintFlags
-> DiagOpts
-> StgPprOpts
-> [LintLocInfo]
-> IdSet
-> Bag SDoc
-> (a, Bag SDoc)
unLintM LintM a
m Module
mod LintFlags
lf DiagOpts
diag_opts StgPprOpts
opts [LintLocInfo]
loc (IdSet
scope IdSet -> IdSet -> IdSet
`unionVarSet` IdSet
new_set) Bag SDoc
errs

getLintFlags :: LintM LintFlags
getLintFlags :: LintM LintFlags
getLintFlags = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (LintFlags, Bag SDoc))
-> LintM LintFlags
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (LintFlags, Bag SDoc))
 -> LintM LintFlags)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (LintFlags, Bag SDoc))
-> LintM LintFlags
forall a b. (a -> b) -> a -> b
$ \Module
_mod LintFlags
lf DiagOpts
_df StgPprOpts
_opts [LintLocInfo]
_loc IdSet
_scope Bag SDoc
errs -> (LintFlags
lf, Bag SDoc
errs)

getStgPprOpts :: LintM StgPprOpts
getStgPprOpts :: LintM StgPprOpts
getStgPprOpts = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (StgPprOpts, Bag SDoc))
-> LintM StgPprOpts
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> (StgPprOpts, Bag SDoc))
 -> LintM StgPprOpts)
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> (StgPprOpts, Bag SDoc))
-> LintM StgPprOpts
forall a b. (a -> b) -> a -> b
$ \Module
_mod LintFlags
_lf DiagOpts
_df StgPprOpts
opts [LintLocInfo]
_loc IdSet
_scope Bag SDoc
errs -> (StgPprOpts
opts, Bag SDoc
errs)

checkInScope :: Id -> LintM ()
checkInScope :: Var -> LintM ()
checkInScope Var
id = (Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> ((), Bag SDoc))
-> LintM ()
forall a.
(Module
 -> LintFlags
 -> DiagOpts
 -> StgPprOpts
 -> [LintLocInfo]
 -> IdSet
 -> Bag SDoc
 -> (a, Bag SDoc))
-> LintM a
LintM ((Module
  -> LintFlags
  -> DiagOpts
  -> StgPprOpts
  -> [LintLocInfo]
  -> IdSet
  -> Bag SDoc
  -> ((), Bag SDoc))
 -> LintM ())
-> (Module
    -> LintFlags
    -> DiagOpts
    -> StgPprOpts
    -> [LintLocInfo]
    -> IdSet
    -> Bag SDoc
    -> ((), Bag SDoc))
-> LintM ()
forall a b. (a -> b) -> a -> b
$ \Module
mod LintFlags
_lf DiagOpts
diag_opts StgPprOpts
_opts [LintLocInfo]
loc IdSet
scope Bag SDoc
errs
 -> if Module -> Name -> Bool
nameIsLocalOrFrom Module
mod (Var -> Name
idName Var
id) Bool -> Bool -> Bool
&& Bool -> Bool
not (Var
id Var -> IdSet -> Bool
`elemVarSet` IdSet
scope) then
        ((), DiagOpts -> Bag SDoc -> SDoc -> [LintLocInfo] -> Bag SDoc
addErr DiagOpts
diag_opts Bag SDoc
errs ([SDoc] -> SDoc
hsep [Var -> SDoc
forall a. Outputable a => a -> SDoc
ppr Var
id, SDoc
dcolon, Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Type
idType Var
id),
                                    String -> SDoc
text String
"is out of scope"]) [LintLocInfo]
loc)
    else
        ((), Bag SDoc
errs)

mkUnliftedTyMsg :: OutputablePass a => StgPprOpts -> Id -> GenStgRhs a -> SDoc
mkUnliftedTyMsg :: StgPprOpts -> Var -> GenStgRhs a -> SDoc
mkUnliftedTyMsg StgPprOpts
opts Var
binder GenStgRhs a
rhs
  = (String -> SDoc
text String
"Let(rec) binder" SDoc -> SDoc -> SDoc
<+> SDoc -> SDoc
quotes (Var -> SDoc
forall a. Outputable a => a -> SDoc
ppr Var
binder) SDoc -> SDoc -> SDoc
<+>
     String -> SDoc
text String
"has unlifted type" SDoc -> SDoc -> SDoc
<+> SDoc -> SDoc
quotes (Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr (Var -> Type
idType Var
binder)))
    SDoc -> SDoc -> SDoc
$$
    (String -> SDoc
text String
"RHS:" SDoc -> SDoc -> SDoc
<+> StgPprOpts -> GenStgRhs a -> SDoc
forall (pass :: StgPass).
OutputablePass pass =>
StgPprOpts -> GenStgRhs pass -> SDoc
pprStgRhs StgPprOpts
opts GenStgRhs a
rhs)