gut existing todo implementation

This commit is contained in:
Mitchell Rosen 2024-06-13 10:29:42 -04:00
parent 87f1544ad2
commit 6e04dbd083
11 changed files with 32 additions and 777 deletions

View File

@ -737,7 +737,7 @@ loop e = do
currentNames <- Branch.toNames <$> Cli.getCurrentBranch0
let sr = Slurp.slurpFile uf vars Slurp.UpdateOp currentNames
previewResponse sourceName sr uf
TodoI patchPath branchPath -> handleTodo patchPath branchPath
TodoI -> handleTodo
TestI testInput -> Tests.handleTest testInput
ExecuteI main args -> handleRun False main args
MakeStandaloneI output main -> doCompile False output main

View File

@ -4,114 +4,22 @@ module Unison.Codebase.Editor.HandleInput.Todo
)
where
import Control.Lens hiding (from)
import Control.Monad.Reader (ask)
import Data.Set qualified as Set
import U.Codebase.Sqlite.Queries qualified as Queries
import Unison.Cli.Monad (Cli)
import Unison.Cli.Monad qualified as Cli
import Unison.Cli.MonadUtils qualified as Cli
import Unison.Cli.PrettyPrintUtils qualified as Cli
import Unison.Codebase (Codebase)
import Unison.Codebase qualified as Codebase
import Unison.Codebase.Branch.Names qualified as Branch
import Unison.Codebase.Editor.DisplayObject
import Unison.Codebase.Editor.Output
import Unison.Codebase.Editor.StructuredArgument qualified as SA
import Unison.Codebase.Editor.TodoOutput qualified as TO
import Unison.Codebase.Patch (Patch (..))
import Unison.Codebase.Patch qualified as Patch
import Unison.Codebase.Path qualified as Path
import Unison.DataDeclaration qualified as DD
import Unison.HashQualified qualified as HQ
import Unison.Names (Names)
import Unison.Names qualified as Names
import Unison.Parser.Ann (Ann (..))
import Unison.Prelude
import Unison.Reference (Reference)
import Unison.Reference qualified as Reference
import Unison.Sqlite qualified as Sqlite
import Unison.Symbol (Symbol)
import Unison.Type (Type)
import Unison.Util.Monoid qualified as Monoid
import Unison.Util.Relation qualified as R
import Unison.Util.TransitiveClosure (transitiveClosure)
handleTodo :: Maybe Path.Split' -> Path.Path' -> Cli ()
handleTodo patchPath branchPath' = do
patch <- Cli.getPatchAt (fromMaybe Cli.defaultPatchPath patchPath)
branchPath <- Cli.resolvePath' branchPath'
doShowTodoOutput patch branchPath
-- | Show todo output if there are any conflicts or edits.
doShowTodoOutput :: Patch -> Path.Absolute -> Cli ()
doShowTodoOutput patch scopePath = do
Cli.Env {codebase} <- ask
names0 <- Branch.toNames <$> Cli.getBranch0At scopePath
todo <- Cli.runTransaction (checkTodo codebase patch names0)
if TO.noConflicts todo && TO.noEdits todo
then Cli.respond NoConflictsOrEdits
else do
Cli.setNumberedArgs $
SA.HashQualified . HQ.HashOnly . Reference.toShortHash . view _2
<$> fst (TO.todoFrontierDependents todo)
pped <- Cli.currentPrettyPrintEnvDecl
Cli.respondNumbered $ TodoOutput pped todo
checkTodo :: Codebase m Symbol Ann -> Patch -> Names -> Sqlite.Transaction (TO.TodoOutput Symbol Ann)
checkTodo codebase patch names0 = do
let -- Get the dependents of a reference which:
-- 1. Don't appear on the LHS of this patch
-- 2. Have a name in this namespace
getDependents :: Reference -> Sqlite.Transaction (Set Reference)
getDependents ref = do
dependents <- Codebase.dependents Queries.ExcludeSelf ref
pure (dependents & removeEditedThings & removeNamelessThings)
-- (r,r2) ∈ dependsOn if r depends on r2, excluding self-references (i.e. (r,r))
dependsOn <- Monoid.foldMapM (\ref -> R.fromManyDom <$> getDependents ref <*> pure ref) edited
let dirty = R.dom dependsOn
transitiveDirty <- transitiveClosure getDependents dirty
(frontierTerms, frontierTypes) <- loadDisplayInfo codebase (R.ran dependsOn)
(dirtyTerms, dirtyTypes) <- loadDisplayInfo codebase dirty
pure $
TO.TodoOutput
(Set.size transitiveDirty)
(frontierTerms, frontierTypes)
(score dirtyTerms, score dirtyTypes)
(Names.conflicts names0)
(Patch.conflicts patch)
where
-- Remove from a all references that were edited, i.e. appear on the LHS of this patch.
removeEditedThings :: Set Reference -> Set Reference
removeEditedThings =
(`Set.difference` edited)
-- Remove all references that don't have a name in the given namespace
removeNamelessThings :: Set Reference -> Set Reference
removeNamelessThings =
Set.filter (Names.contains names0)
-- todo: something more intelligent here?
score :: [(a, b)] -> [(TO.Score, a, b)]
score = map (\(x, y) -> (1, x, y))
edited :: Set Reference
edited = R.dom (Patch._termEdits patch) <> R.dom (Patch._typeEdits patch)
loadDisplayInfo ::
Codebase m Symbol Ann ->
Set Reference ->
Sqlite.Transaction
( [(Reference, Maybe (Type Symbol Ann))],
[(Reference, DisplayObject () (DD.Decl Symbol Ann))]
)
loadDisplayInfo codebase refs = do
termRefs <- filterM (Codebase.isTerm codebase) (toList refs)
typeRefs <- filterM (Codebase.isType codebase) (toList refs)
terms <- forM termRefs $ \r -> (r,) <$> Codebase.getTypeOfTerm codebase r
types <- forM typeRefs $ \r -> (r,) <$> loadTypeDisplayObject codebase r
pure (terms, types)
loadTypeDisplayObject :: Codebase m Symbol Ann -> Reference -> Sqlite.Transaction (DisplayObject () (DD.Decl Symbol Ann))
loadTypeDisplayObject codebase = \case
Reference.Builtin _ -> pure (BuiltinObject ())
Reference.DerivedId id ->
maybe (MissingObject $ Reference.idToShortHash id) UserObject
<$> Codebase.getTypeDeclaration codebase id
handleTodo :: Cli ()
handleTodo = do
branch0 <- Cli.getCurrentBranch0
let names0 = Branch.toNames branch0
let todo =
TO.TodoOutput
{ nameConflicts = Names.conflicts names0
}
pped <- Cli.currentPrettyPrintEnvDecl
Cli.respondNumbered $ TodoOutput pped todo

View File

@ -150,7 +150,7 @@ data Input
| UpdateI OptionalPatch (Set Name)
| Update2I
| PreviewUpdateI (Set Name)
| TodoI (Maybe PatchPath) Path'
| TodoI
| UndoI
| -- First `Maybe Int` is cap on number of results, if any
-- Second `Maybe Int` is cap on diff elements shown, if any

View File

@ -293,8 +293,6 @@ data Output
| PreviewMergeAlreadyUpToDate
(Either Path' (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch))
(Either Path' (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch))
| -- | No conflicts or edits remain for the current patch.
NoConflictsOrEdits
| NotImplemented
| NoBranchWithHash ShortCausalHash
| ListDependencies PPE.PrettyPrintEnv (Set LabeledDependency) [HQ.HashQualified Name] [HQ.HashQualified Name] -- types, terms
@ -554,7 +552,6 @@ isFailure o = case o of
MergeAlreadyUpToDate {} -> False
MergeAlreadyUpToDate2 {} -> False
PreviewMergeAlreadyUpToDate {} -> False
NoConflictsOrEdits {} -> False
ListShallow _ es -> null es
HashAmbiguous {} -> True
ShowReflog {} -> False
@ -669,4 +666,4 @@ isNumberedFailure = \case
ShowDiffAfterUndo {} -> False
ShowDiffNamespace _ _ _ bd -> BD.isEmpty bd
ListNamespaceDependencies {} -> False
TodoOutput _ todo -> TO.todoScore todo > 0 || not (TO.noConflicts todo)
TodoOutput {} -> False

View File

@ -1,70 +1,15 @@
{-# LANGUAGE RecordWildCards #-}
module Unison.Codebase.Editor.TodoOutput
( TodoOutput (..),
noConflicts,
)
where
module Unison.Codebase.Editor.TodoOutput where
import Data.Set qualified as Set
import Unison.Codebase.Editor.DisplayObject (DisplayObject (UserObject))
import Unison.Codebase.Patch (Patch)
import Unison.Codebase.Patch qualified as Patch
import Unison.DataDeclaration (Decl)
import Unison.DataDeclaration qualified as DD
import Unison.LabeledDependency (LabeledDependency)
import Unison.LabeledDependency qualified as LD
import Unison.Names (Names)
import Unison.Names qualified as Names
import Unison.Prelude
import Unison.Reference (Reference)
import Unison.Type (Type)
import Unison.Type qualified as Type
import Unison.Util.Relation qualified as R
type Score = Int
data TodoOutput v a = TodoOutput
{ todoScore :: Score,
todoFrontier ::
( [(Reference, Maybe (Type v a))],
[(Reference, DisplayObject () (Decl v a))]
),
todoFrontierDependents ::
( [(Score, Reference, Maybe (Type v a))],
[(Score, Reference, DisplayObject () (Decl v a))]
),
nameConflicts :: Names,
editConflicts :: Patch
{ nameConflicts :: Names
}
labeledDependencies :: (Ord v) => TodoOutput v a -> Set LabeledDependency
labeledDependencies TodoOutput {..} =
Set.fromList
( -- term refs
[LD.termRef r | (r, _) <- fst todoFrontier]
<> [LD.termRef r | (_, r, _) <- fst todoFrontierDependents]
<> [LD.typeRef r | (r, _) <- snd todoFrontier]
<> [LD.typeRef r | (_, r, _) <- snd todoFrontierDependents]
<>
-- types of term refs
[ LD.typeRef r | (_, Just t) <- fst todoFrontier, r <- toList (Type.dependencies t)
]
<> [ LD.typeRef r | (_, _, Just t) <- fst todoFrontierDependents, r <- toList (Type.dependencies t)
]
<>
-- and decls of type refs
[ labeledDep | (declRef, UserObject d) <- snd todoFrontier, labeledDep <- toList (DD.labeledDeclDependenciesIncludingSelf declRef d)
]
<> [ labeledDep | (_, declRef, UserObject d) <- snd todoFrontierDependents, labeledDep <- toList (DD.labeledDeclDependenciesIncludingSelf declRef d)
]
)
<>
-- name conflicts
Set.map LD.referent (R.ran (Names.terms nameConflicts))
<> Set.map LD.typeRef (R.ran (Names.types nameConflicts))
<> Patch.labeledDependencies editConflicts
noConflicts :: TodoOutput v a -> Bool
noConflicts todo =
nameConflicts todo == mempty && editConflicts todo == Patch.empty
noEdits :: TodoOutput v a -> Bool
noEdits todo =
todoScore todo == 0
nameConflicts todo == mempty

View File

@ -756,30 +756,15 @@ todo =
"todo"
[]
I.Visible
[("patch", Optional, patchArg), ("namespace", Optional, namespaceArg)]
( P.wrapColumn2
[ ( makeExample' todo,
"lists the refactor work remaining in the default patch for the current"
<> " namespace."
),
( makeExample todo ["<patch>"],
"lists the refactor work remaining in the given patch in the current "
<> "namespace."
),
( makeExample todo ["<patch>", "[path]"],
"lists the refactor work remaining in the given patch in given namespace."
)
]
[]
( P.wrap $
makeExample' todo
<> "lists the current namespace's outstanding issues, including conflicted names, dependencies with missing"
<> "names, and merge precondition violations."
)
\case
patchStr : ws -> first warn $ do
patch <- handleSplit'Arg patchStr
branch <- case ws of
[] -> pure Path.relativeEmpty'
[pathStr] -> handlePath'Arg pathStr
_ -> Left "`todo` just takes a patch and one optional namespace"
Right $ Input.TodoI (Just patch) branch
[] -> Right $ Input.TodoI Nothing Path.relativeEmpty'
[] -> Right Input.TodoI
_ -> Left (I.help todo)
load :: InputPattern
load =

View File

@ -65,7 +65,6 @@ import Unison.Codebase.Editor.StructuredArgument (StructuredArgument)
import Unison.Codebase.Editor.StructuredArgument qualified as SA
import Unison.Codebase.Editor.TodoOutput qualified as TO
import Unison.Codebase.IntegrityCheck (IntegrityResult (..), prettyPrintIntegrityErrors)
import Unison.Codebase.Patch (Patch (..))
import Unison.Codebase.Patch qualified as Patch
import Unison.Codebase.Path qualified as Path
import Unison.Codebase.PushBehavior qualified as PushBehavior
@ -73,8 +72,6 @@ import Unison.Codebase.Runtime qualified as Runtime
import Unison.Codebase.ShortCausalHash (ShortCausalHash)
import Unison.Codebase.ShortCausalHash qualified as SCH
import Unison.Codebase.SqliteCodebase.Conversions qualified as Cv
import Unison.Codebase.TermEdit qualified as TermEdit
import Unison.Codebase.TypeEdit qualified as TypeEdit
import Unison.CommandLine (bigproblem, note, tip)
import Unison.CommandLine.FZFResolvers qualified as FZFResolvers
import Unison.CommandLine.InputPattern (InputPattern)
@ -137,7 +134,6 @@ import Unison.Syntax.NamePrinter
prettyReference,
prettyReferent,
prettyShortHash,
styleHashQualified,
)
import Unison.Syntax.NameSegment qualified as NameSegment
import Unison.Syntax.TermPrinter qualified as TermPrinter
@ -1483,8 +1479,6 @@ notifyUser dir = \case
<> P.group (prettyNamespaceKey src <> ".")
DumpNumberedArgs schLength args ->
pure . P.numberedList $ fmap (P.text . IP.formatStructuredArgument (pure schLength)) args
NoConflictsOrEdits ->
pure (P.okCallout "No conflicts or edits in progress.")
HelpMessage pat -> pure $ IP.showPatternHelp pat
NoOp -> pure $ P.string "I didn't make any changes."
DumpBitBooster head map ->
@ -2628,66 +2622,6 @@ renderNameConflicts ppe conflictedNames = do
)
`P.hang` P.lines prettyConflicts
renderEditConflicts ::
PPE.PrettyPrintEnv -> Patch -> Numbered Pretty
renderEditConflicts ppe Patch {..} = do
formattedConflicts <- for editConflicts formatConflict
pure . Monoid.unlessM (null editConflicts) . P.callout "" . P.sep "\n\n" $
[ P.wrap $
"These"
<> P.bold "definitions were edited differently"
<> "in namespaces that have been merged into this one."
<> "You'll have to tell me what to use as the new definition:",
P.indentN 2 (P.lines formattedConflicts)
-- , tip $ "Use " <> makeExample IP.resolve [name (head editConflicts), " <replacement>"] <> " to pick a replacement." -- todo: eventually something with `edit`
]
where
-- todo: could possibly simplify all of this, but today is a copy/paste day.
editConflicts :: [Either (Reference, Set TypeEdit.TypeEdit) (Reference, Set TermEdit.TermEdit)]
editConflicts =
(fmap Left . Map.toList . R.toMultimap . R.filterManyDom $ _typeEdits)
<> (fmap Right . Map.toList . R.toMultimap . R.filterManyDom $ _termEdits)
numberedHQName :: HQ.HashQualified Name -> Numbered Pretty
numberedHQName hqName = do
n <- addNumberedArg $ SA.HashQualified hqName
pure $ formatNum n <> styleHashQualified P.bold hqName
formatTypeEdits ::
(Reference, Set TypeEdit.TypeEdit) ->
Numbered Pretty
formatTypeEdits (r, toList -> es) = do
replacedType <- numberedHQName (PPE.typeName ppe r)
replacements <- for [PPE.typeName ppe r | TypeEdit.Replace r <- es] numberedHQName
pure . P.wrap $
"The type"
<> replacedType
<> "was"
<> ( if TypeEdit.Deprecate `elem` es
then "deprecated and also replaced with"
else "replaced with"
)
`P.hang` P.lines replacements
formatTermEdits ::
(Reference.TermReference, Set TermEdit.TermEdit) ->
Numbered Pretty
formatTermEdits (r, toList -> es) = do
replacedTerm <- numberedHQName (PPE.termName ppe (Referent.Ref r))
replacements <- for [PPE.termName ppe (Referent.Ref r) | TermEdit.Replace r _ <- es] numberedHQName
pure . P.wrap $
"The term"
<> replacedTerm
<> "was"
<> ( if TermEdit.Deprecate `elem` es
then "deprecated and also replaced with"
else "replaced with"
)
`P.hang` P.lines replacements
formatConflict ::
Either
(Reference, Set TypeEdit.TypeEdit)
(Reference.TermReference, Set TermEdit.TermEdit) ->
Numbered Pretty
formatConflict = either formatTypeEdits formatTermEdits
type Numbered = State.State (Int, Seq.Seq StructuredArgument)
addNumberedArg :: StructuredArgument -> Numbered Int
@ -2706,88 +2640,13 @@ runNumbered m =
todoOutput :: (Var v) => PPED.PrettyPrintEnvDecl -> TO.TodoOutput v a -> (Pretty, NumberedArgs)
todoOutput ppe todo = runNumbered do
conflicts <- todoConflicts
edits <- todoEdits
pure (conflicts <> edits)
if TO.noConflicts todo
then pure mempty
else do
nameConflicts <- renderNameConflicts ppeu (TO.nameConflicts todo)
pure $ P.lines $ P.nonEmpty [nameConflicts]
where
ppeu = PPED.unsuffixifiedPPE ppe
ppes = PPED.suffixifiedPPE ppe
(frontierTerms, frontierTypes) = TO.todoFrontier todo
(dirtyTerms, dirtyTypes) = TO.todoFrontierDependents todo
corruptTerms =
[(PPE.termName ppeu (Referent.Ref r), r) | (r, Nothing) <- frontierTerms]
corruptTypes =
[(PPE.typeName ppeu r, r) | (r, MissingObject _) <- frontierTypes]
goodTerms ts =
[(Referent.Ref r, PPE.termName ppeu (Referent.Ref r), typ) | (r, Just typ) <- ts]
todoConflicts :: Numbered Pretty
todoConflicts = do
if TO.noConflicts todo
then pure mempty
else do
editConflicts <- renderEditConflicts ppeu (TO.editConflicts todo)
nameConflicts <- renderNameConflicts ppeu conflictedNames
pure $ P.lines . P.nonEmpty $ [editConflicts, nameConflicts]
where
-- If a conflict is both an edit and a name conflict, we show it in the edit
-- conflicts section
conflictedNames :: Names
conflictedNames = removeEditConflicts (TO.editConflicts todo) (TO.nameConflicts todo)
-- e.g. `foo#a` has been independently updated to `foo#b` and `foo#c`.
-- This means there will be a name conflict:
-- foo -> #b
-- foo -> #c
-- as well as an edit conflict:
-- #a -> #b
-- #a -> #c
-- We want to hide/ignore the name conflicts that are also targets of an
-- edit conflict, so that the edit conflict will be dealt with first.
-- For example, if hash `h` has multiple edit targets { #x, #y, #z, ...},
-- we'll temporarily remove name conflicts pointing to { #x, #y, #z, ...}.
removeEditConflicts :: Patch -> Names -> Names
removeEditConflicts Patch {..} Names {..} = Names terms' types'
where
terms' = R.filterRan (`Set.notMember` conflictedTermEditTargets) terms
types' = R.filterRan (`Set.notMember` conflictedTypeEditTargets) types
conflictedTypeEditTargets :: Set Reference
conflictedTypeEditTargets =
Set.fromList $ toList (R.ran typeEditConflicts) >>= TypeEdit.references
conflictedTermEditTargets :: Set Referent.Referent
conflictedTermEditTargets =
Set.fromList . fmap Referent.Ref $
toList (R.ran termEditConflicts) >>= TermEdit.references
typeEditConflicts = R.filterDom (`R.manyDom` _typeEdits) _typeEdits
termEditConflicts = R.filterDom (`R.manyDom` _termEdits) _termEdits
todoEdits :: Numbered Pretty
todoEdits = do
numberedTypes <- for (unscore <$> dirtyTypes) \(ref, displayObj) -> do
n <- addNumberedArg . SA.HashQualified $ PPE.typeName ppeu ref
pure $ formatNum n <> prettyDeclPair ppeu (ref, displayObj)
let filteredTerms = goodTerms (unscore <$> dirtyTerms)
termNumbers <- for filteredTerms \(ref, _, _) -> do
n <- addNumberedArg . SA.HashQualified $ PPE.termName ppeu ref
pure $ formatNum n
let formattedTerms = TypePrinter.prettySignaturesCT ppes filteredTerms
numberedTerms = zipWith (<>) termNumbers formattedTerms
pure $
Monoid.unlessM (TO.noEdits todo) . P.callout "🚧" . P.sep "\n\n" . P.nonEmpty $
[ P.wrap
( "The namespace has"
<> fromString (show (TO.todoScore todo))
<> "transitive dependent(s) left to upgrade."
<> "Your edit frontier is the dependents of these definitions:"
),
P.indentN 2 . P.lines $
( (prettyDeclPair ppeu <$> toList frontierTypes)
++ TypePrinter.prettySignaturesCT ppes (goodTerms frontierTerms)
),
P.wrap "I recommend working on them in the following order:",
P.lines $ numberedTypes ++ numberedTerms,
formatMissingStuff corruptTerms corruptTypes
]
unscore :: (a, b, c) -> (b, c)
unscore (_score, b, c) = (b, c)
listOfDefinitions ::
(Var v) => Input.FindScope -> PPE.PrettyPrintEnv -> E.ListDetailed -> [SR'.SearchResult' v a] -> IO Pretty

View File

@ -179,14 +179,10 @@ Merge back into the ancestor.
.s> todo
No conflicts or edits in progress.
.m> todo
No conflicts or edits in progress.
```

View File

@ -106,9 +106,7 @@ Let's do the update now, and verify that the definitions all look good and there
.a2> todo
No conflicts or edits in progress.
```
## Record updates
@ -213,8 +211,6 @@ And checking that after updating this record, there's nothing `todo`:
.a4> todo
No conflicts or edits in progress.
```

View File

@ -1,139 +0,0 @@
# Test the `todo` command
## Simple type-changing update.
```ucm:hide
.simple> builtins.merge
```
```unison:hide
x = 1
useX = x + 10
type MyType = MyType Nat
useMyType = match MyType 1 with
MyType a -> a + 10
```
```ucm:hide
.simple> add
```
Perform a type-changing update so dependents are added to our update frontier.
```unison:hide
x = -1
type MyType = MyType Text
```
```ucm:error
.simple> update.old
.simple> todo
```
## A merge with conflicting updates.
```ucm:hide
.mergeA> builtins.merge
```
```unison:hide
x = 1
type MyType = MyType
```
Set up two branches with the same starting point.
```ucm:hide
.mergeA> add
.> fork .mergeA .mergeB
```
Update `x` to a different term in each branch.
```unison:hide
x = 2
type MyType = MyType Nat
```
```ucm:hide
.mergeA> update.old
```
```unison:hide
x = 3
type MyType = MyType Int
```
```ucm:hide
.mergeB> update.old
```
```ucm:error
.mergeA> merge.old .mergeB
.mergeA> todo
```
## A named value that appears on the LHS of a patch isn't shown
```ucm:hide
.lhs> builtins.merge
```
```unison
foo = 801
```
```ucm
.lhs> add
```
```unison
foo = 802
```
```ucm
.lhs> update.old
```
```unison
oldfoo = 801
```
```ucm
.lhs> add
.lhs> todo
```
## A type-changing update to one element of a cycle, which doesn't propagate to the other
```ucm:hide
.cycle2> builtins.merge
```
```unison
even = cases
0 -> true
n -> odd (drop 1 n)
odd = cases
0 -> false
n -> even (drop 1 n)
```
```ucm
.cycle2> add
```
```unison
even = 17
```
```ucm
.cycle2> update.old
```
```ucm:error
.cycle2> todo
```

View File

@ -1,292 +0,0 @@
# Test the `todo` command
## Simple type-changing update.
```unison
x = 1
useX = x + 10
type MyType = MyType Nat
useMyType = match MyType 1 with
MyType a -> a + 10
```
Perform a type-changing update so dependents are added to our update frontier.
```unison
x = -1
type MyType = MyType Text
```
```ucm
.simple> update.old
⍟ I've updated these names to your new definition:
type MyType
x : Int
.simple> todo
🚧
The namespace has 2 transitive dependent(s) left to upgrade.
Your edit frontier is the dependents of these definitions:
type #vijug0om28
#gjmq673r1v : Nat
I recommend working on them in the following order:
1. useMyType : Nat
2. useX : Nat
```
## A merge with conflicting updates.
```unison
x = 1
type MyType = MyType
```
Set up two branches with the same starting point.
Update `x` to a different term in each branch.
```unison
x = 2
type MyType = MyType Nat
```
```unison
x = 3
type MyType = MyType Int
```
```ucm
.mergeA> merge.old .mergeB
Here's what's changed in the current namespace after the
merge:
New name conflicts:
1. type MyType#ig1g2ka7lv
2. ┌ type MyType#8c6f40i3tj
3. └ type MyType#ig1g2ka7lv
4. MyType.MyType#ig1g2ka7lv#0 : Nat -> MyType#ig1g2ka7lv
5. ┌ MyType.MyType#8c6f40i3tj#0 : Int -> MyType#8c6f40i3tj
6. └ MyType.MyType#ig1g2ka7lv#0 : Nat -> MyType#ig1g2ka7lv
7. x#dcgdua2lj6 : Nat
8. ┌ x#dcgdua2lj6 : Nat
9. └ x#f3lgjvjqoo : Nat
Updates:
10. patch patch (added 2 updates)
Tip: You can use `todo` to see if this generated any work to
do in this namespace and `test` to run the tests. Or you
can use `undo` or `reflog` to undo the results of this
merge.
Applying changes from patch...
I tried to auto-apply the patch, but couldn't because it
contained contradictory entries.
.mergeA> todo
These definitions were edited differently in namespaces that
have been merged into this one. You'll have to tell me what to
use as the new definition:
The type 1. #8h7qq3ougl was replaced with
2. MyType#8c6f40i3tj
3. MyType#ig1g2ka7lv
The term 4. #gjmq673r1v was replaced with
5. x#dcgdua2lj6
6. x#f3lgjvjqoo
The term MyType.MyType has conflicting definitions:
7. MyType.MyType#8c6f40i3tj#0
8. MyType.MyType#ig1g2ka7lv#0
Tip: This occurs when merging branches that both independently
introduce the same name. Use `move.term` or `delete.term`
to resolve the conflicts.
```
## A named value that appears on the LHS of a patch isn't shown
```unison
foo = 801
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These new definitions are ok to `add`:
foo : Nat
```
```ucm
.lhs> add
⍟ I've added these definitions:
foo : Nat
```
```unison
foo = 802
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
foo : Nat
```
```ucm
.lhs> update.old
⍟ I've updated these names to your new definition:
foo : Nat
```
```unison
oldfoo = 801
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These new definitions are ok to `add`:
oldfoo : Nat
```
```ucm
.lhs> add
⍟ I've added these definitions:
oldfoo : Nat
.lhs> todo
No conflicts or edits in progress.
```
## A type-changing update to one element of a cycle, which doesn't propagate to the other
```unison
even = cases
0 -> true
n -> odd (drop 1 n)
odd = cases
0 -> false
n -> even (drop 1 n)
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These new definitions are ok to `add`:
even : Nat -> Boolean
odd : Nat -> Boolean
```
```ucm
.cycle2> add
⍟ I've added these definitions:
even : Nat -> Boolean
odd : Nat -> Boolean
```
```unison
even = 17
```
```ucm
Loading changes detected in scratch.u.
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These names already exist. You can `update` them to your
new definition:
even : Nat
```
```ucm
.cycle2> update.old
⍟ I've updated these names to your new definition:
even : Nat
```
```ucm
.cycle2> todo
🚧
The namespace has 1 transitive dependent(s) left to upgrade.
Your edit frontier is the dependents of these definitions:
#kkohl7ba1e : Nat -> Boolean
I recommend working on them in the following order:
1. odd : Nat -> Boolean
```