module Unison.HashQualifiedPrime
  ( HashQualified (..),
    HQSegment,
    toHQ,
    HashOrHQ,
    fromHQ,
    toName,
    nameLength,
    take,
    toHash,
    toTextWith,
    fromNamedReferent,
    fromNamedReference,
    fromName,
    matchesNamedReferent,
    matchesNamedReference,
    requalify,
    searchBySuffix,
    filterBySuffix,
    searchUnconflictedBySuffix,
    filterUnconflictedBySuffix,
  )
where

import Data.Set qualified as Set
import Data.Set.NonEmpty qualified as Set.NonEmpty
import Data.Text qualified as Text
import Unison.HashQualified qualified as HQ
import Unison.Name (Name)
import Unison.Name qualified as Name
import Unison.NameSegment (NameSegment)
import Unison.Prelude
import Unison.Reference (Reference)
import Unison.Reference qualified as Reference
import Unison.Referent (Referent)
import Unison.Referent qualified as Referent
import Unison.ShortHash (ShortHash)
import Unison.ShortHash qualified as SH
import Unison.Util.BiMultimap (BiMultimap)
import Unison.Util.BiMultimap qualified as BiMultimap
import Unison.Util.Relation (Relation)
import Unison.Util.Relation qualified as Relation
import Prelude hiding (take)

-- | Like Unison.HashQualified, but doesn't support a HashOnly variant
data HashQualified n
  = NameOnly n
  | HashQualified n ShortHash
  deriving stock (HashQualified n -> HashQualified n -> Bool
(HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> Eq (HashQualified n)
forall n. Eq n => HashQualified n -> HashQualified n -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall n. Eq n => HashQualified n -> HashQualified n -> Bool
== :: HashQualified n -> HashQualified n -> Bool
$c/= :: forall n. Eq n => HashQualified n -> HashQualified n -> Bool
/= :: HashQualified n -> HashQualified n -> Bool
Eq, (forall a b. (a -> b) -> HashQualified a -> HashQualified b)
-> (forall a b. a -> HashQualified b -> HashQualified a)
-> Functor HashQualified
forall a b. a -> HashQualified b -> HashQualified a
forall a b. (a -> b) -> HashQualified a -> HashQualified b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> HashQualified a -> HashQualified b
fmap :: forall a b. (a -> b) -> HashQualified a -> HashQualified b
$c<$ :: forall a b. a -> HashQualified b -> HashQualified a
<$ :: forall a b. a -> HashQualified b -> HashQualified a
Functor, (forall x. HashQualified n -> Rep (HashQualified n) x)
-> (forall x. Rep (HashQualified n) x -> HashQualified n)
-> Generic (HashQualified n)
forall x. Rep (HashQualified n) x -> HashQualified n
forall x. HashQualified n -> Rep (HashQualified n) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall n x. Rep (HashQualified n) x -> HashQualified n
forall n x. HashQualified n -> Rep (HashQualified n) x
$cfrom :: forall n x. HashQualified n -> Rep (HashQualified n) x
from :: forall x. HashQualified n -> Rep (HashQualified n) x
$cto :: forall n x. Rep (HashQualified n) x -> HashQualified n
to :: forall x. Rep (HashQualified n) x -> HashQualified n
Generic, (forall m. Monoid m => HashQualified m -> m)
-> (forall m a. Monoid m => (a -> m) -> HashQualified a -> m)
-> (forall m a. Monoid m => (a -> m) -> HashQualified a -> m)
-> (forall a b. (a -> b -> b) -> b -> HashQualified a -> b)
-> (forall a b. (a -> b -> b) -> b -> HashQualified a -> b)
-> (forall b a. (b -> a -> b) -> b -> HashQualified a -> b)
-> (forall b a. (b -> a -> b) -> b -> HashQualified a -> b)
-> (forall a. (a -> a -> a) -> HashQualified a -> a)
-> (forall a. (a -> a -> a) -> HashQualified a -> a)
-> (forall a. HashQualified a -> [a])
-> (forall a. HashQualified a -> Bool)
-> (forall a. HashQualified a -> Int)
-> (forall a. Eq a => a -> HashQualified a -> Bool)
-> (forall a. Ord a => HashQualified a -> a)
-> (forall a. Ord a => HashQualified a -> a)
-> (forall a. Num a => HashQualified a -> a)
-> (forall a. Num a => HashQualified a -> a)
-> Foldable HashQualified
forall a. Eq a => a -> HashQualified a -> Bool
forall a. Num a => HashQualified a -> a
forall a. Ord a => HashQualified a -> a
forall m. Monoid m => HashQualified m -> m
forall a. HashQualified a -> Bool
forall a. HashQualified a -> Int
forall a. HashQualified a -> [a]
forall a. (a -> a -> a) -> HashQualified a -> a
forall m a. Monoid m => (a -> m) -> HashQualified a -> m
forall b a. (b -> a -> b) -> b -> HashQualified a -> b
forall a b. (a -> b -> b) -> b -> HashQualified a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => HashQualified m -> m
fold :: forall m. Monoid m => HashQualified m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> HashQualified a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
foldr :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> HashQualified a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
foldl :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> HashQualified a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> HashQualified a -> a
foldr1 :: forall a. (a -> a -> a) -> HashQualified a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> HashQualified a -> a
foldl1 :: forall a. (a -> a -> a) -> HashQualified a -> a
$ctoList :: forall a. HashQualified a -> [a]
toList :: forall a. HashQualified a -> [a]
$cnull :: forall a. HashQualified a -> Bool
null :: forall a. HashQualified a -> Bool
$clength :: forall a. HashQualified a -> Int
length :: forall a. HashQualified a -> Int
$celem :: forall a. Eq a => a -> HashQualified a -> Bool
elem :: forall a. Eq a => a -> HashQualified a -> Bool
$cmaximum :: forall a. Ord a => HashQualified a -> a
maximum :: forall a. Ord a => HashQualified a -> a
$cminimum :: forall a. Ord a => HashQualified a -> a
minimum :: forall a. Ord a => HashQualified a -> a
$csum :: forall a. Num a => HashQualified a -> a
sum :: forall a. Num a => HashQualified a -> a
$cproduct :: forall a. Num a => HashQualified a -> a
product :: forall a. Num a => HashQualified a -> a
Foldable, Eq (HashQualified n)
Eq (HashQualified n) =>
(HashQualified n -> HashQualified n -> Ordering)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> Bool)
-> (HashQualified n -> HashQualified n -> HashQualified n)
-> (HashQualified n -> HashQualified n -> HashQualified n)
-> Ord (HashQualified n)
HashQualified n -> HashQualified n -> Bool
HashQualified n -> HashQualified n -> Ordering
HashQualified n -> HashQualified n -> HashQualified n
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall n. Ord n => Eq (HashQualified n)
forall n. Ord n => HashQualified n -> HashQualified n -> Bool
forall n. Ord n => HashQualified n -> HashQualified n -> Ordering
forall n.
Ord n =>
HashQualified n -> HashQualified n -> HashQualified n
$ccompare :: forall n. Ord n => HashQualified n -> HashQualified n -> Ordering
compare :: HashQualified n -> HashQualified n -> Ordering
$c< :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
< :: HashQualified n -> HashQualified n -> Bool
$c<= :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
<= :: HashQualified n -> HashQualified n -> Bool
$c> :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
> :: HashQualified n -> HashQualified n -> Bool
$c>= :: forall n. Ord n => HashQualified n -> HashQualified n -> Bool
>= :: HashQualified n -> HashQualified n -> Bool
$cmax :: forall n.
Ord n =>
HashQualified n -> HashQualified n -> HashQualified n
max :: HashQualified n -> HashQualified n -> HashQualified n
$cmin :: forall n.
Ord n =>
HashQualified n -> HashQualified n -> HashQualified n
min :: HashQualified n -> HashQualified n -> HashQualified n
Ord, Int -> HashQualified n -> ShowS
[HashQualified n] -> ShowS
HashQualified n -> String
(Int -> HashQualified n -> ShowS)
-> (HashQualified n -> String)
-> ([HashQualified n] -> ShowS)
-> Show (HashQualified n)
forall n. Show n => Int -> HashQualified n -> ShowS
forall n. Show n => [HashQualified n] -> ShowS
forall n. Show n => HashQualified n -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall n. Show n => Int -> HashQualified n -> ShowS
showsPrec :: Int -> HashQualified n -> ShowS
$cshow :: forall n. Show n => HashQualified n -> String
show :: HashQualified n -> String
$cshowList :: forall n. Show n => [HashQualified n] -> ShowS
showList :: [HashQualified n] -> ShowS
Show, Functor HashQualified
Foldable HashQualified
(Functor HashQualified, Foldable HashQualified) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> HashQualified a -> f (HashQualified b))
-> (forall (f :: * -> *) a.
    Applicative f =>
    HashQualified (f a) -> f (HashQualified a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> HashQualified a -> m (HashQualified b))
-> (forall (m :: * -> *) a.
    Monad m =>
    HashQualified (m a) -> m (HashQualified a))
-> Traversable HashQualified
forall (t :: * -> *).
(Functor t, Foldable t) =>
(forall (f :: * -> *) a b.
 Applicative f =>
 (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a.
Monad m =>
HashQualified (m a) -> m (HashQualified a)
forall (f :: * -> *) a.
Applicative f =>
HashQualified (f a) -> f (HashQualified a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> HashQualified a -> m (HashQualified b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashQualified a -> f (HashQualified b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashQualified a -> f (HashQualified b)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> HashQualified a -> f (HashQualified b)
$csequenceA :: forall (f :: * -> *) a.
Applicative f =>
HashQualified (f a) -> f (HashQualified a)
sequenceA :: forall (f :: * -> *) a.
Applicative f =>
HashQualified (f a) -> f (HashQualified a)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> HashQualified a -> m (HashQualified b)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> HashQualified a -> m (HashQualified b)
$csequence :: forall (m :: * -> *) a.
Monad m =>
HashQualified (m a) -> m (HashQualified a)
sequence :: forall (m :: * -> *) a.
Monad m =>
HashQualified (m a) -> m (HashQualified a)
Traversable)

type HQSegment = HashQualified NameSegment

toHQ :: HashQualified n -> HQ.HashQualified n
toHQ :: forall n. HashQualified n -> HashQualified n
toHQ = \case
  NameOnly n
n -> n -> HashQualified n
forall n. n -> HashQualified n
HQ.NameOnly n
n
  HashQualified n
n ShortHash
sh -> n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HQ.HashQualified n
n ShortHash
sh

type HashOrHQ n = Either ShortHash (HashQualified n)

-- | If the 'HQ.HashQualified' is just a 'ShortHash', return it on the 'Left', otherwise return a `HashQualified` on the
--  `Right`.
fromHQ :: HQ.HashQualified n -> HashOrHQ n
fromHQ :: forall n. HashQualified n -> HashOrHQ n
fromHQ = \case
  HQ.NameOnly n
n -> HashQualified n -> HashOrHQ n
forall a b. b -> Either a b
Right (HashQualified n -> HashOrHQ n) -> HashQualified n -> HashOrHQ n
forall a b. (a -> b) -> a -> b
$ n -> HashQualified n
forall n. n -> HashQualified n
NameOnly n
n
  HQ.HashQualified n
n ShortHash
sh -> HashQualified n -> HashOrHQ n
forall a b. b -> Either a b
Right (HashQualified n -> HashOrHQ n) -> HashQualified n -> HashOrHQ n
forall a b. (a -> b) -> a -> b
$ n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n ShortHash
sh
  HQ.HashOnly ShortHash
sh -> ShortHash -> HashOrHQ n
forall a b. a -> Either a b
Left ShortHash
sh

toName :: HashQualified n -> n
toName :: forall n. HashQualified n -> n
toName = \case
  NameOnly n
name -> n
name
  HashQualified n
name ShortHash
_ -> n
name

nameLength :: (Name -> Text) -> HashQualified Name -> Int
nameLength :: (Name -> Text) -> HashQualified Name -> Int
nameLength Name -> Text
nameToText = Text -> Int
Text.length (Text -> Int)
-> (HashQualified Name -> Text) -> HashQualified Name -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Name -> Text) -> HashQualified Name -> Text
forall n. (n -> Text) -> HashQualified n -> Text
toTextWith Name -> Text
nameToText

take :: Int -> HashQualified n -> HashQualified n
take :: forall n. Int -> HashQualified n -> HashQualified n
take Int
i = \case
  n :: HashQualified n
n@(NameOnly n
_) -> HashQualified n
n
  HashQualified n
n ShortHash
s -> if Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then n -> HashQualified n
forall n. n -> HashQualified n
NameOnly n
n else n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n (Int -> ShortHash -> ShortHash
SH.shortenTo Int
i ShortHash
s)

toHash :: HashQualified n -> Maybe ShortHash
toHash :: forall n. HashQualified n -> Maybe ShortHash
toHash = \case
  NameOnly n
_ -> Maybe ShortHash
forall a. Maybe a
Nothing
  HashQualified n
_ ShortHash
sh -> ShortHash -> Maybe ShortHash
forall a. a -> Maybe a
Just ShortHash
sh

toTextWith :: (n -> Text) -> HashQualified n -> Text
toTextWith :: forall n. (n -> Text) -> HashQualified n -> Text
toTextWith n -> Text
f = \case
  NameOnly n
name -> n -> Text
f n
name
  HashQualified n
name ShortHash
hash -> n -> Text
f n
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ShortHash -> Text
SH.toText ShortHash
hash

-- Returns the full referent in the hash.  Use HQ.take to just get a prefix
fromNamedReferent :: n -> Referent -> HashQualified n
fromNamedReferent :: forall n. n -> Referent -> HashQualified n
fromNamedReferent n
n Referent
r = n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n (Referent -> ShortHash
Referent.toShortHash Referent
r)

-- Returns the full reference in the hash.  Use HQ.take to just get a prefix
fromNamedReference :: n -> Reference -> HashQualified n
fromNamedReference :: forall n. n -> Reference -> HashQualified n
fromNamedReference n
n Reference
r = n -> ShortHash -> HashQualified n
forall n. n -> ShortHash -> HashQualified n
HashQualified n
n (Reference -> ShortHash
Reference.toShortHash Reference
r)

fromName :: n -> HashQualified n
fromName :: forall n. n -> HashQualified n
fromName = n -> HashQualified n
forall n. n -> HashQualified n
NameOnly

matchesNamedReferent :: (Eq n) => n -> Referent -> HashQualified n -> Bool
matchesNamedReferent :: forall n. Eq n => n -> Referent -> HashQualified n -> Bool
matchesNamedReferent n
n Referent
r = \case
  NameOnly n
n' -> n
n' n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
n
  HashQualified n
n' ShortHash
sh -> n
n' n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
n Bool -> Bool -> Bool
&& ShortHash
sh ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` Referent -> ShortHash
Referent.toShortHash Referent
r

matchesNamedReference :: (Eq n) => n -> Reference -> HashQualified n -> Bool
matchesNamedReference :: forall n. Eq n => n -> Reference -> HashQualified n -> Bool
matchesNamedReference n
n Reference
r = \case
  NameOnly n
n' -> n
n' n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
n
  HashQualified n
n' ShortHash
sh -> n
n' n -> n -> Bool
forall a. Eq a => a -> a -> Bool
== n
n Bool -> Bool -> Bool
&& ShortHash
sh ShortHash -> Reference -> Bool
`Reference.isPrefixOf` Reference
r

-- Use `requalify hq . Referent.Ref` if you want to pass in a `Reference`.
requalify :: HashQualified Name -> Referent -> HashQualified Name
requalify :: HashQualified Name -> Referent -> HashQualified Name
requalify HashQualified Name
hq Referent
r = case HashQualified Name
hq of
  NameOnly Name
n -> Name -> Referent -> HashQualified Name
forall n. n -> Referent -> HashQualified n
fromNamedReferent Name
n Referent
r
  HashQualified Name
n ShortHash
_ -> Name -> Referent -> HashQualified Name
forall n. n -> Referent -> HashQualified n
fromNamedReferent Name
n Referent
r

-- | Like 'Name.searchBySuffix', but uses a hash-qualified name to search instead.
--
-- The name *and* the hash are used to determine whether something is an exact match. For example, in namespace
-- {foo#foo, hello.foo#bar}, searching for foo#bar will return the singleton set {hello.foo#bar}, because even though
-- there is an exact name match on foo, its hash doesn't match so we fall back to "suffix" matches. This probably isn't
-- a very important detail in practice, but the other possible implementation (do name-only search, *then* filter result
-- down to matching hashes) seems worse.
searchBySuffix :: forall ref. (Ord ref) => (ref -> ShortHash) -> HashQualified Name -> Relation Name ref -> Set ref
searchBySuffix :: forall ref.
Ord ref =>
(ref -> ShortHash)
-> HashQualified Name -> Relation Name ref -> Set ref
searchBySuffix ref -> ShortHash
_ (NameOnly Name
name) Relation Name ref
rel = Name -> Relation Name ref -> Set ref
forall r. Ord r => Name -> Relation Name r -> Set r
Name.searchBySuffix Name
name Relation Name ref
rel
searchBySuffix ref -> ShortHash
refHash (HashQualified Name
name ShortHash
hash) Relation Name ref
rel
  | Set ref -> Bool
forall a. Set a -> Bool
Set.null Set ref
exactMatches = Set ref
suffixMatches
  | Bool
otherwise = Set ref
exactMatches
  where
    exactMatches :: Set ref
    exactMatches :: Set ref
exactMatches =
      Set ref -> Set ref
keepMatchingHashes (Name -> Relation Name ref -> Set ref
forall a b. Ord a => a -> Relation a b -> Set b
Relation.lookupDom Name
name Relation Name ref
rel)

    suffixMatches :: Set ref
    suffixMatches :: Set ref
suffixMatches =
      Set ref -> Set ref
keepMatchingHashes ((Name -> Ordering) -> Relation Name ref -> Set ref
forall a b.
(Ord a, Ord b) =>
(a -> Ordering) -> Relation a b -> Set b
Relation.searchDom (Name -> Name -> Ordering
Name.compareSuffix Name
name) Relation Name ref
rel)

    keepMatchingHashes :: Set ref -> Set ref
    keepMatchingHashes :: Set ref -> Set ref
keepMatchingHashes =
      (ref -> Bool) -> Set ref -> Set ref
forall a. (a -> Bool) -> Set a -> Set a
Set.filter \ref
ref -> ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref

-- | Like 'searchBySuffix', but also keeps the names around.
filterBySuffix ::
  forall ref.
  (Ord ref) =>
  (ref -> ShortHash) ->
  HashQualified Name ->
  Relation Name ref ->
  Relation Name ref
filterBySuffix :: forall ref.
Ord ref =>
(ref -> ShortHash)
-> HashQualified Name -> Relation Name ref -> Relation Name ref
filterBySuffix ref -> ShortHash
_ (NameOnly Name
name) Relation Name ref
rel = Name -> Relation Name ref -> Relation Name ref
forall r. Ord r => Name -> Relation Name r -> Relation Name r
Name.filterBySuffix Name
name Relation Name ref
rel
filterBySuffix ref -> ShortHash
refHash (HashQualified Name
name ShortHash
hash) Relation Name ref
rel
  | Relation Name ref -> Bool
forall a b. Relation a b -> Bool
Relation.null Relation Name ref
exactMatches = Relation Name ref
suffixMatches
  | Bool
otherwise = Relation Name ref
exactMatches
  where
    exactMatches :: Relation Name ref
    exactMatches :: Relation Name ref
exactMatches =
      Name -> Set ref -> Relation Name ref
matches Name
name (Name -> Relation Name ref -> Set ref
forall a b. Ord a => a -> Relation a b -> Set b
Relation.lookupDom Name
name Relation Name ref
rel)

    suffixMatches :: Relation Name ref
    suffixMatches :: Relation Name ref
suffixMatches =
      (Name -> Set ref -> Relation Name ref)
-> (Name -> Ordering) -> Relation Name ref -> Relation Name ref
forall a c b.
(Ord a, Monoid c) =>
(a -> Set b -> c) -> (a -> Ordering) -> Relation a b -> c
Relation.searchDomG Name -> Set ref -> Relation Name ref
matches (Name -> Name -> Ordering
Name.compareSuffix Name
name) Relation Name ref
rel

    matches :: Name -> Set ref -> Relation Name ref
    matches :: Name -> Set ref -> Relation Name ref
matches Name
name =
      (ref -> Bool) -> Set ref -> Set ref
forall a. (a -> Bool) -> Set a -> Set a
Set.filter ref -> Bool
hashMatches
        (Set ref -> Set ref)
-> (Set ref -> Relation Name ref) -> Set ref -> Relation Name ref
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Set ref -> Maybe (NESet ref)
forall a. Set a -> Maybe (NESet a)
Set.NonEmpty.nonEmptySet
        (Set ref -> Maybe (NESet ref))
-> (Maybe (NESet ref) -> Relation Name ref)
-> Set ref
-> Relation Name ref
forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Relation Name ref
-> (NESet ref -> Relation Name ref)
-> Maybe (NESet ref)
-> Relation Name ref
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Relation Name ref
forall a b. Relation a b
Relation.empty (Name -> NESet ref -> Relation Name ref
forall a b. a -> NESet b -> Relation a b
Relation.singletonSet Name
name)

    hashMatches :: ref -> Bool
    hashMatches :: ref -> Bool
hashMatches ref
ref =
      ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref

searchUnconflictedBySuffix ::
  forall ref.
  (Ord ref) =>
  (ref -> ShortHash) ->
  HashQualified Name ->
  BiMultimap ref Name ->
  Set ref
searchUnconflictedBySuffix :: forall ref.
Ord ref =>
(ref -> ShortHash)
-> HashQualified Name -> BiMultimap ref Name -> Set ref
searchUnconflictedBySuffix ref -> ShortHash
_ (NameOnly Name
name) BiMultimap ref Name
m = Name -> BiMultimap ref Name -> Set ref
forall ref. Ord ref => Name -> BiMultimap ref Name -> Set ref
Name.searchUnconflictedBySuffix Name
name BiMultimap ref Name
m
searchUnconflictedBySuffix ref -> ShortHash
refHash (HashQualified Name
name ShortHash
hash) BiMultimap ref Name
m =
  Set ref -> (ref -> Set ref) -> Maybe ref -> Set ref
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Set ref
suffixMatches ref -> Set ref
forall a. a -> Set a
Set.singleton Maybe ref
exactMatch
  where
    exactMatch :: Maybe ref
    exactMatch :: Maybe ref
exactMatch = do
      ref
ref <- Name -> BiMultimap ref Name -> Maybe ref
forall b a. Ord b => b -> BiMultimap a b -> Maybe a
BiMultimap.lookupRan Name
name BiMultimap ref Name
m
      Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref)
      ref -> Maybe ref
forall a. a -> Maybe a
Just ref
ref

    suffixMatches :: Set ref
    suffixMatches :: Set ref
suffixMatches =
      BiMultimap ref Name
m
        BiMultimap ref Name -> (BiMultimap ref Name -> Set ref) -> Set ref
forall a b. a -> (a -> b) -> b
& (ref -> Name -> Set ref)
-> (Name -> Ordering) -> BiMultimap ref Name -> Set ref
forall a m b.
(Ord a, Monoid m) =>
(a -> b -> m) -> (b -> Ordering) -> BiMultimap a b -> m
BiMultimap.searchRan (\ref
ref Name
_ -> ref -> Set ref
forall a. a -> Set a
Set.singleton ref
ref) (Name -> Name -> Ordering
Name.compareSuffix Name
name)
        Set ref -> (Set ref -> Set ref) -> Set ref
forall a b. a -> (a -> b) -> b
& (ref -> Bool) -> Set ref -> Set ref
forall a. (a -> Bool) -> Set a -> Set a
Set.filter \ref
ref -> ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref

filterUnconflictedBySuffix ::
  forall ref.
  (Ord ref) =>
  (ref -> ShortHash) ->
  HashQualified Name ->
  BiMultimap ref Name ->
  BiMultimap ref Name
filterUnconflictedBySuffix :: forall ref.
Ord ref =>
(ref -> ShortHash)
-> HashQualified Name -> BiMultimap ref Name -> BiMultimap ref Name
filterUnconflictedBySuffix ref -> ShortHash
_ (NameOnly Name
name) BiMultimap ref Name
m = Name -> BiMultimap ref Name -> BiMultimap ref Name
forall ref.
Ord ref =>
Name -> BiMultimap ref Name -> BiMultimap ref Name
Name.filterUnconflictedBySuffix Name
name BiMultimap ref Name
m
filterUnconflictedBySuffix ref -> ShortHash
refHash (HashQualified Name
name ShortHash
hash) BiMultimap ref Name
m =
  BiMultimap ref Name
-> (ref -> BiMultimap ref Name) -> Maybe ref -> BiMultimap ref Name
forall b a. b -> (a -> b) -> Maybe a -> b
maybe BiMultimap ref Name
suffixMatches (\ref
ref -> ref -> Name -> BiMultimap ref Name
forall a b. a -> b -> BiMultimap a b
BiMultimap.singleton ref
ref Name
name) Maybe ref
exactMatch
  where
    exactMatch :: Maybe ref
    exactMatch :: Maybe ref
exactMatch = do
      ref
ref <- Name -> BiMultimap ref Name -> Maybe ref
forall b a. Ord b => b -> BiMultimap a b -> Maybe a
BiMultimap.lookupRan Name
name BiMultimap ref Name
m
      Bool -> Maybe ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (ref -> Bool
hashMatches ref
ref)
      ref -> Maybe ref
forall a. a -> Maybe a
Just ref
ref

    suffixMatches :: BiMultimap ref Name
    suffixMatches :: BiMultimap ref Name
suffixMatches =
      (ref -> Name -> BiMultimap ref Name -> BiMultimap ref Name)
-> BiMultimap ref Name
-> (Name -> Ordering)
-> BiMultimap ref Name
-> BiMultimap ref Name
forall a b acc.
(a -> b -> acc -> acc)
-> acc -> (b -> Ordering) -> BiMultimap a b -> acc
BiMultimap.searchrRan ref -> Name -> BiMultimap ref Name -> BiMultimap ref Name
f BiMultimap ref Name
forall a b. (Ord a, Ord b) => BiMultimap a b
BiMultimap.empty (Name -> Name -> Ordering
Name.compareSuffix Name
name) BiMultimap ref Name
m
      where
        f :: ref -> Name -> BiMultimap ref Name -> BiMultimap ref Name
        f :: ref -> Name -> BiMultimap ref Name -> BiMultimap ref Name
f ref
ref Name
name BiMultimap ref Name
acc
          | ref -> Bool
hashMatches ref
ref = ref -> Name -> BiMultimap ref Name -> BiMultimap ref Name
forall a b.
(Ord a, Ord b) =>
a -> b -> BiMultimap a b -> BiMultimap a b
BiMultimap.insert ref
ref Name
name BiMultimap ref Name
acc
          | Bool
otherwise = BiMultimap ref Name
acc

    hashMatches :: ref -> Bool
    hashMatches :: ref -> Bool
hashMatches ref
ref =
      ShortHash
hash ShortHash -> ShortHash -> Bool
`SH.isPrefixOf` ref -> ShortHash
refHash ref
ref

instance (Name.Alphabetical n) => Name.Alphabetical (HashQualified n) where
  compareAlphabetical :: HashQualified n -> HashQualified n -> Ordering
compareAlphabetical (NameOnly n
n) (NameOnly n
n2) = n -> n -> Ordering
forall n. Alphabetical n => n -> n -> Ordering
Name.compareAlphabetical n
n n
n2
  -- NameOnly comes first
  compareAlphabetical NameOnly {} HashQualified {} = Ordering
LT
  compareAlphabetical HashQualified {} NameOnly {} = Ordering
GT
  compareAlphabetical (HashQualified n
n ShortHash
sh) (HashQualified n
n2 ShortHash
sh2) = n -> n -> Ordering
forall n. Alphabetical n => n -> n -> Ordering
Name.compareAlphabetical n
n n
n2 Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> ShortHash -> ShortHash -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ShortHash
sh ShortHash
sh2