⅄ trunk → 21-12-05-sqlite-query-exception

This commit is contained in:
Mitchell Rosen 2021-12-08 20:26:14 -05:00
commit 5e183f5971
31 changed files with 808 additions and 422 deletions

View File

@ -2,6 +2,7 @@
module Unison.Util.Map
( bimap,
bitraverse,
deleteLookup,
foldMapM,
unionWithM,
)
@ -20,6 +21,11 @@ bimap fa fb = Map.fromList . map (B.bimap fa fb) . Map.toList
bitraverse :: (Applicative f, Ord a') => (a -> f a') -> (b -> f b') -> Map a b -> f (Map a' b')
bitraverse fa fb = fmap Map.fromList . traverse (B.bitraverse fa fb) . Map.toList
-- | Like 'Map.delete', but returns the value as well.
deleteLookup :: Ord k => k -> Map k v -> (Maybe v, Map k v)
deleteLookup =
Map.alterF (,Nothing)
-- | Construct a map from a foldable container by mapping each element to monadic action that returns a key and a value.
--
-- The map is constructed from the left: if two elements map to the same key, the second will overwrite the first.

View File

@ -45,6 +45,7 @@ default-extensions:
- NamedFieldPuns
- NumericUnderscores
- OverloadedStrings
- PatternSynonyms
- ScopedTypeVariables
- TupleSections
- TypeApplications

View File

@ -9,6 +9,8 @@ module Unison.Sqlite.Exception
-- ** @SqliteQueryException@
SqliteQueryException (..),
pattern SqliteBusyException,
isSqliteBusyException,
SqliteQueryExceptionInfo (..),
throwSqliteQueryException,
SomeSqliteExceptionReason (..),
@ -74,7 +76,7 @@ rethrowAsSqliteConnectException name file exception = do
------------------------------------------------------------------------------------------------------------------------
-- SomeSqliteException
-- └── SqliteConnectException
-- └── SqliteQueryException
-- | A @SqliteQueryException@ represents an exception thrown during processing a query, paired with some context that
-- resulted in the exception.
@ -101,6 +103,15 @@ instance Exception SqliteQueryException where
toException = toException . SomeSqliteException
fromException = fromException >=> \(SomeSqliteException e) -> cast e
pattern SqliteBusyException :: SqliteQueryException
pattern SqliteBusyException <- (isSqliteBusyException -> True)
isSqliteBusyException :: SqliteQueryException -> Bool
isSqliteBusyException SqliteQueryException {exception = SomeSqliteExceptionReason reason} =
case cast reason of
Just (Sqlite.SQLError Sqlite.ErrorBusy _ _) -> True
_ -> False
data SqliteQueryExceptionInfo params connection = SqliteQueryExceptionInfo
{ connection :: connection,
sql :: Sql,

View File

@ -24,12 +24,12 @@ data JournalMode
journalModeFromText :: Text -> Maybe JournalMode
journalModeFromText = \case
"DELETE" -> Just JournalMode'DELETE
"TRUNCATE" -> Just JournalMode'TRUNCATE
"PERSIST" -> Just JournalMode'PERSIST
"MEMORY" -> Just JournalMode'MEMORY
"WAL" -> Just JournalMode'WAL
"OFF" -> Just JournalMode'OFF
"delete" -> Just JournalMode'DELETE
"truncate" -> Just JournalMode'TRUNCATE
"persist" -> Just JournalMode'PERSIST
"memory" -> Just JournalMode'MEMORY
"wal" -> Just JournalMode'WAL
"off" -> Just JournalMode'OFF
_ -> Nothing
unsafeJournalModeFromText :: HasCallStack => Text -> JournalMode
@ -38,12 +38,12 @@ unsafeJournalModeFromText s =
journalModeToText :: JournalMode -> Text
journalModeToText = \case
JournalMode'DELETE -> "DELETE"
JournalMode'TRUNCATE -> "TRUNCATE"
JournalMode'PERSIST -> "PERSIST"
JournalMode'MEMORY -> "MEMORY"
JournalMode'WAL -> "WAL"
JournalMode'OFF -> "OFF"
JournalMode'DELETE -> "delete"
JournalMode'TRUNCATE -> "truncate"
JournalMode'PERSIST -> "persist"
JournalMode'MEMORY -> "memory"
JournalMode'WAL -> "wal"
JournalMode'OFF -> "off"
trySetJournalMode :: JournalMode -> Transaction ()
trySetJournalMode mode0 = do

View File

@ -50,14 +50,17 @@ module Unison.Sqlite.Transaction
)
where
import Control.Concurrent (threadDelay)
import Control.Exception (Exception (fromException), onException, throwIO)
import Control.Monad.Trans.Reader (ReaderT (..))
import qualified Database.SQLite.Simple as Sqlite
import qualified Database.SQLite.Simple.FromField as Sqlite
import Unison.Prelude
import Unison.Prelude hiding (try)
import Unison.Sqlite.Connection (Connection (..))
import qualified Unison.Sqlite.Connection as Connection
import Unison.Sqlite.Exception (SqliteExceptionReason)
import Unison.Sqlite.Exception (SqliteExceptionReason, SqliteQueryException, pattern SqliteBusyException)
import Unison.Sqlite.Sql
import UnliftIO.Exception (catchAny, try, trySyncOrAsync, uninterruptibleMask)
newtype Transaction a
= Transaction (Connection -> IO a)
@ -67,13 +70,35 @@ newtype Transaction a
-- | Run a transaction on the given connection.
runTransaction :: MonadIO m => Connection -> Transaction a -> m a
runTransaction conn@(Connection _ _ conn0) (Transaction f) =
-- TODO some sensible retry logic
liftIO do
Sqlite.execute_ conn0 "BEGIN"
result <- f conn
Sqlite.execute_ conn0 "COMMIT"
runTransaction conn (Transaction f) = liftIO do
uninterruptibleMask \restore -> do
Connection.execute_ conn "BEGIN"
result <-
-- Catch all exceptions (sync or async), because we want to ROLLBACK the BEGIN no matter what.
trySyncOrAsync @_ @SomeException (restore (f conn)) >>= \case
Left exception -> do
ignoringExceptions rollback
case fromException exception of
Just SqliteBusyException ->
let loop microseconds = do
restore (threadDelay microseconds)
try @_ @SqliteQueryException (Connection.execute_ conn "BEGIN IMMEDIATE") >>= \case
Left SqliteBusyException -> loop (microseconds * 2)
Left exception -> throwIO exception
Right () -> restore (f conn) `onException` ignoringExceptions rollback
in loop 100_000
_ -> throwIO exception
Right result -> pure result
Connection.execute_ conn "COMMIT"
pure result
where
rollback :: IO ()
rollback =
Connection.execute_ conn "ROLLBACK"
ignoringExceptions :: IO () -> IO ()
ignoringExceptions action =
action `catchAny` \_ -> pure ()
-- Without results, with parameters

View File

@ -47,6 +47,7 @@ library
NamedFieldPuns
NumericUnderscores
OverloadedStrings
PatternSynonyms
ScopedTypeVariables
TupleSections
TypeApplications

View File

@ -18,6 +18,12 @@ main =
bench "intersection" $ nf (uncurry R.intersection) rs,
bench "union" $ nf (uncurry R.union) rs
],
env (pure (R.fromList ((,) <$> [(1 :: Int) .. 1000] <*> [(1 :: Int) .. 1000]))) \r ->
bgroup
"replaceDom"
[ bench "old implementation" (nf (oldReplaceDom 1 2) r),
bench "new implementation" (nf (R.replaceDom 2 2) r)
],
env (genRelation @Char @Char 10000 2) \r ->
env (genSet @Char 100) \s ->
bgroup
@ -30,6 +36,10 @@ main =
]
]
oldReplaceDom :: (Ord a, Ord b) => a -> a -> Relation a b -> Relation a b
oldReplaceDom a a' r =
foldl' (\r b -> R.insert a' b $ R.delete a b r) r (R.lookupDom a r)
oldSubtractDom :: (Ord a, Ord b) => Set a -> Relation a b -> Relation a b
oldSubtractDom s r =
R.fromList [(a, b) | (a, b) <- R.toList r, not (a `Set.member` s)]

View File

@ -114,7 +114,9 @@ import qualified Data.Map as Map
import qualified Data.Map.Internal as Map
import Data.Ord (comparing)
import qualified Data.Set as S
import qualified Data.Set as Set
import Unison.Prelude hiding (empty, toList)
import qualified Unison.Util.Map as Map
import qualified Unison.Util.Set as Set
import Prelude hiding (filter, map, null)
@ -602,13 +604,31 @@ searchDom f r = go (domain r)
searchRan :: (Ord a, Ord b) => (b -> Ordering) -> Relation a b -> Set a
searchRan f r = searchDom f (swap r)
-- | @replaceDom x y r@ replaces all @(x, _)@ with @(y, _)@ in @r@.
replaceDom :: (Ord a, Ord b) => a -> a -> Relation a b -> Relation a b
replaceDom a a' r =
foldl' (\r b -> insert a' b $ delete a b r) r (lookupDom a r)
if a == a'
then r
else case Map.deleteLookup a (domain r) of
(Nothing, _) -> r
(Just bs, domain') ->
Relation
{ domain = Map.insertWith Set.union a' bs domain',
range = foldl' (\acc b -> Map.adjust (Set.insert a' . Set.delete a) b acc) (range r) bs
}
-- | @replaceRan x y r@ replaces all @(_, x)@ with @(_, y)@ in @r@.
replaceRan :: (Ord a, Ord b) => b -> b -> Relation a b -> Relation a b
replaceRan b b' r =
foldl' (\r a -> insert a b' $ delete a b r) r (lookupRan b r)
if b == b'
then r
else case Map.deleteLookup b (range r) of
(Nothing, _) -> r
(Just as, range') ->
Relation
{ domain = foldl' (\acc a -> Map.adjust (Set.insert b' . Set.delete b) a acc) (domain r) as,
range = Map.insertWith Set.union b' as range'
}
updateDom :: (Ord a, Ord b) => (a -> a) -> b -> Relation a b -> Relation a b
updateDom f b r =

View File

@ -128,6 +128,9 @@ fromList xs = insertAll xs empty
empty :: (Ord a, Ord b, Ord c) => Relation3 a b c
empty = mempty
null :: Relation3 a b c -> Bool
null r = Map.null $ d1 r
insert, delete
:: (Ord a, Ord b, Ord c)
=> a -> b -> c -> Relation3 a b c -> Relation3 a b c

View File

@ -47,6 +47,9 @@ toList = fmap (\(a,(b,(c,d))) -> (a,b,c,d)) . toNestedList
empty :: (Ord a, Ord b, Ord c, Ord d) => Relation4 a b c d
empty = mempty
null :: Relation4 a b c d -> Bool
null r = Map.null $ d1 r
fromList :: (Ord a, Ord b, Ord c, Ord d) => [(a,b,c,d)] -> Relation4 a b c d
fromList xs = insertAll xs empty

View File

@ -476,6 +476,7 @@ builtinsSrc =
, B "ThreadId.toText" $ threadId --> text
, B "Debug.watch" $ forall1 "a" (\a -> text --> a --> a)
, B "Debug.trace" $ forall1 "a" (\a -> text --> a --> unit)
, B "unsafe.coerceAbilities" $
forall4 "a" "b" "e1" "e2" $ \a b e1 e2 ->
(a --> Type.effect1 () e1 b) --> (a --> Type.effect1 () e2 b)

View File

@ -39,6 +39,7 @@ module Unison.Codebase.Branch
, head
, headHash
, children
, nonEmptyChildren
, deepEdits'
, toList0
-- * step
@ -118,6 +119,7 @@ import qualified Unison.Util.Star3 as Star3
import qualified Unison.Util.List as List
import qualified Data.Semialign as Align
import Data.These (These(..))
import qualified Unison.Util.Relation as Relation
-- | A node in the Unison namespace hierarchy
-- along with its history.
@ -228,6 +230,12 @@ types =
children :: Lens' (Branch0 m) (Map NameSegment (Branch m))
children = lens _children (\Branch0{..} x -> branch0 _terms _types x _edits)
nonEmptyChildren :: Branch0 m -> Map NameSegment (Branch m)
nonEmptyChildren b =
b
& _children
& Map.filter (not . isEmpty0 . head)
-- creates a Branch0 from the primary fields and derives the others.
branch0 ::
forall m.
@ -260,7 +268,7 @@ branch0 terms types children edits =
-- | Derive the 'deepTerms' field of a branch.
deriveDeepTerms :: Branch0 m -> Branch0 m
deriveDeepTerms branch =
branch {deepTerms = makeDeepTerms (_terms branch) (_children branch)}
branch {deepTerms = makeDeepTerms (_terms branch) (nonEmptyChildren branch)}
where
makeDeepTerms :: Metadata.Star Referent NameSegment -> Map NameSegment (Branch m) -> Relation Referent Name
makeDeepTerms terms children =
@ -273,7 +281,7 @@ deriveDeepTerms branch =
-- | Derive the 'deepTypes' field of a branch.
deriveDeepTypes :: Branch0 m -> Branch0 m
deriveDeepTypes branch =
branch {deepTypes = makeDeepTypes (_types branch) (_children branch)}
branch {deepTypes = makeDeepTypes (_types branch) (nonEmptyChildren branch)}
where
makeDeepTypes :: Metadata.Star TypeReference NameSegment -> Map NameSegment (Branch m) -> Relation TypeReference Name
makeDeepTypes types children =
@ -286,7 +294,7 @@ deriveDeepTypes branch =
-- | Derive the 'deepTermMetadata' field of a branch.
deriveDeepTermMetadata :: Branch0 m -> Branch0 m
deriveDeepTermMetadata branch =
branch {deepTermMetadata = makeDeepTermMetadata (_terms branch) (_children branch)}
branch {deepTermMetadata = makeDeepTermMetadata (_terms branch) (nonEmptyChildren branch)}
where
makeDeepTermMetadata :: Metadata.Star Referent NameSegment -> Map NameSegment (Branch m) -> Metadata.R4 Referent Name
makeDeepTermMetadata terms children =
@ -299,7 +307,7 @@ deriveDeepTermMetadata branch =
-- | Derive the 'deepTypeMetadata' field of a branch.
deriveDeepTypeMetadata :: Branch0 m -> Branch0 m
deriveDeepTypeMetadata branch =
branch {deepTypeMetadata = makeDeepTypeMetadata (_types branch) (_children branch)}
branch {deepTypeMetadata = makeDeepTypeMetadata (_types branch) (nonEmptyChildren branch)}
where
makeDeepTypeMetadata :: Metadata.Star TypeReference NameSegment -> Map NameSegment (Branch m) -> Metadata.R4 TypeReference Name
makeDeepTypeMetadata types children =
@ -312,7 +320,7 @@ deriveDeepTypeMetadata branch =
-- | Derive the 'deepPaths' field of a branch.
deriveDeepPaths :: Branch0 m -> Branch0 m
deriveDeepPaths branch =
branch {deepPaths = makeDeepPaths (_children branch)}
branch {deepPaths = makeDeepPaths (nonEmptyChildren branch)}
where
makeDeepPaths :: Map NameSegment (Branch m) -> Set Path
makeDeepPaths children =
@ -325,7 +333,7 @@ deriveDeepPaths branch =
-- | Derive the 'deepEdits' field of a branch.
deriveDeepEdits :: Branch0 m -> Branch0 m
deriveDeepEdits branch =
branch {deepEdits = makeDeepEdits (_edits branch) (_children branch)}
branch {deepEdits = makeDeepEdits (_edits branch) (nonEmptyChildren branch)}
where
makeDeepEdits :: Map NameSegment (EditHash, m Patch) -> Map NameSegment (Branch m) -> Map Name EditHash
makeDeepEdits edits children =
@ -500,9 +508,15 @@ empty0 :: Branch0 m
empty0 =
Branch0 mempty mempty mempty mempty mempty mempty mempty mempty mempty mempty
-- | Checks whether a Branch0 is empty.
-- | Checks whether a Branch0 is empty, which means that the branch contains no terms or
-- types, and that the heads of all children are empty by the same definition.
-- This is not as easy as checking whether the branch is equal to the `empty0` branch
-- because child branches may be empty, but still have history.
isEmpty0 :: Branch0 m -> Bool
isEmpty0 = (== empty0)
isEmpty0 (Branch0 _terms _types _children _edits deepTerms deepTypes _deepTermMetadata _deepTypeMetadata _deepPaths deepEdits) =
Relation.null deepTerms
&& Relation.null deepTypes
&& Map.null deepEdits
-- | Checks whether a branch is empty AND has no history.
isEmpty :: Branch m -> Bool
@ -784,10 +798,13 @@ consBranch ::
-- If the target branch is empty we just replace it.
consBranch Empty headBranch = discardHistory headBranch
consBranch baseBranch headBranch =
Branch $
Causal.consDistinct
(head headBranch & children .~ combinedChildren)
(_history baseBranch)
if baseBranch == headBranch
then baseBranch
else
Branch $
Causal.consDistinct
(head headBranch & children .~ combinedChildren)
(_history baseBranch)
where
combineChildren :: These (Branch m) (Branch m) -> Branch m
combineChildren = \case

View File

@ -14,7 +14,7 @@ where
import qualified Control.Concurrent
import Control.Monad (filterM, unless, when, (>=>))
import Control.Monad.Except (ExceptT, MonadError (throwError), runExceptT, withExceptT)
import Control.Monad.Except (ExceptT (ExceptT), runExceptT, withExceptT)
import qualified Control.Monad.Except as Except
import Control.Monad.Extra (ifM, unlessM)
import qualified Control.Monad.Extra as Monad
@ -110,7 +110,6 @@ import qualified UnliftIO
import UnliftIO.Directory (canonicalizePath, createDirectoryIfMissing, doesDirectoryExist, doesFileExist)
import UnliftIO.STM
import UnliftIO.Exception (catch, bracket)
import Control.Monad.Trans.Except (mapExceptT)
debug, debugProcessBranches, debugCommitFailedTransaction :: Bool
debug = False
@ -174,16 +173,17 @@ createCodebaseOrError' debugName path action = do
fmap (Either.mapLeft CreateCodebaseUnknownSchemaVersion) (sqliteCodebase debugName path action)
openOrCreateCodebaseConnection ::
MonadIO m =>
withOpenOrCreateCodebaseConnection ::
(MonadUnliftIO m) =>
Codebase.DebugName ->
FilePath ->
m (IO (), Connection)
openOrCreateCodebaseConnection debugName path = do
(Connection -> m r) ->
m r
withOpenOrCreateCodebaseConnection debugName path action = do
unlessM
(doesFileExist $ path </> codebasePath)
(initSchemaIfNotExist path)
unsafeGetConnection debugName path
withConnection debugName path action
-- get the codebase in dir
getCodebaseOrError ::
@ -1113,13 +1113,12 @@ pushGitBranch srcConn branch repo (PushGitBranchOpts setRoot _syncMode) = runExc
-- set up the cache dir
remotePath <- time "Git fetch" $ withExceptT C.GitProtocolError $ pullBranch (writeToRead repo)
(closeDestConn, destConn) <- openOrCreateCodebaseConnection "push.dest" remotePath
mapExceptT (`finally` liftIO closeDestConn) $ do
ExceptT . withOpenOrCreateCodebaseConnection "push.dest" remotePath $ \destConn -> do
flip runReaderT destConn $ Q.savepoint "push"
lift . flip State.execStateT emptySyncProgressState $
flip State.execStateT emptySyncProgressState $
syncInternal syncProgress srcConn destConn (Branch.transform lift branch)
flip runReaderT destConn do
if setRoot
result <- if setRoot
then do
let newRootHash = Branch.headHash branch
-- the call to runDB "handles" the possible DB error by bombing
@ -1127,6 +1126,7 @@ pushGitBranch srcConn branch repo (PushGitBranchOpts setRoot _syncMode) = runExc
Nothing -> do
setRepoRoot newRootHash
Q.release "push"
pure $ Right ()
Just oldRootHash -> do
before oldRootHash newRootHash >>= \case
Nothing ->
@ -1139,13 +1139,17 @@ pushGitBranch srcConn branch repo (PushGitBranchOpts setRoot _syncMode) = runExc
++ "."
Just False -> do
Q.rollbackRelease "push"
throwError . C.GitProtocolError $ GitError.PushDestinationHasNewStuff repo
pure . Left . C.GitProtocolError $ GitError.PushDestinationHasNewStuff repo
Just True -> do
setRepoRoot newRootHash
Q.release "push"
else Q.release "push"
pure $ Right ()
else do
Q.release "push"
pure $ Right ()
Q.setJournalMode JournalMode.DELETE
pure result
liftIO do
void $ push remotePath repo
where

View File

@ -762,7 +762,7 @@ data POp
| CVLD -- validate
| VALU | TLTT -- value, Term.Link.toText
-- Debug
| PRNT | INFO
| PRNT | INFO | TRCE
-- STM
| ATOM
deriving (Show,Eq,Ord)

View File

@ -736,6 +736,12 @@ raise
where
i = fromIntegral $ builtinTypeNumbering Map.! Ty.exceptionRef
gen'trace :: Var v => SuperNormal v
gen'trace
= binop0 0 $ \[t,v]
-> TLets Direct [] [] (TPrm TRCE [t,v])
$ TCon Ty.unitRef 0 []
code'missing :: Var v => SuperNormal v
code'missing
= unop0 1 $ \[link,b]
@ -1457,6 +1463,7 @@ builtinLookup
, ("bug", bug "builtin.bug")
, ("todo", bug "builtin.todo")
, ("Debug.watch", watch)
, ("Debug.trace", gen'trace)
, ("unsafe.coerceAbilities", poly'coerce)
, ("Char.toNat", cast Ty.charRef Ty.natRef)

View File

@ -53,6 +53,7 @@ import qualified Unison.LabeledDependency as RF
import Unison.Reference (Reference)
import qualified Unison.Referent as RF (pattern Ref)
import qualified Unison.Reference as RF
import qualified Unison.Util.Text as UT
import Unison.Util.EnumContainers as EC
@ -332,11 +333,22 @@ evalInContext ppe ctx w = do
crs <- readTVarIO (combRefs $ ccache ctx)
let hook = watchHook r
decom = decompile (backReferenceTm crs (decompTm ctx))
prettyError (PE _ p) = p
prettyError (BU nm c) = either id (bugMsg ppe nm) $ decom c
tr tx c = case decom c of
Right dv -> do
putStrLn $ "trace: " ++ UT.unpack tx
putStrLn . toANSI 50 $ pretty ppe dv
Left _ -> do
putStrLn $ "trace: " ++ UT.unpack tx
putStrLn "Couldn't decompile value."
print c
result <- traverse (const $ readIORef r)
. first prettyError
<=< try $ apply0 (Just hook) (ccache ctx) w
<=< try $ apply0 (Just hook) ((ccache ctx) { tracer = tr }) w
pure $ decom =<< result
executeMainComb
@ -483,7 +495,7 @@ getStoredCache = SCache
restoreCache :: StoredCache -> IO CCache
restoreCache (SCache cs crs trs ftm fty int rtm rty)
= CCache builtinForeigns
= CCache builtinForeigns uglyTrace
<$> newTVarIO (cs <> combs)
<*> newTVarIO (crs <> builtinTermBackref)
<*> newTVarIO (trs <> builtinTypeBackref)
@ -493,6 +505,9 @@ restoreCache (SCache cs crs trs ftm fty int rtm rty)
<*> newTVarIO (rtm <> builtinTermNumbering)
<*> newTVarIO (rty <> builtinTypeNumbering)
where
uglyTrace tx c = do
putStrLn $ "trace: " ++ UT.unpack tx
print c
rns = emptyRNs { dnum = refLookup "ty" builtinTypeNumbering }
combs
= mapWithKey

View File

@ -352,7 +352,7 @@ data BPrim2
-- bytes
| TAKB | DRPB | IDXB | CATB -- take,drop,index,append
-- general
| THRO -- throw
| THRO | TRCE -- throw
deriving (Show, Eq, Ord)
data MLit
@ -1074,6 +1074,7 @@ emitPOp ANF.VALU = emitBP1 VALU
-- error call
emitPOp ANF.EROR = emitBP2 THRO
emitPOp ANF.TRCE = emitBP2 TRCE
-- non-prim translations
emitPOp ANF.BLDS = Seq

View File

@ -59,7 +59,10 @@ import Unison.Runtime.Foreign.Function
import Unison.Runtime.Stack
import Unison.Runtime.MCode
import Unison.Util.Text (Text)
import qualified Unison.Type as Rf
import qualified Unison.Builtin.Decls as Rf
import qualified Unison.Util.Bytes as By
import Unison.Util.Pretty (toPlainUnbroken)
@ -74,6 +77,7 @@ type DEnv = EnumMap Word64 Closure
data CCache
= CCache
{ foreignFuncs :: EnumMap Word64 ForeignFunc
, tracer :: Text -> Closure -> IO ()
, combs :: TVar (EnumMap Word64 Combs)
, combRefs :: TVar (EnumMap Word64 Reference)
, tagRefs :: TVar (EnumMap Word64 Reference)
@ -105,7 +109,7 @@ refNumTy' cc r = M.lookup r <$> refNumsTy cc
baseCCache :: IO CCache
baseCCache
= CCache builtinForeigns
= CCache builtinForeigns noTrace
<$> newTVarIO combs
<*> newTVarIO builtinTermBackref
<*> newTVarIO builtinTypeBackref
@ -115,6 +119,7 @@ baseCCache
<*> newTVarIO builtinTermNumbering
<*> newTVarIO builtinTypeNumbering
where
noTrace _ _ = pure ()
ftm = 1 + maximum builtinTermNumbering
fty = 1 + maximum builtinTypeNumbering
@ -184,6 +189,23 @@ apply1 callback env clo = do
where
k0 = CB $ Hook callback
-- Entry point for evaluating a saved continuation.
--
-- The continuation must be from an evaluation context expecting a
-- unit value.
jump0
:: (Stack 'UN -> Stack 'BX -> IO ())
-> CCache -> Closure -> IO ()
jump0 !callback !env !clo = do
ustk <- alloc
bstk <- alloc
(denv, kf) <-
topDEnv <$> readTVarIO (refTy env) <*> readTVarIO (refTm env)
bstk <- bump bstk
poke bstk (Enum Rf.unitRef unitTag)
jump env denv ustk bstk (kf k0) (BArg1 0) clo
where
k0 = CB (Hook callback)
lookupDenv :: Word64 -> DEnv -> Closure
lookupDenv p denv = fromMaybe BlackHole $ EC.lookup p denv
@ -300,6 +322,11 @@ exec !_ !denv !ustk !bstk !k (BPrim2 CMPU i j) = do
ustk <- bump ustk
poke ustk . fromEnum $ universalCompare compare x y
pure (denv, ustk, bstk, k)
exec !env !denv !ustk !bstk !k (BPrim2 TRCE i j) = do
tx <- peekOffBi bstk i
clo <- peekOff bstk j
tracer env tx clo
pure (denv, ustk, bstk, k)
exec !_ !denv !ustk !bstk !k (BPrim2 op i j) = do
(ustk,bstk) <- bprim2 ustk bstk op i j
pure (denv, ustk, bstk, k)
@ -1373,6 +1400,7 @@ bprim2 !_ !bstk THRO i j = do
name <- peekOffBi @Util.Text.Text bstk i
x <- peekOff bstk j
throwIO (BU (Util.Text.toText name) x)
bprim2 !ustk !bstk TRCE _ _ = pure (ustk, bstk) -- impossible
bprim2 !ustk !bstk CMPU _ _ = pure (ustk, bstk) -- impossible
{-# inline bprim2 #-}
@ -1772,6 +1800,13 @@ charTag
= packTags rt 0
| otherwise = error "internal error: charTag"
unitTag :: Word64
unitTag
| Just n <- M.lookup Rf.unitRef builtinTypeNumbering
, rt <- toEnum (fromIntegral n)
= packTags rt 0
| otherwise = error "internal error: unitTag"
universalCompare
:: (Foreign -> Foreign -> Ordering)
-> Closure

View File

@ -428,6 +428,7 @@ instance Tag BPrim2 where
tag2word IDXB = 18
tag2word CATB = 19
tag2word THRO = 20
tag2word TRCE = 21
word2tag 0 = pure EQLU
word2tag 1 = pure CMPU
@ -450,4 +451,5 @@ instance Tag BPrim2 where
word2tag 18 = pure IDXB
word2tag 19 = pure CATB
word2tag 20 = pure THRO
word2tag 21 = pure TRCE
word2tag n = unknownTag "BPrim2" n

View File

@ -431,7 +431,7 @@ findShallowInBranch codebase b = do
[ ShallowBranchEntry ns
(SBH.fullFromHash $ Branch.headHash b)
(defnCount b)
| (ns, b) <- Map.toList $ Branch._children b0
| (ns, b) <- Map.toList $ Branch.nonEmptyChildren b0
]
patchEntries =
[ ShallowPatchEntry ns

View File

@ -660,7 +660,7 @@ loop = do
let dest = resolveToAbsolute dest0
-- if dest isn't empty: leave dest unchanged, and complain.
destb <- getAt dest
if Branch.isEmpty destb
if Branch.isEmpty0 (Branch.head destb)
then do
ok <- updateAtM dest (const $ pure srcb)
if ok then success else respond $ BranchEmpty src0
@ -848,7 +848,7 @@ loop = do
let path = resolveToAbsolute path'
LoopState.currentPathStack %= Nel.cons path
branch' <- getAt path
when (Branch.isEmpty branch') (respond $ CreatedNewBranch path)
when (Branch.isEmpty0 $ Branch.head branch') (respond $ CreatedNewBranch path)
UpI ->
use LoopState.currentPath >>= \p -> case Path.unsnoc (Path.unabsolute p) of
Nothing -> pure ()
@ -1903,8 +1903,8 @@ doPushRemoteBranch repo localPath syncMode remoteTarget = do
shouldPushTo :: PushBehavior -> Branch m -> Bool
shouldPushTo pushBehavior remoteBranch =
case pushBehavior of
PushBehavior.RequireEmpty -> Branch.isEmpty remoteBranch
PushBehavior.RequireNonEmpty -> not (Branch.isEmpty remoteBranch)
PushBehavior.RequireEmpty -> Branch.isEmpty0 (Branch.head remoteBranch)
PushBehavior.RequireNonEmpty -> not (Branch.isEmpty0 (Branch.head remoteBranch))
-- | Handle a @ShowDefinitionI@ input command, i.e. `view` or `edit`.
handleShowDefinition ::

View File

@ -2057,7 +2057,7 @@ bothCompletors c1 c2 q code b currentPath = do
. nubOrdOn Completion.display
$ suggestions1 ++ suggestions2
-- |
-- | A completer for namespace paths.
pathCompletor ::
Applicative f =>
-- | Turns a query and list of possible completions into a 'Completion'.
@ -2092,7 +2092,7 @@ namespaceArg =
-- | Recursively collects all names of namespaces which are children of the branch.
allSubNamespaces :: Branch.Branch0 m -> [Text]
allSubNamespaces b =
flip Map.foldMapWithKey (Branch._children b) $
flip Map.foldMapWithKey (Branch.nonEmptyChildren b) $
\(NameSegment k) (Branch.head -> b') ->
(k : fmap (\sn -> k <> "." <> sn) (allSubNamespaces b'))

View File

@ -40,6 +40,53 @@ test = scope "gitsync22" . tests $
destroyedRemote :
flip map [(Ucm.CodebaseFormat2, "sc")]
\(fmt, name) -> scope name $ tests [
pushPullTest "pull-over-deleted-namespace" fmt
(\repo -> [i|
```unison:hide
x = 1
```
```ucm:hide
.> add
.> push.create ${repo}
```
|])
(\repo -> [i|
```unison:hide
child.y = 2
```
Should be able to pull a branch from the repo over top of our deleted local branch.
```ucm
.> add
.> delete.namespace child
.> pull ${repo} child
```
|])
,
pushPullTest "push-over-deleted-namespace" fmt
(\repo -> [i|
```unison:hide
child.x = 1
y = 2
```
```ucm:hide
.> add
.> delete.namespace child
.> push.create ${repo}
```
|])
(\repo -> [i|
```unison:hide
child.z = 3
```
Should be able to push a branch over top of a deleted remote branch.
```ucm
.> add
.> push.create ${repo}:.child child
```
|])
,
pushPullTest "typeAlias" fmt
(\repo -> [i|
```ucm

View File

@ -86,389 +86,390 @@ Let's try it!
-> Bytes
-> Bytes
-> Bytes
66. Debug.watch : Text -> a -> a
67. unique type Doc
68. Doc.Blob : Text -> Doc
69. Doc.Evaluate : Term -> Doc
70. Doc.Join : [Doc] -> Doc
71. Doc.Link : Link -> Doc
72. Doc.Signature : Term -> Doc
73. Doc.Source : Link -> Doc
74. structural type Either a b
75. Either.Left : a -> Either a b
76. Either.Right : b -> Either a b
77. structural ability Exception
78. Exception.raise : Failure ->{Exception} x
79. builtin type Float
80. Float.* : Float -> Float -> Float
81. Float.+ : Float -> Float -> Float
82. Float.- : Float -> Float -> Float
83. Float./ : Float -> Float -> Float
84. Float.abs : Float -> Float
85. Float.acos : Float -> Float
86. Float.acosh : Float -> Float
87. Float.asin : Float -> Float
88. Float.asinh : Float -> Float
89. Float.atan : Float -> Float
90. Float.atan2 : Float -> Float -> Float
91. Float.atanh : Float -> Float
92. Float.ceiling : Float -> Int
93. Float.cos : Float -> Float
94. Float.cosh : Float -> Float
95. Float.eq : Float -> Float -> Boolean
96. Float.exp : Float -> Float
97. Float.floor : Float -> Int
98. Float.fromRepresentation : Nat -> Float
99. Float.fromText : Text -> Optional Float
100. Float.gt : Float -> Float -> Boolean
101. Float.gteq : Float -> Float -> Boolean
102. Float.log : Float -> Float
103. Float.logBase : Float -> Float -> Float
104. Float.lt : Float -> Float -> Boolean
105. Float.lteq : Float -> Float -> Boolean
106. Float.max : Float -> Float -> Float
107. Float.min : Float -> Float -> Float
108. Float.pow : Float -> Float -> Float
109. Float.round : Float -> Int
110. Float.sin : Float -> Float
111. Float.sinh : Float -> Float
112. Float.sqrt : Float -> Float
113. Float.tan : Float -> Float
114. Float.tanh : Float -> Float
115. Float.toRepresentation : Float -> Nat
116. Float.toText : Float -> Text
117. Float.truncate : Float -> Int
118. Handle.toText : Handle -> Text
119. builtin type Int
120. Int.* : Int -> Int -> Int
121. Int.+ : Int -> Int -> Int
122. Int.- : Int -> Int -> Int
123. Int./ : Int -> Int -> Int
124. Int.and : Int -> Int -> Int
125. Int.complement : Int -> Int
126. Int.eq : Int -> Int -> Boolean
127. Int.fromRepresentation : Nat -> Int
128. Int.fromText : Text -> Optional Int
129. Int.gt : Int -> Int -> Boolean
130. Int.gteq : Int -> Int -> Boolean
131. Int.increment : Int -> Int
132. Int.isEven : Int -> Boolean
133. Int.isOdd : Int -> Boolean
134. Int.leadingZeros : Int -> Nat
135. Int.lt : Int -> Int -> Boolean
136. Int.lteq : Int -> Int -> Boolean
137. Int.mod : Int -> Int -> Int
138. Int.negate : Int -> Int
139. Int.or : Int -> Int -> Int
140. Int.popCount : Int -> Nat
141. Int.pow : Int -> Nat -> Int
142. Int.shiftLeft : Int -> Nat -> Int
143. Int.shiftRight : Int -> Nat -> Int
144. Int.signum : Int -> Int
145. Int.toFloat : Int -> Float
146. Int.toRepresentation : Int -> Nat
147. Int.toText : Int -> Text
148. Int.trailingZeros : Int -> Nat
149. Int.truncate0 : Int -> Nat
150. Int.xor : Int -> Int -> Int
151. unique type io2.BufferMode
152. io2.BufferMode.BlockBuffering : BufferMode
153. io2.BufferMode.LineBuffering : BufferMode
154. io2.BufferMode.NoBuffering : BufferMode
155. io2.BufferMode.SizedBlockBuffering : Nat -> BufferMode
156. unique type io2.Failure
157. io2.Failure.Failure : Type -> Text -> Any -> Failure
158. unique type io2.FileMode
159. io2.FileMode.Append : FileMode
160. io2.FileMode.Read : FileMode
161. io2.FileMode.ReadWrite : FileMode
162. io2.FileMode.Write : FileMode
163. builtin type io2.Handle
164. builtin type io2.IO
165. io2.IO.clientSocket.impl : Text
66. Debug.trace : Text -> a -> ()
67. Debug.watch : Text -> a -> a
68. unique type Doc
69. Doc.Blob : Text -> Doc
70. Doc.Evaluate : Term -> Doc
71. Doc.Join : [Doc] -> Doc
72. Doc.Link : Link -> Doc
73. Doc.Signature : Term -> Doc
74. Doc.Source : Link -> Doc
75. structural type Either a b
76. Either.Left : a -> Either a b
77. Either.Right : b -> Either a b
78. structural ability Exception
79. Exception.raise : Failure ->{Exception} x
80. builtin type Float
81. Float.* : Float -> Float -> Float
82. Float.+ : Float -> Float -> Float
83. Float.- : Float -> Float -> Float
84. Float./ : Float -> Float -> Float
85. Float.abs : Float -> Float
86. Float.acos : Float -> Float
87. Float.acosh : Float -> Float
88. Float.asin : Float -> Float
89. Float.asinh : Float -> Float
90. Float.atan : Float -> Float
91. Float.atan2 : Float -> Float -> Float
92. Float.atanh : Float -> Float
93. Float.ceiling : Float -> Int
94. Float.cos : Float -> Float
95. Float.cosh : Float -> Float
96. Float.eq : Float -> Float -> Boolean
97. Float.exp : Float -> Float
98. Float.floor : Float -> Int
99. Float.fromRepresentation : Nat -> Float
100. Float.fromText : Text -> Optional Float
101. Float.gt : Float -> Float -> Boolean
102. Float.gteq : Float -> Float -> Boolean
103. Float.log : Float -> Float
104. Float.logBase : Float -> Float -> Float
105. Float.lt : Float -> Float -> Boolean
106. Float.lteq : Float -> Float -> Boolean
107. Float.max : Float -> Float -> Float
108. Float.min : Float -> Float -> Float
109. Float.pow : Float -> Float -> Float
110. Float.round : Float -> Int
111. Float.sin : Float -> Float
112. Float.sinh : Float -> Float
113. Float.sqrt : Float -> Float
114. Float.tan : Float -> Float
115. Float.tanh : Float -> Float
116. Float.toRepresentation : Float -> Nat
117. Float.toText : Float -> Text
118. Float.truncate : Float -> Int
119. Handle.toText : Handle -> Text
120. builtin type Int
121. Int.* : Int -> Int -> Int
122. Int.+ : Int -> Int -> Int
123. Int.- : Int -> Int -> Int
124. Int./ : Int -> Int -> Int
125. Int.and : Int -> Int -> Int
126. Int.complement : Int -> Int
127. Int.eq : Int -> Int -> Boolean
128. Int.fromRepresentation : Nat -> Int
129. Int.fromText : Text -> Optional Int
130. Int.gt : Int -> Int -> Boolean
131. Int.gteq : Int -> Int -> Boolean
132. Int.increment : Int -> Int
133. Int.isEven : Int -> Boolean
134. Int.isOdd : Int -> Boolean
135. Int.leadingZeros : Int -> Nat
136. Int.lt : Int -> Int -> Boolean
137. Int.lteq : Int -> Int -> Boolean
138. Int.mod : Int -> Int -> Int
139. Int.negate : Int -> Int
140. Int.or : Int -> Int -> Int
141. Int.popCount : Int -> Nat
142. Int.pow : Int -> Nat -> Int
143. Int.shiftLeft : Int -> Nat -> Int
144. Int.shiftRight : Int -> Nat -> Int
145. Int.signum : Int -> Int
146. Int.toFloat : Int -> Float
147. Int.toRepresentation : Int -> Nat
148. Int.toText : Int -> Text
149. Int.trailingZeros : Int -> Nat
150. Int.truncate0 : Int -> Nat
151. Int.xor : Int -> Int -> Int
152. unique type io2.BufferMode
153. io2.BufferMode.BlockBuffering : BufferMode
154. io2.BufferMode.LineBuffering : BufferMode
155. io2.BufferMode.NoBuffering : BufferMode
156. io2.BufferMode.SizedBlockBuffering : Nat -> BufferMode
157. unique type io2.Failure
158. io2.Failure.Failure : Type -> Text -> Any -> Failure
159. unique type io2.FileMode
160. io2.FileMode.Append : FileMode
161. io2.FileMode.Read : FileMode
162. io2.FileMode.ReadWrite : FileMode
163. io2.FileMode.Write : FileMode
164. builtin type io2.Handle
165. builtin type io2.IO
166. io2.IO.clientSocket.impl : Text
-> Text
->{IO} Either Failure Socket
166. io2.IO.closeFile.impl : Handle ->{IO} Either Failure ()
167. io2.IO.closeSocket.impl : Socket ->{IO} Either Failure ()
168. io2.IO.createDirectory.impl : Text
167. io2.IO.closeFile.impl : Handle ->{IO} Either Failure ()
168. io2.IO.closeSocket.impl : Socket ->{IO} Either Failure ()
169. io2.IO.createDirectory.impl : Text
->{IO} Either Failure ()
169. io2.IO.createTempDirectory.impl : Text
170. io2.IO.createTempDirectory.impl : Text
->{IO} Either
Failure Text
170. io2.IO.delay.impl : Nat ->{IO} Either Failure ()
171. io2.IO.directoryContents.impl : Text
171. io2.IO.delay.impl : Nat ->{IO} Either Failure ()
172. io2.IO.directoryContents.impl : Text
->{IO} Either
Failure [Text]
172. io2.IO.fileExists.impl : Text
173. io2.IO.fileExists.impl : Text
->{IO} Either Failure Boolean
173. io2.IO.forkComp : '{IO} a ->{IO} ThreadId
174. io2.IO.getArgs.impl : '{IO} Either Failure [Text]
175. io2.IO.getBuffering.impl : Handle
174. io2.IO.forkComp : '{IO} a ->{IO} ThreadId
175. io2.IO.getArgs.impl : '{IO} Either Failure [Text]
176. io2.IO.getBuffering.impl : Handle
->{IO} Either
Failure BufferMode
176. io2.IO.getBytes.impl : Handle
177. io2.IO.getBytes.impl : Handle
-> Nat
->{IO} Either Failure Bytes
177. io2.IO.getCurrentDirectory.impl : '{IO} Either
178. io2.IO.getCurrentDirectory.impl : '{IO} Either
Failure Text
178. io2.IO.getEnv.impl : Text ->{IO} Either Failure Text
179. io2.IO.getFileSize.impl : Text ->{IO} Either Failure Nat
180. io2.IO.getFileTimestamp.impl : Text
179. io2.IO.getEnv.impl : Text ->{IO} Either Failure Text
180. io2.IO.getFileSize.impl : Text ->{IO} Either Failure Nat
181. io2.IO.getFileTimestamp.impl : Text
->{IO} Either Failure Nat
181. io2.IO.getLine.impl : Handle ->{IO} Either Failure Text
182. io2.IO.getTempDirectory.impl : '{IO} Either Failure Text
183. io2.IO.handlePosition.impl : Handle
182. io2.IO.getLine.impl : Handle ->{IO} Either Failure Text
183. io2.IO.getTempDirectory.impl : '{IO} Either Failure Text
184. io2.IO.handlePosition.impl : Handle
->{IO} Either Failure Nat
184. io2.IO.isDirectory.impl : Text
185. io2.IO.isDirectory.impl : Text
->{IO} Either Failure Boolean
185. io2.IO.isFileEOF.impl : Handle
186. io2.IO.isFileEOF.impl : Handle
->{IO} Either Failure Boolean
186. io2.IO.isFileOpen.impl : Handle
187. io2.IO.isFileOpen.impl : Handle
->{IO} Either Failure Boolean
187. io2.IO.isSeekable.impl : Handle
188. io2.IO.isSeekable.impl : Handle
->{IO} Either Failure Boolean
188. io2.IO.kill.impl : ThreadId ->{IO} Either Failure ()
189. io2.IO.listen.impl : Socket ->{IO} Either Failure ()
190. io2.IO.openFile.impl : Text
189. io2.IO.kill.impl : ThreadId ->{IO} Either Failure ()
190. io2.IO.listen.impl : Socket ->{IO} Either Failure ()
191. io2.IO.openFile.impl : Text
-> FileMode
->{IO} Either Failure Handle
191. io2.IO.putBytes.impl : Handle
192. io2.IO.putBytes.impl : Handle
-> Bytes
->{IO} Either Failure ()
192. io2.IO.ref : a ->{IO} Ref {IO} a
193. io2.IO.removeDirectory.impl : Text
193. io2.IO.ref : a ->{IO} Ref {IO} a
194. io2.IO.removeDirectory.impl : Text
->{IO} Either Failure ()
194. io2.IO.removeFile.impl : Text ->{IO} Either Failure ()
195. io2.IO.renameDirectory.impl : Text
195. io2.IO.removeFile.impl : Text ->{IO} Either Failure ()
196. io2.IO.renameDirectory.impl : Text
-> Text
->{IO} Either Failure ()
196. io2.IO.renameFile.impl : Text
197. io2.IO.renameFile.impl : Text
-> Text
->{IO} Either Failure ()
197. io2.IO.seekHandle.impl : Handle
198. io2.IO.seekHandle.impl : Handle
-> SeekMode
-> Int
->{IO} Either Failure ()
198. io2.IO.serverSocket.impl : Optional Text
199. io2.IO.serverSocket.impl : Optional Text
-> Text
->{IO} Either Failure Socket
199. io2.IO.setBuffering.impl : Handle
200. io2.IO.setBuffering.impl : Handle
-> BufferMode
->{IO} Either Failure ()
200. io2.IO.setCurrentDirectory.impl : Text
201. io2.IO.setCurrentDirectory.impl : Text
->{IO} Either
Failure ()
201. io2.IO.socketAccept.impl : Socket
202. io2.IO.socketAccept.impl : Socket
->{IO} Either Failure Socket
202. io2.IO.socketPort.impl : Socket ->{IO} Either Failure Nat
203. io2.IO.socketReceive.impl : Socket
203. io2.IO.socketPort.impl : Socket ->{IO} Either Failure Nat
204. io2.IO.socketReceive.impl : Socket
-> Nat
->{IO} Either Failure Bytes
204. io2.IO.socketSend.impl : Socket
205. io2.IO.socketSend.impl : Socket
-> Bytes
->{IO} Either Failure ()
205. io2.IO.stdHandle : StdHandle -> Handle
206. io2.IO.systemTime.impl : '{IO} Either Failure Nat
207. io2.IO.systemTimeMicroseconds : '{IO} Int
208. unique type io2.IOError
209. io2.IOError.AlreadyExists : IOError
210. io2.IOError.EOF : IOError
211. io2.IOError.IllegalOperation : IOError
212. io2.IOError.NoSuchThing : IOError
213. io2.IOError.PermissionDenied : IOError
214. io2.IOError.ResourceBusy : IOError
215. io2.IOError.ResourceExhausted : IOError
216. io2.IOError.UserError : IOError
217. unique type io2.IOFailure
218. builtin type io2.MVar
219. io2.MVar.isEmpty : MVar a ->{IO} Boolean
220. io2.MVar.new : a ->{IO} MVar a
221. io2.MVar.newEmpty : '{IO} MVar a
222. io2.MVar.put.impl : MVar a -> a ->{IO} Either Failure ()
223. io2.MVar.read.impl : MVar a ->{IO} Either Failure a
224. io2.MVar.swap.impl : MVar a -> a ->{IO} Either Failure a
225. io2.MVar.take.impl : MVar a ->{IO} Either Failure a
226. io2.MVar.tryPut.impl : MVar a
206. io2.IO.stdHandle : StdHandle -> Handle
207. io2.IO.systemTime.impl : '{IO} Either Failure Nat
208. io2.IO.systemTimeMicroseconds : '{IO} Int
209. unique type io2.IOError
210. io2.IOError.AlreadyExists : IOError
211. io2.IOError.EOF : IOError
212. io2.IOError.IllegalOperation : IOError
213. io2.IOError.NoSuchThing : IOError
214. io2.IOError.PermissionDenied : IOError
215. io2.IOError.ResourceBusy : IOError
216. io2.IOError.ResourceExhausted : IOError
217. io2.IOError.UserError : IOError
218. unique type io2.IOFailure
219. builtin type io2.MVar
220. io2.MVar.isEmpty : MVar a ->{IO} Boolean
221. io2.MVar.new : a ->{IO} MVar a
222. io2.MVar.newEmpty : '{IO} MVar a
223. io2.MVar.put.impl : MVar a -> a ->{IO} Either Failure ()
224. io2.MVar.read.impl : MVar a ->{IO} Either Failure a
225. io2.MVar.swap.impl : MVar a -> a ->{IO} Either Failure a
226. io2.MVar.take.impl : MVar a ->{IO} Either Failure a
227. io2.MVar.tryPut.impl : MVar a
-> a
->{IO} Either Failure Boolean
227. io2.MVar.tryRead.impl : MVar a
228. io2.MVar.tryRead.impl : MVar a
->{IO} Either
Failure (Optional a)
228. io2.MVar.tryTake : MVar a ->{IO} Optional a
229. unique type io2.SeekMode
230. io2.SeekMode.AbsoluteSeek : SeekMode
231. io2.SeekMode.RelativeSeek : SeekMode
232. io2.SeekMode.SeekFromEnd : SeekMode
233. builtin type io2.Socket
234. unique type io2.StdHandle
235. io2.StdHandle.StdErr : StdHandle
236. io2.StdHandle.StdIn : StdHandle
237. io2.StdHandle.StdOut : StdHandle
238. builtin type io2.STM
239. io2.STM.atomically : '{STM} a ->{IO} a
240. io2.STM.retry : '{STM} a
241. builtin type io2.ThreadId
242. builtin type io2.Tls
243. builtin type io2.Tls.Cipher
244. builtin type io2.Tls.ClientConfig
245. io2.Tls.ClientConfig.certificates.set : [SignedCert]
229. io2.MVar.tryTake : MVar a ->{IO} Optional a
230. unique type io2.SeekMode
231. io2.SeekMode.AbsoluteSeek : SeekMode
232. io2.SeekMode.RelativeSeek : SeekMode
233. io2.SeekMode.SeekFromEnd : SeekMode
234. builtin type io2.Socket
235. unique type io2.StdHandle
236. io2.StdHandle.StdErr : StdHandle
237. io2.StdHandle.StdIn : StdHandle
238. io2.StdHandle.StdOut : StdHandle
239. builtin type io2.STM
240. io2.STM.atomically : '{STM} a ->{IO} a
241. io2.STM.retry : '{STM} a
242. builtin type io2.ThreadId
243. builtin type io2.Tls
244. builtin type io2.Tls.Cipher
245. builtin type io2.Tls.ClientConfig
246. io2.Tls.ClientConfig.certificates.set : [SignedCert]
-> ClientConfig
-> ClientConfig
246. io2.TLS.ClientConfig.ciphers.set : [Cipher]
247. io2.TLS.ClientConfig.ciphers.set : [Cipher]
-> ClientConfig
-> ClientConfig
247. io2.Tls.ClientConfig.default : Text
248. io2.Tls.ClientConfig.default : Text
-> Bytes
-> ClientConfig
248. io2.Tls.ClientConfig.versions.set : [Version]
249. io2.Tls.ClientConfig.versions.set : [Version]
-> ClientConfig
-> ClientConfig
249. io2.Tls.decodeCert.impl : Bytes
250. io2.Tls.decodeCert.impl : Bytes
-> Either Failure SignedCert
250. io2.Tls.decodePrivateKey : Bytes -> [PrivateKey]
251. io2.Tls.encodeCert : SignedCert -> Bytes
252. io2.Tls.encodePrivateKey : PrivateKey -> Bytes
253. io2.Tls.handshake.impl : Tls ->{IO} Either Failure ()
254. io2.Tls.newClient.impl : ClientConfig
251. io2.Tls.decodePrivateKey : Bytes -> [PrivateKey]
252. io2.Tls.encodeCert : SignedCert -> Bytes
253. io2.Tls.encodePrivateKey : PrivateKey -> Bytes
254. io2.Tls.handshake.impl : Tls ->{IO} Either Failure ()
255. io2.Tls.newClient.impl : ClientConfig
-> Socket
->{IO} Either Failure Tls
255. io2.Tls.newServer.impl : ServerConfig
256. io2.Tls.newServer.impl : ServerConfig
-> Socket
->{IO} Either Failure Tls
256. builtin type io2.Tls.PrivateKey
257. io2.Tls.receive.impl : Tls ->{IO} Either Failure Bytes
258. io2.Tls.send.impl : Tls -> Bytes ->{IO} Either Failure ()
259. builtin type io2.Tls.ServerConfig
260. io2.Tls.ServerConfig.certificates.set : [SignedCert]
257. builtin type io2.Tls.PrivateKey
258. io2.Tls.receive.impl : Tls ->{IO} Either Failure Bytes
259. io2.Tls.send.impl : Tls -> Bytes ->{IO} Either Failure ()
260. builtin type io2.Tls.ServerConfig
261. io2.Tls.ServerConfig.certificates.set : [SignedCert]
-> ServerConfig
-> ServerConfig
261. io2.Tls.ServerConfig.ciphers.set : [Cipher]
262. io2.Tls.ServerConfig.ciphers.set : [Cipher]
-> ServerConfig
-> ServerConfig
262. io2.Tls.ServerConfig.default : [SignedCert]
263. io2.Tls.ServerConfig.default : [SignedCert]
-> PrivateKey
-> ServerConfig
263. io2.Tls.ServerConfig.versions.set : [Version]
264. io2.Tls.ServerConfig.versions.set : [Version]
-> ServerConfig
-> ServerConfig
264. builtin type io2.Tls.SignedCert
265. io2.Tls.terminate.impl : Tls ->{IO} Either Failure ()
266. builtin type io2.Tls.Version
267. unique type io2.TlsFailure
268. builtin type io2.TVar
269. io2.TVar.new : a ->{STM} TVar a
270. io2.TVar.newIO : a ->{IO} TVar a
271. io2.TVar.read : TVar a ->{STM} a
272. io2.TVar.readIO : TVar a ->{IO} a
273. io2.TVar.swap : TVar a -> a ->{STM} a
274. io2.TVar.write : TVar a -> a ->{STM} ()
275. unique type IsPropagated
276. IsPropagated.IsPropagated : IsPropagated
277. unique type IsTest
278. IsTest.IsTest : IsTest
279. unique type Link
280. builtin type Link.Term
281. Link.Term : Term -> Link
282. Link.Term.toText : Term -> Text
283. builtin type Link.Type
284. Link.Type : Type -> Link
285. builtin type List
286. List.++ : [a] -> [a] -> [a]
287. List.+: : a -> [a] -> [a]
288. List.:+ : [a] -> a -> [a]
289. List.at : Nat -> [a] -> Optional a
290. List.cons : a -> [a] -> [a]
291. List.drop : Nat -> [a] -> [a]
292. List.empty : [a]
293. List.size : [a] -> Nat
294. List.snoc : [a] -> a -> [a]
295. List.take : Nat -> [a] -> [a]
296. metadata.isPropagated : IsPropagated
297. metadata.isTest : IsTest
298. builtin type Nat
299. Nat.* : Nat -> Nat -> Nat
300. Nat.+ : Nat -> Nat -> Nat
301. Nat./ : Nat -> Nat -> Nat
302. Nat.and : Nat -> Nat -> Nat
303. Nat.complement : Nat -> Nat
304. Nat.drop : Nat -> Nat -> Nat
305. Nat.eq : Nat -> Nat -> Boolean
306. Nat.fromText : Text -> Optional Nat
307. Nat.gt : Nat -> Nat -> Boolean
308. Nat.gteq : Nat -> Nat -> Boolean
309. Nat.increment : Nat -> Nat
310. Nat.isEven : Nat -> Boolean
311. Nat.isOdd : Nat -> Boolean
312. Nat.leadingZeros : Nat -> Nat
313. Nat.lt : Nat -> Nat -> Boolean
314. Nat.lteq : Nat -> Nat -> Boolean
315. Nat.mod : Nat -> Nat -> Nat
316. Nat.or : Nat -> Nat -> Nat
317. Nat.popCount : Nat -> Nat
318. Nat.pow : Nat -> Nat -> Nat
319. Nat.shiftLeft : Nat -> Nat -> Nat
320. Nat.shiftRight : Nat -> Nat -> Nat
321. Nat.sub : Nat -> Nat -> Int
322. Nat.toFloat : Nat -> Float
323. Nat.toInt : Nat -> Int
324. Nat.toText : Nat -> Text
325. Nat.trailingZeros : Nat -> Nat
326. Nat.xor : Nat -> Nat -> Nat
327. structural type Optional a
328. Optional.None : Optional a
329. Optional.Some : a -> Optional a
330. builtin type Ref
331. Ref.read : Ref g a ->{g} a
332. Ref.write : Ref g a -> a ->{g} ()
333. builtin type Request
334. builtin type Scope
335. Scope.ref : a ->{Scope s} Ref {Scope s} a
336. Scope.run : (∀ s. '{g, Scope s} r) ->{g} r
337. structural type SeqView a b
338. SeqView.VElem : a -> b -> SeqView a b
339. SeqView.VEmpty : SeqView a b
340. Socket.toText : Socket -> Text
341. unique type Test.Result
342. Test.Result.Fail : Text -> Result
343. Test.Result.Ok : Text -> Result
344. builtin type Text
345. Text.!= : Text -> Text -> Boolean
346. Text.++ : Text -> Text -> Text
347. Text.drop : Nat -> Text -> Text
348. Text.empty : Text
349. Text.eq : Text -> Text -> Boolean
350. Text.fromCharList : [Char] -> Text
351. Text.fromUtf8.impl : Bytes -> Either Failure Text
352. Text.gt : Text -> Text -> Boolean
353. Text.gteq : Text -> Text -> Boolean
354. Text.lt : Text -> Text -> Boolean
355. Text.lteq : Text -> Text -> Boolean
356. Text.repeat : Nat -> Text -> Text
357. Text.size : Text -> Nat
358. Text.take : Nat -> Text -> Text
359. Text.toCharList : Text -> [Char]
360. Text.toUtf8 : Text -> Bytes
361. Text.uncons : Text -> Optional (Char, Text)
362. Text.unsnoc : Text -> Optional (Text, Char)
363. ThreadId.toText : ThreadId -> Text
364. todo : a -> b
365. structural type Tuple a b
366. Tuple.Cons : a -> b -> Tuple a b
367. structural type Unit
368. Unit.Unit : ()
369. Universal.< : a -> a -> Boolean
370. Universal.<= : a -> a -> Boolean
371. Universal.== : a -> a -> Boolean
372. Universal.> : a -> a -> Boolean
373. Universal.>= : a -> a -> Boolean
374. Universal.compare : a -> a -> Int
375. unsafe.coerceAbilities : (a ->{e1} b) -> a ->{e2} b
376. builtin type Value
377. Value.dependencies : Value -> [Term]
378. Value.deserialize : Bytes -> Either Text Value
379. Value.load : Value ->{IO} Either [Term] a
380. Value.serialize : Value -> Bytes
381. Value.value : a -> Value
265. builtin type io2.Tls.SignedCert
266. io2.Tls.terminate.impl : Tls ->{IO} Either Failure ()
267. builtin type io2.Tls.Version
268. unique type io2.TlsFailure
269. builtin type io2.TVar
270. io2.TVar.new : a ->{STM} TVar a
271. io2.TVar.newIO : a ->{IO} TVar a
272. io2.TVar.read : TVar a ->{STM} a
273. io2.TVar.readIO : TVar a ->{IO} a
274. io2.TVar.swap : TVar a -> a ->{STM} a
275. io2.TVar.write : TVar a -> a ->{STM} ()
276. unique type IsPropagated
277. IsPropagated.IsPropagated : IsPropagated
278. unique type IsTest
279. IsTest.IsTest : IsTest
280. unique type Link
281. builtin type Link.Term
282. Link.Term : Term -> Link
283. Link.Term.toText : Term -> Text
284. builtin type Link.Type
285. Link.Type : Type -> Link
286. builtin type List
287. List.++ : [a] -> [a] -> [a]
288. List.+: : a -> [a] -> [a]
289. List.:+ : [a] -> a -> [a]
290. List.at : Nat -> [a] -> Optional a
291. List.cons : a -> [a] -> [a]
292. List.drop : Nat -> [a] -> [a]
293. List.empty : [a]
294. List.size : [a] -> Nat
295. List.snoc : [a] -> a -> [a]
296. List.take : Nat -> [a] -> [a]
297. metadata.isPropagated : IsPropagated
298. metadata.isTest : IsTest
299. builtin type Nat
300. Nat.* : Nat -> Nat -> Nat
301. Nat.+ : Nat -> Nat -> Nat
302. Nat./ : Nat -> Nat -> Nat
303. Nat.and : Nat -> Nat -> Nat
304. Nat.complement : Nat -> Nat
305. Nat.drop : Nat -> Nat -> Nat
306. Nat.eq : Nat -> Nat -> Boolean
307. Nat.fromText : Text -> Optional Nat
308. Nat.gt : Nat -> Nat -> Boolean
309. Nat.gteq : Nat -> Nat -> Boolean
310. Nat.increment : Nat -> Nat
311. Nat.isEven : Nat -> Boolean
312. Nat.isOdd : Nat -> Boolean
313. Nat.leadingZeros : Nat -> Nat
314. Nat.lt : Nat -> Nat -> Boolean
315. Nat.lteq : Nat -> Nat -> Boolean
316. Nat.mod : Nat -> Nat -> Nat
317. Nat.or : Nat -> Nat -> Nat
318. Nat.popCount : Nat -> Nat
319. Nat.pow : Nat -> Nat -> Nat
320. Nat.shiftLeft : Nat -> Nat -> Nat
321. Nat.shiftRight : Nat -> Nat -> Nat
322. Nat.sub : Nat -> Nat -> Int
323. Nat.toFloat : Nat -> Float
324. Nat.toInt : Nat -> Int
325. Nat.toText : Nat -> Text
326. Nat.trailingZeros : Nat -> Nat
327. Nat.xor : Nat -> Nat -> Nat
328. structural type Optional a
329. Optional.None : Optional a
330. Optional.Some : a -> Optional a
331. builtin type Ref
332. Ref.read : Ref g a ->{g} a
333. Ref.write : Ref g a -> a ->{g} ()
334. builtin type Request
335. builtin type Scope
336. Scope.ref : a ->{Scope s} Ref {Scope s} a
337. Scope.run : (∀ s. '{g, Scope s} r) ->{g} r
338. structural type SeqView a b
339. SeqView.VElem : a -> b -> SeqView a b
340. SeqView.VEmpty : SeqView a b
341. Socket.toText : Socket -> Text
342. unique type Test.Result
343. Test.Result.Fail : Text -> Result
344. Test.Result.Ok : Text -> Result
345. builtin type Text
346. Text.!= : Text -> Text -> Boolean
347. Text.++ : Text -> Text -> Text
348. Text.drop : Nat -> Text -> Text
349. Text.empty : Text
350. Text.eq : Text -> Text -> Boolean
351. Text.fromCharList : [Char] -> Text
352. Text.fromUtf8.impl : Bytes -> Either Failure Text
353. Text.gt : Text -> Text -> Boolean
354. Text.gteq : Text -> Text -> Boolean
355. Text.lt : Text -> Text -> Boolean
356. Text.lteq : Text -> Text -> Boolean
357. Text.repeat : Nat -> Text -> Text
358. Text.size : Text -> Nat
359. Text.take : Nat -> Text -> Text
360. Text.toCharList : Text -> [Char]
361. Text.toUtf8 : Text -> Bytes
362. Text.uncons : Text -> Optional (Char, Text)
363. Text.unsnoc : Text -> Optional (Text, Char)
364. ThreadId.toText : ThreadId -> Text
365. todo : a -> b
366. structural type Tuple a b
367. Tuple.Cons : a -> b -> Tuple a b
368. structural type Unit
369. Unit.Unit : ()
370. Universal.< : a -> a -> Boolean
371. Universal.<= : a -> a -> Boolean
372. Universal.== : a -> a -> Boolean
373. Universal.> : a -> a -> Boolean
374. Universal.>= : a -> a -> Boolean
375. Universal.compare : a -> a -> Int
376. unsafe.coerceAbilities : (a ->{e1} b) -> a ->{e2} b
377. builtin type Value
378. Value.dependencies : Value -> [Term]
379. Value.deserialize : Bytes -> Either Text Value
380. Value.load : Value ->{IO} Either [Term] a
381. Value.serialize : Value -> Bytes
382. Value.value : a -> Value
.builtin> alias.many 94-104 .mylib
@ -477,17 +478,17 @@ Let's try it!
Added definitions:
1. Float.cosh : Float -> Float
2. Float.eq : Float -> Float -> Boolean
3. Float.exp : Float -> Float
4. Float.floor : Float -> Int
5. Float.fromRepresentation : Nat -> Float
6. Float.fromText : Text -> Optional Float
7. Float.gt : Float -> Float -> Boolean
8. Float.gteq : Float -> Float -> Boolean
9. Float.log : Float -> Float
10. Float.logBase : Float -> Float -> Float
11. Float.lt : Float -> Float -> Boolean
1. Float.cos : Float -> Float
2. Float.cosh : Float -> Float
3. Float.eq : Float -> Float -> Boolean
4. Float.exp : Float -> Float
5. Float.floor : Float -> Int
6. Float.fromRepresentation : Nat -> Float
7. Float.fromText : Text -> Optional Float
8. Float.gt : Float -> Float -> Boolean
9. Float.gteq : Float -> Float -> Boolean
10. Float.log : Float -> Float
11. Float.logBase : Float -> Float -> Float
Tip: You can use `undo` or `reflog` to undo this change.
@ -547,17 +548,17 @@ I want to incorporate a few more from another namespace:
.mylib> find
1. Float.cosh : Float -> Float
2. Float.eq : Float -> Float -> Boolean
3. Float.exp : Float -> Float
4. Float.floor : Float -> Int
5. Float.fromRepresentation : Nat -> Float
6. Float.fromText : Text -> Optional Float
7. Float.gt : Float -> Float -> Boolean
8. Float.gteq : Float -> Float -> Boolean
9. Float.log : Float -> Float
10. Float.logBase : Float -> Float -> Float
11. Float.lt : Float -> Float -> Boolean
1. Float.cos : Float -> Float
2. Float.cosh : Float -> Float
3. Float.eq : Float -> Float -> Boolean
4. Float.exp : Float -> Float
5. Float.floor : Float -> Int
6. Float.fromRepresentation : Nat -> Float
7. Float.fromText : Text -> Optional Float
8. Float.gt : Float -> Float -> Boolean
9. Float.gteq : Float -> Float -> Boolean
10. Float.log : Float -> Float
11. Float.logBase : Float -> Float -> Float
12. List.adjacentPairs : [a] -> [(a, a)]
13. List.all : (a ->{g} Boolean) -> [a] ->{g} Boolean
14. List.any : (a ->{g} Boolean) -> [a] ->{g} Boolean

View File

@ -19,7 +19,7 @@ The `builtins.merge` command adds the known builtins to a `builtin` subnamespace
8. Char/ (3 definitions)
9. Code (builtin type)
10. Code/ (8 definitions)
11. Debug/ (1 definition)
11. Debug/ (2 definitions)
12. Doc (type)
13. Doc/ (6 definitions)
14. Either (type)

View File

@ -0,0 +1,62 @@
# Empty namespace behaviours
```unison:hide
mynamespace.x = 1
```
```ucm:hide
.> add
.> delete.namespace mynamespace
```
The deleted namespace shouldn't appear in `ls` output.
```ucm:error
.> ls
```
```ucm:error
.> ls.verbose
```
```ucm:error
.> find mynamespace
```
## history
The history of the namespace should still exist if requested explicitly.
```ucm
.> history mynamespace
```
Merging an empty namespace should still copy its history if it has some.
```ucm
.empty> history
.empty> merge .mynamespace
.empty> history
```
Add and then delete a term to add some history to a deleted namespace.
```unison:hide
deleted.x = 1
stuff.thing = 2
```
```ucm:hide
.> add
.> delete.namespace .deleted
```
I should be allowed to fork over a deleted namespace
```ucm
.> fork stuff deleted
```
The history from the `deleted` namespace should have been overwritten by the history from `stuff`.
```ucm
.> history stuff
.> history deleted
```

View File

@ -0,0 +1,114 @@
# Empty namespace behaviours
```unison
mynamespace.x = 1
```
The deleted namespace shouldn't appear in `ls` output.
```ucm
.> ls
nothing to show
```
```ucm
.> ls.verbose
😶
No results. Check your spelling, or try using tab completion
to supply command arguments.
```
```ucm
.> find mynamespace
😶
No results. Check your spelling, or try using tab completion
to supply command arguments.
```
## history
The history of the namespace should still exist if requested explicitly.
```ucm
.> history mynamespace
Note: The most recent namespace hash is immediately below this
message.
#qjc20aua9h
- Deletes:
x
#hkrqt3tm05 (start of history)
```
Merging an empty namespace should still copy its history if it has some.
```ucm
☝️ The namespace .empty is empty.
.empty> history
☝️ The namespace .empty is empty.
.empty> merge .mynamespace
Nothing changed as a result of the merge.
.empty> history
Note: The most recent namespace hash is immediately below this
message.
#qjc20aua9h
- Deletes:
x
#hkrqt3tm05 (start of history)
```
Add and then delete a term to add some history to a deleted namespace.
```unison
deleted.x = 1
stuff.thing = 2
```
I should be allowed to fork over a deleted namespace
```ucm
.> fork stuff deleted
Done.
```
The history from the `deleted` namespace should have been overwritten by the history from `stuff`.
```ucm
.> history stuff
Note: The most recent namespace hash is immediately below this
message.
#3bm1524lb7 (start of history)
.> history deleted
Note: The most recent namespace hash is immediately below this
message.
#3bm1524lb7 (start of history)
```

View File

@ -23,7 +23,7 @@ Technically, the definitions all exist, but they have no names. `builtins.merge`
.foo> ls
1. builtin/ (381 definitions)
1. builtin/ (382 definitions)
```
And for a limited time, you can get even more builtin goodies:
@ -35,7 +35,7 @@ And for a limited time, you can get even more builtin goodies:
.foo> ls
1. builtin/ (549 definitions)
1. builtin/ (550 definitions)
```
More typically, you'd start out by pulling `base.

View File

@ -125,13 +125,13 @@ We can also delete the fork if we're done with it. (Don't worry, it's still in t
Note: The most recent namespace hash is immediately below this
message.
#7gjmqmlj0v
#5aa4qmhvur
- Deletes:
feature1.y
#7qqt9t3qr5
#g1jho38v97
+ Adds / updates:
@ -142,26 +142,26 @@ We can also delete the fork if we're done with it. (Don't worry, it's still in t
Original name New name(s)
feature1.y master.y
#u86vero990
#dkcip47417
+ Adds / updates:
feature1.y
#el4liebh4m
#at9qnsl83m
> Moves:
Original name New name
x master.x
#pne2sthbc8
#g271dghaje
+ Adds / updates:
x
#qnkdl1f20n (start of history)
#aooso6apun (start of history)
```
To resurrect an old version of a namespace, you can learn its hash via the `history` command, then use `fork #namespacehash .newname`.

View File

@ -59,16 +59,16 @@ y = 2
most recent, along with the command that got us there. Try:
`fork 2 .old`
`fork #7m7gaa64si .old` to make an old namespace
`fork #ttu893rclh .old` to make an old namespace
accessible again,
`reset-root #7m7gaa64si` to reset the root namespace and
`reset-root #ttu893rclh` to reset the root namespace and
its history to that of the
specified namespace.
1. #k8o73d0cc0 : add
2. #7m7gaa64si : add
3. #qnkdl1f20n : builtins.merge
1. #opcc5n8q9a : add
2. #ttu893rclh : add
3. #aooso6apun : builtins.merge
4. #sjg2v58vn2 : (initial reflogged namespace)
```

View File

@ -13,7 +13,7 @@ Let's look at some examples. We'll start with a namespace with just the builtins
#tfjjgvaq9l (start of history)
#afd37h0nli (start of history)
.> fork builtin builtin2
@ -42,21 +42,21 @@ Now suppose we `fork` a copy of builtin, then rename `Nat.+` to `frobnicate`, th
Note: The most recent namespace hash is immediately below this
message.
#uiahjr3nvu
#k528t27n2n
> Moves:
Original name New name
Nat.frobnicate Nat.+
#ov2s5dsaba
#3a5rbkh4bd
> Moves:
Original name New name
Nat.+ Nat.frobnicate
#tfjjgvaq9l (start of history)
#afd37h0nli (start of history)
```
If we merge that back into `builtin`, we get that same chain of history:
@ -71,21 +71,21 @@ If we merge that back into `builtin`, we get that same chain of history:
Note: The most recent namespace hash is immediately below this
message.
#uiahjr3nvu
#k528t27n2n
> Moves:
Original name New name
Nat.frobnicate Nat.+
#ov2s5dsaba
#3a5rbkh4bd
> Moves:
Original name New name
Nat.+ Nat.frobnicate
#tfjjgvaq9l (start of history)
#afd37h0nli (start of history)
```
Let's try again, but using a `merge.squash` (or just `squash`) instead. The history will be unchanged:
@ -106,7 +106,7 @@ Let's try again, but using a `merge.squash` (or just `squash`) instead. The hist
#tfjjgvaq9l (start of history)
#afd37h0nli (start of history)
```
The churn that happened in `mybuiltin` namespace ended up back in the same spot, so the squash merge of that namespace with our original namespace had no effect.
@ -485,13 +485,13 @@ This checks to see that squashing correctly preserves deletions:
Note: The most recent namespace hash is immediately below this
message.
#dp0rpp67if
#jma01uqhdr
- Deletes:
Nat.* Nat.+
#tfjjgvaq9l (start of history)
#afd37h0nli (start of history)
```
Notice that `Nat.+` and `Nat.*` are deleted by the squash, and we see them deleted in one atomic step in the history.