mirror of
https://github.com/unisonweb/unison.git
synced 2024-09-11 10:35:57 +03:00
Merge remote-tracking branch 'upstream/trunk' into new-transcript-parser
This commit is contained in:
commit
bf442467a4
@ -178,6 +178,7 @@ invertDomain =
|
|||||||
g x acc y =
|
g x acc y =
|
||||||
Map.insert y x acc
|
Map.insert y x acc
|
||||||
|
|
||||||
|
-- | Construct a left-unique relation from a mapping from its right-elements to its left-elements.
|
||||||
fromRange :: (Ord a, Ord b) => Map b a -> BiMultimap a b
|
fromRange :: (Ord a, Ord b) => Map b a -> BiMultimap a b
|
||||||
fromRange m =
|
fromRange m =
|
||||||
BiMultimap (Map.foldlWithKey' f Map.empty m) m
|
BiMultimap (Map.foldlWithKey' f Map.empty m) m
|
||||||
|
@ -139,6 +139,7 @@ import Unison.NameSegment (NameSegment)
|
|||||||
import Unison.NameSegment qualified as NameSegment
|
import Unison.NameSegment qualified as NameSegment
|
||||||
import Unison.Prelude hiding (empty)
|
import Unison.Prelude hiding (empty)
|
||||||
import Unison.Reference (TermReference, TermReferenceId, TypeReference, TypeReferenceId)
|
import Unison.Reference (TermReference, TermReferenceId, TypeReference, TypeReferenceId)
|
||||||
|
import Unison.Reference qualified as Reference
|
||||||
import Unison.Referent (Referent)
|
import Unison.Referent (Referent)
|
||||||
import Unison.Referent qualified as Referent
|
import Unison.Referent qualified as Referent
|
||||||
import Unison.Util.List qualified as List
|
import Unison.Util.List qualified as List
|
||||||
@ -148,7 +149,6 @@ import Unison.Util.Set qualified as Set
|
|||||||
import Unison.Util.Star2 qualified as Star2
|
import Unison.Util.Star2 qualified as Star2
|
||||||
import Witherable (FilterableWithIndex (imapMaybe))
|
import Witherable (FilterableWithIndex (imapMaybe))
|
||||||
import Prelude hiding (head, read, subtract)
|
import Prelude hiding (head, read, subtract)
|
||||||
import qualified Unison.Reference as Reference
|
|
||||||
|
|
||||||
instance AsEmpty (Branch m) where
|
instance AsEmpty (Branch m) where
|
||||||
_Empty = prism' (const empty) matchEmpty
|
_Empty = prism' (const empty) matchEmpty
|
||||||
@ -215,7 +215,6 @@ deepTypeReferenceIds :: Branch0 m -> Set TypeReferenceId
|
|||||||
deepTypeReferenceIds =
|
deepTypeReferenceIds =
|
||||||
Set.mapMaybe Reference.toId . deepTypeReferences
|
Set.mapMaybe Reference.toId . deepTypeReferences
|
||||||
|
|
||||||
|
|
||||||
namespaceStats :: Branch0 m -> NamespaceStats
|
namespaceStats :: Branch0 m -> NamespaceStats
|
||||||
namespaceStats b =
|
namespaceStats b =
|
||||||
NamespaceStats
|
NamespaceStats
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Unison.Codebase.Causal
|
module Unison.Codebase.Causal
|
||||||
( Causal (currentHash, head, tail, tails),
|
( Causal (currentHash, valueHash, head, tail, tails),
|
||||||
pattern One,
|
pattern One,
|
||||||
pattern Cons,
|
pattern Cons,
|
||||||
pattern Merge,
|
pattern Merge,
|
||||||
@ -40,7 +40,8 @@ import Unison.Codebase.Causal.Type
|
|||||||
currentHash,
|
currentHash,
|
||||||
head,
|
head,
|
||||||
tail,
|
tail,
|
||||||
tails
|
tails,
|
||||||
|
valueHash
|
||||||
),
|
),
|
||||||
before,
|
before,
|
||||||
lca,
|
lca,
|
||||||
|
@ -9,6 +9,9 @@ module Unison.Codebase.Editor.HandleInput.Merge2
|
|||||||
LcaMergeInfo (..),
|
LcaMergeInfo (..),
|
||||||
doMerge,
|
doMerge,
|
||||||
doMergeLocalBranch,
|
doMergeLocalBranch,
|
||||||
|
|
||||||
|
-- * API exported for @todo@
|
||||||
|
hasDefnsInLib,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@ -86,6 +89,7 @@ import Unison.Merge.EitherWay (EitherWay (..))
|
|||||||
import Unison.Merge.EitherWayI (EitherWayI (..))
|
import Unison.Merge.EitherWayI (EitherWayI (..))
|
||||||
import Unison.Merge.EitherWayI qualified as EitherWayI
|
import Unison.Merge.EitherWayI qualified as EitherWayI
|
||||||
import Unison.Merge.Libdeps qualified as Merge
|
import Unison.Merge.Libdeps qualified as Merge
|
||||||
|
import Unison.Merge.PartialDeclNameLookup (PartialDeclNameLookup)
|
||||||
import Unison.Merge.PartitionCombinedDiffs (partitionCombinedDiffs)
|
import Unison.Merge.PartitionCombinedDiffs (partitionCombinedDiffs)
|
||||||
import Unison.Merge.Synhashed (Synhashed (..))
|
import Unison.Merge.Synhashed (Synhashed (..))
|
||||||
import Unison.Merge.Synhashed qualified as Synhashed
|
import Unison.Merge.Synhashed qualified as Synhashed
|
||||||
@ -139,7 +143,6 @@ import Unison.Util.SyntaxText (SyntaxText')
|
|||||||
import Unison.Var (Var)
|
import Unison.Var (Var)
|
||||||
import Witch (unsafeFrom)
|
import Witch (unsafeFrom)
|
||||||
import Prelude hiding (unzip, zip, zipWith)
|
import Prelude hiding (unzip, zip, zipWith)
|
||||||
import Unison.Merge.PartialDeclNameLookup (PartialDeclNameLookup)
|
|
||||||
|
|
||||||
handleMerge :: ProjectAndBranch (Maybe ProjectName) ProjectBranchName -> Cli ()
|
handleMerge :: ProjectAndBranch (Maybe ProjectName) ProjectBranchName -> Cli ()
|
||||||
handleMerge (ProjectAndBranch maybeBobProjectName bobBranchName) = do
|
handleMerge (ProjectAndBranch maybeBobProjectName bobBranchName) = do
|
||||||
@ -239,11 +242,7 @@ doMerge info = do
|
|||||||
|
|
||||||
-- Assert that neither Alice nor Bob have defns in lib
|
-- Assert that neither Alice nor Bob have defns in lib
|
||||||
for_ [(mergeTarget, branches.alice), (mergeSource, branches.bob)] \(who, branch) -> do
|
for_ [(mergeTarget, branches.alice), (mergeSource, branches.bob)] \(who, branch) -> do
|
||||||
libdeps <-
|
whenM (Cli.runTransaction (hasDefnsInLib branch)) do
|
||||||
case Map.lookup NameSegment.libSegment branch.children of
|
|
||||||
Nothing -> pure V2.Branch.empty
|
|
||||||
Just libdeps -> Cli.runTransaction libdeps.value
|
|
||||||
when (not (Map.null libdeps.terms) || not (Map.null libdeps.types)) do
|
|
||||||
done (Output.MergeDefnsInLib who)
|
done (Output.MergeDefnsInLib who)
|
||||||
|
|
||||||
-- Load Alice/Bob/LCA definitions and decl name lookups
|
-- Load Alice/Bob/LCA definitions and decl name lookups
|
||||||
@ -486,6 +485,17 @@ loadLibdeps branches = do
|
|||||||
libdepsBranch <- libdepsCausal.value
|
libdepsBranch <- libdepsCausal.value
|
||||||
pure libdepsBranch.children
|
pure libdepsBranch.children
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Merge precondition violation checks
|
||||||
|
|
||||||
|
hasDefnsInLib :: Applicative m => V2.Branch m -> m Bool
|
||||||
|
hasDefnsInLib branch = do
|
||||||
|
libdeps <-
|
||||||
|
case Map.lookup NameSegment.libSegment branch.children of
|
||||||
|
Nothing -> pure V2.Branch.empty
|
||||||
|
Just libdeps -> libdeps.value
|
||||||
|
pure (not (Map.null libdeps.terms) || not (Map.null libdeps.types))
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Creating Unison files
|
-- Creating Unison files
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ module Unison.Codebase.Editor.HandleInput.Todo
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
import Data.Either qualified as Either
|
||||||
import Data.Set qualified as Set
|
import Data.Set qualified as Set
|
||||||
|
import U.Codebase.HashTags (BranchHash (..))
|
||||||
import U.Codebase.Sqlite.Operations qualified as Operations
|
import U.Codebase.Sqlite.Operations qualified as Operations
|
||||||
import Unison.Builtin qualified as Builtin
|
import Unison.Builtin qualified as Builtin
|
||||||
import Unison.Cli.Monad (Cli)
|
import Unison.Cli.Monad (Cli)
|
||||||
@ -14,7 +16,11 @@ import Unison.Cli.PrettyPrintUtils qualified as Cli
|
|||||||
import Unison.Codebase qualified as Codebase
|
import Unison.Codebase qualified as Codebase
|
||||||
import Unison.Codebase.Branch qualified as Branch
|
import Unison.Codebase.Branch qualified as Branch
|
||||||
import Unison.Codebase.Branch.Names qualified as Branch
|
import Unison.Codebase.Branch.Names qualified as Branch
|
||||||
|
import Unison.Codebase.Causal qualified as Causal
|
||||||
|
import Unison.Codebase.Editor.HandleInput.Merge2 (hasDefnsInLib)
|
||||||
import Unison.Codebase.Editor.Output
|
import Unison.Codebase.Editor.Output
|
||||||
|
import Unison.Hash (HashFor (..))
|
||||||
|
import Unison.Merge.DeclCoherencyCheck (IncoherentDeclReasons (..), checkAllDeclCoherency)
|
||||||
import Unison.Names qualified as Names
|
import Unison.Names qualified as Names
|
||||||
import Unison.Prelude
|
import Unison.Prelude
|
||||||
import Unison.Reference (TermReference)
|
import Unison.Reference (TermReference)
|
||||||
@ -26,11 +32,22 @@ handleTodo :: Cli ()
|
|||||||
handleTodo = do
|
handleTodo = do
|
||||||
-- For now, we don't go through any great trouble to seek out the root of the project branch. Just assume the current
|
-- For now, we don't go through any great trouble to seek out the root of the project branch. Just assume the current
|
||||||
-- namespace is the root, which will be the case unless the user uses `deprecated.cd`.
|
-- namespace is the root, which will be the case unless the user uses `deprecated.cd`.
|
||||||
currentNamespace <- Cli.getCurrentBranch0
|
currentCausal <- Cli.getCurrentBranch
|
||||||
|
let currentNamespace = Branch.head currentCausal
|
||||||
let currentNamespaceWithoutLibdeps = Branch.deleteLibdeps currentNamespace
|
let currentNamespaceWithoutLibdeps = Branch.deleteLibdeps currentNamespace
|
||||||
|
|
||||||
(dependentsOfTodo, directDependencies, hashLen) <-
|
(defnsInLib, dependentsOfTodo, directDependencies, hashLen, incoherentDeclReasons) <-
|
||||||
Cli.runTransaction do
|
Cli.runTransaction do
|
||||||
|
-- We call a shared `hasDefnsLib` helper even though we could easily duplicate the logic with the branch in hand
|
||||||
|
defnsInLib <- do
|
||||||
|
branch <-
|
||||||
|
currentCausal
|
||||||
|
& Branch._history
|
||||||
|
& Causal.valueHash
|
||||||
|
& coerce @_ @BranchHash
|
||||||
|
& Operations.expectBranchByBranchHash
|
||||||
|
hasDefnsInLib branch
|
||||||
|
|
||||||
let todoReference :: TermReference
|
let todoReference :: TermReference
|
||||||
todoReference =
|
todoReference =
|
||||||
Set.asSingleton (Names.refTermsNamed Builtin.names (Name.unsafeParseText "todo"))
|
Set.asSingleton (Names.refTermsNamed Builtin.names (Name.unsafeParseText "todo"))
|
||||||
@ -51,20 +68,28 @@ handleTodo = do
|
|||||||
|
|
||||||
hashLen <- Codebase.hashLength
|
hashLen <- Codebase.hashLength
|
||||||
|
|
||||||
pure (dependentsOfTodo.terms, directDependencies, hashLen)
|
incoherentDeclReasons <-
|
||||||
|
fmap (Either.fromLeft (IncoherentDeclReasons [] [] [] [])) $
|
||||||
|
checkAllDeclCoherency
|
||||||
|
Operations.expectDeclNumConstructors
|
||||||
|
(Names.lenientToNametree (Branch.toNames currentNamespaceWithoutLibdeps))
|
||||||
|
|
||||||
|
pure (defnsInLib, dependentsOfTodo.terms, directDependencies, hashLen, incoherentDeclReasons)
|
||||||
|
|
||||||
ppe <- Cli.currentPrettyPrintEnvDecl
|
ppe <- Cli.currentPrettyPrintEnvDecl
|
||||||
|
|
||||||
Cli.respondNumbered $
|
Cli.respondNumbered $
|
||||||
Output'Todo
|
Output'Todo
|
||||||
TodoOutput
|
TodoOutput
|
||||||
{ hashLen,
|
{ defnsInLib,
|
||||||
dependentsOfTodo,
|
dependentsOfTodo,
|
||||||
directDependenciesWithoutNames =
|
directDependenciesWithoutNames =
|
||||||
Defns
|
Defns
|
||||||
{ terms = Set.difference directDependencies.terms (Branch.deepTermReferences currentNamespace),
|
{ terms = Set.difference directDependencies.terms (Branch.deepTermReferences currentNamespace),
|
||||||
types = Set.difference directDependencies.types (Branch.deepTypeReferences currentNamespace)
|
types = Set.difference directDependencies.types (Branch.deepTypeReferences currentNamespace)
|
||||||
},
|
},
|
||||||
|
hashLen,
|
||||||
|
incoherentDeclReasons,
|
||||||
nameConflicts = Names.conflicts (Branch.toNames currentNamespaceWithoutLibdeps),
|
nameConflicts = Names.conflicts (Branch.toNames currentNamespaceWithoutLibdeps),
|
||||||
ppe
|
ppe
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ import Unison.Hash (Hash)
|
|||||||
import Unison.HashQualified qualified as HQ
|
import Unison.HashQualified qualified as HQ
|
||||||
import Unison.HashQualified' qualified as HQ'
|
import Unison.HashQualified' qualified as HQ'
|
||||||
import Unison.LabeledDependency (LabeledDependency)
|
import Unison.LabeledDependency (LabeledDependency)
|
||||||
|
import Unison.Merge.DeclCoherencyCheck (IncoherentDeclReasons (..))
|
||||||
import Unison.Name (Name)
|
import Unison.Name (Name)
|
||||||
import Unison.NameSegment (NameSegment)
|
import Unison.NameSegment (NameSegment)
|
||||||
import Unison.Names (Names)
|
import Unison.Names (Names)
|
||||||
@ -154,9 +155,11 @@ data NumberedOutput
|
|||||||
(Map LabeledDependency (Set Name)) -- Mapping of external dependencies to their local dependents.
|
(Map LabeledDependency (Set Name)) -- Mapping of external dependencies to their local dependents.
|
||||||
|
|
||||||
data TodoOutput = TodoOutput
|
data TodoOutput = TodoOutput
|
||||||
{ dependentsOfTodo :: !(Set TermReferenceId),
|
{ defnsInLib :: !Bool,
|
||||||
|
dependentsOfTodo :: !(Set TermReferenceId),
|
||||||
directDependenciesWithoutNames :: !(DefnsF Set TermReference TypeReference),
|
directDependenciesWithoutNames :: !(DefnsF Set TermReference TypeReference),
|
||||||
hashLen :: !Int,
|
hashLen :: !Int,
|
||||||
|
incoherentDeclReasons :: !IncoherentDeclReasons,
|
||||||
nameConflicts :: !Names,
|
nameConflicts :: !Names,
|
||||||
ppe :: !PrettyPrintEnvDecl
|
ppe :: !PrettyPrintEnvDecl
|
||||||
}
|
}
|
||||||
@ -166,6 +169,8 @@ todoOutputIsEmpty todo =
|
|||||||
Set.null todo.dependentsOfTodo
|
Set.null todo.dependentsOfTodo
|
||||||
&& defnsAreEmpty todo.directDependenciesWithoutNames
|
&& defnsAreEmpty todo.directDependenciesWithoutNames
|
||||||
&& Names.isEmpty todo.nameConflicts
|
&& Names.isEmpty todo.nameConflicts
|
||||||
|
&& not todo.defnsInLib
|
||||||
|
&& todo.incoherentDeclReasons == IncoherentDeclReasons [] [] [] []
|
||||||
|
|
||||||
data AmbiguousReset'Argument
|
data AmbiguousReset'Argument
|
||||||
= AmbiguousReset'Hash
|
= AmbiguousReset'Hash
|
||||||
|
@ -87,6 +87,7 @@ import Unison.Hash32 (Hash32)
|
|||||||
import Unison.HashQualified qualified as HQ
|
import Unison.HashQualified qualified as HQ
|
||||||
import Unison.HashQualified' qualified as HQ'
|
import Unison.HashQualified' qualified as HQ'
|
||||||
import Unison.LabeledDependency as LD
|
import Unison.LabeledDependency as LD
|
||||||
|
import Unison.Merge.DeclCoherencyCheck (IncoherentDeclReasons (..))
|
||||||
import Unison.Name (Name)
|
import Unison.Name (Name)
|
||||||
import Unison.Name qualified as Name
|
import Unison.Name qualified as Name
|
||||||
import Unison.NameSegment qualified as NameSegment
|
import Unison.NameSegment qualified as NameSegment
|
||||||
@ -1401,6 +1402,7 @@ notifyUser dir = \case
|
|||||||
<> "the same on both branches, or making neither of them a builtin, and then try the merge again."
|
<> "the same on both branches, or making neither of them a builtin, and then try the merge again."
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
-- Note [ConstructorAliasMessage] If you change this, also change the other similar one
|
||||||
MergeConstructorAlias aliceOrBob typeName conName1 conName2 ->
|
MergeConstructorAlias aliceOrBob typeName conName1 conName2 ->
|
||||||
pure . P.lines $
|
pure . P.lines $
|
||||||
[ P.wrap "Sorry, I wasn't able to perform the merge:",
|
[ P.wrap "Sorry, I wasn't able to perform the merge:",
|
||||||
@ -1416,6 +1418,7 @@ notifyUser dir = \case
|
|||||||
"",
|
"",
|
||||||
P.wrap "Please delete all but one name for each constructor, and then try merging again."
|
P.wrap "Please delete all but one name for each constructor, and then try merging again."
|
||||||
]
|
]
|
||||||
|
-- Note [DefnsInLibMessage] If you change this, also change the other similar one
|
||||||
MergeDefnsInLib aliceOrBob ->
|
MergeDefnsInLib aliceOrBob ->
|
||||||
pure . P.lines $
|
pure . P.lines $
|
||||||
[ P.wrap "Sorry, I wasn't able to perform the merge:",
|
[ P.wrap "Sorry, I wasn't able to perform the merge:",
|
||||||
@ -1428,6 +1431,7 @@ notifyUser dir = \case
|
|||||||
"",
|
"",
|
||||||
P.wrap "Please move or remove it and then try merging again."
|
P.wrap "Please move or remove it and then try merging again."
|
||||||
]
|
]
|
||||||
|
-- Note [MissingConstructorNameMessage] If you change this, also change the other similar one
|
||||||
MergeMissingConstructorName aliceOrBob name ->
|
MergeMissingConstructorName aliceOrBob name ->
|
||||||
pure . P.lines $
|
pure . P.lines $
|
||||||
[ P.wrap "Sorry, I wasn't able to perform the merge:",
|
[ P.wrap "Sorry, I wasn't able to perform the merge:",
|
||||||
@ -1446,6 +1450,7 @@ notifyUser dir = \case
|
|||||||
<> IP.makeExample IP.aliasTerm ["<hash>", prettyName name <> ".<ConstructorName>"]
|
<> IP.makeExample IP.aliasTerm ["<hash>", prettyName name <> ".<ConstructorName>"]
|
||||||
<> "to give names to each unnamed constructor, and then try the merge again."
|
<> "to give names to each unnamed constructor, and then try the merge again."
|
||||||
]
|
]
|
||||||
|
-- Note [NestedDeclAliasMessage] If you change this, also change the other similar one
|
||||||
MergeNestedDeclAlias aliceOrBob shorterName longerName ->
|
MergeNestedDeclAlias aliceOrBob shorterName longerName ->
|
||||||
pure . P.wrap $
|
pure . P.wrap $
|
||||||
"On"
|
"On"
|
||||||
@ -1456,6 +1461,7 @@ notifyUser dir = \case
|
|||||||
<> P.group (prettyName shorterName <> ".")
|
<> P.group (prettyName shorterName <> ".")
|
||||||
<> "I'm not able to perform a merge when a type exists nested under an alias of itself. Please separate them or"
|
<> "I'm not able to perform a merge when a type exists nested under an alias of itself. Please separate them or"
|
||||||
<> "delete one copy, and then try merging again."
|
<> "delete one copy, and then try merging again."
|
||||||
|
-- Note [StrayConstructorMessage] If you change this, also change the other similar one
|
||||||
MergeStrayConstructor aliceOrBob name ->
|
MergeStrayConstructor aliceOrBob name ->
|
||||||
pure . P.lines $
|
pure . P.lines $
|
||||||
[ P.wrap $
|
[ P.wrap $
|
||||||
@ -2607,20 +2613,20 @@ unsafePrettyTermResultSig' ppe = \case
|
|||||||
head (TypePrinter.prettySignaturesCT ppe [(r, name, typ)])
|
head (TypePrinter.prettySignaturesCT ppe [(r, name, typ)])
|
||||||
_ -> error "Don't pass Nothing"
|
_ -> error "Don't pass Nothing"
|
||||||
|
|
||||||
renderNameConflicts :: PPE.PrettyPrintEnv -> Names -> Numbered Pretty
|
renderNameConflicts :: Int -> Names -> Numbered Pretty
|
||||||
renderNameConflicts ppe conflictedNames = do
|
renderNameConflicts hashLen conflictedNames = do
|
||||||
let conflictedTypeNames :: Map Name [HQ.HashQualified Name]
|
let conflictedTypeNames :: Map Name [HQ.HashQualified Name]
|
||||||
conflictedTypeNames =
|
conflictedTypeNames =
|
||||||
conflictedNames
|
conflictedNames
|
||||||
& Names.types
|
& Names.types
|
||||||
& R.domain
|
& R.domain
|
||||||
& fmap (foldMap (pure @[] . PPE.typeName ppe))
|
& Map.mapWithKey \name -> map (HQ.take hashLen . HQ.HashQualified name . Reference.toShortHash) . Set.toList
|
||||||
let conflictedTermNames :: Map Name [HQ.HashQualified Name]
|
let conflictedTermNames :: Map Name [HQ.HashQualified Name]
|
||||||
conflictedTermNames =
|
conflictedTermNames =
|
||||||
conflictedNames
|
conflictedNames
|
||||||
& Names.terms
|
& Names.terms
|
||||||
& R.domain
|
& R.domain
|
||||||
& fmap (foldMap (pure @[] . PPE.termName ppe))
|
& Map.mapWithKey \name -> map (HQ.take hashLen . HQ.HashQualified name . Referent.toShortHash) . Set.toList
|
||||||
let allConflictedNames :: [Name]
|
let allConflictedNames :: [Name]
|
||||||
allConflictedNames = Set.toList (Map.keysSet conflictedTermNames <> Map.keysSet conflictedTypeNames)
|
allConflictedNames = Set.toList (Map.keysSet conflictedTermNames <> Map.keysSet conflictedTypeNames)
|
||||||
prettyConflictedTypes <- showConflictedNames "type" conflictedTypeNames
|
prettyConflictedTypes <- showConflictedNames "type" conflictedTypeNames
|
||||||
@ -2653,13 +2659,14 @@ renderNameConflicts ppe conflictedNames = do
|
|||||||
prettyConflicts <- for hashes \hash -> do
|
prettyConflicts <- for hashes \hash -> do
|
||||||
n <- addNumberedArg $ SA.HashQualified hash
|
n <- addNumberedArg $ SA.HashQualified hash
|
||||||
pure $ formatNum n <> (P.blue . P.syntaxToColor . prettyHashQualified $ hash)
|
pure $ formatNum n <> (P.blue . P.syntaxToColor . prettyHashQualified $ hash)
|
||||||
pure . P.wrap $
|
pure $
|
||||||
( "The "
|
P.wrap
|
||||||
<> thingKind
|
( "The "
|
||||||
<> " "
|
<> thingKind
|
||||||
<> P.green (prettyName name)
|
<> " "
|
||||||
<> " has conflicting definitions:"
|
<> P.green (prettyName name)
|
||||||
)
|
<> " has conflicting definitions:"
|
||||||
|
)
|
||||||
<> P.newline
|
<> P.newline
|
||||||
<> P.newline
|
<> P.newline
|
||||||
<> P.indentN 2 (P.lines prettyConflicts)
|
<> P.indentN 2 (P.lines prettyConflicts)
|
||||||
@ -2685,11 +2692,6 @@ handleTodoOutput :: TodoOutput -> Numbered Pretty
|
|||||||
handleTodoOutput todo
|
handleTodoOutput todo
|
||||||
| todoOutputIsEmpty todo = pure "You have no pending todo items. Good work! ✅"
|
| todoOutputIsEmpty todo = pure "You have no pending todo items. Good work! ✅"
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
prettyConflicts <-
|
|
||||||
if todo.nameConflicts == mempty
|
|
||||||
then pure mempty
|
|
||||||
else renderNameConflicts todo.ppe.unsuffixifiedPPE todo.nameConflicts
|
|
||||||
|
|
||||||
prettyDependentsOfTodo <- do
|
prettyDependentsOfTodo <- do
|
||||||
if Set.null todo.dependentsOfTodo
|
if Set.null todo.dependentsOfTodo
|
||||||
then pure mempty
|
then pure mempty
|
||||||
@ -2738,11 +2740,159 @@ handleTodoOutput todo
|
|||||||
<> P.newline
|
<> P.newline
|
||||||
<> P.indentN 2 (P.lines types)
|
<> P.indentN 2 (P.lines types)
|
||||||
|
|
||||||
|
prettyConflicts <-
|
||||||
|
if todo.nameConflicts == mempty
|
||||||
|
then pure mempty
|
||||||
|
else renderNameConflicts todo.hashLen todo.nameConflicts
|
||||||
|
|
||||||
|
let prettyDefnsInLib =
|
||||||
|
if todo.defnsInLib
|
||||||
|
then
|
||||||
|
P.wrap $
|
||||||
|
-- Note [DefnsInLibMessage] If you change this, also change the other similar one
|
||||||
|
"There's a type or term at the top level of the `lib` namespace, where I only expect to find"
|
||||||
|
<> "subnamespaces representing library dependencies. Please move or remove it."
|
||||||
|
else mempty
|
||||||
|
|
||||||
|
prettyConstructorAliases <-
|
||||||
|
let -- We want to filter out constructor aliases whose types are part of a "nested decl alias" problem, because
|
||||||
|
-- otherwise we'd essentially be reporting those issues twice.
|
||||||
|
--
|
||||||
|
-- That is, if we have two nested aliases like
|
||||||
|
--
|
||||||
|
-- Foo = #XYZ
|
||||||
|
-- Foo.Bar = #XYZ#0
|
||||||
|
--
|
||||||
|
-- Foo.inner.Alias = #XYZ
|
||||||
|
-- Foo.inner.Alias.Constructor = #XYZ#0
|
||||||
|
--
|
||||||
|
-- then we'd prefer to say "oh no Foo and Foo.inner.Alias are aliases" but *not* additionally say "oh no
|
||||||
|
-- Foo.Bar and Foo.inner.Alias.Constructor are aliases".
|
||||||
|
notNestedDeclAlias (typeName, _, _) =
|
||||||
|
foldr
|
||||||
|
(\(short, long) acc -> typeName /= short && typeName /= long && acc)
|
||||||
|
True
|
||||||
|
todo.incoherentDeclReasons.nestedDeclAliases
|
||||||
|
in case filter notNestedDeclAlias todo.incoherentDeclReasons.constructorAliases of
|
||||||
|
[] -> pure mempty
|
||||||
|
aliases -> do
|
||||||
|
things <-
|
||||||
|
for aliases \(typeName, conName1, conName2) -> do
|
||||||
|
n1 <- addNumberedArg (SA.Name conName1)
|
||||||
|
n2 <- addNumberedArg (SA.Name conName2)
|
||||||
|
pure (typeName, formatNum n1 <> prettyName conName1, formatNum n2 <> prettyName conName2)
|
||||||
|
pure $
|
||||||
|
things
|
||||||
|
& map
|
||||||
|
( \(typeName, prettyCon1, prettyCon2) ->
|
||||||
|
-- Note [ConstructorAliasMessage] If you change this, also change the other similar one
|
||||||
|
P.wrap ("The type" <> prettyName typeName <> "has a constructor with multiple names.")
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.indentN 2 (P.lines [prettyCon1, prettyCon2])
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.wrap "Please delete all but one name for each constructor."
|
||||||
|
)
|
||||||
|
& P.sep "\n\n"
|
||||||
|
|
||||||
|
prettyMissingConstructorNames <-
|
||||||
|
case NEList.nonEmpty todo.incoherentDeclReasons.missingConstructorNames of
|
||||||
|
Nothing -> pure mempty
|
||||||
|
Just types0 -> do
|
||||||
|
stuff <-
|
||||||
|
for types0 \typ -> do
|
||||||
|
n <- addNumberedArg (SA.Name typ)
|
||||||
|
pure (n, typ)
|
||||||
|
-- Note [MissingConstructorNameMessage] If you change this, also change the other similar one
|
||||||
|
pure $
|
||||||
|
P.wrap
|
||||||
|
"These types have some constructors with missing names."
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.indentN 2 (P.lines (fmap (\(n, typ) -> formatNum n <> prettyName typ) stuff))
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.wrap
|
||||||
|
( "You can use"
|
||||||
|
<> IP.makeExample
|
||||||
|
IP.view
|
||||||
|
[ let firstNum = fst (NEList.head stuff)
|
||||||
|
lastNum = fst (NEList.last stuff)
|
||||||
|
in if firstNum == lastNum
|
||||||
|
then P.string (show firstNum)
|
||||||
|
else P.string (show firstNum) <> "-" <> P.string (show lastNum)
|
||||||
|
]
|
||||||
|
<> "and"
|
||||||
|
<> IP.makeExample IP.aliasTerm ["<hash>", "<TypeName>.<ConstructorName>"]
|
||||||
|
<> "to give names to each unnamed constructor."
|
||||||
|
)
|
||||||
|
|
||||||
|
prettyNestedDeclAliases <-
|
||||||
|
case todo.incoherentDeclReasons.nestedDeclAliases of
|
||||||
|
[] -> pure mempty
|
||||||
|
aliases0 -> do
|
||||||
|
aliases1 <-
|
||||||
|
for aliases0 \(short, long) -> do
|
||||||
|
n1 <- addNumberedArg (SA.Name short)
|
||||||
|
n2 <- addNumberedArg (SA.Name long)
|
||||||
|
pure (formatNum n1 <> prettyName short, formatNum n2 <> prettyName long)
|
||||||
|
-- Note [NestedDeclAliasMessage] If you change this, also change the other similar one
|
||||||
|
pure $
|
||||||
|
aliases1
|
||||||
|
& map
|
||||||
|
( \(short, long) ->
|
||||||
|
P.wrap
|
||||||
|
( "These types are aliases, but one is nested under the other. Please separate them or delete"
|
||||||
|
<> "one copy."
|
||||||
|
)
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.indentN 2 (P.lines [short, long])
|
||||||
|
)
|
||||||
|
& P.sep "\n\n"
|
||||||
|
|
||||||
|
prettyStrayConstructors <-
|
||||||
|
case todo.incoherentDeclReasons.strayConstructors of
|
||||||
|
[] -> pure mempty
|
||||||
|
constructors -> do
|
||||||
|
nums <-
|
||||||
|
for constructors \constructor -> do
|
||||||
|
addNumberedArg (SA.Name constructor)
|
||||||
|
-- Note [StrayConstructorMessage] If you change this, also change the other similar one
|
||||||
|
pure $
|
||||||
|
P.wrap "These constructors are not nested beneath their corresponding type names:"
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.indentN
|
||||||
|
2
|
||||||
|
( P.lines
|
||||||
|
( zipWith
|
||||||
|
(\n constructor -> formatNum n <> prettyName constructor)
|
||||||
|
nums
|
||||||
|
constructors
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<> P.newline
|
||||||
|
<> P.newline
|
||||||
|
<> P.wrap
|
||||||
|
( "For each one, please either use"
|
||||||
|
<> IP.makeExample' IP.moveAll
|
||||||
|
<> "to move if, or if it's an extra copy, you can simply"
|
||||||
|
<> IP.makeExample' IP.delete
|
||||||
|
<> "it."
|
||||||
|
)
|
||||||
|
|
||||||
(pure . P.sep "\n\n" . P.nonEmpty)
|
(pure . P.sep "\n\n" . P.nonEmpty)
|
||||||
[ prettyDependentsOfTodo,
|
[ prettyDependentsOfTodo,
|
||||||
prettyDirectTermDependenciesWithoutNames,
|
prettyDirectTermDependenciesWithoutNames,
|
||||||
prettyDirectTypeDependenciesWithoutNames,
|
prettyDirectTypeDependenciesWithoutNames,
|
||||||
prettyConflicts
|
prettyConflicts,
|
||||||
|
prettyDefnsInLib,
|
||||||
|
prettyConstructorAliases,
|
||||||
|
prettyMissingConstructorNames,
|
||||||
|
prettyNestedDeclAliases,
|
||||||
|
prettyStrayConstructors
|
||||||
]
|
]
|
||||||
|
|
||||||
listOfDefinitions ::
|
listOfDefinitions ::
|
||||||
|
@ -66,6 +66,7 @@ default-extensions:
|
|||||||
- DerivingStrategies
|
- DerivingStrategies
|
||||||
- DerivingVia
|
- DerivingVia
|
||||||
- DoAndIfThenElse
|
- DoAndIfThenElse
|
||||||
|
- DuplicateRecordFields
|
||||||
- FlexibleContexts
|
- FlexibleContexts
|
||||||
- FlexibleInstances
|
- FlexibleInstances
|
||||||
- GADTs
|
- GADTs
|
||||||
|
@ -49,12 +49,15 @@ module Unison.Names
|
|||||||
hashQualifyTypesRelation,
|
hashQualifyTypesRelation,
|
||||||
hashQualifyTermsRelation,
|
hashQualifyTermsRelation,
|
||||||
fromTermsAndTypes,
|
fromTermsAndTypes,
|
||||||
|
lenientToNametree,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Map qualified as Map
|
import Data.Map qualified as Map
|
||||||
|
import Data.Semialign (alignWith)
|
||||||
import Data.Set qualified as Set
|
import Data.Set qualified as Set
|
||||||
import Data.Text qualified as Text
|
import Data.Text qualified as Text
|
||||||
|
import Data.These (These (..))
|
||||||
import Text.FuzzyFind qualified as FZF
|
import Text.FuzzyFind qualified as FZF
|
||||||
import Unison.ConstructorReference (GConstructorReference (..))
|
import Unison.ConstructorReference (GConstructorReference (..))
|
||||||
import Unison.ConstructorType qualified as CT
|
import Unison.ConstructorType qualified as CT
|
||||||
@ -64,6 +67,7 @@ import Unison.LabeledDependency (LabeledDependency)
|
|||||||
import Unison.LabeledDependency qualified as LD
|
import Unison.LabeledDependency qualified as LD
|
||||||
import Unison.Name (Name)
|
import Unison.Name (Name)
|
||||||
import Unison.Name qualified as Name
|
import Unison.Name qualified as Name
|
||||||
|
import Unison.NameSegment (NameSegment)
|
||||||
import Unison.Prelude
|
import Unison.Prelude
|
||||||
import Unison.Reference (Reference, TermReference, TypeReference)
|
import Unison.Reference (Reference, TermReference, TypeReference)
|
||||||
import Unison.Reference qualified as Reference
|
import Unison.Reference qualified as Reference
|
||||||
@ -71,6 +75,10 @@ import Unison.Referent (Referent)
|
|||||||
import Unison.Referent qualified as Referent
|
import Unison.Referent qualified as Referent
|
||||||
import Unison.ShortHash (ShortHash)
|
import Unison.ShortHash (ShortHash)
|
||||||
import Unison.ShortHash qualified as SH
|
import Unison.ShortHash qualified as SH
|
||||||
|
import Unison.Util.BiMultimap (BiMultimap)
|
||||||
|
import Unison.Util.BiMultimap qualified as BiMultimap
|
||||||
|
import Unison.Util.Defns (Defns (..), DefnsF)
|
||||||
|
import Unison.Util.Nametree (Nametree, unflattenNametree)
|
||||||
import Unison.Util.Relation (Relation)
|
import Unison.Util.Relation (Relation)
|
||||||
import Unison.Util.Relation qualified as R
|
import Unison.Util.Relation qualified as R
|
||||||
import Unison.Util.Relation qualified as Relation
|
import Unison.Util.Relation qualified as Relation
|
||||||
@ -95,7 +103,7 @@ instance Monoid (Names) where
|
|||||||
mempty = Names mempty mempty
|
mempty = Names mempty mempty
|
||||||
|
|
||||||
isEmpty :: Names -> Bool
|
isEmpty :: Names -> Bool
|
||||||
isEmpty n = R.null (terms n) && R.null (types n)
|
isEmpty n = R.null n.terms && R.null n.types
|
||||||
|
|
||||||
map :: (Name -> Name) -> Names -> Names
|
map :: (Name -> Name) -> Names -> Names
|
||||||
map f (Names {terms, types}) = Names terms' types'
|
map f (Names {terms, types}) = Names terms' types'
|
||||||
@ -122,8 +130,8 @@ fuzzyFind nameToText query names =
|
|||||||
. Prelude.filter prefilter
|
. Prelude.filter prefilter
|
||||||
. Map.toList
|
. Map.toList
|
||||||
-- `mapMonotonic` is safe here and saves a log n factor
|
-- `mapMonotonic` is safe here and saves a log n factor
|
||||||
$ (Set.mapMonotonic Left <$> R.toMultimap (terms names))
|
$ (Set.mapMonotonic Left <$> R.toMultimap names.terms)
|
||||||
<> (Set.mapMonotonic Right <$> R.toMultimap (types names))
|
<> (Set.mapMonotonic Right <$> R.toMultimap names.types)
|
||||||
where
|
where
|
||||||
lowerqueryt = Text.toLower . Text.pack <$> query
|
lowerqueryt = Text.toLower . Text.pack <$> query
|
||||||
-- For performance, case-insensitive substring matching as a pre-filter
|
-- For performance, case-insensitive substring matching as a pre-filter
|
||||||
@ -250,8 +258,8 @@ unionLeft' ::
|
|||||||
Names
|
Names
|
||||||
unionLeft' shouldOmit a b = Names terms' types'
|
unionLeft' shouldOmit a b = Names terms' types'
|
||||||
where
|
where
|
||||||
terms' = foldl' go (terms a) (R.toList $ terms b)
|
terms' = foldl' go a.terms (R.toList b.terms)
|
||||||
types' = foldl' go (types a) (R.toList $ types b)
|
types' = foldl' go a.types (R.toList b.types)
|
||||||
go :: (Ord a, Ord b) => Relation a b -> (a, b) -> Relation a b
|
go :: (Ord a, Ord b) => Relation a b -> (a, b) -> Relation a b
|
||||||
go acc (n, r) = if shouldOmit n r acc then acc else R.insert n r acc
|
go acc (n, r) = if shouldOmit n r acc then acc else R.insert n r acc
|
||||||
|
|
||||||
@ -260,7 +268,7 @@ numHashChars :: Int
|
|||||||
numHashChars = 3
|
numHashChars = 3
|
||||||
|
|
||||||
termsNamed :: Names -> Name -> Set Referent
|
termsNamed :: Names -> Name -> Set Referent
|
||||||
termsNamed = flip R.lookupDom . terms
|
termsNamed = flip R.lookupDom . (.terms)
|
||||||
|
|
||||||
-- | Get all terms with a specific name.
|
-- | Get all terms with a specific name.
|
||||||
refTermsNamed :: Names -> Name -> Set TermReference
|
refTermsNamed :: Names -> Name -> Set TermReference
|
||||||
@ -281,13 +289,13 @@ refTermsHQNamed names = \case
|
|||||||
in Set.mapMaybe f (termsNamed names name)
|
in Set.mapMaybe f (termsNamed names name)
|
||||||
|
|
||||||
typesNamed :: Names -> Name -> Set TypeReference
|
typesNamed :: Names -> Name -> Set TypeReference
|
||||||
typesNamed = flip R.lookupDom . types
|
typesNamed = flip R.lookupDom . (.types)
|
||||||
|
|
||||||
namesForReferent :: Names -> Referent -> Set Name
|
namesForReferent :: Names -> Referent -> Set Name
|
||||||
namesForReferent names r = R.lookupRan r (terms names)
|
namesForReferent names r = R.lookupRan r names.terms
|
||||||
|
|
||||||
namesForReference :: Names -> TypeReference -> Set Name
|
namesForReference :: Names -> TypeReference -> Set Name
|
||||||
namesForReference names r = R.lookupRan r (types names)
|
namesForReference names r = R.lookupRan r names.types
|
||||||
|
|
||||||
termAliases :: Names -> Name -> Referent -> Set Name
|
termAliases :: Names -> Name -> Referent -> Set Name
|
||||||
termAliases names n r = Set.delete n $ namesForReferent names r
|
termAliases names n r = Set.delete n $ namesForReferent names r
|
||||||
@ -422,20 +430,20 @@ filterTypes f (Names terms types) = Names terms (R.filterDom f types)
|
|||||||
difference :: Names -> Names -> Names
|
difference :: Names -> Names -> Names
|
||||||
difference a b =
|
difference a b =
|
||||||
Names
|
Names
|
||||||
(R.difference (terms a) (terms b))
|
(R.difference a.terms b.terms)
|
||||||
(R.difference (types a) (types b))
|
(R.difference a.types b.types)
|
||||||
|
|
||||||
contains :: Names -> Reference -> Bool
|
contains :: Names -> Reference -> Bool
|
||||||
contains names =
|
contains names =
|
||||||
-- We want to compute `termsReferences` only once, if `contains` is partially applied to a `Names`, and called over
|
-- We want to compute `termsReferences` only once, if `contains` is partially applied to a `Names`, and called over
|
||||||
-- and over for different references. GHC would probably float `termsReferences` out without the explicit lambda, but
|
-- and over for different references. GHC would probably float `termsReferences` out without the explicit lambda, but
|
||||||
-- it's written like this just to be sure.
|
-- it's written like this just to be sure.
|
||||||
\r -> Set.member r termsReferences || R.memberRan r (types names)
|
\r -> Set.member r termsReferences || R.memberRan r names.types
|
||||||
where
|
where
|
||||||
-- this check makes `contains` O(n) instead of O(log n)
|
-- this check makes `contains` O(n) instead of O(log n)
|
||||||
termsReferences :: Set TermReference
|
termsReferences :: Set TermReference
|
||||||
termsReferences =
|
termsReferences =
|
||||||
Set.map Referent.toReference (R.ran (terms names))
|
Set.map Referent.toReference (R.ran names.terms)
|
||||||
|
|
||||||
-- | filters out everything from the domain except what's conflicted
|
-- | filters out everything from the domain except what's conflicted
|
||||||
conflicts :: Names -> Names
|
conflicts :: Names -> Names
|
||||||
@ -448,9 +456,9 @@ conflicts Names {..} = Names (R.filterManyDom terms) (R.filterManyDom types)
|
|||||||
-- See usage in `FileParser` for handling precendence of symbol
|
-- See usage in `FileParser` for handling precendence of symbol
|
||||||
-- resolution where local names are preferred to codebase names.
|
-- resolution where local names are preferred to codebase names.
|
||||||
shadowTerms :: [Name] -> Names -> Names
|
shadowTerms :: [Name] -> Names -> Names
|
||||||
shadowTerms ns n0 = Names terms' (types n0)
|
shadowTerms ns n0 = Names terms' n0.types
|
||||||
where
|
where
|
||||||
terms' = foldl' go (terms n0) ns
|
terms' = foldl' go n0.terms ns
|
||||||
go ts name = R.deleteDom name ts
|
go ts name = R.deleteDom name ts
|
||||||
|
|
||||||
-- | Given a mapping from name to qualified name, update a `Names`,
|
-- | Given a mapping from name to qualified name, update a `Names`,
|
||||||
@ -461,8 +469,8 @@ shadowTerms ns n0 = Names terms' (types n0)
|
|||||||
importing :: [(Name, Name)] -> Names -> Names
|
importing :: [(Name, Name)] -> Names -> Names
|
||||||
importing shortToLongName ns =
|
importing shortToLongName ns =
|
||||||
Names
|
Names
|
||||||
(foldl' go (terms ns) shortToLongName)
|
(foldl' go ns.terms shortToLongName)
|
||||||
(foldl' go (types ns) shortToLongName)
|
(foldl' go ns.types shortToLongName)
|
||||||
where
|
where
|
||||||
go :: (Ord r) => Relation Name r -> (Name, Name) -> Relation Name r
|
go :: (Ord r) => Relation Name r -> (Name, Name) -> Relation Name r
|
||||||
go m (shortname, qname) = case Name.searchByRankedSuffix qname m of
|
go m (shortname, qname) = case Name.searchByRankedSuffix qname m of
|
||||||
@ -476,8 +484,8 @@ importing shortToLongName ns =
|
|||||||
-- `[(foo, io.foo), (bar, io.bar)]`.
|
-- `[(foo, io.foo), (bar, io.bar)]`.
|
||||||
expandWildcardImport :: Name -> Names -> [(Name, Name)]
|
expandWildcardImport :: Name -> Names -> [(Name, Name)]
|
||||||
expandWildcardImport prefix ns =
|
expandWildcardImport prefix ns =
|
||||||
[(suffix, full) | Just (suffix, full) <- go <$> R.toList (terms ns)]
|
[(suffix, full) | Just (suffix, full) <- go <$> R.toList ns.terms]
|
||||||
<> [(suffix, full) | Just (suffix, full) <- go <$> R.toList (types ns)]
|
<> [(suffix, full) | Just (suffix, full) <- go <$> R.toList ns.types]
|
||||||
where
|
where
|
||||||
go :: (Name, a) -> Maybe (Name, Name)
|
go :: (Name, a) -> Maybe (Name, Name)
|
||||||
go (full, _) = do
|
go (full, _) = do
|
||||||
@ -498,7 +506,7 @@ constructorsForType r ns =
|
|||||||
possibleDatas = [Referent.Con (ConstructorReference r cid) CT.Data | cid <- [0 ..]]
|
possibleDatas = [Referent.Con (ConstructorReference r cid) CT.Data | cid <- [0 ..]]
|
||||||
possibleEffects = [Referent.Con (ConstructorReference r cid) CT.Effect | cid <- [0 ..]]
|
possibleEffects = [Referent.Con (ConstructorReference r cid) CT.Effect | cid <- [0 ..]]
|
||||||
trim [] = []
|
trim [] = []
|
||||||
trim (h : t) = case R.lookupRan h (terms ns) of
|
trim (h : t) = case R.lookupRan h ns.terms of
|
||||||
s
|
s
|
||||||
| Set.null s -> []
|
| Set.null s -> []
|
||||||
| otherwise -> [(n, h) | n <- toList s] ++ trim t
|
| otherwise -> [(n, h) | n <- toList s] ++ trim t
|
||||||
@ -517,3 +525,29 @@ hashQualifyRelation fromNamedRef rel = R.map go rel
|
|||||||
if Set.size (R.lookupDom n rel) > 1
|
if Set.size (R.lookupDom n rel) > 1
|
||||||
then (HQ.take numHashChars $ fromNamedRef n r, r)
|
then (HQ.take numHashChars $ fromNamedRef n r, r)
|
||||||
else (HQ.NameOnly n, r)
|
else (HQ.NameOnly n, r)
|
||||||
|
|
||||||
|
-- | "Leniently" view a Names as a NameTree
|
||||||
|
--
|
||||||
|
-- This function is "lenient" in the sense that it does not handle conflicted names with any smarts whatsoever. The
|
||||||
|
-- resulting nametree will simply contain one of the associated references of a conflicted name - we don't specify
|
||||||
|
-- which.
|
||||||
|
lenientToNametree :: Names -> Nametree (DefnsF (Map NameSegment) Referent TypeReference)
|
||||||
|
lenientToNametree names =
|
||||||
|
alignWith
|
||||||
|
( \case
|
||||||
|
This terms -> Defns {terms, types = Map.empty}
|
||||||
|
That types -> Defns {terms = Map.empty, types}
|
||||||
|
These terms types -> Defns {terms, types}
|
||||||
|
)
|
||||||
|
(lenientRelationToNametree names.terms)
|
||||||
|
(lenientRelationToNametree names.types)
|
||||||
|
where
|
||||||
|
lenientRelationToNametree :: Ord a => Relation Name a -> Nametree (Map NameSegment a)
|
||||||
|
lenientRelationToNametree =
|
||||||
|
unflattenNametree . lenientRelationToLeftUniqueRelation
|
||||||
|
|
||||||
|
lenientRelationToLeftUniqueRelation :: (Ord a, Ord b) => Relation a b -> BiMultimap b a
|
||||||
|
lenientRelationToLeftUniqueRelation =
|
||||||
|
-- The partial `Set.findMin` are fine here because Relation.domain only has non-empty Set values. A NESet would be
|
||||||
|
-- better.
|
||||||
|
BiMultimap.fromRange . Map.map Set.findMin . Relation.domain
|
||||||
|
@ -72,6 +72,7 @@ library
|
|||||||
DerivingStrategies
|
DerivingStrategies
|
||||||
DerivingVia
|
DerivingVia
|
||||||
DoAndIfThenElse
|
DoAndIfThenElse
|
||||||
|
DuplicateRecordFields
|
||||||
FlexibleContexts
|
FlexibleContexts
|
||||||
FlexibleInstances
|
FlexibleInstances
|
||||||
GADTs
|
GADTs
|
||||||
@ -140,6 +141,7 @@ test-suite tests
|
|||||||
DerivingStrategies
|
DerivingStrategies
|
||||||
DerivingVia
|
DerivingVia
|
||||||
DoAndIfThenElse
|
DoAndIfThenElse
|
||||||
|
DuplicateRecordFields
|
||||||
FlexibleContexts
|
FlexibleContexts
|
||||||
FlexibleInstances
|
FlexibleInstances
|
||||||
GADTs
|
GADTs
|
||||||
|
@ -83,15 +83,17 @@ module Unison.Merge.DeclCoherencyCheck
|
|||||||
( IncoherentDeclReason (..),
|
( IncoherentDeclReason (..),
|
||||||
checkDeclCoherency,
|
checkDeclCoherency,
|
||||||
lenientCheckDeclCoherency,
|
lenientCheckDeclCoherency,
|
||||||
|
|
||||||
|
-- * Getting all failures rather than just the first
|
||||||
|
IncoherentDeclReasons (..),
|
||||||
|
checkAllDeclCoherency,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Lens ((%=), (.=), _2)
|
import Control.Lens ((%=), (.=), _2)
|
||||||
import Control.Monad.Except (ExceptT)
|
|
||||||
import Control.Monad.Except qualified as Except
|
import Control.Monad.Except qualified as Except
|
||||||
import Control.Monad.State.Strict (StateT)
|
import Control.Monad.State.Strict (StateT)
|
||||||
import Control.Monad.State.Strict qualified as State
|
import Control.Monad.State.Strict qualified as State
|
||||||
import Control.Monad.Trans.Except qualified as Except (except)
|
|
||||||
import Data.Functor.Compose (Compose (..))
|
import Data.Functor.Compose (Compose (..))
|
||||||
import Data.IntMap.Strict (IntMap)
|
import Data.IntMap.Strict (IntMap)
|
||||||
import Data.IntMap.Strict qualified as IntMap
|
import Data.IntMap.Strict qualified as IntMap
|
||||||
@ -136,87 +138,190 @@ checkDeclCoherency ::
|
|||||||
(TypeReferenceId -> m Int) ->
|
(TypeReferenceId -> m Int) ->
|
||||||
Nametree (DefnsF (Map NameSegment) Referent TypeReference) ->
|
Nametree (DefnsF (Map NameSegment) Referent TypeReference) ->
|
||||||
m (Either IncoherentDeclReason DeclNameLookup)
|
m (Either IncoherentDeclReason DeclNameLookup)
|
||||||
checkDeclCoherency loadDeclNumConstructors =
|
checkDeclCoherency loadDeclNumConstructors nametree =
|
||||||
Except.runExceptT
|
Except.runExceptT
|
||||||
. fmap (view #declNameLookup)
|
( checkDeclCoherencyWith
|
||||||
|
(lift . loadDeclNumConstructors)
|
||||||
|
OnIncoherentDeclReasons
|
||||||
|
{ onConstructorAlias = \x y z -> Except.throwError (IncoherentDeclReason'ConstructorAlias x y z), -- :: Name -> Name -> Name -> m (),
|
||||||
|
onMissingConstructorName = \x -> Except.throwError (IncoherentDeclReason'MissingConstructorName x), -- :: Name -> m (),
|
||||||
|
onNestedDeclAlias = \x y -> Except.throwError (IncoherentDeclReason'NestedDeclAlias x y), -- :: Name -> Name -> m (),
|
||||||
|
onStrayConstructor = \x -> Except.throwError (IncoherentDeclReason'StrayConstructor x) -- :: Name -> m ()
|
||||||
|
}
|
||||||
|
nametree
|
||||||
|
)
|
||||||
|
|
||||||
|
data IncoherentDeclReasons = IncoherentDeclReasons
|
||||||
|
{ constructorAliases :: ![(Name, Name, Name)],
|
||||||
|
missingConstructorNames :: ![Name],
|
||||||
|
nestedDeclAliases :: ![(Name, Name)],
|
||||||
|
strayConstructors :: ![Name]
|
||||||
|
}
|
||||||
|
deriving stock (Eq, Generic)
|
||||||
|
|
||||||
|
-- | Like 'checkDeclCoherency', but returns info about all of the incoherent decls found, not just the first.
|
||||||
|
checkAllDeclCoherency ::
|
||||||
|
forall m.
|
||||||
|
Monad m =>
|
||||||
|
(TypeReferenceId -> m Int) ->
|
||||||
|
Nametree (DefnsF (Map NameSegment) Referent TypeReference) ->
|
||||||
|
m (Either IncoherentDeclReasons DeclNameLookup)
|
||||||
|
checkAllDeclCoherency loadDeclNumConstructors nametree = do
|
||||||
|
State.runStateT doCheck emptyReasons <&> \(declNameLookup, reasons) ->
|
||||||
|
if reasons == emptyReasons
|
||||||
|
then Right declNameLookup
|
||||||
|
else Left (reverseReasons reasons)
|
||||||
|
where
|
||||||
|
doCheck :: StateT IncoherentDeclReasons m DeclNameLookup
|
||||||
|
doCheck =
|
||||||
|
checkDeclCoherencyWith
|
||||||
|
(lift . loadDeclNumConstructors)
|
||||||
|
( OnIncoherentDeclReasons
|
||||||
|
{ onConstructorAlias = \x y z -> #constructorAliases %= ((x, y, z) :),
|
||||||
|
onMissingConstructorName = \x -> #missingConstructorNames %= (x :),
|
||||||
|
onNestedDeclAlias = \x y -> #nestedDeclAliases %= ((x, y) :),
|
||||||
|
onStrayConstructor = \x -> #strayConstructors %= (x :)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
nametree
|
||||||
|
|
||||||
|
emptyReasons :: IncoherentDeclReasons
|
||||||
|
emptyReasons =
|
||||||
|
IncoherentDeclReasons [] [] [] []
|
||||||
|
|
||||||
|
reverseReasons :: IncoherentDeclReasons -> IncoherentDeclReasons
|
||||||
|
reverseReasons reasons =
|
||||||
|
IncoherentDeclReasons
|
||||||
|
{ constructorAliases = reverse reasons.constructorAliases,
|
||||||
|
missingConstructorNames = reverse reasons.missingConstructorNames,
|
||||||
|
nestedDeclAliases = reverse reasons.nestedDeclAliases,
|
||||||
|
strayConstructors = reverse reasons.strayConstructors
|
||||||
|
}
|
||||||
|
|
||||||
|
data OnIncoherentDeclReasons m = OnIncoherentDeclReasons
|
||||||
|
{ onConstructorAlias :: Name -> Name -> Name -> m (),
|
||||||
|
onMissingConstructorName :: Name -> m (),
|
||||||
|
onNestedDeclAlias :: Name -> Name -> m (),
|
||||||
|
onStrayConstructor :: Name -> m ()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkDeclCoherencyWith ::
|
||||||
|
forall m.
|
||||||
|
Monad m =>
|
||||||
|
(TypeReferenceId -> m Int) ->
|
||||||
|
OnIncoherentDeclReasons m ->
|
||||||
|
Nametree (DefnsF (Map NameSegment) Referent TypeReference) ->
|
||||||
|
m DeclNameLookup
|
||||||
|
checkDeclCoherencyWith loadDeclNumConstructors callbacks =
|
||||||
|
fmap (view #declNameLookup)
|
||||||
. (`State.execStateT` DeclCoherencyCheckState Map.empty (DeclNameLookup Map.empty Map.empty))
|
. (`State.execStateT` DeclCoherencyCheckState Map.empty (DeclNameLookup Map.empty Map.empty))
|
||||||
. go []
|
. go []
|
||||||
where
|
where
|
||||||
go ::
|
go ::
|
||||||
[NameSegment] ->
|
[NameSegment] ->
|
||||||
(Nametree (DefnsF (Map NameSegment) Referent TypeReference)) ->
|
(Nametree (DefnsF (Map NameSegment) Referent TypeReference)) ->
|
||||||
StateT DeclCoherencyCheckState (ExceptT IncoherentDeclReason m) ()
|
StateT DeclCoherencyCheckState m ()
|
||||||
go prefix (Nametree defns children) = do
|
go prefix (Nametree defns children) = do
|
||||||
for_ (Map.toList defns.terms) \case
|
for_ (Map.toList defns.terms) (checkDeclCoherencyWith_DoTerms callbacks prefix)
|
||||||
(_, Referent.Ref _) -> pure ()
|
|
||||||
(_, Referent.Con (ConstructorReference (ReferenceBuiltin _) _) _) -> pure ()
|
|
||||||
(name, Referent.Con (ConstructorReference (ReferenceDerived typeRef) conId) _) -> do
|
|
||||||
DeclCoherencyCheckState {expectedConstructors} <- State.get
|
|
||||||
expectedConstructors1 <- lift (Except.except (Map.upsertF f typeRef expectedConstructors))
|
|
||||||
#expectedConstructors .= expectedConstructors1
|
|
||||||
where
|
|
||||||
f ::
|
|
||||||
Maybe (Name, ConstructorNames) ->
|
|
||||||
Either IncoherentDeclReason (Name, ConstructorNames)
|
|
||||||
f = \case
|
|
||||||
Nothing -> Left (IncoherentDeclReason'StrayConstructor name1)
|
|
||||||
Just (typeName, expected) ->
|
|
||||||
case recordConstructorName conId name1 expected of
|
|
||||||
Left existingName -> Left (IncoherentDeclReason'ConstructorAlias typeName existingName name1)
|
|
||||||
Right expected1 -> Right (typeName, expected1)
|
|
||||||
where
|
|
||||||
name1 = fullName name
|
|
||||||
|
|
||||||
childrenWeWentInto <-
|
childrenWeWentInto <-
|
||||||
forMaybe (Map.toList defns.types) \case
|
forMaybe
|
||||||
(_, ReferenceBuiltin _) -> pure Nothing
|
(Map.toList defns.types)
|
||||||
(name, ReferenceDerived typeRef) -> do
|
(checkDeclCoherencyWith_DoTypes loadDeclNumConstructors callbacks go prefix children)
|
||||||
DeclCoherencyCheckState {expectedConstructors} <- State.get
|
let childrenWeHaventGoneInto = children `Map.withoutKeys` Set.fromList childrenWeWentInto
|
||||||
whatHappened <- do
|
for_ (Map.toList childrenWeHaventGoneInto) \(name, child) -> go (name : prefix) child
|
||||||
let recordNewDecl ::
|
|
||||||
Maybe (Name, ConstructorNames) ->
|
checkDeclCoherencyWith_DoTerms ::
|
||||||
Compose (ExceptT IncoherentDeclReason m) WhatHappened (Name, ConstructorNames)
|
forall m.
|
||||||
recordNewDecl =
|
Monad m =>
|
||||||
Compose . \case
|
OnIncoherentDeclReasons m ->
|
||||||
Just (shorterTypeName, _) -> Except.throwError (IncoherentDeclReason'NestedDeclAlias shorterTypeName typeName)
|
[NameSegment] ->
|
||||||
Nothing ->
|
(NameSegment, Referent) ->
|
||||||
lift (loadDeclNumConstructors typeRef) <&> \case
|
StateT DeclCoherencyCheckState m ()
|
||||||
0 -> UninhabitedDecl
|
checkDeclCoherencyWith_DoTerms callbacks prefix = \case
|
||||||
n -> InhabitedDecl (typeName, emptyConstructorNames n)
|
(_, Referent.Ref _) -> pure ()
|
||||||
lift (getCompose (Map.upsertF recordNewDecl typeRef expectedConstructors))
|
(_, Referent.Con (ConstructorReference (ReferenceBuiltin _) _) _) -> pure ()
|
||||||
case whatHappened of
|
(name, Referent.Con (ConstructorReference (ReferenceDerived typeRef) conId) _) -> do
|
||||||
UninhabitedDecl -> do
|
state <- State.get
|
||||||
#declNameLookup . #declToConstructors %= Map.insert typeName []
|
whenJustM (lift (runMaybeT (Map.upsertF f typeRef state.expectedConstructors))) \expectedConstructors1 ->
|
||||||
pure Nothing
|
#expectedConstructors .= expectedConstructors1
|
||||||
InhabitedDecl expectedConstructors1 -> do
|
where
|
||||||
child <-
|
f :: Maybe (Name, ConstructorNames) -> MaybeT m (Name, ConstructorNames)
|
||||||
Map.lookup name children & onNothing do
|
f = \case
|
||||||
Except.throwError (IncoherentDeclReason'MissingConstructorName typeName)
|
Nothing -> do
|
||||||
#expectedConstructors .= expectedConstructors1
|
lift (callbacks.onStrayConstructor name1)
|
||||||
go (name : prefix) child
|
MaybeT (pure Nothing)
|
||||||
DeclCoherencyCheckState {expectedConstructors} <- State.get
|
Just (typeName, expected) ->
|
||||||
-- fromJust is safe here because we upserted `typeRef` key above
|
case recordConstructorName conId name1 expected of
|
||||||
let (fromJust -> (_typeName, maybeConstructorNames), expectedConstructors1) =
|
Left existingName -> do
|
||||||
Map.deleteLookup typeRef expectedConstructors
|
lift (callbacks.onConstructorAlias typeName existingName name1)
|
||||||
constructorNames <-
|
MaybeT (pure Nothing)
|
||||||
sequence (IntMap.elems maybeConstructorNames) & onNothing do
|
Right expected1 -> pure (typeName, expected1)
|
||||||
Except.throwError (IncoherentDeclReason'MissingConstructorName typeName)
|
where
|
||||||
#expectedConstructors .= expectedConstructors1
|
name1 =
|
||||||
|
Name.fromReverseSegments (name :| prefix)
|
||||||
|
|
||||||
|
checkDeclCoherencyWith_DoTypes ::
|
||||||
|
forall m.
|
||||||
|
Monad m =>
|
||||||
|
(TypeReferenceId -> m Int) ->
|
||||||
|
OnIncoherentDeclReasons m ->
|
||||||
|
( [NameSegment] ->
|
||||||
|
(Nametree (DefnsF (Map NameSegment) Referent TypeReference)) ->
|
||||||
|
StateT DeclCoherencyCheckState m ()
|
||||||
|
) ->
|
||||||
|
[NameSegment] ->
|
||||||
|
Map NameSegment (Nametree (DefnsF (Map NameSegment) Referent TypeReference)) ->
|
||||||
|
(NameSegment, TypeReference) ->
|
||||||
|
StateT DeclCoherencyCheckState m (Maybe NameSegment)
|
||||||
|
checkDeclCoherencyWith_DoTypes loadDeclNumConstructors callbacks go prefix children = \case
|
||||||
|
(_, ReferenceBuiltin _) -> pure Nothing
|
||||||
|
(name, ReferenceDerived typeRef) -> do
|
||||||
|
state <- State.get
|
||||||
|
maybeWhatHappened <- do
|
||||||
|
let recordNewDecl ::
|
||||||
|
Maybe (Name, ConstructorNames) ->
|
||||||
|
Compose (MaybeT m) WhatHappened (Name, ConstructorNames)
|
||||||
|
recordNewDecl =
|
||||||
|
Compose . \case
|
||||||
|
Just (shorterTypeName, _) -> do
|
||||||
|
lift (callbacks.onNestedDeclAlias shorterTypeName typeName)
|
||||||
|
MaybeT (pure Nothing)
|
||||||
|
Nothing ->
|
||||||
|
lift (loadDeclNumConstructors typeRef) <&> \case
|
||||||
|
0 -> UninhabitedDecl
|
||||||
|
n -> InhabitedDecl (typeName, emptyConstructorNames n)
|
||||||
|
lift (runMaybeT (getCompose (Map.upsertF recordNewDecl typeRef state.expectedConstructors)))
|
||||||
|
case maybeWhatHappened of
|
||||||
|
Nothing -> pure Nothing
|
||||||
|
Just UninhabitedDecl -> do
|
||||||
|
#declNameLookup . #declToConstructors %= Map.insert typeName []
|
||||||
|
pure Nothing
|
||||||
|
Just (InhabitedDecl expectedConstructors1) -> do
|
||||||
|
case Map.lookup name children of
|
||||||
|
Nothing -> do
|
||||||
|
lift (callbacks.onMissingConstructorName typeName)
|
||||||
|
pure Nothing
|
||||||
|
Just child -> do
|
||||||
|
#expectedConstructors .= expectedConstructors1
|
||||||
|
go (name : prefix) child
|
||||||
|
state <- State.get
|
||||||
|
-- fromJust is safe here because we upserted `typeRef` key above
|
||||||
|
let (fromJust -> (_typeName, maybeConstructorNames), expectedConstructors1) =
|
||||||
|
Map.deleteLookup typeRef state.expectedConstructors
|
||||||
|
#expectedConstructors .= expectedConstructors1
|
||||||
|
case sequence (IntMap.elems maybeConstructorNames) of
|
||||||
|
Nothing -> lift (callbacks.onMissingConstructorName typeName)
|
||||||
|
Just constructorNames -> do
|
||||||
#declNameLookup . #constructorToDecl %= \constructorToDecl ->
|
#declNameLookup . #constructorToDecl %= \constructorToDecl ->
|
||||||
List.foldl'
|
List.foldl'
|
||||||
(\acc constructorName -> Map.insert constructorName typeName acc)
|
(\acc constructorName -> Map.insert constructorName typeName acc)
|
||||||
constructorToDecl
|
constructorToDecl
|
||||||
constructorNames
|
constructorNames
|
||||||
#declNameLookup . #declToConstructors %= Map.insert typeName constructorNames
|
#declNameLookup . #declToConstructors %= Map.insert typeName constructorNames
|
||||||
pure (Just name)
|
pure (Just name)
|
||||||
where
|
where
|
||||||
typeName = fullName name
|
typeName =
|
||||||
|
Name.fromReverseSegments (name :| prefix)
|
||||||
let childrenWeHaventGoneInto = children `Map.withoutKeys` Set.fromList childrenWeWentInto
|
|
||||||
for_ (Map.toList childrenWeHaventGoneInto) \(name, child) -> go (name : prefix) child
|
|
||||||
where
|
|
||||||
fullName name =
|
|
||||||
Name.fromReverseSegments (name :| prefix)
|
|
||||||
|
|
||||||
-- | A lenient variant of 'checkDeclCoherency' - so lenient it can't even fail! It returns partial decl name lookup,
|
-- | A lenient variant of 'checkDeclCoherency' - so lenient it can't even fail! It returns partial decl name lookup,
|
||||||
-- which doesn't require a name for every constructor, and allows a constructor with a nameless decl.
|
-- which doesn't require a name for every constructor, and allows a constructor with a nameless decl.
|
||||||
|
@ -3,19 +3,15 @@
|
|||||||
When there's nothing to do, `todo` says this:
|
When there's nothing to do, `todo` says this:
|
||||||
|
|
||||||
```ucm
|
```ucm
|
||||||
project/main> todo
|
scratch/main> todo
|
||||||
```
|
```
|
||||||
|
|
||||||
# Conflicted names
|
|
||||||
|
|
||||||
The todo command shows conflicted names (not demonstrated here yet because it is not easy to create them for tests, yet).
|
|
||||||
|
|
||||||
# Dependents of `todo`
|
# Dependents of `todo`
|
||||||
|
|
||||||
The `todo` command shows local (outside `lib`) terms that directly call `todo`.
|
The `todo` command shows local (outside `lib`) terms that directly call `todo`.
|
||||||
|
|
||||||
```ucm:hide
|
```ucm:hide
|
||||||
project/main> builtins.mergeio lib.builtins
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
```
|
```
|
||||||
|
|
||||||
```unison
|
```unison
|
||||||
@ -27,12 +23,12 @@ bar = foo + foo
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ucm
|
```ucm
|
||||||
project/main> add
|
scratch/main> add
|
||||||
project/main> todo
|
scratch/main> todo
|
||||||
```
|
```
|
||||||
|
|
||||||
```ucm:hide
|
```ucm:hide
|
||||||
project/main> delete.project project
|
scratch/main> delete.project scratch
|
||||||
```
|
```
|
||||||
|
|
||||||
# Direct dependencies without names
|
# Direct dependencies without names
|
||||||
@ -41,7 +37,7 @@ The `todo` command shows hashes of direct dependencies of local (outside `lib`)
|
|||||||
the current namespace.
|
the current namespace.
|
||||||
|
|
||||||
```ucm:hide
|
```ucm:hide
|
||||||
project/main> builtins.mergeio lib.builtins
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
```
|
```
|
||||||
|
|
||||||
```unison
|
```unison
|
||||||
@ -50,11 +46,143 @@ baz = foo.bar + foo.bar
|
|||||||
```
|
```
|
||||||
|
|
||||||
```ucm
|
```ucm
|
||||||
project/main> add
|
scratch/main> add
|
||||||
project/main> delete.namespace.force foo
|
scratch/main> delete.namespace.force foo
|
||||||
project/main> todo
|
scratch/main> todo
|
||||||
```
|
```
|
||||||
|
|
||||||
```ucm:hide
|
```ucm:hide
|
||||||
project/main> delete.project project
|
scratch/main> delete.project scratch
|
||||||
|
```
|
||||||
|
|
||||||
|
# Conflicted names
|
||||||
|
|
||||||
|
The `todo` command shows conflicted names.
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
|
```
|
||||||
|
|
||||||
|
```unison
|
||||||
|
foo = 16
|
||||||
|
bar = 17
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm
|
||||||
|
scratch/main> add
|
||||||
|
scratch/main> debug.alias.term.force foo bar
|
||||||
|
scratch/main> todo
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> delete.project scratch
|
||||||
|
```
|
||||||
|
|
||||||
|
# Definitions in lib
|
||||||
|
|
||||||
|
The `todo` command complains about terms and types directly in `lib`.
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
|
```
|
||||||
|
|
||||||
|
```unison
|
||||||
|
lib.foo = 16
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm
|
||||||
|
scratch/main> add
|
||||||
|
scratch/main> todo
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> delete.project scratch
|
||||||
|
```
|
||||||
|
|
||||||
|
# Constructor aliases
|
||||||
|
|
||||||
|
The `todo` command complains about constructor aliases.
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
|
```
|
||||||
|
|
||||||
|
```unison
|
||||||
|
type Foo = One
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm
|
||||||
|
scratch/main> add
|
||||||
|
scratch/main> alias.term Foo.One Foo.Two
|
||||||
|
scratch/main> todo
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> delete.project scratch
|
||||||
|
```
|
||||||
|
|
||||||
|
# Missing constructor names
|
||||||
|
|
||||||
|
The `todo` command complains about missing constructor names.
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
|
```
|
||||||
|
|
||||||
|
```unison
|
||||||
|
type Foo = Bar
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm
|
||||||
|
scratch/main> add
|
||||||
|
scratch/main> delete.term Foo.Bar
|
||||||
|
scratch/main> todo
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> delete.project scratch
|
||||||
|
```
|
||||||
|
|
||||||
|
# Nested decl aliases
|
||||||
|
|
||||||
|
The `todo` command complains about nested decl aliases.
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
|
```
|
||||||
|
|
||||||
|
```unison
|
||||||
|
structural type Foo a = One a | Two a a
|
||||||
|
structural type Foo.inner.Bar a = Uno a | Dos a a
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm
|
||||||
|
scratch/main> add
|
||||||
|
scratch/main> todo
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> delete.project scratch
|
||||||
|
```
|
||||||
|
|
||||||
|
# Stray constructors
|
||||||
|
|
||||||
|
The `todo` command complains about stray constructors.
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> builtins.mergeio lib.builtins
|
||||||
|
```
|
||||||
|
|
||||||
|
```unison
|
||||||
|
type Foo = Bar
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm
|
||||||
|
scratch/main> add
|
||||||
|
scratch/main> alias.term Foo.Bar Baz
|
||||||
|
scratch/main> todo
|
||||||
|
```
|
||||||
|
|
||||||
|
```ucm:hide
|
||||||
|
scratch/main> delete.project scratch
|
||||||
```
|
```
|
||||||
|
@ -3,15 +3,11 @@
|
|||||||
When there's nothing to do, `todo` says this:
|
When there's nothing to do, `todo` says this:
|
||||||
|
|
||||||
``` ucm
|
``` ucm
|
||||||
project/main> todo
|
scratch/main> todo
|
||||||
|
|
||||||
You have no pending todo items. Good work! ✅
|
You have no pending todo items. Good work! ✅
|
||||||
|
|
||||||
```
|
```
|
||||||
# Conflicted names
|
|
||||||
|
|
||||||
The todo command shows conflicted names (not demonstrated here yet because it is not easy to create them for tests, yet).
|
|
||||||
|
|
||||||
# Dependents of `todo`
|
# Dependents of `todo`
|
||||||
|
|
||||||
The `todo` command shows local (outside `lib`) terms that directly call `todo`.
|
The `todo` command shows local (outside `lib`) terms that directly call `todo`.
|
||||||
@ -39,14 +35,14 @@ bar = foo + foo
|
|||||||
|
|
||||||
```
|
```
|
||||||
``` ucm
|
``` ucm
|
||||||
project/main> add
|
scratch/main> add
|
||||||
|
|
||||||
⍟ I've added these definitions:
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
bar : Nat
|
bar : Nat
|
||||||
foo : Nat
|
foo : Nat
|
||||||
|
|
||||||
project/main> todo
|
scratch/main> todo
|
||||||
|
|
||||||
These terms call `todo`:
|
These terms call `todo`:
|
||||||
|
|
||||||
@ -78,14 +74,14 @@ baz = foo.bar + foo.bar
|
|||||||
|
|
||||||
```
|
```
|
||||||
``` ucm
|
``` ucm
|
||||||
project/main> add
|
scratch/main> add
|
||||||
|
|
||||||
⍟ I've added these definitions:
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
baz : Nat
|
baz : Nat
|
||||||
foo.bar : Nat
|
foo.bar : Nat
|
||||||
|
|
||||||
project/main> delete.namespace.force foo
|
scratch/main> delete.namespace.force foo
|
||||||
|
|
||||||
Done.
|
Done.
|
||||||
|
|
||||||
@ -97,10 +93,261 @@ project/main> delete.namespace.force foo
|
|||||||
Dependency Referenced In
|
Dependency Referenced In
|
||||||
bar 1. baz
|
bar 1. baz
|
||||||
|
|
||||||
project/main> todo
|
scratch/main> todo
|
||||||
|
|
||||||
These terms do not have any names in the current namespace:
|
These terms do not have any names in the current namespace:
|
||||||
|
|
||||||
1. #1jujb8oelv
|
1. #1jujb8oelv
|
||||||
|
|
||||||
```
|
```
|
||||||
|
# Conflicted names
|
||||||
|
|
||||||
|
The `todo` command shows conflicted names.
|
||||||
|
|
||||||
|
``` unison
|
||||||
|
foo = 16
|
||||||
|
bar = 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 new definitions are ok to `add`:
|
||||||
|
|
||||||
|
bar : Nat
|
||||||
|
foo : Nat
|
||||||
|
|
||||||
|
```
|
||||||
|
``` ucm
|
||||||
|
scratch/main> add
|
||||||
|
|
||||||
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
|
bar : Nat
|
||||||
|
foo : Nat
|
||||||
|
|
||||||
|
scratch/main> debug.alias.term.force foo bar
|
||||||
|
|
||||||
|
Done.
|
||||||
|
|
||||||
|
scratch/main> todo
|
||||||
|
|
||||||
|
❓
|
||||||
|
|
||||||
|
The term bar has conflicting definitions:
|
||||||
|
|
||||||
|
1. bar#14ibahkll6
|
||||||
|
2. bar#cq22mm4sca
|
||||||
|
|
||||||
|
Tip: Use `move.term` or `delete.term` to resolve the
|
||||||
|
conflicts.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Definitions in lib
|
||||||
|
|
||||||
|
The `todo` command complains about terms and types directly in `lib`.
|
||||||
|
|
||||||
|
``` unison
|
||||||
|
lib.foo = 16
|
||||||
|
```
|
||||||
|
|
||||||
|
``` 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`:
|
||||||
|
|
||||||
|
lib.foo : Nat
|
||||||
|
|
||||||
|
```
|
||||||
|
``` ucm
|
||||||
|
scratch/main> add
|
||||||
|
|
||||||
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
|
lib.foo : Nat
|
||||||
|
|
||||||
|
scratch/main> todo
|
||||||
|
|
||||||
|
There's a type or term at the top level of the `lib`
|
||||||
|
namespace, where I only expect to find subnamespaces
|
||||||
|
representing library dependencies. Please move or remove it.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Constructor aliases
|
||||||
|
|
||||||
|
The `todo` command complains about constructor aliases.
|
||||||
|
|
||||||
|
``` unison
|
||||||
|
type Foo = One
|
||||||
|
```
|
||||||
|
|
||||||
|
``` 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`:
|
||||||
|
|
||||||
|
type Foo
|
||||||
|
|
||||||
|
```
|
||||||
|
``` ucm
|
||||||
|
scratch/main> add
|
||||||
|
|
||||||
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
|
type Foo
|
||||||
|
|
||||||
|
scratch/main> alias.term Foo.One Foo.Two
|
||||||
|
|
||||||
|
Done.
|
||||||
|
|
||||||
|
scratch/main> todo
|
||||||
|
|
||||||
|
The type Foo has a constructor with multiple names.
|
||||||
|
|
||||||
|
1. Foo.One
|
||||||
|
2. Foo.Two
|
||||||
|
|
||||||
|
Please delete all but one name for each constructor.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Missing constructor names
|
||||||
|
|
||||||
|
The `todo` command complains about missing constructor names.
|
||||||
|
|
||||||
|
``` unison
|
||||||
|
type Foo = Bar
|
||||||
|
```
|
||||||
|
|
||||||
|
``` 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`:
|
||||||
|
|
||||||
|
type Foo
|
||||||
|
|
||||||
|
```
|
||||||
|
``` ucm
|
||||||
|
scratch/main> add
|
||||||
|
|
||||||
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
|
type Foo
|
||||||
|
|
||||||
|
scratch/main> delete.term Foo.Bar
|
||||||
|
|
||||||
|
Done.
|
||||||
|
|
||||||
|
scratch/main> todo
|
||||||
|
|
||||||
|
These types have some constructors with missing names.
|
||||||
|
|
||||||
|
1. Foo
|
||||||
|
|
||||||
|
You can use `view 1` and
|
||||||
|
`alias.term <hash> <TypeName>.<ConstructorName>` to give names
|
||||||
|
to each unnamed constructor.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Nested decl aliases
|
||||||
|
|
||||||
|
The `todo` command complains about nested decl aliases.
|
||||||
|
|
||||||
|
``` unison
|
||||||
|
structural type Foo a = One a | Two a a
|
||||||
|
structural type Foo.inner.Bar a = Uno a | Dos a a
|
||||||
|
```
|
||||||
|
|
||||||
|
``` 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`:
|
||||||
|
|
||||||
|
structural type Foo a
|
||||||
|
structural type Foo.inner.Bar a
|
||||||
|
|
||||||
|
```
|
||||||
|
``` ucm
|
||||||
|
scratch/main> add
|
||||||
|
|
||||||
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
|
structural type Foo a
|
||||||
|
structural type Foo.inner.Bar a
|
||||||
|
|
||||||
|
scratch/main> todo
|
||||||
|
|
||||||
|
These types are aliases, but one is nested under the other.
|
||||||
|
Please separate them or delete one copy.
|
||||||
|
|
||||||
|
1. Foo
|
||||||
|
2. Foo.inner.Bar
|
||||||
|
|
||||||
|
```
|
||||||
|
# Stray constructors
|
||||||
|
|
||||||
|
The `todo` command complains about stray constructors.
|
||||||
|
|
||||||
|
``` unison
|
||||||
|
type Foo = Bar
|
||||||
|
```
|
||||||
|
|
||||||
|
``` 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`:
|
||||||
|
|
||||||
|
type Foo
|
||||||
|
|
||||||
|
```
|
||||||
|
``` ucm
|
||||||
|
scratch/main> add
|
||||||
|
|
||||||
|
⍟ I've added these definitions:
|
||||||
|
|
||||||
|
type Foo
|
||||||
|
|
||||||
|
scratch/main> alias.term Foo.Bar Baz
|
||||||
|
|
||||||
|
Done.
|
||||||
|
|
||||||
|
scratch/main> todo
|
||||||
|
|
||||||
|
These constructors are not nested beneath their corresponding
|
||||||
|
type names:
|
||||||
|
|
||||||
|
1. Baz
|
||||||
|
|
||||||
|
For each one, please either use `move` to move if, or if it's
|
||||||
|
an extra copy, you can simply `delete` it.
|
||||||
|
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user