{-# LANGUAGE FlexibleContexts #-}

module GHC.Iface.Errors
  ( badIfaceFile
  , cannotFindInterface
  , cantFindInstalledErr
  , cannotFindModule
  ) where

import GHC.Platform.Profile
import GHC.Platform.Ways
import GHC.Utils.Panic.Plain
import GHC.Driver.DynFlags
import GHC.Driver.Env
import GHC.Data.Maybe
import GHC.Prelude
import GHC.Unit
import GHC.Unit.Env
import GHC.Unit.Finder.Types
import GHC.Utils.Outputable as Outputable
import GHC.Iface.Errors.Types

-- -----------------------------------------------------------------------------
-- Error messages

badIfaceFile :: String -> SDoc -> SDoc
badIfaceFile :: String -> SDoc -> SDoc
badIfaceFile String
file SDoc
err
  = [SDoc] -> SDoc
forall doc. IsDoc doc => [doc] -> doc
vcat [String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Bad interface file:" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+> String -> SDoc
forall doc. IsLine doc => String -> doc
text String
file,
          Int -> SDoc -> SDoc
nest Int
4 SDoc
err]

cannotFindInterface :: UnitState -> Maybe HomeUnit -> Profile
                    -> ModuleName -> InstalledFindResult -> MissingInterfaceError
cannotFindInterface :: UnitState
-> Maybe HomeUnit
-> Profile
-> ModuleName
-> InstalledFindResult
-> MissingInterfaceError
cannotFindInterface UnitState
us Maybe HomeUnit
mhu Profile
p ModuleName
mn InstalledFindResult
ifr =
  UnitState
-> FindingModuleOrInterface
-> CantFindInstalled
-> MissingInterfaceError
CantFindErr UnitState
us FindingModuleOrInterface
FindingInterface (CantFindInstalled -> MissingInterfaceError)
-> CantFindInstalled -> MissingInterfaceError
forall a b. (a -> b) -> a -> b
$
  UnitState
-> Maybe HomeUnit
-> Profile
-> ModuleName
-> InstalledFindResult
-> CantFindInstalled
cantFindInstalledErr UnitState
us Maybe HomeUnit
mhu Profile
p ModuleName
mn InstalledFindResult
ifr

cantFindInstalledErr
    :: UnitState
    -> Maybe HomeUnit
    -> Profile
    -> ModuleName
    -> InstalledFindResult
    -> CantFindInstalled
cantFindInstalledErr :: UnitState
-> Maybe HomeUnit
-> Profile
-> ModuleName
-> InstalledFindResult
-> CantFindInstalled
cantFindInstalledErr UnitState
unit_state Maybe HomeUnit
mhome_unit Profile
profile ModuleName
mod_name InstalledFindResult
find_result
  = ModuleName -> CantFindInstalledReason -> CantFindInstalled
CantFindInstalled ModuleName
mod_name CantFindInstalledReason
more_info
  where
    build_tag :: String
build_tag  = Ways -> String
waysBuildTag (Profile -> Ways
profileWays Profile
profile)

    more_info :: CantFindInstalledReason
more_info
      = case InstalledFindResult
find_result of
            InstalledNoPackage UnitId
pkg
                -> UnitId -> [UnitInfo] -> CantFindInstalledReason
NoUnitIdMatching UnitId
pkg (UnitState -> PackageId -> [UnitInfo]
searchPackageId UnitState
unit_state (FastString -> PackageId
PackageId (UnitId -> FastString
unitIdFS UnitId
pkg)))

            InstalledNotFound [String]
files Maybe UnitId
mb_pkg
                | Just UnitId
pkg <- Maybe UnitId
mb_pkg
                , Maybe HomeUnit -> UnitId -> Bool
forall u. Maybe (GenHomeUnit u) -> UnitId -> Bool
notHomeUnitId Maybe HomeUnit
mhome_unit UnitId
pkg
                -> UnitId -> [String] -> CantFindInstalledReason
not_found_in_package UnitId
pkg [String]
files

                | [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
files
                -> CantFindInstalledReason
NotAModule

                | Bool
otherwise
                -> [String] -> CantFindInstalledReason
CouldntFindInFiles [String]
files

            InstalledFindResult
_ -> String -> CantFindInstalledReason
forall a. HasCallStack => String -> a
panic String
"cantFindInstalledErr"

    not_found_in_package :: UnitId -> [String] -> CantFindInstalledReason
not_found_in_package UnitId
pkg [String]
files
       | String
build_tag String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
""
       = let
            build :: String
build = if String
build_tag String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"p" then String
"profiling"
                                        else String
"\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
build_tag String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
         in
         String -> UnitId -> [String] -> CantFindInstalledReason
MissingPackageWayFiles String
build UnitId
pkg [String]
files
       | Bool
otherwise
       = UnitId -> [String] -> CantFindInstalledReason
MissingPackageFiles UnitId
pkg [String]
files



cannotFindModule :: HscEnv -> ModuleName -> FindResult -> MissingInterfaceError
cannotFindModule :: HscEnv -> ModuleName -> FindResult -> MissingInterfaceError
cannotFindModule HscEnv
hsc_env = UnitEnv
-> Profile -> ModuleName -> FindResult -> MissingInterfaceError
cannotFindModule'
    (HscEnv -> UnitEnv
hsc_unit_env HscEnv
hsc_env)
    (DynFlags -> Profile
targetProfile (HscEnv -> DynFlags
hsc_dflags HscEnv
hsc_env))


cannotFindModule' :: UnitEnv -> Profile -> ModuleName -> FindResult
                  -> MissingInterfaceError
cannotFindModule' :: UnitEnv
-> Profile -> ModuleName -> FindResult -> MissingInterfaceError
cannotFindModule' UnitEnv
unit_env Profile
profile ModuleName
mod FindResult
res =
  UnitState
-> FindingModuleOrInterface
-> CantFindInstalled
-> MissingInterfaceError
CantFindErr (HasDebugCallStack => UnitEnv -> UnitState
UnitEnv -> UnitState
ue_units UnitEnv
unit_env) FindingModuleOrInterface
FindingModule (CantFindInstalled -> MissingInterfaceError)
-> CantFindInstalled -> MissingInterfaceError
forall a b. (a -> b) -> a -> b
$
  UnitEnv -> Profile -> ModuleName -> FindResult -> CantFindInstalled
cantFindErr UnitEnv
unit_env
              Profile
profile
              ModuleName
mod
              FindResult
res

cantFindErr
    :: UnitEnv
    -> Profile
    -> ModuleName
    -> FindResult
    -> CantFindInstalled
cantFindErr :: UnitEnv -> Profile -> ModuleName -> FindResult -> CantFindInstalled
cantFindErr UnitEnv
_ Profile
_ ModuleName
mod_name (FoundMultiple [(Module, ModuleOrigin)]
mods)
  = ModuleName -> CantFindInstalledReason -> CantFindInstalled
CantFindInstalled ModuleName
mod_name ([(Module, ModuleOrigin)] -> CantFindInstalledReason
MultiplePackages [(Module, ModuleOrigin)]
mods)

cantFindErr UnitEnv
unit_env Profile
profile ModuleName
mod_name FindResult
find_result
  = ModuleName -> CantFindInstalledReason -> CantFindInstalled
CantFindInstalled ModuleName
mod_name CantFindInstalledReason
more_info
  where
    mhome_unit :: Maybe HomeUnit
mhome_unit = UnitEnv -> Maybe HomeUnit
ue_homeUnit UnitEnv
unit_env
    more_info :: CantFindInstalledReason
more_info
      = case FindResult
find_result of
            NoPackage Unit
pkg
                -> UnitId -> [UnitInfo] -> CantFindInstalledReason
NoUnitIdMatching (Unit -> UnitId
toUnitId Unit
pkg) []
            NotFound { fr_paths :: FindResult -> [String]
fr_paths = [String]
files, fr_pkg :: FindResult -> Maybe Unit
fr_pkg = Maybe Unit
mb_pkg
                     , fr_mods_hidden :: FindResult -> [Unit]
fr_mods_hidden = [Unit]
mod_hiddens, fr_pkgs_hidden :: FindResult -> [Unit]
fr_pkgs_hidden = [Unit]
pkg_hiddens
                     , fr_unusables :: FindResult -> [(Unit, UnusableUnitReason)]
fr_unusables = [(Unit, UnusableUnitReason)]
unusables, fr_suggestions :: FindResult -> [ModuleSuggestion]
fr_suggestions = [ModuleSuggestion]
suggest }
                | Just Unit
pkg <- Maybe Unit
mb_pkg
                , Maybe HomeUnit
Nothing <- Maybe HomeUnit
mhome_unit           -- no home-unit
                -> UnitId -> [String] -> CantFindInstalledReason
not_found_in_package (Unit -> UnitId
toUnitId Unit
pkg) [String]
files

                | Just Unit
pkg <- Maybe Unit
mb_pkg
                , Just HomeUnit
home_unit <- Maybe HomeUnit
mhome_unit    -- there is a home-unit but the
                , Bool -> Bool
not (HomeUnit -> Unit -> Bool
isHomeUnit HomeUnit
home_unit Unit
pkg)  -- module isn't from it
                -> UnitId -> [String] -> CantFindInstalledReason
not_found_in_package (Unit -> UnitId
toUnitId Unit
pkg) [String]
files

                | Bool -> Bool
not ([ModuleSuggestion] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ModuleSuggestion]
suggest)
                -> [ModuleSuggestion] -> [String] -> CantFindInstalledReason
ModuleSuggestion [ModuleSuggestion]
suggest [String]
files

                | [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
files Bool -> Bool -> Bool
&& [Unit] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Unit]
mod_hiddens Bool -> Bool -> Bool
&&
                  [Unit] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Unit]
pkg_hiddens Bool -> Bool -> Bool
&& [(Unit, UnusableUnitReason)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Unit, UnusableUnitReason)]
unusables
                -> CantFindInstalledReason
NotAModule

                | Bool
otherwise
                -> [(Unit, Maybe UnitInfo)]
-> [Unit]
-> [(Unit, UnusableUnitReason)]
-> [String]
-> CantFindInstalledReason
GenericMissing
                    ((Unit -> (Unit, Maybe UnitInfo))
-> [Unit] -> [(Unit, Maybe UnitInfo)]
forall a b. (a -> b) -> [a] -> [b]
map ((\Unit
uid -> (Unit
uid, UnitState -> Unit -> Maybe UnitInfo
lookupUnit (HasDebugCallStack => UnitEnv -> UnitState
UnitEnv -> UnitState
ue_units UnitEnv
unit_env) Unit
uid))) [Unit]
pkg_hiddens)
                    [Unit]
mod_hiddens [(Unit, UnusableUnitReason)]
unusables [String]
files
            FindResult
_ -> String -> CantFindInstalledReason
forall a. HasCallStack => String -> a
panic String
"cantFindErr"

    build_tag :: String
build_tag = Ways -> String
waysBuildTag (Profile -> Ways
profileWays Profile
profile)

    not_found_in_package :: UnitId -> [String] -> CantFindInstalledReason
not_found_in_package UnitId
pkg [String]
files
       | String
build_tag String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
""
       = let
            build :: String
build = if String
build_tag String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"p" then String
"profiling"
                                        else String
"\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
build_tag String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
         in
         String -> UnitId -> [String] -> CantFindInstalledReason
MissingPackageWayFiles String
build UnitId
pkg [String]
files

       | Bool
otherwise
       = UnitId -> [String] -> CantFindInstalledReason
MissingPackageFiles UnitId
pkg [String]
files