@@ -14,6 +14,7 @@ module Unison.Codebase.Editor.HandleInput.Update2
1414where
1515
1616import Control.Lens (over , (^.) )
17+ import Control.Lens qualified as Lens
1718import Control.Monad.RWS (ask )
1819import Data.Foldable qualified as Foldable
1920import Data.List.NonEmpty qualified as NonEmpty
@@ -35,6 +36,7 @@ import Unison.Codebase.Branch qualified as Branch
3536import Unison.Codebase.Branch.Names qualified as Branch
3637import Unison.Codebase.Branch.Type (Branch0 )
3738import Unison.Codebase.BranchUtil qualified as BranchUtil
39+ import Unison.Codebase.Editor.Output (Output )
3840import Unison.Codebase.Editor.Output qualified as Output
3941import Unison.Codebase.Path (Path )
4042import Unison.Codebase.Path qualified as Path
@@ -64,6 +66,7 @@ import Unison.Prelude
6466import Unison.PrettyPrintEnvDecl (PrettyPrintEnvDecl )
6567import Unison.PrettyPrintEnvDecl qualified as PPED
6668import Unison.PrettyPrintEnvDecl.Names qualified as PPE
69+ import Unison.Reference (TypeReferenceId )
6770import Unison.Reference qualified as Reference (fromId )
6871import Unison.Referent (Referent )
6972import Unison.Referent qualified as Referent
@@ -77,6 +80,7 @@ import Unison.Type (Type)
7780import Unison.UnisonFile qualified as UF
7881import Unison.UnisonFile.Names qualified as UF
7982import Unison.UnisonFile.Type (TypecheckedUnisonFile , UnisonFile )
83+ import Unison.Util.Monoid qualified as Monoid
8084import Unison.Util.Nametree (Defns (.. ))
8185import Unison.Util.Pretty (Pretty )
8286import Unison.Util.Pretty qualified as Pretty
@@ -98,14 +102,14 @@ handleUpdate2 = do
98102 let ctorNames = forwardCtorNames namesExcludingLibdeps
99103
100104 Cli. respond Output. UpdateLookingForDependents
101- (pped, bigUf) <- Cli. runTransaction do
105+ (pped, bigUf) <- Cli. runTransactionWithRollback \ abort -> do
102106 dependents <-
103107 Ops. dependentsWithinScope
104108 (Names. referenceIds namesExcludingLibdeps)
105109 (getExistingReferencesNamed termAndDeclNames namesExcludingLibdeps)
106110 -- - construct PPE for printing UF* for typechecking (whatever data structure we decide to print)
107111 pped <- Codebase. hashLength <&> (`PPE.fromNamesDecl` (NamesWithHistory. fromCurrentNames namesIncludingLibdeps))
108- bigUf <- buildBigUnisonFile codebase tuf dependents namesExcludingLibdeps ctorNames
112+ bigUf <- buildBigUnisonFile abort codebase tuf dependents namesExcludingLibdeps ctorNames
109113 let tufPped = PPE. fromNamesDecl 8 (Names. NamesWithHistory (UF. typecheckedToNames tuf) mempty )
110114
111115 pure (pped `PPED.addFallback` tufPped, bigUf)
@@ -161,16 +165,14 @@ makeParsingEnv path names = do
161165 }
162166
163167-- save definitions and namespace
164- saveTuf :: (Name -> [Name ]) -> TypecheckedUnisonFile Symbol Ann -> Cli ()
168+ saveTuf :: (Name -> Either Output [Name ]) -> TypecheckedUnisonFile Symbol Ann -> Cli ()
165169saveTuf getConstructors tuf = do
166170 Cli. Env {codebase} <- ask
167171 currentPath <- Cli. getCurrentPath
168- Cli. runTransaction $ Codebase. addDefsToCodebase codebase tuf
169- Cli. stepAt
170- " update"
171- ( Path. unabsolute currentPath,
172- Branch. batchUpdates (typecheckedUnisonFileToBranchUpdates getConstructors tuf)
173- )
172+ branchUpdates <- Cli. runTransactionWithRollback \ abort -> do
173+ Codebase. addDefsToCodebase codebase tuf
174+ typecheckedUnisonFileToBranchUpdates abort getConstructors tuf
175+ Cli. stepAt " update" (Path. unabsolute currentPath, Branch. batchUpdates branchUpdates)
174176
175177-- @typecheckedUnisonFileToBranchUpdates getConstructors file@ returns a list of branch updates (suitable for passing
176178-- along to `batchUpdates` or some "step at" combinator) that corresponds to using all of the contents of @file@.
@@ -184,28 +186,30 @@ saveTuf getConstructors tuf = do
184186--
185187-- [ ("foo.bar", insert-term("baz",<#foo>)) ]
186188typecheckedUnisonFileToBranchUpdates ::
187- (Name -> [Name ]) ->
188- TypecheckedUnisonFile Symbol a ->
189- [(Path , Branch0 m -> Branch0 m )]
190- typecheckedUnisonFileToBranchUpdates getConstructors tuf =
191- declUpdates ++ termUpdates
189+ (forall void . Output -> Transaction void ) ->
190+ (Name -> Either Output [Name ]) ->
191+ TypecheckedUnisonFile Symbol Ann ->
192+ Transaction [(Path , Branch0 m -> Branch0 m )]
193+ typecheckedUnisonFileToBranchUpdates abort getConstructors tuf = do
194+ declUpdates <- makeDeclUpdates abort
195+ pure $ declUpdates ++ termUpdates
192196 where
193- declUpdates :: [(Path , Branch0 m -> Branch0 m )]
194- declUpdates =
195- fold
196- [ foldMap makeDataDeclUpdates (Map. toList $ UF. dataDeclarationsId' tuf),
197- foldMap makeEffectDeclUpdates (Map. toList $ UF. effectDeclarationsId' tuf)
198- ]
197+ makeDeclUpdates :: forall m . (forall void . Output -> Transaction void ) -> Transaction [(Path , Branch0 m -> Branch0 m )]
198+ makeDeclUpdates abort = do
199+ dataDeclUpdates <- Monoid. foldMapM makeDataDeclUpdates (Map. toList $ UF. dataDeclarationsId' tuf)
200+ effectDeclUpdates <- Monoid. foldMapM makeEffectDeclUpdates (Map. toList $ UF. effectDeclarationsId' tuf)
201+ pure $ dataDeclUpdates <> effectDeclUpdates
199202 where
200203 makeDataDeclUpdates (symbol, (typeRefId, dataDecl)) = makeDeclUpdates (symbol, (typeRefId, Right dataDecl))
201204 makeEffectDeclUpdates (symbol, (typeRefId, effectDecl)) = makeDeclUpdates (symbol, (typeRefId, Left effectDecl))
202- makeDeclUpdates (symbol, (typeRefId, decl)) =
205+ makeDeclUpdates :: (Symbol , (TypeReferenceId , Decl Symbol Ann )) -> Transaction [(Path , Branch0 m -> Branch0 m )]
206+ makeDeclUpdates (symbol, (typeRefId, decl)) = do
207+ -- some decls will be deleted, we want to delete their
208+ -- constructors as well
209+ deleteConstructorActions <- case map (BranchUtil. makeAnnihilateTermName . Path. splitFromName) <$> getConstructors (Name. unsafeFromVar symbol) of
210+ Left err -> abort err
211+ Right actions -> pure actions
203212 let deleteTypeAction = BranchUtil. makeAnnihilateTypeName split
204- -- some decls will be deleted, we want to delete their constructors as well
205- deleteConstructorActions =
206- map
207- (BranchUtil. makeAnnihilateTermName . Path. splitFromName)
208- (getConstructors (Name. unsafeFromVar symbol))
209213 split = splitVar symbol
210214 insertTypeAction = BranchUtil. makeAddTypeName split (Reference. fromId typeRefId) Map. empty
211215 insertTypeConstructorActions =
@@ -218,7 +222,7 @@ typecheckedUnisonFileToBranchUpdates getConstructors tuf =
218222 referentIdsWithNames
219223 deleteStuff = deleteTypeAction : deleteConstructorActions
220224 addStuff = insertTypeAction : insertTypeConstructorActions
221- in deleteStuff ++ addStuff
225+ pure $ deleteStuff ++ addStuff
222226
223227 termUpdates :: [(Path , Branch0 m -> Branch0 m )]
224228 termUpdates =
@@ -243,36 +247,38 @@ getExistingReferencesNamed defns names = fromTerms <> fromTypes
243247 fromTypes = foldMap (\ n -> Relation. lookupDom n $ Names. types names) (defns ^. # types)
244248
245249buildBigUnisonFile ::
250+ (forall a . Output -> Transaction a ) ->
246251 Codebase IO Symbol Ann ->
247252 TypecheckedUnisonFile Symbol Ann ->
248253 Map Reference. Id ReferenceType ->
249254 Names ->
250255 Map ForwardName (Referent , Name ) ->
251256 Transaction (UnisonFile Symbol Ann )
252- buildBigUnisonFile c tuf dependents names ctorNames =
253- addDefinitionsToUnisonFile c names ctorNames dependents (UF. discardTypes tuf)
257+ buildBigUnisonFile abort c tuf dependents names ctorNames =
258+ addDefinitionsToUnisonFile abort c names ctorNames dependents (UF. discardTypes tuf)
254259
255- -- | @addDefinitionsToUnisonFile codebase names ctorNames definitions file@ adds all @definitions@ to @file@, avoiding
260+ -- | @addDefinitionsToUnisonFile abort codebase names ctorNames definitions file@ adds all @definitions@ to @file@, avoiding
256261-- overwriting anything already in @file@. Every definition is put into the file with every naming it has in @names@ "on
257262-- the left-hand-side of the equals" (but yes type decls don't really have a LHS).
258263--
259264-- TODO: find a better module for this function, as it's used in a couple places
260265addDefinitionsToUnisonFile ::
266+ (forall void . Output -> Transaction void ) ->
261267 Codebase IO Symbol Ann ->
262268 Names ->
263269 Map ForwardName (Referent , Name ) ->
264270 Map Reference. Id ReferenceType ->
265271 UnisonFile Symbol Ann ->
266272 Transaction (UnisonFile Symbol Ann )
267- addDefinitionsToUnisonFile c names ctorNames dependents initialUnisonFile =
273+ addDefinitionsToUnisonFile abort c names ctorNames dependents initialUnisonFile =
268274 -- for each dependent, add its definition with all its names to the UnisonFile
269275 foldM addComponent initialUnisonFile (Map. toList dependents')
270276 where
271277 dependents' :: Map Hash ReferenceType = Map. mapKeys (\ (Reference. Id h _pos) -> h) dependents
272278 addComponent :: UnisonFile Symbol Ann -> (Hash , ReferenceType ) -> Transaction (UnisonFile Symbol Ann )
273279 addComponent uf (h, rt) = case rt of
274280 Reference. RtTerm -> addTermComponent h uf
275- Reference. RtType -> addDeclComponent h uf
281+ Reference. RtType -> addDeclComponent abort h uf
276282 addTermComponent :: Hash -> UnisonFile Symbol Ann -> Transaction (UnisonFile Symbol Ann )
277283 addTermComponent h uf = do
278284 termComponent <- Codebase. unsafeGetTermComponent c h
@@ -292,32 +298,37 @@ addDefinitionsToUnisonFile c names ctorNames dependents initialUnisonFile =
292298
293299 -- given a dependent hash, include that component in the scratch file
294300 -- todo: wundefined: cut off constructor name prefixes
295- addDeclComponent :: Hash -> UnisonFile Symbol Ann -> Transaction (UnisonFile Symbol Ann )
296- addDeclComponent h uf = do
301+ addDeclComponent :: ( forall a . Output -> Transaction a ) -> Hash -> UnisonFile Symbol Ann -> Transaction (UnisonFile Symbol Ann )
302+ addDeclComponent abort h uf = do
297303 declComponent <- fromJust <$> Codebase. getDeclComponent h
298- pure $ foldl' addDeclElement uf (zip declComponent [0 .. ])
304+ foldM addDeclElement uf (zip declComponent [0 .. ])
299305 where
300306 -- for each name a decl has, update its constructor names according to what exists in the namespace
301- addDeclElement :: UnisonFile Symbol Ann -> (Decl Symbol Ann , Reference. Pos ) -> UnisonFile Symbol Ann
307+ addDeclElement :: UnisonFile Symbol Ann -> (Decl Symbol Ann , Reference. Pos ) -> Transaction ( UnisonFile Symbol Ann )
302308 addDeclElement uf (decl, i) = do
303309 let declNames = Relation. lookupRan (Reference. Derived h i) names. types
304310 -- look up names for this decl's constructor based on the decl's name, and embed them in the decl definition.
305- foldl' (addRebuiltDefinition decl) uf declNames
311+ foldM (addRebuiltDefinition decl) uf declNames
306312 where
307313 -- skip any definitions that already have names, we don't want to overwrite what the user has supplied
314+ addRebuiltDefinition :: (Decl Symbol Ann ) -> UnisonFile Symbol Ann -> Name -> Transaction (UnisonFile Symbol Ann )
308315 addRebuiltDefinition decl uf name = case decl of
309- Left ed -> uf {UF. effectDeclarationsId = Map. insertWith (\ _new old -> old) (Name. toVar name) (Reference. Id h i, Decl. EffectDeclaration $ overwriteConstructorNames name ed. toDataDecl) uf. effectDeclarationsId}
310- Right dd -> uf {UF. dataDeclarationsId = Map. insertWith (\ _new old -> old) (Name. toVar name) (Reference. Id h i, overwriteConstructorNames name dd) uf. dataDeclarationsId}
311- overwriteConstructorNames :: Name -> DataDeclaration Symbol Ann -> DataDeclaration Symbol Ann
316+ Left ed ->
317+ overwriteConstructorNames name ed. toDataDecl >>= \ case
318+ ed' -> pure uf {UF. effectDeclarationsId = Map. insertWith (\ _new old -> old) (Name. toVar name) (Reference. Id h i, Decl. EffectDeclaration ed') uf. effectDeclarationsId}
319+ Right dd ->
320+ overwriteConstructorNames name dd >>= \ case
321+ dd' -> pure uf {UF. dataDeclarationsId = Map. insertWith (\ _new old -> old) (Name. toVar name) (Reference. Id h i, dd') uf. dataDeclarationsId}
322+ overwriteConstructorNames :: Name -> DataDeclaration Symbol Ann -> Transaction (DataDeclaration Symbol Ann )
312323 overwriteConstructorNames name dd =
313- let constructorNames :: [Symbol ]
314- constructorNames =
315- Name. toVar . fromJust . Name. stripNamePrefix name
316- <$> findCtorNames names ctorNames ( Just $ Decl. constructorCount dd) name
324+ let constructorNames :: Transaction [Symbol ]
325+ constructorNames = case findCtorNames names ctorNames ( Just $ Decl. constructorCount dd) name of
326+ Left err -> abort err
327+ Right array -> pure $ Name. toVar . fromJust . Name. stripNamePrefix name <$> array
317328 swapConstructorNames oldCtors =
318329 let (annotations, _vars, types) = unzip3 oldCtors
319- in zip3 annotations constructorNames types
320- in over Decl. constructors_ swapConstructorNames dd
330+ in zip3 annotations <$> constructorNames <*> pure types
331+ in Lens. traverseOf Decl. constructors_ swapConstructorNames dd
321332
322333-- | O(r + c * d) touches all the referents (r), and all the NameSegments (d) of all of the Con referents (c)
323334forwardCtorNames :: Names -> Map ForwardName (Referent , Name )
@@ -329,7 +340,7 @@ forwardCtorNames names =
329340 ]
330341
331342-- | given a decl name, find names for all of its constructors, in order.
332- findCtorNames :: Names -> Map ForwardName (Referent , Name ) -> Maybe Int -> Name -> [Name ]
343+ findCtorNames :: Names -> Map ForwardName (Referent , Name ) -> Maybe Int -> Name -> Either Output. Output [Name ]
333344findCtorNames names forwardCtorNames ctorCount n =
334345 let declRef = Set. findMin $ Relation. lookupDom n names. types
335346 f = ForwardName. fromName n
@@ -348,9 +359,10 @@ findCtorNames names forwardCtorNames ctorCount n =
348359 m = foldl' insertShortest mempty (Foldable. toList center)
349360 ctorCountGuess = fromMaybe (Map. size m) ctorCount
350361 in if Map. size m == ctorCountGuess && all (isJust . flip Map. lookup m) [0 .. fromIntegral ctorCountGuess - 1 ]
351- then Map. elems m
352- else error $ " incomplete constructor mapping for " ++ show n ++ " : " ++ show ( Map. keys m) ++ " out of " ++ show ctorCountGuess
362+ then Right $ Map. elems m
363+ else Left $ Output. UpdateIncompleteConstructorSet n m ctorCountGuess
353364
365+ -- Used by `findCtorNames` to filter `forwardCtorNames` to a narrow range which will be searched linearly.
354366-- >>> incrementLastSegmentChar $ ForwardName.fromName $ Name.unsafeFromText "foo.bar.quux"
355367-- ForwardName {toList = "foo" :| ["bar","quuy"]}
356368incrementLastSegmentChar :: ForwardName -> ForwardName
@@ -367,7 +379,7 @@ incrementLastSegmentChar (ForwardName segments) =
367379 else Text. init text `Text.append` Text. singleton (succ $ Text. last text)
368380 in NameSegment incrementedText
369381
370- getTermAndDeclNames :: Var v => TypecheckedUnisonFile v a -> Defns (Set Name ) (Set Name )
382+ getTermAndDeclNames :: ( Var v ) => TypecheckedUnisonFile v a -> Defns (Set Name ) (Set Name )
371383getTermAndDeclNames tuf = Defns (terms <> effectCtors <> dataCtors) (effects <> datas)
372384 where
373385 terms = keysToNames $ UF. hashTermsId tuf
0 commit comments