    {-# LANGUAGE PatternSynonyms #-}

    {-

    This module contains helper functions for reporting and creating
    unbound variables.

    -}
    module GHC.Rename.Unbound
       ( mkUnboundName
       , mkUnboundNameRdr
       , mkUnboundGRE
       , mkUnboundGRERdr
       , isUnboundName
       , reportUnboundName
       , reportUnboundName'
       , unknownNameSuggestions
       , similarNameSuggestions
       , fieldSelectorSuggestions
       , WhatLooking(..)
       , WhereLooking(..)
       , LookingFor(..)
       , unboundName
       , unboundNameX
       , unboundTermNameInTypes
       , IsTermInTypes(..)
       , notInScopeErr
       , nameSpacesRelated
       , termNameInType
       )
    where

    import GHC.Prelude

    import GHC.Driver.DynFlags
    import GHC.Driver.Ppr

    import GHC.Tc.Errors.Types
    import GHC.Tc.Utils.Monad
    import GHC.Builtin.Names ( mkUnboundName, isUnboundName, getUnique)
    import GHC.Utils.Misc
    import GHC.Utils.Panic (panic)

    import GHC.Data.Maybe
    import GHC.Data.FastString

    import qualified GHC.LanguageExtensions as LangExt

    import GHC.Types.Hint
      ( GhcHint (SuggestExtension, RemindFieldSelectorSuppressed, ImportSuggestion, SuggestSimilarNames)
      , LanguageExtensionHint (SuggestSingleExtension)
      , ImportSuggestion(..), SimilarName(..), HowInScope(..) )
    import GHC.Types.SrcLoc as SrcLoc
    import GHC.Types.Name
    import GHC.Types.Name.Reader
    import GHC.Types.Unique.DFM (udfmToList)

    import GHC.Unit.Module
    import GHC.Unit.Module.Imported
    import GHC.Unit.Home.ModInfo

    import GHC.Data.Bag
    import GHC.Utils.Outputable (empty)

    import Data.List (sortBy, partition, nub)
    import Data.List.NonEmpty ( pattern (:|), NonEmpty )
    import Data.Function ( on )
    import qualified Data.Semigroup as S

    {-
    ************************************************************************
    *                                                                      *
                   What to do when a lookup fails
    *                                                                      *
    ************************************************************************
    -}

    -- What kind of suggestion are we looking for? #19843
    data WhatLooking = WL_Anything    -- Any binding
                     | WL_Constructor -- Constructors and pattern synonyms
                            -- E.g. in K { f1 = True }, if K is not in scope,
                            -- suggest only constructors
                     | WL_RecField    -- Record fields
                            -- E.g. in K { f1 = True, f2 = False }, if f2 is not in
                            -- scope, suggest only constructor fields
                     | WL_None        -- No suggestions
                            -- WS_None is used for rebindable syntax, where there
                            -- is no point in suggesting alternative spellings
                     deriving WhatLooking -> WhatLooking -> Bool
    (WhatLooking -> WhatLooking -> Bool)
    -> (WhatLooking -> WhatLooking -> Bool) -> Eq WhatLooking
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: WhatLooking -> WhatLooking -> Bool
    == :: WhatLooking -> WhatLooking -> Bool
    $c/= :: WhatLooking -> WhatLooking -> Bool
    /= :: WhatLooking -> WhatLooking -> Bool
    Eq

    data WhereLooking = WL_Anywhere   -- Any binding
                      | WL_Global     -- Any top-level binding (local or imported)
                      | WL_LocalTop   -- Any top-level binding in this module
                      | WL_LocalOnly
                            -- Only local bindings
                            -- (pattern synonyms declarations,
                            -- see Note [Renaming pattern synonym variables]
                            -- in GHC.Rename.Bind)

    data LookingFor = LF { LookingFor -> WhatLooking
    lf_which :: WhatLooking
                         , LookingFor -> WhereLooking
    lf_where :: WhereLooking
                         }

    data IsTermInTypes = UnknownTermInTypes RdrName | TermInTypes RdrName | NoTermInTypes

    mkUnboundNameRdr :: RdrName -> Name
    mkUnboundNameRdr :: RdrName -> Name
    mkUnboundNameRdr RdrName
    rdr = OccName -> Name
    mkUnboundName (RdrName -> OccName
    rdrNameOcc RdrName
    rdr)

    mkUnboundGRE :: OccName -> GlobalRdrElt
    mkUnboundGRE :: OccName -> GlobalRdrElt
    mkUnboundGRE OccName
    occ = GREInfo -> Parent -> Name -> GlobalRdrElt
    mkLocalGRE GREInfo
    UnboundGRE Parent
    NoParent (Name -> GlobalRdrElt) -> Name -> GlobalRdrElt
    forall a b. (a -> b) -> a -> b
    $ OccName -> Name
    mkUnboundName OccName
    occ

    mkUnboundGRERdr :: RdrName -> GlobalRdrElt
    mkUnboundGRERdr :: RdrName -> GlobalRdrElt
    mkUnboundGRERdr RdrName
    rdr = GREInfo -> Parent -> Name -> GlobalRdrElt
    mkLocalGRE GREInfo
    UnboundGRE Parent
    NoParent (Name -> GlobalRdrElt) -> Name -> GlobalRdrElt
    forall a b. (a -> b) -> a -> b
    $ RdrName -> Name
    mkUnboundNameRdr RdrName
    rdr

    reportUnboundName' :: WhatLooking -> RdrName -> RnM Name
    reportUnboundName' :: WhatLooking -> RdrName -> RnM Name
    reportUnboundName' WhatLooking
    what_look RdrName
    rdr = LookingFor -> RdrName -> RnM Name
    unboundName (WhatLooking -> WhereLooking -> LookingFor
    LF WhatLooking
    what_look WhereLooking
    WL_Anywhere) RdrName
    rdr

    reportUnboundName :: RdrName -> RnM Name
    reportUnboundName :: RdrName -> RnM Name
    reportUnboundName = WhatLooking -> RdrName -> RnM Name
    reportUnboundName' WhatLooking
    WL_Anything

    unboundName :: LookingFor -> RdrName -> RnM Name
    unboundName :: LookingFor -> RdrName -> RnM Name
    unboundName LookingFor
    lf RdrName
    rdr = LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameX LookingFor
    lf RdrName
    rdr []

    unboundNameX :: LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameX :: LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameX LookingFor
    looking_for RdrName
    rdr_name [GhcHint]
    hints
      = IsTermInTypes -> LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameOrTermInType IsTermInTypes
    NoTermInTypes LookingFor
    looking_for RdrName
    rdr_name [GhcHint]
    hints

    unboundTermNameInTypes :: LookingFor -> RdrName -> RdrName  -> RnM Name
    unboundTermNameInTypes :: LookingFor -> RdrName -> RdrName -> RnM Name
    unboundTermNameInTypes LookingFor
    looking_for RdrName
    rdr_name RdrName
    demoted_rdr_name
      = IsTermInTypes -> LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameOrTermInType (RdrName -> IsTermInTypes
    UnknownTermInTypes RdrName
    demoted_rdr_name) LookingFor
    looking_for RdrName
    rdr_name []

    -- Catches imported qualified terms in type signatures
    -- with proper error message and suggestions
    termNameInType :: LookingFor -> RdrName -> RdrName -> [GhcHint] -> RnM Name
    termNameInType :: LookingFor -> RdrName -> RdrName -> [GhcHint] -> RnM Name
    termNameInType LookingFor
    looking_for RdrName
    rdr_name RdrName
    demoted_rdr_name [GhcHint]
    external_hints
      = IsTermInTypes -> LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameOrTermInType (RdrName -> IsTermInTypes
    TermInTypes RdrName
    demoted_rdr_name) LookingFor
    looking_for RdrName
    rdr_name [GhcHint]
    external_hints

    unboundNameOrTermInType :: IsTermInTypes -> LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameOrTermInType :: IsTermInTypes -> LookingFor -> RdrName -> [GhcHint] -> RnM Name
    unboundNameOrTermInType IsTermInTypes
    if_term_in_type LookingFor
    looking_for RdrName
    rdr_name [GhcHint]
    hints
      = do  { dflags <- IOEnv (Env TcGblEnv TcLclEnv) DynFlags
    forall (m :: * -> *). HasDynFlags m => m DynFlags
    getDynFlags
            ; let show_helpful_errors = GeneralFlag -> DynFlags -> Bool
    gopt GeneralFlag
    Opt_HelpfulErrors DynFlags
    dflags
            ; if not show_helpful_errors
              then addErr $ make_error [] hints
              else do { local_env  <- getLocalRdrEnv
                      ; global_env <- getGlobalRdrEnv
                      ; impInfo <- getImports
                      ; currmod <- getModule
                      ; hpt <- getHpt
                      ; let (imp_errs, suggs) =
                              unknownNameSuggestions_ looking_for
                                dflags hpt currmod global_env local_env impInfo
                                rdr_name
                      ; addErr $
                          make_error imp_errs (hints ++ suggs) }
            ; return (mkUnboundNameRdr rdr_name) }
        where
          name_to_search :: RdrName
    name_to_search = case IsTermInTypes
    if_term_in_type of
            IsTermInTypes
    NoTermInTypes                   -> RdrName
    rdr_name
            UnknownTermInTypes RdrName
    demoted_name -> RdrName
    demoted_name
            TermInTypes RdrName
    demoted_name        -> RdrName
    demoted_name

          err :: NotInScopeError
    err = WhereLooking -> RdrName -> NotInScopeError
    notInScopeErr (LookingFor -> WhereLooking
    lf_where LookingFor
    looking_for) RdrName
    name_to_search

          make_error :: [ImportError] -> [GhcHint] -> TcRnMessage
    make_error [ImportError]
    imp_errs [GhcHint]
    hints = case IsTermInTypes
    if_term_in_type of
            TermInTypes RdrName
    demoted_name -> RdrName -> [GhcHint] -> TcRnMessage
    TcRnTermNameInType RdrName
    demoted_name [GhcHint]
    hints
            IsTermInTypes
    _ -> NotInScopeError
    -> RdrName -> [ImportError] -> [GhcHint] -> TcRnMessage
    TcRnNotInScope NotInScopeError
    err RdrName
    name_to_search [ImportError]
    imp_errs [GhcHint]
    hints

    notInScopeErr :: WhereLooking -> RdrName -> NotInScopeError
    notInScopeErr :: WhereLooking -> RdrName -> NotInScopeError
    notInScopeErr WhereLooking
    where_look RdrName
    rdr_name
      | Just Name
    name <- RdrName -> Maybe Name
    isExact_maybe RdrName
    rdr_name
      = Name -> NotInScopeError
    NoExactName Name
    name
      | WhereLooking
    WL_LocalTop <- WhereLooking
    where_look
      = NotInScopeError
    NoTopLevelBinding
      | Bool
    otherwise
      = NotInScopeError
    NotInScope

    -- | Called from the typechecker ("GHC.Tc.Errors") when we find an unbound variable
    unknownNameSuggestions :: LocalRdrEnv -> WhatLooking -> RdrName -> RnM ([ImportError], [GhcHint])
    unknownNameSuggestions :: LocalRdrEnv
    -> WhatLooking -> RdrName -> RnM ([ImportError], [GhcHint])
    unknownNameSuggestions LocalRdrEnv
    lcl_env WhatLooking
    what_look RdrName
    tried_rdr_name =
      do { dflags  <- IOEnv (Env TcGblEnv TcLclEnv) DynFlags
    forall (m :: * -> *). HasDynFlags m => m DynFlags
    getDynFlags
         ; hpt     <- getHpt
         ; rdr_env <- getGlobalRdrEnv
         ; imp_info <- getImports
         ; curr_mod <- getModule
         ; return $
            unknownNameSuggestions_
              (LF what_look WL_Anywhere)
              dflags hpt curr_mod rdr_env lcl_env imp_info tried_rdr_name }

    unknownNameSuggestions_ :: LookingFor -> DynFlags
                           -> HomePackageTable -> Module
                           -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
                           -> RdrName -> ([ImportError], [GhcHint])
    unknownNameSuggestions_ :: LookingFor
    -> DynFlags
    -> HomePackageTable
    -> Module
    -> GlobalRdrEnv
    -> LocalRdrEnv
    -> ImportAvails
    -> RdrName
    -> ([ImportError], [GhcHint])
    unknownNameSuggestions_ LookingFor
    looking_for DynFlags
    dflags HomePackageTable
    hpt Module
    curr_mod GlobalRdrEnv
    global_env LocalRdrEnv
    local_env
                              ImportAvails
    imports RdrName
    tried_rdr_name = ([ImportError]
    imp_errs, [GhcHint]
    suggs)
      where
        suggs :: [GhcHint]
    suggs = [[GhcHint]] -> [GhcHint]
    forall a. Monoid a => [a] -> a
    mconcat
          [ (NonEmpty SimilarName -> GhcHint) -> [SimilarName] -> [GhcHint]
    forall a b. (NonEmpty a -> b) -> [a] -> [b]
    if_ne (RdrName -> NonEmpty SimilarName -> GhcHint
    SuggestSimilarNames RdrName
    tried_rdr_name) ([SimilarName] -> [GhcHint]) -> [SimilarName] -> [GhcHint]
    forall a b. (a -> b) -> a -> b
    $
              LookingFor
    -> DynFlags
    -> GlobalRdrEnv
    -> LocalRdrEnv
    -> RdrName
    -> [SimilarName]
    similarNameSuggestions LookingFor
    looking_for DynFlags
    dflags GlobalRdrEnv
    global_env LocalRdrEnv
    local_env RdrName
    tried_rdr_name
          , (ImportSuggestion -> GhcHint) -> [ImportSuggestion] -> [GhcHint]
    forall a b. (a -> b) -> [a] -> [b]
    map (OccName -> ImportSuggestion -> GhcHint
    ImportSuggestion (OccName -> ImportSuggestion -> GhcHint)
    -> OccName -> ImportSuggestion -> GhcHint
    forall a b. (a -> b) -> a -> b
    $ RdrName -> OccName
    rdrNameOcc RdrName
    tried_rdr_name) [ImportSuggestion]
    imp_suggs
          , RdrName -> [GhcHint]
    extensionSuggestions RdrName
    tried_rdr_name
          , GlobalRdrEnv -> RdrName -> [GhcHint]
    fieldSelectorSuggestions GlobalRdrEnv
    global_env RdrName
    tried_rdr_name ]
        ([ImportError]
    imp_errs, [ImportSuggestion]
    imp_suggs) = LookingFor
    -> GlobalRdrEnv
    -> HomePackageTable
    -> Module
    -> ImportAvails
    -> RdrName
    -> ([ImportError], [ImportSuggestion])
    importSuggestions LookingFor
    looking_for GlobalRdrEnv
    global_env HomePackageTable
    hpt Module
    curr_mod ImportAvails
    imports RdrName
    tried_rdr_name

        if_ne :: (NonEmpty a -> b) -> [a] -> [b]
        if_ne :: forall a b. (NonEmpty a -> b) -> [a] -> [b]
    if_ne NonEmpty a -> b
    _ []       = []
        if_ne NonEmpty a -> b
    f (a
    a : [a]
    as) = [NonEmpty a -> b
    f (a
    a a -> [a] -> NonEmpty a
    forall a. a -> [a] -> NonEmpty a
    :| [a]
    as)]

    -- | When the name is in scope as field whose selector has been suppressed by
    -- NoFieldSelectors, display a helpful message explaining this.
    fieldSelectorSuggestions :: GlobalRdrEnv -> RdrName -> [GhcHint]
    fieldSelectorSuggestions :: GlobalRdrEnv -> RdrName -> [GhcHint]
    fieldSelectorSuggestions GlobalRdrEnv
    global_env RdrName
    tried_rdr_name
      | [GlobalRdrElt] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [GlobalRdrElt]
    gres = []
      | Bool
    otherwise = [RdrName -> [Name] -> GhcHint
    RemindFieldSelectorSuppressed RdrName
    tried_rdr_name [Name]
    parents]
      where
        gres :: [GlobalRdrElt]
    gres = (GlobalRdrElt -> Bool) -> [GlobalRdrElt] -> [GlobalRdrElt]
    forall a. (a -> Bool) -> [a] -> [a]
    filter GlobalRdrElt -> Bool
    isNoFieldSelectorGRE
             ([GlobalRdrElt] -> [GlobalRdrElt])
    -> [GlobalRdrElt] -> [GlobalRdrElt]
    forall a b. (a -> b) -> a -> b
    $ GlobalRdrEnv -> LookupGRE GREInfo -> [GlobalRdrElt]
    forall info.
    GlobalRdrEnvX info -> LookupGRE info -> [GlobalRdrEltX info]
    lookupGRE GlobalRdrEnv
    global_env (RdrName -> WhichGREs GREInfo -> LookupGRE GREInfo
    forall info. RdrName -> WhichGREs info -> LookupGRE info
    LookupRdrName RdrName
    tried_rdr_name WhichGREs GREInfo
    AllRelevantGREs)
        parents :: [Name]
    parents = [ Name
    parent | ParentIs Name
    parent <- (GlobalRdrElt -> Parent) -> [GlobalRdrElt] -> [Parent]
    forall a b. (a -> b) -> [a] -> [b]
    map GlobalRdrElt -> Parent
    forall info. GlobalRdrEltX info -> Parent
    greParent [GlobalRdrElt]
    gres ]

    similarNameSuggestions :: LookingFor -> DynFlags
                           -> GlobalRdrEnv -> LocalRdrEnv
                           -> RdrName -> [SimilarName]
    similarNameSuggestions :: LookingFor
    -> DynFlags
    -> GlobalRdrEnv
    -> LocalRdrEnv
    -> RdrName
    -> [SimilarName]
    similarNameSuggestions looking_for :: LookingFor
    looking_for@(LF WhatLooking
    what_look WhereLooking
    where_look) DynFlags
    dflags GlobalRdrEnv
    global_env
                           LocalRdrEnv
    local_env RdrName
    tried_rdr_name
      = String -> [(String, SimilarName)] -> [SimilarName]
    forall a. String -> [(String, a)] -> [a]
    fuzzyLookup (DynFlags -> RdrName -> String
    forall a. Outputable a => DynFlags -> a -> String
    showPpr DynFlags
    dflags RdrName
    tried_rdr_name) [(String, SimilarName)]
    all_possibilities
      where
        all_possibilities :: [(String, SimilarName)]
        all_possibilities :: [(String, SimilarName)]
    all_possibilities = case WhatLooking
    what_look of
          WhatLooking
    WL_None -> []
          WhatLooking
    _ -> [ (DynFlags -> RdrName -> String
    forall a. Outputable a => DynFlags -> a -> String
    showPpr DynFlags
    dflags RdrName
    r, RdrName -> Maybe HowInScope -> SimilarName
    SimilarRdrName RdrName
    r (HowInScope -> Maybe HowInScope
    forall a. a -> Maybe a
    Just (HowInScope -> Maybe HowInScope) -> HowInScope -> Maybe HowInScope
    forall a b. (a -> b) -> a -> b
    $ SrcSpan -> HowInScope
    LocallyBoundAt SrcSpan
    loc))
               | (RdrName
    r,SrcSpan
    loc) <- LocalRdrEnv -> [(RdrName, SrcSpan)]
    local_possibilities LocalRdrEnv
    local_env ]
            [(String, SimilarName)]
    -> [(String, SimilarName)] -> [(String, SimilarName)]
    forall a. [a] -> [a] -> [a]
    ++ [ (DynFlags -> RdrName -> String
    forall a. Outputable a => DynFlags -> a -> String
    showPpr DynFlags
    dflags RdrName
    r, SimilarName
    rp) | (RdrName
    r, SimilarName
    rp) <- GlobalRdrEnv -> [(RdrName, SimilarName)]
    global_possibilities GlobalRdrEnv
    global_env ]

        tried_occ :: OccName
    tried_occ     = RdrName -> OccName
    rdrNameOcc RdrName
    tried_rdr_name
        tried_is_sym :: Bool
    tried_is_sym  = OccName -> Bool
    isSymOcc OccName
    tried_occ
        tried_ns :: NameSpace
    tried_ns      = OccName -> NameSpace
    occNameSpace OccName
    tried_occ
        tried_is_qual :: Bool
    tried_is_qual = RdrName -> Bool
    isQual RdrName
    tried_rdr_name

        correct_name_space :: OccName -> Bool
    correct_name_space OccName
    occ =
          (DynFlags -> WhatLooking -> NameSpace -> NameSpace -> Bool
    nameSpacesRelated DynFlags
    dflags WhatLooking
    what_look NameSpace
    tried_ns (OccName -> NameSpace
    occNameSpace OccName
    occ))
          Bool -> Bool -> Bool
    && OccName -> Bool
    isSymOcc OccName
    occ Bool -> Bool -> Bool
    forall a. Eq a => a -> a -> Bool
    == Bool
    tried_is_sym
            -- Treat operator and non-operators as non-matching
            -- This heuristic avoids things like
            --      Not in scope 'f'; perhaps you meant '+' (from Prelude)

        local_ok :: Bool
    local_ok = case WhereLooking
    where_look of { WhereLooking
    WL_Anywhere  -> Bool
    True
                                      ; WhereLooking
    WL_LocalOnly -> Bool
    True
                                      ; WhereLooking
    _            -> Bool
    False }

        local_possibilities :: LocalRdrEnv -> [(RdrName, SrcSpan)]
        local_possibilities :: LocalRdrEnv -> [(RdrName, SrcSpan)]
    local_possibilities LocalRdrEnv
    env
          | Bool
    tried_is_qual = []
          | Bool -> Bool
    not Bool
    local_ok  = []
          | Bool
    otherwise     = [ (OccName -> RdrName
    mkRdrUnqual OccName
    occ, Name -> SrcSpan
    nameSrcSpan Name
    name)
                            | Name
    name <- LocalRdrEnv -> [Name]
    localRdrEnvElts LocalRdrEnv
    env
                            , let occ :: OccName
    occ = Name -> OccName
    nameOccName Name
    name
                            , OccName -> Bool
    correct_name_space OccName
    occ]

        global_possibilities :: GlobalRdrEnv -> [(RdrName, SimilarName)]
        global_possibilities :: GlobalRdrEnv -> [(RdrName, SimilarName)]
    global_possibilities GlobalRdrEnv
    global_env
          | Bool
    tried_is_qual = [ (RdrName
    rdr_qual, RdrName -> Maybe HowInScope -> SimilarName
    SimilarRdrName RdrName
    rdr_qual (HowInScope -> Maybe HowInScope
    forall a. a -> Maybe a
    Just HowInScope
    how))
                            | GlobalRdrElt
    gre <- GlobalRdrEnv -> [GlobalRdrElt]
    forall info. GlobalRdrEnvX info -> [GlobalRdrEltX info]
    globalRdrEnvElts GlobalRdrEnv
    global_env
                            , LookingFor -> GlobalRdrElt -> Bool
    isGreOk LookingFor
    looking_for GlobalRdrElt
    gre
                            , let occ :: OccName
    occ = GlobalRdrElt -> OccName
    forall info. GlobalRdrEltX info -> OccName
    greOccName GlobalRdrElt
    gre
                            , OccName -> Bool
    correct_name_space OccName
    occ
                            , (ModuleName
    mod, HowInScope
    how) <- GlobalRdrElt -> [(ModuleName, HowInScope)]
    qualsInScope GlobalRdrElt
    gre
                            , let rdr_qual :: RdrName
    rdr_qual = ModuleName -> OccName -> RdrName
    mkRdrQual ModuleName
    mod OccName
    occ ]

          | Bool
    otherwise = [ (RdrName
    rdr_unqual, SimilarName
    sim)
                        | GlobalRdrElt
    gre <- GlobalRdrEnv -> [GlobalRdrElt]
    forall info. GlobalRdrEnvX info -> [GlobalRdrEltX info]
    globalRdrEnvElts GlobalRdrEnv
    global_env
                        , LookingFor -> GlobalRdrElt -> Bool
    isGreOk LookingFor
    looking_for GlobalRdrElt
    gre
                        , let occ :: OccName
    occ = GlobalRdrElt -> OccName
    forall info. GlobalRdrEltX info -> OccName
    greOccName GlobalRdrElt
    gre
                              rdr_unqual :: RdrName
    rdr_unqual = OccName -> RdrName
    mkRdrUnqual OccName
    occ
                        , OccName -> Bool
    correct_name_space OccName
    occ
                        , SimilarName
    sim <- case (GlobalRdrElt -> [HowInScope]
    unquals_in_scope GlobalRdrElt
    gre, GlobalRdrElt -> [SimilarName]
    quals_only GlobalRdrElt
    gre) of
                                    (HowInScope
    how:[HowInScope]
    _, [SimilarName]
    _)    -> [ RdrName -> Maybe HowInScope -> SimilarName
    SimilarRdrName RdrName
    rdr_unqual (HowInScope -> Maybe HowInScope
    forall a. a -> Maybe a
    Just HowInScope
    how) ]
                                    ([],    SimilarName
    pr:[SimilarName]
    _) -> [ SimilarName
    pr ]  -- See Note [Only-quals]
                                    ([],    [])   -> [] ]

                  -- Note [Only-quals]
                  -- ~~~~~~~~~~~~~~~~~
                  -- The second alternative returns those names with the same
                  -- OccName as the one we tried, but live in *qualified* imports
                  -- e.g. if you have:
                  --
                  -- > import qualified Data.Map as Map
                  -- > foo :: Map
                  --
                  -- then we suggest @Map.Map@.

        --------------------
        unquals_in_scope :: GlobalRdrElt -> [HowInScope]
        unquals_in_scope :: GlobalRdrElt -> [HowInScope]
    unquals_in_scope (gre :: GlobalRdrElt
    gre@GRE { gre_lcl :: forall info. GlobalRdrEltX info -> Bool
    gre_lcl = Bool
    lcl, gre_imp :: forall info. GlobalRdrEltX info -> Bag ImportSpec
    gre_imp = Bag ImportSpec
    is })
          | Bool
    lcl       = [ SrcSpan -> HowInScope
    LocallyBoundAt (GlobalRdrElt -> SrcSpan
    forall info. GlobalRdrEltX info -> SrcSpan
    greDefinitionSrcSpan GlobalRdrElt
    gre) ]
          | Bool
    otherwise = [ ImpDeclSpec -> HowInScope
    ImportedBy ImpDeclSpec
    ispec
                        | ImportSpec
    i <- Bag ImportSpec -> [ImportSpec]
    forall a. Bag a -> [a]
    bagToList Bag ImportSpec
    is, let ispec :: ImpDeclSpec
    ispec = ImportSpec -> ImpDeclSpec
    is_decl ImportSpec
    i
                        , Bool -> Bool
    not (ImpDeclSpec -> Bool
    is_qual ImpDeclSpec
    ispec) ]

        --------------------
        quals_only :: GlobalRdrElt -> [SimilarName]
        -- Ones for which *only* the qualified version is in scope
        quals_only :: GlobalRdrElt -> [SimilarName]
    quals_only (gre :: GlobalRdrElt
    gre@GRE { gre_imp :: forall info. GlobalRdrEltX info -> Bag ImportSpec
    gre_imp = Bag ImportSpec
    is })
          = [ (RdrName -> Maybe HowInScope -> SimilarName
    SimilarRdrName (ModuleName -> OccName -> RdrName
    mkRdrQual (ImpDeclSpec -> ModuleName
    is_as ImpDeclSpec
    ispec) (GlobalRdrElt -> OccName
    forall info. GlobalRdrEltX info -> OccName
    greOccName GlobalRdrElt
    gre)) (HowInScope -> Maybe HowInScope
    forall a. a -> Maybe a
    Just (HowInScope -> Maybe HowInScope) -> HowInScope -> Maybe HowInScope
    forall a b. (a -> b) -> a -> b
    $ ImpDeclSpec -> HowInScope
    ImportedBy ImpDeclSpec
    ispec))
            | ImportSpec
    i <- Bag ImportSpec -> [ImportSpec]
    forall a. Bag a -> [a]
    bagToList Bag ImportSpec
    is, let ispec :: ImpDeclSpec
    ispec = ImportSpec -> ImpDeclSpec
    is_decl ImportSpec
    i, ImpDeclSpec -> Bool
    is_qual ImpDeclSpec
    ispec ]

    -- | Generate errors and helpful suggestions if a qualified name Mod.foo is not in scope.
    importSuggestions :: LookingFor
                      -> GlobalRdrEnv
                      -> HomePackageTable -> Module
                      -> ImportAvails -> RdrName -> ([ImportError], [ImportSuggestion])
    importSuggestions :: LookingFor
    -> GlobalRdrEnv
    -> HomePackageTable
    -> Module
    -> ImportAvails
    -> RdrName
    -> ([ImportError], [ImportSuggestion])
    importSuggestions LookingFor
    looking_for GlobalRdrEnv
    global_env HomePackageTable
    hpt Module
    currMod ImportAvails
    imports RdrName
    rdr_name
      | WhereLooking
    WL_LocalOnly <- LookingFor -> WhereLooking
    lf_where LookingFor
    looking_for       = ([], [])
      | WhereLooking
    WL_LocalTop  <- LookingFor -> WhereLooking
    lf_where LookingFor
    looking_for       = ([], [])
      | Bool -> Bool
    not (RdrName -> Bool
    isQual RdrName
    rdr_name Bool -> Bool -> Bool
    || RdrName -> Bool
    isUnqual RdrName
    rdr_name) = ([], [])
      | [(Module, ImportedModsVal)] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [(Module, ImportedModsVal)]
    interesting_imports
      , Just ModuleName
    name <- Maybe ModuleName
    mod_name
      , ModuleName -> Bool
    show_not_imported_line ModuleName
    name
      = ([ModuleName -> ImportError
    MissingModule ModuleName
    name], [])
      | Bool
    is_qualified
      , [(Module, ImportedModsVal)] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [(Module, ImportedModsVal)]
    helpful_imports
      , (Module
    mod : [Module]
    mods) <- ((Module, ImportedModsVal) -> Module)
    -> [(Module, ImportedModsVal)] -> [Module]
    forall a b. (a -> b) -> [a] -> [b]
    map (Module, ImportedModsVal) -> Module
    forall a b. (a, b) -> a
    fst [(Module, ImportedModsVal)]
    interesting_imports
      = ([NonEmpty Module -> OccName -> ImportError
    ModulesDoNotExport (Module
    mod Module -> [Module] -> NonEmpty Module
    forall a. a -> [a] -> NonEmpty a
    :| [Module]
    mods) OccName
    occ_name], [])
      | (Module, ImportedModsVal)
    mod : [(Module, ImportedModsVal)]
    mods <- [(Module, ImportedModsVal)]
    helpful_imports_non_hiding
      = ([], [NonEmpty (Module, ImportedModsVal) -> ImportSuggestion
    CouldImportFrom ((Module, ImportedModsVal)
    mod (Module, ImportedModsVal)
    -> [(Module, ImportedModsVal)]
    -> NonEmpty (Module, ImportedModsVal)
    forall a. a -> [a] -> NonEmpty a
    :| [(Module, ImportedModsVal)]
    mods)])
      | (Module, ImportedModsVal)
    mod : [(Module, ImportedModsVal)]
    mods <- [(Module, ImportedModsVal)]
    helpful_imports_hiding
      = ([], [NonEmpty (Module, ImportedModsVal) -> ImportSuggestion
    CouldUnhideFrom ((Module, ImportedModsVal)
    mod (Module, ImportedModsVal)
    -> [(Module, ImportedModsVal)]
    -> NonEmpty (Module, ImportedModsVal)
    forall a. a -> [a] -> NonEmpty a
    :| [(Module, ImportedModsVal)]
    mods)])
      | Bool
    otherwise
      = ([], [])
     where
      is_qualified :: Bool
    is_qualified = RdrName -> Bool
    isQual RdrName
    rdr_name
      (Maybe ModuleName
    mod_name, OccName
    occ_name) = case RdrName
    rdr_name of
        Unqual OccName
    occ_name        -> (Maybe ModuleName
    forall a. Maybe a
    Nothing, OccName
    occ_name)
        Qual ModuleName
    mod_name OccName
    occ_name -> (ModuleName -> Maybe ModuleName
    forall a. a -> Maybe a
    Just ModuleName
    mod_name, OccName
    occ_name)
        RdrName
    _                      -> String -> (Maybe ModuleName, OccName)
    forall a. HasCallStack => String -> a
    panic String
    "importSuggestions: dead code"

      -- What import statements provide "Mod" at all
      -- or, if this is an unqualified name, are not qualified imports
      interesting_imports :: [(Module, ImportedModsVal)]
    interesting_imports = [ (Module
    mod, ImportedModsVal
    imp)
        | (Module
    mod, [ImportedBy]
    mod_imports) <- ModuleEnv [ImportedBy] -> [(Module, [ImportedBy])]
    forall a. ModuleEnv a -> [(Module, a)]
    moduleEnvToList (ImportAvails -> ModuleEnv [ImportedBy]
    imp_mods ImportAvails
    imports)
        , Just ImportedModsVal
    imp <- Maybe ImportedModsVal -> [Maybe ImportedModsVal]
    forall a. a -> [a]
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe ImportedModsVal -> [Maybe ImportedModsVal])
    -> Maybe ImportedModsVal -> [Maybe ImportedModsVal]
    forall a b. (a -> b) -> a -> b
    $ [ImportedModsVal] -> Maybe ImportedModsVal
    pick ([ImportedBy] -> [ImportedModsVal]
    importedByUser [ImportedBy]
    mod_imports)
        ]

      -- We want to keep only one for each original module; preferably one with an
      -- explicit import list (for no particularly good reason)
      pick :: [ImportedModsVal] -> Maybe ImportedModsVal
      pick :: [ImportedModsVal] -> Maybe ImportedModsVal
    pick = [ImportedModsVal] -> Maybe ImportedModsVal
    forall a. [a] -> Maybe a
    listToMaybe ([ImportedModsVal] -> Maybe ImportedModsVal)
    -> ([ImportedModsVal] -> [ImportedModsVal])
    -> [ImportedModsVal]
    -> Maybe ImportedModsVal
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ImportedModsVal -> ImportedModsVal -> Ordering)
    -> [ImportedModsVal] -> [ImportedModsVal]
    forall a. (a -> a -> Ordering) -> [a] -> [a]
    sortBy ImportedModsVal -> ImportedModsVal -> Ordering
    cmp ([ImportedModsVal] -> [ImportedModsVal])
    -> ([ImportedModsVal] -> [ImportedModsVal])
    -> [ImportedModsVal]
    -> [ImportedModsVal]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (ImportedModsVal -> Bool) -> [ImportedModsVal] -> [ImportedModsVal]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ImportedModsVal -> Bool
    select
        where select :: ImportedModsVal -> Bool
    select ImportedModsVal
    imv = case Maybe ModuleName
    mod_name of Just ModuleName
    name -> ImportedModsVal -> ModuleName
    imv_name ImportedModsVal
    imv ModuleName -> ModuleName -> Bool
    forall a. Eq a => a -> a -> Bool
    == ModuleName
    name
                                            Maybe ModuleName
    Nothing   -> Bool -> Bool
    not (ImportedModsVal -> Bool
    imv_qualified ImportedModsVal
    imv)
              cmp :: ImportedModsVal -> ImportedModsVal -> Ordering
    cmp = (Bool -> Bool -> Ordering)
    -> (ImportedModsVal -> Bool)
    -> ImportedModsVal
    -> ImportedModsVal
    -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    on Bool -> Bool -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare ImportedModsVal -> Bool
    imv_is_hiding (ImportedModsVal -> ImportedModsVal -> Ordering)
    -> (ImportedModsVal -> ImportedModsVal -> Ordering)
    -> ImportedModsVal
    -> ImportedModsVal
    -> Ordering
    forall a. Semigroup a => a -> a -> a
    S.<> (SrcSpan -> SrcSpan -> Ordering)
    -> (ImportedModsVal -> SrcSpan)
    -> ImportedModsVal
    -> ImportedModsVal
    -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    on SrcSpan -> SrcSpan -> Ordering
    SrcLoc.leftmost_smallest ImportedModsVal -> SrcSpan
    imv_span

      -- Which of these would export a 'foo'
      -- (all of these are restricted imports, because if they were not, we
      -- wouldn't have an out-of-scope error in the first place)
      helpful_imports :: [(Module, ImportedModsVal)]
    helpful_imports = ((Module, ImportedModsVal) -> Bool)
    -> [(Module, ImportedModsVal)] -> [(Module, ImportedModsVal)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Module, ImportedModsVal) -> Bool
    helpful [(Module, ImportedModsVal)]
    interesting_imports
        where helpful :: (Module, ImportedModsVal) -> Bool
    helpful (Module
    _,ImportedModsVal
    imv)
                = (GlobalRdrElt -> Bool) -> [GlobalRdrElt] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any (LookingFor -> GlobalRdrElt -> Bool
    isGreOk LookingFor
    looking_for) ([GlobalRdrElt] -> Bool) -> [GlobalRdrElt] -> Bool
    forall a b. (a -> b) -> a -> b
    $
                  GlobalRdrEnv -> LookupGRE GREInfo -> [GlobalRdrElt]
    forall info.
    GlobalRdrEnvX info -> LookupGRE info -> [GlobalRdrEltX info]
    lookupGRE (ImportedModsVal -> GlobalRdrEnv
    imv_all_exports ImportedModsVal
    imv)
                    (OccName -> WhichGREs GREInfo -> LookupGRE GREInfo
    forall info. OccName -> WhichGREs info -> LookupGRE info
    LookupOccName OccName
    occ_name (WhichGREs GREInfo -> LookupGRE GREInfo)
    -> WhichGREs GREInfo -> LookupGRE GREInfo
    forall a b. (a -> b) -> a -> b
    $ FieldsOrSelectors -> WhichGREs GREInfo
    RelevantGREsFOS FieldsOrSelectors
    WantNormal)

      -- Which of these do that because of an explicit hiding list resp. an
      -- explicit import list
      ([(Module, ImportedModsVal)]
    helpful_imports_hiding, [(Module, ImportedModsVal)]
    helpful_imports_non_hiding)
        = ((Module, ImportedModsVal) -> Bool)
    -> [(Module, ImportedModsVal)]
    -> ([(Module, ImportedModsVal)], [(Module, ImportedModsVal)])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    partition (ImportedModsVal -> Bool
    imv_is_hiding (ImportedModsVal -> Bool)
    -> ((Module, ImportedModsVal) -> ImportedModsVal)
    -> (Module, ImportedModsVal)
    -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Module, ImportedModsVal) -> ImportedModsVal
    forall a b. (a, b) -> b
    snd) [(Module, ImportedModsVal)]
    helpful_imports

      -- See Note [When to show/hide the module-not-imported line]
      show_not_imported_line :: ModuleName -> Bool                    -- #15611
      show_not_imported_line :: ModuleName -> Bool
    show_not_imported_line ModuleName
    modnam
          | ModuleName
    modnam ModuleName -> [ModuleName] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [ModuleName]
    glob_mods               = Bool
    False    -- #14225     -- 1
          | Module -> ModuleName
    forall unit. GenModule unit -> ModuleName
    moduleName Module
    currMod ModuleName -> ModuleName -> Bool
    forall a. Eq a => a -> a -> Bool
    == ModuleName
    modnam          = Bool
    False                  -- 2.1
          | ModuleName -> [Unique] -> Bool
    forall {a}. Uniquable a => a -> [Unique] -> Bool
    is_last_loaded_mod ModuleName
    modnam [Unique]
    hpt_uniques = Bool
    False                  -- 2.2
          | Bool
    otherwise                             = Bool
    True
        where
          hpt_uniques :: [Unique]
    hpt_uniques = ((Unique, HomeModInfo) -> Unique)
    -> [(Unique, HomeModInfo)] -> [Unique]
    forall a b. (a -> b) -> [a] -> [b]
    map (Unique, HomeModInfo) -> Unique
    forall a b. (a, b) -> a
    fst (HomePackageTable -> [(Unique, HomeModInfo)]
    forall {k} (key :: k) elt. UniqDFM key elt -> [(Unique, elt)]
    udfmToList HomePackageTable
    hpt)
          is_last_loaded_mod :: a -> [Unique] -> Bool
    is_last_loaded_mod a
    modnam [Unique]
    uniqs = [Unique] -> Maybe Unique
    forall a. [a] -> Maybe a
    lastMaybe [Unique]
    uniqs Maybe Unique -> Maybe Unique -> Bool
    forall a. Eq a => a -> a -> Bool
    == Unique -> Maybe Unique
    forall a. a -> Maybe a
    Just (a -> Unique
    forall a. Uniquable a => a -> Unique
    getUnique a
    modnam)
          glob_mods :: [ModuleName]
    glob_mods = [ModuleName] -> [ModuleName]
    forall a. Eq a => [a] -> [a]
    nub [ ModuleName
    mod
                          | GlobalRdrElt
    gre <- GlobalRdrEnv -> [GlobalRdrElt]
    forall info. GlobalRdrEnvX info -> [GlobalRdrEltX info]
    globalRdrEnvElts GlobalRdrEnv
    global_env
                          , (ModuleName
    mod, HowInScope
    _) <- GlobalRdrElt -> [(ModuleName, HowInScope)]
    qualsInScope GlobalRdrElt
    gre
                          ]

    extensionSuggestions :: RdrName -> [GhcHint]
    extensionSuggestions :: RdrName -> [GhcHint]
    extensionSuggestions RdrName
    rdrName
      | RdrName
    rdrName RdrName -> RdrName -> Bool
    forall a. Eq a => a -> a -> Bool
    == NameSpace -> FastString -> RdrName
    mkUnqual NameSpace
    varName (String -> FastString
    fsLit String
    "mdo") Bool -> Bool -> Bool
    ||
        RdrName
    rdrName RdrName -> RdrName -> Bool
    forall a. Eq a => a -> a -> Bool
    == NameSpace -> FastString -> RdrName
    mkUnqual NameSpace
    varName (String -> FastString
    fsLit String
    "rec")
      = [LanguageExtensionHint -> GhcHint
    SuggestExtension (LanguageExtensionHint -> GhcHint)
    -> LanguageExtensionHint -> GhcHint
    forall a b. (a -> b) -> a -> b
    $ SDoc -> Extension -> LanguageExtensionHint
    SuggestSingleExtension SDoc
    forall doc. IsOutput doc => doc
    empty Extension
    LangExt.RecursiveDo]
      | Bool
    otherwise
      = []

    qualsInScope :: GlobalRdrElt -> [(ModuleName, HowInScope)]
    -- Ones for which the qualified version is in scope
    qualsInScope :: GlobalRdrElt -> [(ModuleName, HowInScope)]
    qualsInScope gre :: GlobalRdrElt
    gre@GRE { gre_lcl :: forall info. GlobalRdrEltX info -> Bool
    gre_lcl = Bool
    lcl, gre_imp :: forall info. GlobalRdrEltX info -> Bag ImportSpec
    gre_imp = Bag ImportSpec
    is }
          | Bool
    lcl = case GlobalRdrElt -> Maybe Module
    forall info. GlobalRdrEltX info -> Maybe Module
    greDefinitionModule GlobalRdrElt
    gre of
                    Maybe Module
    Nothing -> []
                    Just Module
    m  -> [(Module -> ModuleName
    forall unit. GenModule unit -> ModuleName
    moduleName Module
    m, SrcSpan -> HowInScope
    LocallyBoundAt (GlobalRdrElt -> SrcSpan
    forall info. GlobalRdrEltX info -> SrcSpan
    greDefinitionSrcSpan GlobalRdrElt
    gre))]
          | Bool
    otherwise = [ (ImpDeclSpec -> ModuleName
    is_as ImpDeclSpec
    ispec, ImpDeclSpec -> HowInScope
    ImportedBy ImpDeclSpec
    ispec)
                        | ImportSpec
    i <- Bag ImportSpec -> [ImportSpec]
    forall a. Bag a -> [a]
    bagToList Bag ImportSpec
    is, let ispec :: ImpDeclSpec
    ispec = ImportSpec -> ImpDeclSpec
    is_decl ImportSpec
    i ]

    isGreOk :: LookingFor -> GlobalRdrElt -> Bool
    isGreOk :: LookingFor -> GlobalRdrElt -> Bool
    isGreOk (LF WhatLooking
    what_look WhereLooking
    where_look) GlobalRdrElt
    gre = Bool
    what_ok Bool -> Bool -> Bool
    && Bool
    where_ok
      where
        -- when looking for record fields, what_ok checks whether the GRE is a
        -- record field. Otherwise, it checks whether the GRE is a record field
        -- defined in a module with -XNoFieldSelectors - it wouldn't be a useful
        -- suggestion in that case.
        what_ok :: Bool
    what_ok  = case WhatLooking
    what_look of
                     WhatLooking
    WL_RecField -> GlobalRdrElt -> Bool
    forall info. GlobalRdrEltX info -> Bool
    isRecFldGRE GlobalRdrElt
    gre
                     WhatLooking
    _           -> Bool -> Bool
    not (GlobalRdrElt -> Bool
    isNoFieldSelectorGRE GlobalRdrElt
    gre)

        where_ok :: Bool
    where_ok = case WhereLooking
    where_look of
                     WhereLooking
    WL_LocalTop  -> GlobalRdrElt -> Bool
    forall info. GlobalRdrEltX info -> Bool
    isLocalGRE GlobalRdrElt
    gre
                     WhereLooking
    WL_LocalOnly -> Bool
    False
                     WhereLooking
    _            -> Bool
    True

    -- see Note [Related name spaces]
    nameSpacesRelated :: DynFlags    -- ^ to find out whether -XDataKinds is enabled
                      -> WhatLooking -- ^ What kind of name are we looking for
                      -> NameSpace   -- ^ Name space of the original name
                      -> NameSpace   -- ^ Name space of a name that might have been meant
                      -> Bool
    nameSpacesRelated :: DynFlags -> WhatLooking -> NameSpace -> NameSpace -> Bool
    nameSpacesRelated DynFlags
    dflags WhatLooking
    what_looking NameSpace
    ns NameSpace
    ns'
      | NameSpace
    ns NameSpace -> NameSpace -> Bool
    forall a. Eq a => a -> a -> Bool
    == NameSpace
    ns'
      = Bool
    True
      | Bool
    otherwise
      = [Bool] -> Bool
    forall (t :: * -> *). Foldable t => t Bool -> Bool
    or [ NameSpace -> Bool
    other_ns NameSpace
    ns'
           | (NameSpace -> Bool
    orig_ns, [(NameSpace -> Bool, [WhatLooking])]
    others) <- [(NameSpace -> Bool, [(NameSpace -> Bool, [WhatLooking])])]
    other_namespaces
           , NameSpace -> Bool
    orig_ns NameSpace
    ns
           , (NameSpace -> Bool
    other_ns, [WhatLooking]
    wls) <- [(NameSpace -> Bool, [WhatLooking])]
    others
           , WhatLooking
    what_looking WhatLooking -> [WhatLooking] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` WhatLooking
    WL_Anything WhatLooking -> [WhatLooking] -> [WhatLooking]
    forall a. a -> [a] -> [a]
    : [WhatLooking]
    wls
           ]
      where
        -- explanation:
        -- [(orig_ns, [(other_ns, what_looking_possibilities)])]
        -- A particular other_ns is related if the original namespace is orig_ns
        -- and what_looking is either WL_Anything or is one of
        -- what_looking_possibilities
        other_namespaces :: [(NameSpace -> Bool, [(NameSpace -> Bool, [WhatLooking])])]
    other_namespaces =
          [ (NameSpace -> Bool
    isVarNameSpace     , [(NameSpace -> Bool
    isFieldNameSpace  , [WhatLooking
    WL_RecField])
                                  ,(NameSpace -> Bool
    isDataConNameSpace, [WhatLooking
    WL_Constructor])])
          , (NameSpace -> Bool
    isDataConNameSpace , [(NameSpace -> Bool
    isVarNameSpace    , [WhatLooking
    WL_RecField])])
          , (NameSpace -> Bool
    isTvNameSpace      , (NameSpace -> Bool
    isTcClsNameSpace   , [WhatLooking
    WL_Constructor])
                                  (NameSpace -> Bool, [WhatLooking])
    -> [(NameSpace -> Bool, [WhatLooking])]
    -> [(NameSpace -> Bool, [WhatLooking])]
    forall a. a -> [a] -> [a]
    : [(NameSpace -> Bool, [WhatLooking])]
    promoted_datacons)
          , (NameSpace -> Bool
    isTcClsNameSpace   , (NameSpace -> Bool
    isTvNameSpace     , [])
                                  (NameSpace -> Bool, [WhatLooking])
    -> [(NameSpace -> Bool, [WhatLooking])]
    -> [(NameSpace -> Bool, [WhatLooking])]
    forall a. a -> [a] -> [a]
    : [(NameSpace -> Bool, [WhatLooking])]
    promoted_datacons)
          ]
        -- If -XDataKinds is enabled, the data constructor name space is also
        -- related to the type-level name spaces
        data_kinds :: Bool
    data_kinds = Extension -> DynFlags -> Bool
    xopt Extension
    LangExt.DataKinds DynFlags
    dflags
        promoted_datacons :: [(NameSpace -> Bool, [WhatLooking])]
    promoted_datacons = [(NameSpace -> Bool
    isDataConNameSpace, [WhatLooking
    WL_Constructor]) | Bool
    data_kinds]

    {- Note [Related name spaces]
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Name spaces are related if there is a chance to mean the one when one writes
    the other, i.e. variables <-> data constructors and type variables <-> type
    constructors.

    In most contexts, this mistake can happen in both directions. Not so in
    patterns:

    When a user writes
            foo (just a) = ...
    It is possible that they meant to use `Just` instead. However, when they write
            foo (Map a) = ...
    It is unlikely that they mean to use `map`, since variables cannot be used here.

    Similarly, when we look for record fields, data constructors are not in a
    related namespace.

    Furthermore, with -XDataKinds, the data constructor name space is related to
    the type variable and type constructor name spaces.

    Note [When to show/hide the module-not-imported line]           -- #15611
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    For the error message:
        Not in scope X.Y
        Module X does not export Y
        No module named ‘X’ is imported:
    there are 2 cases, where we hide the last "no module is imported" line:
    1. If the module X has been imported.
    2. If the module X is the current module. There are 2 subcases:
       2.1 If the unknown module name is in a input source file,
           then we can use the getModule function to get the current module name.
           (See test T15611a)
       2.2 If the unknown module name has been entered by the user in GHCi,
           then the getModule function returns something like "interactive:Ghci1",
           and we have to check the current module in the last added entry of
           the HomePackageTable. (See test T15611b)
    -}