module Unison.Merge.Mergeblob2
  ( Mergeblob2 (..),
    Mergeblob2Error (..),
    makeMergeblob2,
  )
where

import Data.List qualified as List
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Unison.ConstructorReference (GConstructorReference (..))
import Unison.DataDeclaration (Decl)
import Unison.DeclNameLookup (DeclNameLookup)
import Unison.Merge.EitherWay (EitherWay (..))
import Unison.Merge.FindConflictedAlias (findConflictedAlias)
import Unison.Merge.Mergeblob1 (Mergeblob1 (..))
import Unison.Merge.PartitionCombinedDiffs (narrowConflictsToNonBuiltins)
import Unison.Merge.ThreeWay (ThreeWay)
import Unison.Merge.ThreeWay qualified as ThreeWay
import Unison.Merge.TwoWay (TwoWay (..))
import Unison.Merge.TwoWay qualified as TwoWay
import Unison.Merge.Unconflicts (Unconflicts)
import Unison.Merge.Unconflicts qualified as Unconflicts
import Unison.Name (Name)
import Unison.NameSegment (NameSegment)
import Unison.Parser.Ann (Ann)
import Unison.Prelude
import Unison.Reference (TermReference, TermReferenceId, TypeReference, TypeReferenceId)
import Unison.Reference qualified as Reference
import Unison.Referent (Referent)
import Unison.Referent qualified as Referent
import Unison.Symbol (Symbol)
import Unison.Term (Term)
import Unison.Type (Type)
import Unison.Util.BiMultimap (BiMultimap)
import Unison.Util.BiMultimap qualified as BiMultimap
import Unison.Util.Defn (Defn)
import Unison.Util.Defns (Defns (..), DefnsF, defnsAreEmpty, zipDefnsWith)

data Mergeblob2 libdep = Mergeblob2
  { forall libdep.
Mergeblob2 libdep
-> TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts :: TwoWay (DefnsF (Map Name) TermReferenceId TypeReferenceId),
    forall libdep.
Mergeblob2 libdep
-> TwoWay (DefnsF Set TermReference TermReference)
coreDependencies :: TwoWay (DefnsF Set TermReference TypeReference),
    forall libdep. Mergeblob2 libdep -> TwoWay DeclNameLookup
declNameLookups :: TwoWay DeclNameLookup,
    forall libdep.
Mergeblob2 libdep
-> ThreeWay
     (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
defns :: ThreeWay (Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)),
    forall libdep. Mergeblob2 libdep -> Bool
hasConflicts :: Bool,
    forall libdep.
Mergeblob2 libdep
-> TwoWay
     (DefnsF
        (Map Name)
        (TermReferenceId, (Term Symbol Ann, Type Symbol Ann))
        (TermReferenceId, Decl Symbol Ann))
hydratedDefns ::
      TwoWay
        ( DefnsF
            (Map Name)
            (TermReferenceId, (Term Symbol Ann, Type Symbol Ann))
            (TypeReferenceId, Decl Symbol Ann)
        ),
    forall libdep. Mergeblob2 libdep -> Map NameSegment libdep
libdeps :: Map NameSegment libdep,
    forall libdep. Mergeblob2 libdep -> TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes :: TwoWay (DefnsF Set Name Name),
    forall libdep.
Mergeblob2 libdep -> DefnsF Unconflicts Referent TermReference
unconflicts :: DefnsF Unconflicts Referent TypeReference
  }

data Mergeblob2Error
  = Mergeblob2Error'ConflictedAlias (EitherWay (Defn (Name, Name) (Name, Name)))
  | Mergeblob2Error'ConflictedBuiltin (Defn Name Name)

makeMergeblob2 :: Mergeblob1 libdep -> Either Mergeblob2Error (Mergeblob2 libdep)
makeMergeblob2 :: forall libdep.
Mergeblob1 libdep -> Either Mergeblob2Error (Mergeblob2 libdep)
makeMergeblob2 Mergeblob1 libdep
blob = do
  -- Bail early if it looks like we can't proceed with the merge, because Alice or Bob has one or more conflicted alias
  TwoWay
  (Defn (Name, Name) (Name, Name)
   -> EitherWay (Defn (Name, Name) (Name, Name)),
   DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference)
-> ((Defn (Name, Name) (Name, Name)
     -> EitherWay (Defn (Name, Name) (Name, Name)),
     DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference)
    -> Either Mergeblob2Error ())
-> Either Mergeblob2Error ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ ((,) ((Defn (Name, Name) (Name, Name)
  -> EitherWay (Defn (Name, Name) (Name, Name)))
 -> DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference
 -> (Defn (Name, Name) (Name, Name)
     -> EitherWay (Defn (Name, Name) (Name, Name)),
     DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference))
-> TwoWay
     (Defn (Name, Name) (Name, Name)
      -> EitherWay (Defn (Name, Name) (Name, Name)))
-> TwoWay
     (DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference
      -> (Defn (Name, Name) (Name, Name)
          -> EitherWay (Defn (Name, Name) (Name, Name)),
          DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Defn (Name, Name) (Name, Name)
 -> EitherWay (Defn (Name, Name) (Name, Name)))
-> (Defn (Name, Name) (Name, Name)
    -> EitherWay (Defn (Name, Name) (Name, Name)))
-> TwoWay
     (Defn (Name, Name) (Name, Name)
      -> EitherWay (Defn (Name, Name) (Name, Name)))
forall a. a -> a -> TwoWay a
TwoWay Defn (Name, Name) (Name, Name)
-> EitherWay (Defn (Name, Name) (Name, Name))
forall a. a -> EitherWay a
Alice Defn (Name, Name) (Name, Name)
-> EitherWay (Defn (Name, Name) (Name, Name))
forall a. a -> EitherWay a
Bob TwoWay
  (DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference
   -> (Defn (Name, Name) (Name, Name)
       -> EitherWay (Defn (Name, Name) (Name, Name)),
       DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference))
-> TwoWay
     (DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference)
-> TwoWay
     (Defn (Name, Name) (Name, Name)
      -> EitherWay (Defn (Name, Name) (Name, Name)),
      DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference)
forall a b. TwoWay (a -> b) -> TwoWay a -> TwoWay b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Mergeblob1 libdep
blob.diffs) \(Defn (Name, Name) (Name, Name)
-> EitherWay (Defn (Name, Name) (Name, Name))
who, DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference
diff) ->
    Maybe (Defn (Name, Name) (Name, Name))
-> (Defn (Name, Name) (Name, Name) -> Either Mergeblob2Error ())
-> Either Mergeblob2Error ()
forall (m :: * -> *) a.
Applicative m =>
Maybe a -> (a -> m ()) -> m ()
whenJust (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
-> DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference
-> Maybe (Defn (Name, Name) (Name, Name))
forall name (synhashed :: * -> *) term typ.
(Ord name, forall ref. Eq (synhashed ref), Ord term, Ord typ) =>
Defns (BiMultimap term name) (BiMultimap typ name)
-> DefnsF3 (Map name) DiffOp synhashed term typ
-> Maybe (Defn (name, name) (name, name))
findConflictedAlias Mergeblob1 libdep
blob.defns.lca DefnsF3 (Map Name) DiffOp Synhashed Referent TermReference
diff) ((Defn (Name, Name) (Name, Name) -> Either Mergeblob2Error ())
 -> Either Mergeblob2Error ())
-> (Defn (Name, Name) (Name, Name) -> Either Mergeblob2Error ())
-> Either Mergeblob2Error ()
forall a b. (a -> b) -> a -> b
$
      Mergeblob2Error -> Either Mergeblob2Error ()
forall a b. a -> Either a b
Left (Mergeblob2Error -> Either Mergeblob2Error ())
-> (Defn (Name, Name) (Name, Name) -> Mergeblob2Error)
-> Defn (Name, Name) (Name, Name)
-> Either Mergeblob2Error ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EitherWay (Defn (Name, Name) (Name, Name)) -> Mergeblob2Error
Mergeblob2Error'ConflictedAlias (EitherWay (Defn (Name, Name) (Name, Name)) -> Mergeblob2Error)
-> (Defn (Name, Name) (Name, Name)
    -> EitherWay (Defn (Name, Name) (Name, Name)))
-> Defn (Name, Name) (Name, Name)
-> Mergeblob2Error
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Defn (Name, Name) (Name, Name)
-> EitherWay (Defn (Name, Name) (Name, Name))
who

  TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts <- TwoWay (DefnsF (Map Name) TermReference TermReference)
-> Either
     (Defn Name Name)
     (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId))
narrowConflictsToNonBuiltins Mergeblob1 libdep
blob.conflicts Either
  (Defn Name Name)
  (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId))
-> (Either
      (Defn Name Name)
      (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId))
    -> Either
         Mergeblob2Error
         (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)))
-> Either
     Mergeblob2Error
     (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId))
forall a b. a -> (a -> b) -> b
& (Defn Name Name -> Mergeblob2Error)
-> Either
     (Defn Name Name)
     (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId))
-> Either
     Mergeblob2Error
     (TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId))
forall a c b. (a -> c) -> Either a b -> Either c b
mapLeft Defn Name Name -> Mergeblob2Error
Mergeblob2Error'ConflictedBuiltin

  let soloUpdatesAndDeletes :: TwoWay (DefnsF Set Name Name)
      soloUpdatesAndDeletes :: TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes =
        DefnsF Unconflicts Referent TermReference
-> TwoWay (DefnsF Set Name Name)
forall term typ.
DefnsF Unconflicts term typ -> TwoWay (DefnsF Set Name Name)
Unconflicts.soloUpdatesAndDeletes Mergeblob1 libdep
blob.unconflicts

  let coreDependencies :: TwoWay (DefnsF Set TermReference TypeReference)
      coreDependencies :: TwoWay (DefnsF Set TermReference TermReference)
coreDependencies =
        TwoWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay (DefnsF Set TermReferenceId TermReferenceId)
-> TwoWay (DefnsF Set Name Name)
-> TwoWay (DefnsF Set TermReference TermReference)
identifyCoreDependencies
          (ThreeWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay
     (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
forall a. ThreeWay a -> TwoWay a
ThreeWay.forgetLca Mergeblob1 libdep
blob.defns)
          ((Map Name TermReferenceId -> Set TermReferenceId)
-> (Map Name TermReferenceId -> Set TermReferenceId)
-> DefnsF (Map Name) TermReferenceId TermReferenceId
-> DefnsF Set TermReferenceId TermReferenceId
forall a b c d. (a -> b) -> (c -> d) -> Defns a c -> Defns b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap ([TermReferenceId] -> Set TermReferenceId
forall a. Ord a => [a] -> Set a
Set.fromList ([TermReferenceId] -> Set TermReferenceId)
-> (Map Name TermReferenceId -> [TermReferenceId])
-> Map Name TermReferenceId
-> Set TermReferenceId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Name TermReferenceId -> [TermReferenceId]
forall k a. Map k a -> [a]
Map.elems) ([TermReferenceId] -> Set TermReferenceId
forall a. Ord a => [a] -> Set a
Set.fromList ([TermReferenceId] -> Set TermReferenceId)
-> (Map Name TermReferenceId -> [TermReferenceId])
-> Map Name TermReferenceId
-> Set TermReferenceId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Name TermReferenceId -> [TermReferenceId]
forall k a. Map k a -> [a]
Map.elems) (DefnsF (Map Name) TermReferenceId TermReferenceId
 -> DefnsF Set TermReferenceId TermReferenceId)
-> TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
-> TwoWay (DefnsF Set TermReferenceId TermReferenceId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts)
          TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes

  pure
    Mergeblob2
      { TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
$sel:conflicts:Mergeblob2 :: TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts :: TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts,
        TwoWay (DefnsF Set TermReference TermReference)
$sel:coreDependencies:Mergeblob2 :: TwoWay (DefnsF Set TermReference TermReference)
coreDependencies :: TwoWay (DefnsF Set TermReference TermReference)
coreDependencies,
        $sel:declNameLookups:Mergeblob2 :: TwoWay DeclNameLookup
declNameLookups = Mergeblob1 libdep
blob.declNameLookups,
        $sel:defns:Mergeblob2 :: ThreeWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
defns = Mergeblob1 libdep
blob.defns,
        -- Eh, they'd either both be null, or neither, but just check both maps anyway
        $sel:hasConflicts:Mergeblob2 :: Bool
hasConflicts = Bool -> Bool
not (DefnsF (Map Name) TermReferenceId TermReferenceId -> Bool
forall (f :: * -> *) (g :: * -> *) a b.
(Foldable f, Foldable g) =>
Defns (f a) (g b) -> Bool
defnsAreEmpty TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts.alice) Bool -> Bool -> Bool
|| Bool -> Bool
not (DefnsF (Map Name) TermReferenceId TermReferenceId -> Bool
forall (f :: * -> *) (g :: * -> *) a b.
(Foldable f, Foldable g) =>
Defns (f a) (g b) -> Bool
defnsAreEmpty TwoWay (DefnsF (Map Name) TermReferenceId TermReferenceId)
conflicts.bob),
        $sel:hydratedDefns:Mergeblob2 :: TwoWay
  (DefnsF
     (Map Name)
     (TermReferenceId, (Term Symbol Ann, Type Symbol Ann))
     (TermReferenceId, Decl Symbol Ann))
hydratedDefns = ThreeWay
  (DefnsF
     (Map Name)
     (TermReferenceId, (Term Symbol Ann, Type Symbol Ann))
     (TermReferenceId, Decl Symbol Ann))
-> TwoWay
     (DefnsF
        (Map Name)
        (TermReferenceId, (Term Symbol Ann, Type Symbol Ann))
        (TermReferenceId, Decl Symbol Ann))
forall a. ThreeWay a -> TwoWay a
ThreeWay.forgetLca Mergeblob1 libdep
blob.hydratedDefns,
        $sel:libdeps:Mergeblob2 :: Map NameSegment libdep
libdeps = Mergeblob1 libdep
blob.libdeps,
        TwoWay (DefnsF Set Name Name)
$sel:soloUpdatesAndDeletes:Mergeblob2 :: TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes :: TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes,
        $sel:unconflicts:Mergeblob2 :: DefnsF Unconflicts Referent TermReference
unconflicts = Mergeblob1 libdep
blob.unconflicts
      }

identifyCoreDependencies ::
  TwoWay (Defns (BiMultimap Referent Name) (BiMultimap TypeReference Name)) ->
  TwoWay (DefnsF Set TermReferenceId TypeReferenceId) ->
  TwoWay (DefnsF Set Name Name) ->
  TwoWay (DefnsF Set TermReference TypeReference)
identifyCoreDependencies :: TwoWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay (DefnsF Set TermReferenceId TermReferenceId)
-> TwoWay (DefnsF Set Name Name)
-> TwoWay (DefnsF Set TermReference TermReference)
identifyCoreDependencies TwoWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
defns TwoWay (DefnsF Set TermReferenceId TermReferenceId)
conflicts TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes = do
  [TwoWay (DefnsF Set TermReference TermReference)]
-> TwoWay (DefnsF Set TermReference TermReference)
forall m. Monoid m => [m] -> m
forall (t :: * -> *) m. (Foldable t, Monoid m) => t m -> m
fold
    [ -- One source of dependencies: Alice's versions of Bob's unconflicted deletes and updates, and vice-versa.
      --
      -- This is name-based: if Bob updates the *name* "foo", then we go find the thing that Alice calls "foo" (if
      -- anything), no matter what its hash is.
      Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
-> DefnsF Set TermReference TermReference
forall name.
Defns (BiMultimap Referent name) (BiMultimap TermReference name)
-> DefnsF Set TermReference TermReference
defnsReferences
        (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
 -> DefnsF Set TermReference TermReference)
-> TwoWay
     (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay (DefnsF Set TermReference TermReference)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ( (Set Name -> BiMultimap Referent Name -> BiMultimap Referent Name)
-> (Set Name
    -> BiMultimap TermReference Name -> BiMultimap TermReference Name)
-> DefnsF Set Name Name
-> Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
-> Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
forall tm1 tm2 tm3 ty1 ty2 ty3.
(tm1 -> tm2 -> tm3)
-> (ty1 -> ty2 -> ty3)
-> Defns tm1 ty1
-> Defns tm2 ty2
-> Defns tm3 ty3
zipDefnsWith Set Name -> BiMultimap Referent Name -> BiMultimap Referent Name
forall a b.
(Ord a, Ord b) =>
Set b -> BiMultimap a b -> BiMultimap a b
BiMultimap.restrictRan Set Name
-> BiMultimap TermReference Name -> BiMultimap TermReference Name
forall a b.
(Ord a, Ord b) =>
Set b -> BiMultimap a b -> BiMultimap a b
BiMultimap.restrictRan
                (DefnsF Set Name Name
 -> Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
 -> Defns
      (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay (DefnsF Set Name Name)
-> TwoWay
     (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
      -> Defns
           (BiMultimap Referent Name) (BiMultimap TermReference Name))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TwoWay (DefnsF Set Name Name) -> TwoWay (DefnsF Set Name Name)
forall a. TwoWay a -> TwoWay a
TwoWay.swap TwoWay (DefnsF Set Name Name)
soloUpdatesAndDeletes
                TwoWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name)
   -> Defns
        (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay
     (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
-> TwoWay
     (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
forall a b. TwoWay (a -> b) -> TwoWay a -> TwoWay b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TwoWay
  (Defns (BiMultimap Referent Name) (BiMultimap TermReference Name))
defns
            ),
      -- The other source of dependencies: Alice's own conflicted things, and ditto for Bob.
      --
      -- An example: suppose Alice has foo#alice and Bob has foo#bob, so foo is conflicted. Furthermore, suppose
      -- Alice has bar#bar that depends on foo#alice.
      --
      -- We want Alice's #alice to be considered a dependency, so that when we go off and find dependents of these
      -- dependencies to put in the scratch file for type checking and propagation, we find bar#bar.
      --
      -- Note that this is necessary even if bar#bar is unconflicted! We don't want bar#bar to be put directly
      -- into the namespace / parsing context for the conflicted merge, because it has an unnamed reference on
      -- foo#alice. It rather ought to be in the scratchfile alongside the conflicted foo#alice and foo#bob, so
      -- that when that conflict is resolved, it will propagate to bar.
      (Set TermReferenceId -> Set TermReference)
-> (Set TermReferenceId -> Set TermReference)
-> DefnsF Set TermReferenceId TermReferenceId
-> DefnsF Set TermReference TermReference
forall a b c d. (a -> b) -> (c -> d) -> Defns a c -> Defns b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap ((TermReferenceId -> TermReference)
-> Set TermReferenceId -> Set TermReference
forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map TermReferenceId -> TermReference
forall h t. Id' h -> Reference' t h
Reference.DerivedId) ((TermReferenceId -> TermReference)
-> Set TermReferenceId -> Set TermReference
forall b a. Ord b => (a -> b) -> Set a -> Set b
Set.map TermReferenceId -> TermReference
forall h t. Id' h -> Reference' t h
Reference.DerivedId) (DefnsF Set TermReferenceId TermReferenceId
 -> DefnsF Set TermReference TermReference)
-> TwoWay (DefnsF Set TermReferenceId TermReferenceId)
-> TwoWay (DefnsF Set TermReference TermReference)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TwoWay (DefnsF Set TermReferenceId TermReferenceId)
conflicts
    ]

defnsReferences ::
  Defns (BiMultimap Referent name) (BiMultimap TypeReference name) ->
  DefnsF Set TermReference TypeReference
defnsReferences :: forall name.
Defns (BiMultimap Referent name) (BiMultimap TermReference name)
-> DefnsF Set TermReference TermReference
defnsReferences Defns (BiMultimap Referent name) (BiMultimap TermReference name)
defns =
  (DefnsF Set TermReference TermReference
 -> Referent -> DefnsF Set TermReference TermReference)
-> DefnsF Set TermReference TermReference
-> [Referent]
-> DefnsF Set TermReference TermReference
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl' DefnsF Set TermReference TermReference
-> Referent -> DefnsF Set TermReference TermReference
f Defns {$sel:terms:Defns :: Set TermReference
terms = Set TermReference
forall a. Set a
Set.empty, $sel:types:Defns :: Set TermReference
types = BiMultimap TermReference name -> Set TermReference
forall a b. BiMultimap a b -> Set a
BiMultimap.dom Defns (BiMultimap Referent name) (BiMultimap TermReference name)
defns.types} (Set Referent -> [Referent]
forall a. Set a -> [a]
Set.toList (BiMultimap Referent name -> Set Referent
forall a b. BiMultimap a b -> Set a
BiMultimap.dom Defns (BiMultimap Referent name) (BiMultimap TermReference name)
defns.terms))
  where
    f :: DefnsF Set TermReference TypeReference -> Referent -> DefnsF Set TermReference TypeReference
    f :: DefnsF Set TermReference TermReference
-> Referent -> DefnsF Set TermReference TermReference
f DefnsF Set TermReference TermReference
acc = \case
      Referent.Con (ConstructorReference TermReference
ref ConstructorId
_) ConstructorType
_ ->
        let !types :: Set TermReference
types = TermReference -> Set TermReference -> Set TermReference
forall a. Ord a => a -> Set a -> Set a
Set.insert TermReference
ref DefnsF Set TermReference TermReference
acc.types
         in Defns {$sel:terms:Defns :: Set TermReference
terms = DefnsF Set TermReference TermReference
acc.terms, Set TermReference
$sel:types:Defns :: Set TermReference
types :: Set TermReference
types}
      Referent.Ref TermReference
ref ->
        let !terms :: Set TermReference
terms = TermReference -> Set TermReference -> Set TermReference
forall a. Ord a => a -> Set a -> Set a
Set.insert TermReference
ref DefnsF Set TermReference TermReference
acc.terms
         in Defns {Set TermReference
$sel:terms:Defns :: Set TermReference
terms :: Set TermReference
terms, $sel:types:Defns :: Set TermReference
types = DefnsF Set TermReference TermReference
acc.types}