77{-# LANGUAGE UndecidableInstances #-}
88{-# LANGUAGE ViewPatterns #-}
99
10- module Unison.Hashing.V2.ABT (Unison.ABT. Term , hash , hashComponents ) where
10+ module Unison.Hashing.V2.ABT
11+ ( Unison.ABT. Term ,
12+ IncompleteElementOrderingError (.. ),
13+ hash ,
14+ hashComponents ,
15+ )
16+ where
1117
18+ import Data.Containers.ListUtils qualified as List
1219import Data.List hiding (cycle , find )
1320import Data.List qualified as List (sort )
1421import Data.Map qualified as Map
@@ -20,20 +27,25 @@ import Unison.Hashing.V2.Tokenizable qualified as Hashable
2027import Unison.Prelude
2128import Prelude hiding (abs , cycle )
2229
30+ data IncompleteElementOrderingError = IncompleteElementOrderingError
31+ deriving (Show , Eq , Ord )
32+
2333-- Hash a strongly connected component and sort its definitions into a canonical order.
2434hashComponent ::
2535 forall a f v .
2636 (Functor f , Hashable1 f , Foldable f , Eq v , Show v , Ord v ) =>
2737 Map. Map v (Term f v a ) ->
28- (Hash , [(v , Term f v a )])
29- hashComponent byName =
38+ Either IncompleteElementOrderingError (Hash , [(v , Term f v a )])
39+ hashComponent byName = do
3040 let ts = Map. toList byName
3141 -- First, compute a canonical hash ordering of the component, as well as an environment in which we can hash
3242 -- individual names.
3343 (hashes, env) = doHashCycle [] ts
34- -- Construct a list of tokens that is shared by all members of the component. They are disambiguated only by their
35- -- name that gets tumbled into the hash.
36- commonTokens :: [Hashable. Token ]
44+ when (List. nubOrd hashes /= hashes) $ do
45+ Left IncompleteElementOrderingError
46+ -- Construct a list of tokens that is shared by all members of the component. They are disambiguated only by their
47+ -- name that gets tumbled into the hash.
48+ let commonTokens :: [Hashable. Token ]
3749 commonTokens = Hashable. Tag 1 : map Hashable. Hashed hashes
3850 -- Use a helper function that hashes a single term given its name, now that we have an environment in which we can
3951 -- look the name up, as well as the common tokens.
@@ -47,30 +59,33 @@ hashComponent byName =
4759 & sortOn fst
4860 & unzip
4961 overallHash = Hashable. accumulate (map Hashable. Hashed hashes')
50- in (overallHash, permutedTerms)
62+ pure (overallHash, permutedTerms)
5163
5264-- Group the definitions into strongly connected components and hash
5365-- each component. Substitute the hash of each component into subsequent
5466-- components (using the `termFromHash` function). Requires that the
5567-- overall component has no free variables.
5668hashComponents ::
69+ forall f v a .
5770 (Functor f , Hashable1 f , Foldable f , Eq v , Show v , Var v ) =>
5871 (Hash -> Word64 -> Term f v () ) ->
5972 Map. Map v (Term f v a ) ->
60- [(Hash , [(v , Term f v a )])]
61- hashComponents termFromHash termsByName =
73+ Either IncompleteElementOrderingError [(Hash , [(v , Term f v a )])]
74+ hashComponents termFromHash termsByName = do
6275 let bound = Set. fromList (Map. keys termsByName)
6376 escapedVars = Set. unions (freeVars <$> Map. elems termsByName) `Set.difference` bound
6477 sccs = components (Map. toList termsByName)
65- go _ [] = []
66- go prevHashes (component : rest) =
78+ go :: Map v (Term f v () ) -> [[(v , Term f v a )]] -> Either IncompleteElementOrderingError [(Hash , [(v , Term f v a )])]
79+ go _ [] = pure $ []
80+ go prevHashes (component : rest) = do
6781 let sub = substsInheritAnnotation (Map. toList prevHashes)
68- (h, sortedComponent) = hashComponent $ Map. fromList [(v, sub t) | (v, t) <- component]
69- curHashes = Map. fromList [(v, termFromHash h i) | ((v, _), i) <- sortedComponent `zip` [0 .. ]]
82+ (h, sortedComponent) <- hashComponent $ Map. fromList [(v, sub t) | (v, t) <- component]
83+ let curHashes = Map. fromList [(v, termFromHash h i) | ((v, _), i) <- sortedComponent `zip` [0 .. ]]
7084 newHashes = prevHashes `Map.union` curHashes
7185 newHashesL = Map. toList newHashes
7286 sortedComponent' = [(v, substsInheritAnnotation newHashesL t) | (v, t) <- sortedComponent]
73- in (h, sortedComponent') : go newHashes rest
87+ sortedRest <- go newHashes rest
88+ pure $ ((h, sortedComponent') : sortedRest)
7489 in if Set. null escapedVars
7590 then go Map. empty sccs
7691 else
0 commit comments