    {-# LANGUAGE PatternSynonyms #-}

    {-

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

    -}
    module GHC.Rename.Unbound
       ( mkUnboundName
       , mkUnboundNameRdr
       , isUnboundName
       , reportUnboundName
       , reportUnboundName'
       , unknownNameSuggestions
       , WhatLooking(..)
       , WhereLooking(..)
       , LookingFor(..)
       , unboundName
       , unboundNameX
       , notInScopeErr
       , nameSpacesRelated
       )
    where

    import GHC.Prelude

    import GHC.Driver.Session
    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.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 )

    {-
    ************************************************************************
    *                                                                      *
                   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
                         }

    mkUnboundNameRdr :: RdrName -> Name
    mkUnboundNameRdr :: RdrName -> Name
    mkUnboundNameRdr RdrName
    rdr = OccName -> Name
    mkUnboundName (RdrName -> OccName
    rdrNameOcc 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
      = do  { DynFlags
    dflags <- IOEnv (Env TcGblEnv TcLclEnv) DynFlags
    forall (m :: * -> *). HasDynFlags m => m DynFlags
    getDynFlags
            ; let show_helpful_errors :: Bool
    show_helpful_errors = GeneralFlag -> DynFlags -> Bool
    gopt GeneralFlag
    Opt_HelpfulErrors DynFlags
    dflags
                  err :: NotInScopeError
    err = WhereLooking -> RdrName -> NotInScopeError
    notInScopeErr (LookingFor -> WhereLooking
    lf_where LookingFor
    looking_for) RdrName
    rdr_name
            ; if Bool -> Bool
    not Bool
    show_helpful_errors
              then TcRnMessage -> IOEnv (Env TcGblEnv TcLclEnv) ()
    addErr (TcRnMessage -> IOEnv (Env TcGblEnv TcLclEnv) ())
    -> TcRnMessage -> IOEnv (Env TcGblEnv TcLclEnv) ()
    forall a b. (a -> b) -> a -> b
    $ NotInScopeError
    -> RdrName -> [ImportError] -> [GhcHint] -> TcRnMessage
    TcRnNotInScope NotInScopeError
    err RdrName
    rdr_name [] [GhcHint]
    hints
              else do { LocalRdrEnv
    local_env  <- RnM LocalRdrEnv
    getLocalRdrEnv
                      ; GlobalRdrEnv
    global_env <- TcRn GlobalRdrEnv
    getGlobalRdrEnv
                      ; ImportAvails
    impInfo <- TcRn ImportAvails
    getImports
                      ; Module
    currmod <- IOEnv (Env TcGblEnv TcLclEnv) Module
    forall (m :: * -> *). HasModule m => m Module
    getModule
                      ; HomePackageTable
    hpt <- TcRnIf TcGblEnv TcLclEnv HomePackageTable
    forall gbl lcl. TcRnIf gbl lcl HomePackageTable
    getHpt
                      ; let ([ImportError]
    imp_errs, [GhcHint]
    suggs) =
                              LookingFor
    -> DynFlags
    -> HomePackageTable
    -> Module
    -> GlobalRdrEnv
    -> LocalRdrEnv
    -> ImportAvails
    -> RdrName
    -> ([ImportError], [GhcHint])
    unknownNameSuggestions_ LookingFor
    looking_for
                                DynFlags
    dflags HomePackageTable
    hpt Module
    currmod GlobalRdrEnv
    global_env LocalRdrEnv
    local_env ImportAvails
    impInfo
                                RdrName
    rdr_name
                      ; TcRnMessage -> IOEnv (Env TcGblEnv TcLclEnv) ()
    addErr (TcRnMessage -> IOEnv (Env TcGblEnv TcLclEnv) ())
    -> TcRnMessage -> IOEnv (Env TcGblEnv TcLclEnv) ()
    forall a b. (a -> b) -> a -> b
    $
                          NotInScopeError
    -> RdrName -> [ImportError] -> [GhcHint] -> TcRnMessage
    TcRnNotInScope NotInScopeError
    err RdrName
    rdr_name [ImportError]
    imp_errs ([GhcHint]
    hints [GhcHint] -> [GhcHint] -> [GhcHint]
    forall a. [a] -> [a] -> [a]
    ++ [GhcHint]
    suggs) }
            ; Name -> RnM Name
    forall a. a -> IOEnv (Env TcGblEnv TcLclEnv) a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (RdrName -> Name
    mkUnboundNameRdr RdrName
    rdr_name) }

    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 :: WhatLooking -> DynFlags
                           -> HomePackageTable -> Module
                           -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
                           -> RdrName -> ([ImportError], [GhcHint])
    unknownNameSuggestions :: WhatLooking
    -> DynFlags
    -> HomePackageTable
    -> Module
    -> GlobalRdrEnv
    -> LocalRdrEnv
    -> ImportAvails
    -> RdrName
    -> ([ImportError], [GhcHint])
    unknownNameSuggestions WhatLooking
    what_look = LookingFor
    -> DynFlags
    -> HomePackageTable
    -> Module
    -> GlobalRdrEnv
    -> LocalRdrEnv
    -> ImportAvails
    -> RdrName
    -> ([ImportError], [GhcHint])
    unknownNameSuggestions_ (WhatLooking -> WhereLooking -> LookingFor
    LF WhatLooking
    what_look WhereLooking
    WL_Anywhere)

    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 ImportSuggestion -> GhcHint
    ImportSuggestion [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
    $
                   RdrName -> GlobalRdrEnv -> [GlobalRdrElt]
    lookupGRE_RdrName' RdrName
    tried_rdr_name GlobalRdrEnv
    global_env
        parents :: [Name]
    parents = [ Name
    parent | ParentIs Name
    parent <- (GlobalRdrElt -> Parent) -> [GlobalRdrElt] -> [Parent]
    forall a b. (a -> b) -> [a] -> [b]
    map GlobalRdrElt -> Parent
    gre_par [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 -> HowInScope -> SimilarName
    SimilarRdrName RdrName
    r (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 -> HowInScope -> SimilarName
    SimilarRdrName RdrName
    rdr_qual HowInScope
    how)
                            | GlobalRdrElt
    gre <- GlobalRdrEnv -> [GlobalRdrElt]
    globalRdrEnvElts GlobalRdrEnv
    global_env
                            , LookingFor -> GlobalRdrElt -> Bool
    isGreOk LookingFor
    looking_for GlobalRdrElt
    gre
                            , let occ :: OccName
    occ = GlobalRdrElt -> 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]
    globalRdrEnvElts GlobalRdrEnv
    global_env
                        , LookingFor -> GlobalRdrElt -> Bool
    isGreOk LookingFor
    looking_for GlobalRdrElt
    gre
                        , let occ :: OccName
    occ = GlobalRdrElt -> 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 -> HowInScope -> SimilarName
    SimilarRdrName RdrName
    rdr_unqual 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 :: GlobalRdrElt -> Bool
    gre_lcl = Bool
    lcl, gre_imp :: GlobalRdrElt -> Bag ImportSpec
    gre_imp = Bag ImportSpec
    is })
          | Bool
    lcl       = [ SrcSpan -> HowInScope
    LocallyBoundAt (GlobalRdrElt -> 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 :: GlobalRdrElt -> Bag ImportSpec
    gre_imp = Bag ImportSpec
    is })
          = [ (RdrName -> HowInScope -> SimilarName
    SimilarRdrName (ModuleName -> OccName -> RdrName
    mkRdrQual (ImpDeclSpec -> ModuleName
    is_as ImpDeclSpec
    ispec) (GlobalRdrElt -> OccName
    greOccName GlobalRdrElt
    gre)) (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) -> OccName -> ImportSuggestion
    CouldImportFrom ((Module, ImportedModsVal)
    mod (Module, ImportedModsVal)
    -> [(Module, ImportedModsVal)]
    -> NonEmpty (Module, ImportedModsVal)
    forall a. a -> [a] -> NonEmpty a
    :| [(Module, ImportedModsVal)]
    mods) OccName
    occ_name])
      | (Module, ImportedModsVal)
    mod : [(Module, ImportedModsVal)]
    mods <- [(Module, ImportedModsVal)]
    helpful_imports_hiding
      = ([], [NonEmpty (Module, ImportedModsVal) -> OccName -> ImportSuggestion
    CouldUnhideFrom ((Module, ImportedModsVal)
    mod (Module, ImportedModsVal)
    -> [(Module, ImportedModsVal)]
    -> NonEmpty (Module, ImportedModsVal)
    forall a. a -> [a] -> NonEmpty a
    :| [(Module, ImportedModsVal)]
    mods) OccName
    occ_name])
      | 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
    error 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 ImportedModsVal
    a ImportedModsVal
    b =
                (Bool -> Bool -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare (Bool -> Bool -> Ordering)
    -> (ImportedModsVal -> Bool)
    -> ImportedModsVal
    -> ImportedModsVal
    -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` ImportedModsVal -> Bool
    imv_is_hiding) ImportedModsVal
    a ImportedModsVal
    b
                  Ordering -> Ordering -> Ordering
    `thenCmp`
                (SrcSpan -> SrcSpan -> Ordering
    SrcLoc.leftmost_smallest (SrcSpan -> SrcSpan -> Ordering)
    -> (ImportedModsVal -> SrcSpan)
    -> ImportedModsVal
    -> ImportedModsVal
    -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` ImportedModsVal -> SrcSpan
    imv_span) ImportedModsVal
    a ImportedModsVal
    b

      -- 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 -> OccName -> [GlobalRdrElt]
    lookupGlobalRdrEnv (ImportedModsVal -> GlobalRdrEnv
    imv_all_exports ImportedModsVal
    imv) OccName
    occ_name

      -- 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 key elt. UniqDFM key elt -> [(Unique, elt)]
    udfmToList HomePackageTable
    hpt)
          is_last_loaded_mod :: a -> [Unique] -> Bool
    is_last_loaded_mod a
    _ []         = Bool
    False
          is_last_loaded_mod a
    modnam [Unique]
    uniqs = [Unique] -> Unique
    forall a. HasCallStack => [a] -> a
    last [Unique]
    uniqs Unique -> Unique -> Bool
    forall a. Eq a => a -> a -> Bool
    == 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]
    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
    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 :: GlobalRdrElt -> Bool
    gre_lcl = Bool
    lcl, gre_imp :: GlobalRdrElt -> Bag ImportSpec
    gre_imp = Bag ImportSpec
    is }
          | Bool
    lcl = case GlobalRdrElt -> 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
    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
    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
    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
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` NameSpace
    ns NameSpace -> [NameSpace] -> [NameSpace]
    forall a. a -> [a] -> [a]
    : [ NameSpace
    other_ns
                        | (NameSpace
    orig_ns, [(NameSpace, [WhatLooking])]
    others) <- [(NameSpace, [(NameSpace, [WhatLooking])])]
    other_namespaces
                        , NameSpace
    ns NameSpace -> NameSpace -> Bool
    forall a. Eq a => a -> a -> Bool
    == NameSpace
    orig_ns
                        , (NameSpace
    other_ns, [WhatLooking]
    wls) <- [(NameSpace, [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, [(NameSpace, [WhatLooking])])]
    other_namespaces =
          [ (NameSpace
    varName  , [(NameSpace
    dataName, [WhatLooking
    WL_Constructor])])
          , (NameSpace
    dataName , [(NameSpace
    varName , [WhatLooking
    WL_RecField])])
          , (NameSpace
    tvName   , (NameSpace
    tcClsName, [WhatLooking
    WL_Constructor]) (NameSpace, [WhatLooking])
    -> [(NameSpace, [WhatLooking])] -> [(NameSpace, [WhatLooking])]
    forall a. a -> [a] -> [a]
    : [(NameSpace, [WhatLooking])]
    promoted_datacons)
          , (NameSpace
    tcClsName, (NameSpace
    tvName   , []) (NameSpace, [WhatLooking])
    -> [(NameSpace, [WhatLooking])] -> [(NameSpace, [WhatLooking])]
    forall a. a -> [a] -> [a]
    : [(NameSpace, [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, [WhatLooking])]
    promoted_datacons = [(NameSpace
    dataName, [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)
    -}