    {-# LANGUAGE CPP #-}
    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE MultiWayIf #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE PatternSynonyms #-}
    {-# LANGUAGE TemplateHaskell #-}

    -- | Definitions for fixity analysis.
    module Ormolu.Fixity
      ( OpName,
        pattern OpName,
        unOpName,
        occOpName,
        FixityDirection (..),
        FixityInfo (..),
        FixityMap,
        LazyFixityMap,
        lookupFixity,
        HackageInfo (..),
        defaultStrategyThreshold,
        defaultFixityInfo,
        buildFixityMap,
        buildFixityMap',
        bootPackages,
        packageToOps,
        packageToPopularity,
      )
    where

    import qualified Data.Binary as Binary
    import qualified Data.Binary.Get as Binary
    import qualified Data.ByteString.Lazy as BL
    import Data.Foldable (foldl')
    import Data.List.NonEmpty (NonEmpty ((:|)))
    import qualified Data.List.NonEmpty as NE
    import Data.Map.Strict (Map)
    import qualified Data.Map.Strict as Map
    import Data.Maybe (fromMaybe)
    import Data.MemoTrie (memo)
    import Data.Semigroup (sconcat)
    import Data.Set (Set)
    import qualified Data.Set as Set
    import Distribution.Types.PackageName (PackageName, mkPackageName, unPackageName)
    import Ormolu.Fixity.Internal
    #if BUNDLE_FIXITIES
    import Data.FileEmbed (embedFile)
    #else
    import qualified Data.ByteString.Unsafe as BU
    import Foreign.Ptr
    import System.Environment (getEnv)
    import System.IO.Unsafe (unsafePerformIO)
    #endif

    packageToOps :: Map PackageName FixityMap
    packageToPopularity :: Map PackageName Int
    #if BUNDLE_FIXITIES
    HackageInfo Map PackageName FixityMap
    packageToOps Map PackageName Int
    packageToPopularity =
      Get HackageInfo -> ByteString -> HackageInfo
    forall a. Get a -> ByteString -> a
    Binary.runGet Get HackageInfo
    forall t. Binary t => Get t
    Binary.get (ByteString -> HackageInfo) -> ByteString -> HackageInfo
    forall a b. (a -> b) -> a -> b
    $
        ByteString -> ByteString
    BL.fromStrict $(embedFile "extract-hackage-info/hackage-info.bin")
    #else
    -- The GHC WASM backend does not yet support Template Haskell, so we instead
    -- pass in the encoded fixity DB at runtime by storing the pointer and length of
    -- the bytes in an environment variable.
    HackageInfo packageToOps packageToPopularity = unsafePerformIO $ do
      (ptr, len) <- read <$> getEnv "ORMOLU_HACKAGE_INFO"
      Binary.runGet Binary.get . BL.fromStrict
        <$> BU.unsafePackMallocCStringLen (intPtrToPtr $ IntPtr ptr, len)
    {-# NOINLINE packageToOps #-}
    {-# NOINLINE packageToPopularity #-}
    #endif

    -- | List of packages shipped with GHC, for which the download count from
    -- Hackage does not reflect their high popularity.
    -- See https://github.com/tweag/ormolu/pull/830#issuecomment-986609572.
    -- "base" is not is this list, because it is already whitelisted
    -- by buildFixityMap'.
    bootPackages :: Set PackageName
    bootPackages :: Set PackageName
    bootPackages =
      [PackageName] -> Set PackageName
    forall a. Ord a => [a] -> Set a
    Set.fromList
        [ PackageName
    "array",
          PackageName
    "binary",
          PackageName
    "bytestring",
          PackageName
    "containers",
          PackageName
    "deepseq",
          PackageName
    "directory",
          PackageName
    "exceptions",
          PackageName
    "filepath",
          PackageName
    "ghc-binary",
          PackageName
    "mtl",
          PackageName
    "parsec",
          PackageName
    "process",
          PackageName
    "stm",
          PackageName
    "template-haskell",
          PackageName
    "terminfo",
          PackageName
    "text",
          PackageName
    "time",
          PackageName
    "transformers",
          PackageName
    "unix",
          PackageName
    "Win32"
        ]

    -- | The default value for the popularity ratio threshold, after which a
    -- very popular definition from packageToOps will completely rule out
    -- conflicting definitions instead of being merged with them.
    defaultStrategyThreshold :: Float
    defaultStrategyThreshold :: Float
    defaultStrategyThreshold = Float
    0.9

    -- | Build a fixity map using the given popularity threshold and a list of
    -- cabal dependencies. Dependencies from the list have higher priority than
    -- other packages.
    buildFixityMap ::
      -- | Popularity ratio threshold, after which a very popular package will
      -- completely rule out conflicting definitions coming from other packages
      -- instead of being merged with them
      Float ->
      -- | Explicitly known dependencies
      Set PackageName ->
      -- | Resulting map
      LazyFixityMap
    buildFixityMap :: Float -> Set PackageName -> LazyFixityMap
    buildFixityMap = Map PackageName FixityMap
    -> Map PackageName Int
    -> Set PackageName
    -> Float
    -> Set PackageName
    -> LazyFixityMap
    buildFixityMap' Map PackageName FixityMap
    packageToOps Map PackageName Int
    packageToPopularity Set PackageName
    bootPackages

    -- | Build a fixity map using the given popularity threshold and a list of
    -- cabal dependencies. Dependencies from the list have higher priority than
    -- other packages. This specific version of the function allows the user to
    -- specify the package databases used to build the final fixity map.
    buildFixityMap' ::
      -- | Map from package to fixity map for operators defined in this package
      Map PackageName FixityMap ->
      -- | Map from package to popularity
      Map PackageName Int ->
      -- | Higher priority packages
      Set PackageName ->
      -- | Popularity ratio threshold, after which a very popular package will
      -- completely rule out conflicting definitions coming from other packages
      -- instead of being merged with them
      Float ->
      -- | Explicitly known dependencies
      Set PackageName ->
      -- | Resulting map
      LazyFixityMap
    buildFixityMap' :: Map PackageName FixityMap
    -> Map PackageName Int
    -> Set PackageName
    -> Float
    -> Set PackageName
    -> LazyFixityMap
    buildFixityMap'
      Map PackageName FixityMap
    operatorMap
      Map PackageName Int
    popularityMap
      Set PackageName
    higherPriorityPackages
      Float
    strategyThreshold = (Set PackageName -> LazyFixityMap)
    -> Set PackageName -> LazyFixityMap
    forall v. (Set PackageName -> v) -> Set PackageName -> v
    memoSet ((Set PackageName -> LazyFixityMap)
     -> Set PackageName -> LazyFixityMap)
    -> (Set PackageName -> LazyFixityMap)
    -> Set PackageName
    -> LazyFixityMap
    forall a b. (a -> b) -> a -> b
    $ \Set PackageName
    dependencies ->
        let baseFixityMap :: FixityMap
    baseFixityMap =
              OpName -> FixityInfo -> FixityMap -> FixityMap
    forall k a. Ord k => k -> a -> Map k a -> Map k a
    Map.insert OpName
    ":" FixityInfo
    colonFixityInfo (FixityMap -> FixityMap) -> FixityMap -> FixityMap
    forall a b. (a -> b) -> a -> b
    $
                FixityMap -> Maybe FixityMap -> FixityMap
    forall a. a -> Maybe a -> a
    fromMaybe FixityMap
    forall k a. Map k a
    Map.empty (Maybe FixityMap -> FixityMap) -> Maybe FixityMap -> FixityMap
    forall a b. (a -> b) -> a -> b
    $
                  PackageName -> Map PackageName FixityMap -> Maybe FixityMap
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup PackageName
    "base" Map PackageName FixityMap
    operatorMap
            cabalFixityMap :: FixityMap
    cabalFixityMap =
              [(PackageName, FixityMap)] -> FixityMap
    mergeAll (PackageName -> (PackageName, FixityMap)
    buildPackageFixityMap (PackageName -> (PackageName, FixityMap))
    -> [PackageName] -> [(PackageName, FixityMap)]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Set PackageName -> [PackageName]
    forall a. Set a -> [a]
    Set.toList Set PackageName
    dependencies)
            higherPriorityFixityMap :: FixityMap
    higherPriorityFixityMap =
              [(PackageName, FixityMap)] -> FixityMap
    mergeAll (PackageName -> (PackageName, FixityMap)
    buildPackageFixityMap (PackageName -> (PackageName, FixityMap))
    -> [PackageName] -> [(PackageName, FixityMap)]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Set PackageName -> [PackageName]
    forall a. Set a -> [a]
    Set.toList Set PackageName
    higherPriorityPackages)
            remainingFixityMap :: FixityMap
    remainingFixityMap =
              Map PackageName Int
    -> Float -> [(PackageName, FixityMap)] -> FixityMap
    mergeFixityMaps
                Map PackageName Int
    popularityMap
                Float
    strategyThreshold
                (PackageName -> (PackageName, FixityMap)
    buildPackageFixityMap (PackageName -> (PackageName, FixityMap))
    -> [PackageName] -> [(PackageName, FixityMap)]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Set PackageName -> [PackageName]
    forall a. Set a -> [a]
    Set.toList Set PackageName
    remainingPackages)
            remainingPackages :: Set PackageName
    remainingPackages =
              Map PackageName FixityMap -> Set PackageName
    forall k a. Map k a -> Set k
    Map.keysSet Map PackageName FixityMap
    operatorMap
                Set PackageName -> Set PackageName -> Set PackageName
    forall a. Ord a => Set a -> Set a -> Set a
    `Set.difference` Set PackageName -> Set PackageName -> Set PackageName
    forall a. Ord a => Set a -> Set a -> Set a
    Set.union Set PackageName
    dependencies Set PackageName
    higherPriorityPackages
            buildPackageFixityMap :: PackageName -> (PackageName, FixityMap)
    buildPackageFixityMap PackageName
    packageName =
              ( PackageName
    packageName,
                FixityMap -> Maybe FixityMap -> FixityMap
    forall a. a -> Maybe a -> a
    fromMaybe FixityMap
    forall k a. Map k a
    Map.empty (Maybe FixityMap -> FixityMap) -> Maybe FixityMap -> FixityMap
    forall a b. (a -> b) -> a -> b
    $
                  PackageName -> Map PackageName FixityMap -> Maybe FixityMap
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup PackageName
    packageName Map PackageName FixityMap
    operatorMap
              )
            -- we need a threshold > 1.0 so that no dependency can reach the
            -- threshold
            mergeAll :: [(PackageName, FixityMap)] -> FixityMap
    mergeAll = Map PackageName Int
    -> Float -> [(PackageName, FixityMap)] -> FixityMap
    mergeFixityMaps Map PackageName Int
    forall k a. Map k a
    Map.empty Float
    10.0
         in [FixityMap] -> LazyFixityMap
    LazyFixityMap
              [ FixityMap
    baseFixityMap,
                FixityMap
    cabalFixityMap,
                FixityMap
    higherPriorityFixityMap,
                FixityMap
    remainingFixityMap
              ]

    memoSet :: (Set PackageName -> v) -> Set PackageName -> v
    memoSet :: forall v. (Set PackageName -> v) -> Set PackageName -> v
    memoSet Set PackageName -> v
    f = ([String] -> v) -> [String] -> v
    forall t a. HasTrie t => (t -> a) -> t -> a
    memo (Set PackageName -> v
    f (Set PackageName -> v)
    -> ([String] -> Set PackageName) -> [String] -> v
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [PackageName] -> Set PackageName
    forall a. Eq a => [a] -> Set a
    Set.fromAscList ([PackageName] -> Set PackageName)
    -> ([String] -> [PackageName]) -> [String] -> Set PackageName
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> PackageName) -> [String] -> [PackageName]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap String -> PackageName
    mkPackageName) ([String] -> v)
    -> (Set PackageName -> [String]) -> Set PackageName -> v
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (PackageName -> String) -> [PackageName] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap PackageName -> String
    unPackageName ([PackageName] -> [String])
    -> (Set PackageName -> [PackageName])
    -> Set PackageName
    -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Set PackageName -> [PackageName]
    forall a. Set a -> [a]
    Set.toAscList

    -- | Merge a list of individual fixity maps, coming from different packages.
    -- Package popularities and the given threshold are used to choose between
    -- the "keep best only" (>= threshold) and "merge all" (< threshold)
    -- strategies when conflicting definitions are encountered for an operator.
    mergeFixityMaps ::
      -- | Map from package name to 30-days download count
      Map PackageName Int ->
      -- | Popularity ratio threshold
      Float ->
      -- | List of (package name, package fixity map) to merge
      [(PackageName, FixityMap)] ->
      -- | Resulting fixity map
      FixityMap
    mergeFixityMaps :: Map PackageName Int
    -> Float -> [(PackageName, FixityMap)] -> FixityMap
    mergeFixityMaps Map PackageName Int
    popularityMap Float
    threshold [(PackageName, FixityMap)]
    packageMaps =
      (Map FixityInfo Int -> FixityInfo)
    -> Map OpName (Map FixityInfo Int) -> FixityMap
    forall a b k. (a -> b) -> Map k a -> Map k b
    Map.map
        (Float -> NonEmpty (FixityInfo, Int) -> FixityInfo
    useThreshold Float
    threshold (NonEmpty (FixityInfo, Int) -> FixityInfo)
    -> (Map FixityInfo Int -> NonEmpty (FixityInfo, Int))
    -> Map FixityInfo Int
    -> FixityInfo
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [(FixityInfo, Int)] -> NonEmpty (FixityInfo, Int)
    forall a. HasCallStack => [a] -> NonEmpty a
    NE.fromList ([(FixityInfo, Int)] -> NonEmpty (FixityInfo, Int))
    -> (Map FixityInfo Int -> [(FixityInfo, Int)])
    -> Map FixityInfo Int
    -> NonEmpty (FixityInfo, Int)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Map FixityInfo Int -> [(FixityInfo, Int)]
    forall k a. Map k a -> [(k, a)]
    Map.toList)
        Map OpName (Map FixityInfo Int)
    scoredMap
      where
        scoredMap :: Map OpName (Map FixityInfo Int)
    scoredMap = (Map FixityInfo (NonEmpty PackageName) -> Map FixityInfo Int)
    -> Map OpName (Map FixityInfo (NonEmpty PackageName))
    -> Map OpName (Map FixityInfo Int)
    forall a b k. (a -> b) -> Map k a -> Map k b
    Map.map Map FixityInfo (NonEmpty PackageName) -> Map FixityInfo Int
    getScores Map OpName (Map FixityInfo (NonEmpty PackageName))
    opFixityMap
        -- when we encounter a duplicate key (op1) in the unionsWith operation,
        -- we have
        --   op1 -map-> {definitions1 -map-> originPackages}
        --   op1 -map-> {definitions2 -map-> originPackages}
        -- so we merge the keys (which have the type:
        -- Map FixityInfo (NonEmpty PackageName))
        -- using 'Map.unionWith (<>)', to "concatenate" the list of
        -- definitions for this operator, and to also "concatenate" origin
        -- packages if a same definition is found in both maps
        opFixityMap :: Map OpName (Map FixityInfo (NonEmpty PackageName))
    opFixityMap =
          (Map FixityInfo (NonEmpty PackageName)
     -> Map FixityInfo (NonEmpty PackageName)
     -> Map FixityInfo (NonEmpty PackageName))
    -> [Map OpName (Map FixityInfo (NonEmpty PackageName))]
    -> Map OpName (Map FixityInfo (NonEmpty PackageName))
    forall (f :: * -> *) k a.
    (Foldable f, Ord k) =>
    (a -> a -> a) -> f (Map k a) -> Map k a
    Map.unionsWith
            ((NonEmpty PackageName
     -> NonEmpty PackageName -> NonEmpty PackageName)
    -> Map FixityInfo (NonEmpty PackageName)
    -> Map FixityInfo (NonEmpty PackageName)
    -> Map FixityInfo (NonEmpty PackageName)
    forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
    Map.unionWith NonEmpty PackageName
    -> NonEmpty PackageName -> NonEmpty PackageName
    forall a. Semigroup a => a -> a -> a
    (<>))
            ((PackageName, FixityMap)
    -> Map OpName (Map FixityInfo (NonEmpty PackageName))
    opFixityMapFrom ((PackageName, FixityMap)
     -> Map OpName (Map FixityInfo (NonEmpty PackageName)))
    -> [(PackageName, FixityMap)]
    -> [Map OpName (Map FixityInfo (NonEmpty PackageName))]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> [(PackageName, FixityMap)]
    packageMaps)
        useThreshold ::
          -- Threshold
          Float ->
          -- List of conflicting (definition, score) for a given operator
          NonEmpty (FixityInfo, Int) ->
          -- Resulting fixity, using the specified threshold to choose between
          -- strategy "keep best only" and "merge all"
          FixityInfo
        useThreshold :: Float -> NonEmpty (FixityInfo, Int) -> FixityInfo
    useThreshold Float
    t NonEmpty (FixityInfo, Int)
    fixScores =
          if Int -> Float
    forall {a}. Integral a => a -> Float
    toFloat Int
    maxScore Float -> Float -> Float
    forall a. Fractional a => a -> a -> a
    / Int -> Float
    forall {a}. Integral a => a -> Float
    toFloat Int
    sumScores Float -> Float -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Float
    t
            then NonEmpty FixityInfo -> FixityInfo
    forall a. Semigroup a => NonEmpty a -> a
    sconcat (NonEmpty FixityInfo -> FixityInfo)
    -> (NonEmpty (FixityInfo, Int) -> NonEmpty FixityInfo)
    -> NonEmpty (FixityInfo, Int)
    -> FixityInfo
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((FixityInfo, Int) -> FixityInfo)
    -> NonEmpty (FixityInfo, Int) -> NonEmpty FixityInfo
    forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (FixityInfo, Int) -> FixityInfo
    forall a b. (a, b) -> a
    fst (NonEmpty (FixityInfo, Int) -> FixityInfo)
    -> NonEmpty (FixityInfo, Int) -> FixityInfo
    forall a b. (a -> b) -> a -> b
    $ NonEmpty (FixityInfo, Int)
    maxs -- merge potential ex-aequo winners
            else NonEmpty FixityInfo -> FixityInfo
    forall a. Semigroup a => NonEmpty a -> a
    sconcat (NonEmpty FixityInfo -> FixityInfo)
    -> (NonEmpty (FixityInfo, Int) -> NonEmpty FixityInfo)
    -> NonEmpty (FixityInfo, Int)
    -> FixityInfo
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ((FixityInfo, Int) -> FixityInfo)
    -> NonEmpty (FixityInfo, Int) -> NonEmpty FixityInfo
    forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (FixityInfo, Int) -> FixityInfo
    forall a b. (a, b) -> a
    fst (NonEmpty (FixityInfo, Int) -> FixityInfo)
    -> NonEmpty (FixityInfo, Int) -> FixityInfo
    forall a b. (a -> b) -> a -> b
    $ NonEmpty (FixityInfo, Int)
    fixScores
          where
            toFloat :: a -> Float
    toFloat a
    x = a -> Float
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral a
    x :: Float
            maxs :: NonEmpty (FixityInfo, Int)
    maxs = ((FixityInfo, Int) -> Int)
    -> NonEmpty (FixityInfo, Int) -> NonEmpty (FixityInfo, Int)
    forall b a. Ord b => (a -> b) -> NonEmpty a -> NonEmpty a
    maxWith (FixityInfo, Int) -> Int
    forall a b. (a, b) -> b
    snd NonEmpty (FixityInfo, Int)
    fixScores
            maxScore :: Int
    maxScore = (FixityInfo, Int) -> Int
    forall a b. (a, b) -> b
    snd ((FixityInfo, Int) -> Int) -> (FixityInfo, Int) -> Int
    forall a b. (a -> b) -> a -> b
    $ NonEmpty (FixityInfo, Int) -> (FixityInfo, Int)
    forall a. NonEmpty a -> a
    NE.head NonEmpty (FixityInfo, Int)
    maxs
            sumScores :: Int
    sumScores = (Int -> Int -> Int) -> Int -> NonEmpty Int -> Int
    forall b a. (b -> a -> b) -> b -> NonEmpty a -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' Int -> Int -> Int
    forall a. Num a => a -> a -> a
    (+) Int
    0 ((FixityInfo, Int) -> Int
    forall a b. (a, b) -> b
    snd ((FixityInfo, Int) -> Int)
    -> NonEmpty (FixityInfo, Int) -> NonEmpty Int
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> NonEmpty (FixityInfo, Int)
    fixScores)
        getScores ::
          -- Map for a given operator associating each of its conflicting
          -- definitions with the packages that define it
          Map FixityInfo (NonEmpty PackageName) ->
          -- Map for a given operator associating each of its conflicting
          -- definitions with their score (= sum of the popularity of the
          -- packages that define it)
          Map FixityInfo Int
        getScores :: Map FixityInfo (NonEmpty PackageName) -> Map FixityInfo Int
    getScores =
          (NonEmpty PackageName -> Int)
    -> Map FixityInfo (NonEmpty PackageName) -> Map FixityInfo Int
    forall a b k. (a -> b) -> Map k a -> Map k b
    Map.map
            (NonEmpty Int -> Int
    forall a. Num a => NonEmpty a -> a
    forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
    sum (NonEmpty Int -> Int)
    -> (NonEmpty PackageName -> NonEmpty Int)
    -> NonEmpty PackageName
    -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (PackageName -> Int) -> NonEmpty PackageName -> NonEmpty Int
    forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (Int -> Maybe Int -> Int
    forall a. a -> Maybe a -> a
    fromMaybe Int
    0 (Maybe Int -> Int)
    -> (PackageName -> Maybe Int) -> PackageName -> Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (PackageName -> Map PackageName Int -> Maybe Int)
    -> Map PackageName Int -> PackageName -> Maybe Int
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip PackageName -> Map PackageName Int -> Maybe Int
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup Map PackageName Int
    popularityMap))
        opFixityMapFrom ::
          -- (packageName, package fixity map)
          (PackageName, FixityMap) ->
          -- Map associating each operator of the package with a
          -- {map for a given operator associating each of its definitions with
          -- the list of packages that define it}
          -- (this list can only be == [packageName] in the context of this
          -- function)
          Map OpName (Map FixityInfo (NonEmpty PackageName))
        opFixityMapFrom :: (PackageName, FixityMap)
    -> Map OpName (Map FixityInfo (NonEmpty PackageName))
    opFixityMapFrom (PackageName
    packageName, FixityMap
    opsMap) =
          (FixityInfo -> Map FixityInfo (NonEmpty PackageName))
    -> FixityMap -> Map OpName (Map FixityInfo (NonEmpty PackageName))
    forall a b k. (a -> b) -> Map k a -> Map k b
    Map.map
            ((FixityInfo
     -> NonEmpty PackageName -> Map FixityInfo (NonEmpty PackageName))
    -> NonEmpty PackageName
    -> FixityInfo
    -> Map FixityInfo (NonEmpty PackageName)
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip FixityInfo
    -> NonEmpty PackageName -> Map FixityInfo (NonEmpty PackageName)
    forall k a. k -> a -> Map k a
    Map.singleton (PackageName
    packageName PackageName -> [PackageName] -> NonEmpty PackageName
    forall a. a -> [a] -> NonEmpty a
    :| []))
            FixityMap
    opsMap
        maxWith :: (Ord b) => (a -> b) -> NonEmpty a -> NonEmpty a
        maxWith :: forall b a. Ord b => (a -> b) -> NonEmpty a -> NonEmpty a
    maxWith a -> b
    f NonEmpty a
    xs = (b, NonEmpty a) -> NonEmpty a
    forall a b. (a, b) -> b
    snd ((b, NonEmpty a) -> NonEmpty a) -> (b, NonEmpty a) -> NonEmpty a
    forall a b. (a -> b) -> a -> b
    $ ((b, NonEmpty a) -> a -> (b, NonEmpty a))
    -> (b, NonEmpty a) -> [a] -> (b, NonEmpty a)
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (b, NonEmpty a) -> a -> (b, NonEmpty a)
    comp (a -> b
    f a
    h, a
    h a -> [a] -> NonEmpty a
    forall a. a -> [a] -> NonEmpty a
    :| []) [a]
    t
          where
            a
    h :| [a]
    t = NonEmpty a
    xs
            comp :: (b, NonEmpty a) -> a -> (b, NonEmpty a)
    comp (b
    fMax, NonEmpty a
    maxs) a
    x =
              let fX :: b
    fX = a -> b
    f a
    x
               in if
                      | b
    fMax b -> b -> Bool
    forall a. Ord a => a -> a -> Bool
    < b
    fX -> (b
    fX, a
    x a -> [a] -> NonEmpty a
    forall a. a -> [a] -> NonEmpty a
    :| [])
                      | b
    fMax b -> b -> Bool
    forall a. Eq a => a -> a -> Bool
    == b
    fX -> (b
    fMax, a -> NonEmpty a -> NonEmpty a
    forall a. a -> NonEmpty a -> NonEmpty a
    NE.cons a
    x NonEmpty a
    maxs)
                      | Bool
    otherwise -> (b
    fMax, NonEmpty a
    maxs)