Merge branch 'master' into CompilerBug

This commit is contained in:
Arya Irani 2019-11-20 17:02:19 -05:00 committed by GitHub
commit f9a348dbce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 523 additions and 251 deletions

View File

@ -0,0 +1,9 @@
module Unison.Codebase.BranchLoadMode where
-- When loading a nonexistent branch, what should happen?
-- Could bomb (`FailIfMissing`) or return the empty branch (`EmptyIfMissing`).
--
-- `EmptyIfMissing` mode is used when attempting to load a user-specified
-- branch. `FailIfMissing` is used when loading the root branch - if the root
-- does not exist, that's a serious problem.
data BranchLoadMode = FailIfMissing | EmptyIfMissing deriving (Eq, Show)

View File

@ -38,6 +38,7 @@ import Unison.ShortHash ( ShortHash )
import Unison.Type ( Type )
import Unison.Codebase.ShortBranchHash
( ShortBranchHash )
import Unison.Codebase.BranchLoadMode (BranchLoadMode)
type AmbientAbilities v = [Type v Ann]
@ -127,7 +128,7 @@ data Command m i v a where
LoadLocalBranch :: Branch.Hash -> Command m i v (Branch m)
LoadRemoteRootBranch ::
RemoteRepo -> Command m i v (Either GitError (Branch m))
BranchLoadMode -> RemoteRepo -> Command m i v (Either GitError (Branch m))
-- returns NoRemoteNamespaceWithHash or RemoteNamespaceHashAmbiguous
-- if no exact match.

View File

@ -74,27 +74,30 @@ shallowPullFromGit localPath url gitBranch = do
pullGitRootBranch
:: MonadIO m
=> FilePath
-> BranchLoadMode
-> Codebase m v a
-> Text
-> Maybe Text
-> ExceptT GitError m (Branch m)
pullGitRootBranch localPath codebase url treeish =
pullGitBranch localPath codebase url treeish Nothing
pullGitRootBranch localPath loadMode codebase url treeish =
pullGitBranch localPath codebase url treeish (Left loadMode)
-- pull repo & load arbitrary branch
-- if `loadInfo` is Left, we try to load the root branch;
-- if Right, we try to load the specified hash
pullGitBranch
:: MonadIO m
=> FilePath
-> Codebase m v a
-> Text
-> Maybe Text
-> Maybe ShortBranchHash
-> Either BranchLoadMode ShortBranchHash
-> ExceptT GitError m (Branch m)
pullGitBranch localPath codebase url treeish sbh = do
pullGitBranch localPath codebase url treeish loadInfo = do
pullFromGit localPath url treeish
branch <- case sbh of
Nothing -> lift $ FC.getRootBranch (localPath </> codebasePath)
Just sbh -> do
branch <- case loadInfo of
Left loadMode -> lift $ FC.getRootBranch loadMode gitCodebasePath
Right sbh -> do
branchCompletions <- lift $ FC.branchHashesByPrefix gitCodebasePath sbh
case toList branchCompletions of
[] -> throwError $ NoRemoteNamespaceWithHash url treeish sbh
@ -122,15 +125,8 @@ clone :: MonadError GitError m => MonadIO m => Text -> FilePath -> m ()
clone uri localPath = "git" ["clone", uri, Text.pack localPath]
`onError` throwError (NoRemoteRepoAt uri)
shallowClone :: MonadError GitError m => MonadIO m => Text -> FilePath -> m ()
shallowClone uri localPath =
"git" ["clone", "--depth=1", uri, Text.pack localPath]
`onError` throwError (NoRemoteRepoAt uri)
pull :: MonadError GitError m => MonadIO m => FilePath -> Text -> Maybe Text -> m ()
pull localPath uri treeish = do
gitIn localPath (["fetch", uri] ++ toList treeish)
`onError` throwError (NoRemoteRepoAt uri)
pull localPath _uri treeish = do
for_ treeish $ \treeish ->
liftIO $ gitIn localPath ["checkout", treeish]

View File

@ -122,9 +122,9 @@ commandLine config awaitInput setBranchRef rt notifyUser codebase =
SyncLocalRootBranch branch -> do
setBranchRef branch
Codebase.putRootBranch codebase branch
LoadRemoteRootBranch GitRepo {..} -> do
LoadRemoteRootBranch loadMode GitRepo {..} -> do
tmp <- tempGitDir url commit
runExceptT $ Git.pullGitRootBranch tmp codebase url commit
runExceptT $ Git.pullGitRootBranch tmp loadMode codebase url commit
SyncRemoteRootBranch GitRepo {..} branch -> do
tmp <- tempGitDir url commit
runExceptT
@ -152,7 +152,7 @@ commandLine config awaitInput setBranchRef rt notifyUser codebase =
BranchHashesByPrefix h -> Codebase.branchHashesByPrefix codebase h
LoadRemoteShortBranch GitRepo{..} sbh -> do
tmp <- tempGitDir url commit
runExceptT $ Git.pullGitBranch tmp codebase url commit (Just sbh)
runExceptT $ Git.pullGitBranch tmp codebase url commit (Right sbh)
ParseType names (src, _) -> pure $
Parsers.parseType (Text.unpack src) (Parser.ParsingEnv mempty names)

View File

@ -1,8 +1,6 @@
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
--{-# OPTIONS_GHC -Wno-unused-imports #-} -- todo: delete
{-# OPTIONS_GHC -Wno-unused-top-binds #-} -- todo: delete
{-# OPTIONS_GHC -Wno-unused-local-binds #-} -- todo: delete
--{-# OPTIONS_GHC -Wno-unused-matches #-} -- todo: delete
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE OverloadedStrings #-}
@ -54,6 +52,7 @@ import Unison.Codebase.Branch ( Branch(..)
, Branch0(..)
)
import qualified Unison.Codebase.Branch as Branch
import Unison.Codebase.BranchLoadMode ( BranchLoadMode(FailIfMissing, EmptyIfMissing) )
import qualified Unison.Codebase.BranchUtil as BranchUtil
import qualified Unison.Codebase.Causal as Causal
import qualified Unison.Codebase.Metadata as Metadata
@ -245,10 +244,10 @@ loop = do
let lexed = L.lexer (Text.unpack sourceName) (Text.unpack text)
withFile [] sourceName (text, lexed) $ \unisonFile -> do
sr <- toSlurpResult unisonFile <$> slurpResultNames0
hnames <- makeShadowedPrintNamesFromLabeled
names <- makeShadowedPrintNamesFromLabeled
(UF.termSignatureExternalLabeledDependencies unisonFile)
(UF.typecheckedToNames0 unisonFile)
ppe <- prettyPrintEnv hnames
ppe <- PPE.suffixifiedPPE <$> prettyPrintEnvDecl names
eval (Notify $ Typechecked sourceName ppe sr unisonFile)
r <- eval . Evaluate ppe $ unisonFile
case r of
@ -586,7 +585,7 @@ loop = do
NamesI thing -> do
len <- eval CodebaseHashLength
parseNames0 <- basicParseNames0
parseNames0 <- Names3.suffixify0 <$> basicParseNames0
let filtered = case thing of
HQ.HashOnly shortHash ->
Names.filterBySHs (Set.singleton shortHash) parseNames0
@ -829,7 +828,7 @@ loop = do
-- We might like to make sure that the user search terms get used as
-- the names in the pretty-printer, but the current implementation
-- doesn't.
ppe <- prettyPrintEnv printNames
ppe <- prettyPrintEnvDecl printNames
let loc = case outputLoc of
ConsoleLocation -> Nothing
FileLocation path -> Just path
@ -855,7 +854,7 @@ loop = do
FindShallowI pathArg -> do
prettyPrintNames0 <- basicPrettyPrintNames0
ppe <- prettyPrintEnv $ Names prettyPrintNames0 mempty
ppe <- fmap PPE.suffixifiedPPE . prettyPrintEnvDecl $ Names prettyPrintNames0 mempty
hashLen <- eval CodebaseHashLength
let pathArgAbs = Path.toAbsolutePath currentPath' pathArg
b0 <- Branch.head <$> getAt pathArgAbs
@ -944,7 +943,7 @@ loop = do
Right results -> do
numberedArgs .= fmap searchResultToHQString results
results' <- loadSearchResults results
ppe <- prettyPrintEnv =<<
ppe <- prettyPrintEnv . Names3.suffixify =<<
makePrintNamesFromLabeled'
(foldMap SR'.labeledDependencies results')
respond $ ListOfDefinitions ppe isVerbose results'
@ -1057,11 +1056,11 @@ loop = do
stepAt ( Path.unabsolute currentPath'
, doSlurpAdds (Slurp.adds sr) uf)
eval . AddDefsToCodebase . filterBySlurpResult sr $ uf
ppe <- prettyPrintEnv =<<
ppe <- prettyPrintEnvDecl =<<
makeShadowedPrintNamesFromLabeled
(UF.termSignatureExternalLabeledDependencies uf)
(UF.typecheckedToNames0 uf)
respond $ SlurpOutput input ppe sr
respond $ SlurpOutput input (PPE.suffixifiedPPE ppe) sr
UpdateI maybePatchPath hqs -> case uf of
Nothing -> respond $ NoUnisonFile input
@ -1161,7 +1160,7 @@ loop = do
TodoI patchPath branchPath' -> do
patch <- getPatchAt (fromMaybe defaultPatchPath patchPath)
names <- makePrintNamesFromLabeled' $ Patch.labeledDependencies patch
ppe <- prettyPrintEnv names
ppe <- prettyPrintEnvDecl names
branch <- getAt $ Path.toAbsolutePath currentPath' branchPath'
let names0 = Branch.toNames0 (Branch.head branch)
-- showTodoOutput only needs the local references
@ -1278,7 +1277,7 @@ loop = do
Left e -> eval . Notify $ e
Right (repo, Nothing, remotePath) -> do
-- push from srcb to repo's remotePath
eval (LoadRemoteRootBranch repo) >>= \case
eval (LoadRemoteRootBranch EmptyIfMissing repo) >>= \case
Left e -> eval . Notify $ GitError input e
Right remoteRoot -> do
newRemoteRoot <- eval . Eval $
@ -1360,14 +1359,15 @@ loop = do
doDisplay :: Var v => OutputLocation -> Names -> Referent -> Action' m v ()
doDisplay outputLoc names r = do
let tm = Term.fromReferent External r
ppe <- prettyPrintEnv names
ppe <- prettyPrintEnvDecl names
latestFile' <- use latestFile
let
loc = case outputLoc of
ConsoleLocation -> Nothing
FileLocation path -> Just path
LatestFileLocation -> fmap fst latestFile' <|> Just "scratch.u"
evalTerm r = fmap ErrorUtil.hush . eval $ Evaluate1 ppe (Term.ref External r)
evalTerm r = fmap ErrorUtil.hush . eval $
Evaluate1 (PPE.suffixifiedPPE ppe) (Term.ref External r)
loadTerm (Reference.DerivedId r) = eval $ LoadTerm r
loadTerm _ = pure Nothing
loadDecl (Reference.DerivedId r) = eval $ LoadType r
@ -1416,10 +1416,11 @@ getLinks input src mdTypeStr = do
\r -> loadTypeOfTerm (Referent.Ref r)
let deps = Set.map LD.termRef results <>
Set.unions [ Set.map LD.typeRef . Type.dependencies $ t | Just t <- sigs ]
ppe <- prettyPrintEnv =<< makePrintNamesFromLabeled' deps
let sortedSigs = sortOn snd (toList results `zip` sigs)
let out = [(PPE.termName ppe (Referent.Ref r), r, t) | (r, t) <- sortedSigs ]
pure (Right (ppe, out))
ppe <- prettyPrintEnvDecl =<< makePrintNamesFromLabeled' deps
let ppeDecl = PPE.unsuffixifiedPPE ppe
let sortedSigs = sortOn snd (toList results `zip` sigs)
let out = [(PPE.termName ppeDecl (Referent.Ref r), r, t) | (r, t) <- sortedSigs ]
pure (Right (PPE.suffixifiedPPE ppe, out))
resolveShortBranchHash ::
Input -> ShortBranchHash -> Action' m v (Either (Output v) (Branch m))
@ -1444,11 +1445,11 @@ propagatePatch inputDescription patch scopePath = do
let names0 = Branch.toNames0 (Branch.head scope)
-- this will be different AFTER the update succeeds
names <- makePrintNamesFromLabeled' (Patch.labeledDependencies patch)
ppe <- prettyPrintEnv names
ppe <- prettyPrintEnvDecl names
showTodoOutput ppe patch names0
pure changed
showTodoOutput :: PPE.PrettyPrintEnv -> Patch -> Names0 -> Action' m v ()
showTodoOutput :: PPE.PrettyPrintEnvDecl -> Patch -> Names0 -> Action' m v ()
showTodoOutput ppe patch names0 = do
todo <- checkTodo patch names0
numberedArgs .=
@ -1648,7 +1649,8 @@ searchBranchExact len names queries = let
respond :: Output v -> Action m i v ()
respond output = eval $ Notify output
-- merges the specified remote branch into the specified local absolute path
-- Merges the specified remote branch into the specified local absolute path.
-- Implementation detail of PullRemoteBranchI
loadRemoteBranchAt
:: Var v
=> Monad m
@ -1658,7 +1660,7 @@ loadRemoteBranchAt
-> Path.Absolute
-> Action' m v ()
loadRemoteBranchAt input inputDescription (repo, sbh, remotePath) p = do
b <- eval $ maybe (LoadRemoteRootBranch repo)
b <- eval $ maybe (LoadRemoteRootBranch FailIfMissing repo)
(LoadRemoteShortBranch repo) sbh
case b of
Left e -> eval . Notify $ GitError input e
@ -2053,6 +2055,9 @@ lexedSource name src = do
prettyPrintEnv :: Names -> Action' m v PPE.PrettyPrintEnv
prettyPrintEnv ns = eval CodebaseHashLength <&> (`PPE.fromNames` ns)
prettyPrintEnvDecl :: Names -> Action' m v PPE.PrettyPrintEnvDecl
prettyPrintEnvDecl ns = eval CodebaseHashLength <&> (`PPE.fromNamesDecl` ns)
parseSearchType :: (Monad m, Var v)
=> Input -> String -> Action' m v (Either (Output v) (Type v Ann))
parseSearchType input typ = fmap Type.removeAllEffectVars <$> parseType input typ
@ -2061,7 +2066,10 @@ parseType :: (Monad m, Var v)
=> Input -> String -> Action' m v (Either (Output v) (Type v Ann))
parseType input src = do
-- `show Input` is the name of the "file" being lexed
(names, lexed) <- lexedSource (Text.pack $ show input) (Text.pack src)
(names0, lexed) <- lexedSource (Text.pack $ show input) (Text.pack src)
parseNames <- Names3.suffixify0 <$> basicParseNames0
let names = Names3.push (Names3.currentNames names0)
(Names3.Names parseNames (Names3.oldNames names0))
e <- eval $ ParseType names lexed
pure $ case e of
Left err -> Left $ TypeParseError input src err

View File

@ -125,10 +125,10 @@ data Output v
| DisplayRendered (Maybe FilePath) (P.Pretty P.ColorText)
-- "display" definitions, possibly to a FilePath on disk (e.g. editing)
| DisplayDefinitions (Maybe FilePath)
PPE.PrettyPrintEnv
PPE.PrettyPrintEnvDecl
(Map Reference (DisplayThing (Decl v Ann)))
(Map Reference (DisplayThing (Term v Ann)))
| TodoOutput PPE.PrettyPrintEnv (TO.TodoOutput v Ann)
| TodoOutput PPE.PrettyPrintEnvDecl (TO.TodoOutput v Ann)
| TestIncrementalOutputStart PPE.PrettyPrintEnv (Int,Int) Reference (Term v Ann)
| TestIncrementalOutputEnd PPE.PrettyPrintEnv (Int,Int) Reference (Term v Ann)
| TestResults TestReportStats
@ -147,7 +147,7 @@ data Output v
| NoConfiguredGitUrl PushPull Path'
| ConfiguredGitUrlParseError PushPull Path' Text String
| ConfiguredGitUrlIncludesShortBranchHash PushPull RemoteRepo ShortBranchHash Path
| DisplayLinks PPE.PrettyPrintEnv Metadata.Metadata
| DisplayLinks PPE.PrettyPrintEnvDecl Metadata.Metadata
(Map Reference (DisplayThing (Decl v Ann)))
(Map Reference (DisplayThing (Term v Ann)))
| LinkFailure Input

View File

@ -70,6 +70,7 @@ import Unison.Codebase.Causal ( Causal
import qualified Unison.Codebase.Causal as Causal
import Unison.Codebase.Branch ( Branch )
import qualified Unison.Codebase.Branch as Branch
import Unison.Codebase.BranchLoadMode ( BranchLoadMode(FailIfMissing, EmptyIfMissing) )
import qualified Unison.Codebase.Reflog as Reflog
import qualified Unison.Codebase.Serialization as S
import qualified Unison.Codebase.Serialization.V1
@ -274,16 +275,10 @@ touchReferentFile id fp = do
-- checks if `path` looks like a unison codebase
minimalCodebaseStructure :: CodebasePath -> [FilePath]
minimalCodebaseStructure root =
[ termsDir root
, typesDir root
, branchesDir root
, branchHeadDir root
, editsDir root
]
minimalCodebaseStructure root = [ branchHeadDir root ]
-- checks if a minimal codebase structure exists at `path`
exists :: CodebasePath -> IO Bool
exists :: MonadIO m => CodebasePath -> m Bool
exists root =
and <$> traverse doesDirectoryExist (minimalCodebaseStructure root)
@ -292,14 +287,6 @@ initialize :: CodebasePath -> IO ()
initialize path =
traverse_ (createDirectoryIfMissing True) (minimalCodebaseStructure path)
-- When loading a nonexistent branch, what should happen?
-- Could bomb (`FailIfMissing`) or return the empty branch (`EmptyIfMissing`).
--
-- `EmptyIfMissing` mode is used when attempting to load a user-specified
-- branch. `FailIfMissing` is used when loading the root branch - if the root
-- does not exist, that's a serious problem.
data BranchLoadMode = FailIfMissing | EmptyIfMissing deriving Eq
branchFromFiles :: MonadIO m => BranchLoadMode -> FilePath -> Branch.Hash -> m (Branch m)
branchFromFiles loadMode rootDir h@(RawHash h') = do
fileExists <- doesFileExist (branchPath rootDir h')
@ -324,20 +311,26 @@ branchFromFiles loadMode rootDir h@(RawHash h') = do
Left err -> failWith $ InvalidEditsFile file err
Right edits -> pure edits
getRootBranch :: MonadIO m => CodebasePath -> m (Branch m)
getRootBranch root = do
unlessM (doesDirectoryExist $ branchHeadDir root)
(failWith . NoBranchHead $ branchHeadDir root)
liftIO (listDirectory $ branchHeadDir root) >>= \case
[] -> failWith . NoBranchHead $ branchHeadDir root
[single] -> go single
conflict -> traverse go conflict >>= \case
x : xs -> foldM Branch.merge x xs
[] -> failWith . NoBranchHead $ branchHeadDir root
-- returns Nothing if `root` has no root branch (in `branchHeadDir root`)
getRootBranch ::
MonadIO m => BranchLoadMode -> CodebasePath -> m (Branch m)
getRootBranch loadMode root = do
ifM (exists root)
(liftIO (listDirectory $ branchHeadDir root) >>= \case
[] -> missing
[single] -> go single
conflict -> traverse go conflict >>= \case
x : xs -> foldM Branch.merge x xs
[] -> missing
)
missing
where
go single = case hashFromString single of
Nothing -> failWith $ CantParseBranchHead single
Just h -> branchFromFiles FailIfMissing root (RawHash h)
missing = case loadMode of
FailIfMissing -> failWith . NoBranchHead $ branchHeadDir root
EmptyIfMissing -> pure $ Branch.empty
putRootBranch :: MonadIO m => CodebasePath -> Branch m -> m ()
putRootBranch root b = do
@ -409,6 +402,9 @@ referentToString = Text.unpack . Referent.toText
copyDir :: (FilePath -> Bool) -> FilePath -> FilePath -> IO ()
copyDir predicate from to = do
createDirectoryIfMissing True to
-- createDir doesn't create a new directory on disk,
-- it creates a description of an existing directory,
-- and it crashes if `from` doesn't exist.
d <- createDir from
when (predicate $ dirPath d) $ do
forM_ (subDirs d)
@ -418,10 +414,13 @@ copyDir predicate from to = do
unless exists . copyFile path $ replaceRoot from to path
copyFromGit :: MonadIO m => FilePath -> FilePath -> m ()
copyFromGit = (liftIO .) . flip
(copyDir (\x -> not ((".git" `isSuffixOf` x) || ("_head" `isSuffixOf` x))))
copyFromGit to from = liftIO . whenM (doesDirectoryExist from) $
copyDir (\x -> not ((".git" `isSuffixOf` x) || ("_head" `isSuffixOf` x)))
from to
writeAllTermsAndTypes
-- Create a codebase structure at `localPath` if none exists, and
-- copy (merge) all codebase elements from the current codebase into it.
syncToDirectory
:: forall m v a
. (MonadUnliftIO m)
=> Var v
@ -432,8 +431,8 @@ writeAllTermsAndTypes
-> FilePath
-> Branch m
-> m (Branch m)
writeAllTermsAndTypes fmtV fmtA codebase localPath branch = do
b <- doesDirectoryExist localPath
syncToDirectory fmtV fmtA codebase localPath branch = do
b <- (liftIO . exists) localPath
if b then do
let code = codebase1 fmtV fmtA localPath
remoteRoot <- Codebase.getRootBranch code
@ -584,7 +583,7 @@ codebase1 fmtV@(S.Format getV putV) fmtA@(S.Format getA putA) path =
getDecl
(putTerm putV putA path)
(putDecl putV putA path)
(getRootBranch path)
(getRootBranch FailIfMissing path)
(putRootBranch path)
(branchHeadUpdates path)
(branchFromFiles EmptyIfMissing path)
@ -593,7 +592,7 @@ codebase1 fmtV@(S.Format getV putV) fmtA@(S.Format getA putA) path =
(copyFromGit path)
-- This is fine as long as watat doesn't call
-- syncToDirectory c
(writeAllTermsAndTypes fmtV fmtA c)
(syncToDirectory fmtV fmtA c)
watches
getWatch
(putWatch putV putA path)

View File

@ -24,49 +24,54 @@ import qualified Unison.Util.SyntaxText as S
type Pretty = P.Pretty P.ColorText
displayTerm :: (Var v, Monad m)
=> PPE.PrettyPrintEnv
=> PPE.PrettyPrintEnvDecl
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
-> (Referent -> m (Maybe (Type v a)))
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
-> (Reference -> m (Maybe (DD.Decl v a)))
-> AnnotatedTerm v a
-> m Pretty
displayTerm ppe terms typeOf eval types tm = case tm of
displayTerm pped terms typeOf eval types tm = case tm of
-- todo: can dispatch on other things with special rendering
Term.Ref' r -> eval r >>= \case
Nothing -> pure $ termName ppe (Referent.Ref r)
Just tm -> displayDoc ppe terms typeOf eval types tm
_ -> displayDoc ppe terms typeOf eval types tm
Nothing -> pure $ termName (PPE.suffixifiedPPE pped) (Referent.Ref r)
Just tm -> displayDoc pped terms typeOf eval types tm
_ -> displayDoc pped terms typeOf eval types tm
displayDoc :: (Var v, Monad m)
=> PPE.PrettyPrintEnv
=> PPE.PrettyPrintEnvDecl
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
-> (Referent -> m (Maybe (Type v a)))
-> (Reference -> m (Maybe (AnnotatedTerm v a)))
-> (Reference -> m (Maybe (DD.Decl v a)))
-> AnnotatedTerm v a
-> m Pretty
displayDoc ppe terms typeOf evaluated types t = go t
displayDoc pped terms typeOf evaluated types t = go t
where
go (DD.DocJoin docs) = foldMap id <$> traverse go docs
go (DD.DocBlob txt) = pure $ P.paragraphyText txt
go (DD.DocLink (DD.LinkTerm (Term.TermLink' r))) = pure $ P.underline (termName ppe r)
go (DD.DocLink (DD.LinkType (Term.TypeLink' r))) = pure $ P.underline (typeName ppe r)
go (DD.DocLink (DD.LinkTerm (Term.TermLink' r))) =
pure $ P.underline (termName (PPE.suffixifiedPPE pped) r)
go (DD.DocLink (DD.LinkType (Term.TypeLink' r))) =
pure $ P.underline (typeName (PPE.suffixifiedPPE pped) r)
go (DD.DocSource (DD.LinkTerm (Term.TermLink' r))) = prettyTerm terms r
go (DD.DocSource (DD.LinkType (Term.TypeLink' r))) = prettyType r
go (DD.DocSignature (Term.TermLink' r)) = prettySignature r
go (DD.DocEvaluate (Term.TermLink' r)) = prettyTerm evaluated r
go tm = pure $ TP.pretty ppe tm
go tm = pure $ TP.pretty (PPE.suffixifiedPPE pped) tm
prettySignature r = typeOf r >>= \case
Nothing -> pure $ termName ppe r
Just typ -> pure $ P.group $ TypePrinter.prettySignatures ppe [(PPE.termName ppe r, typ)]
Nothing -> pure $ termName (PPE.unsuffixifiedPPE pped) r
Just typ -> pure . P.group $
TypePrinter.prettySignatures
(PPE.suffixifiedPPE pped)
[(PPE.termName (PPE.unsuffixifiedPPE pped) r, typ)]
prettyTerm terms r = case r of
Referent.Ref (Reference.Builtin _) -> prettySignature r
Referent.Ref ref -> terms ref >>= \case
Referent.Ref ref -> let ppe = PPE.declarationPPE pped ref in terms ref >>= \case
Nothing -> pure $ "😶 Missing term source for: " <> termName ppe r
Just tm -> pure . P.syntaxToColor $ P.group $ TP.prettyBinding ppe (PPE.termName ppe r) tm
Referent.Con r _ _ -> prettyType r
prettyType r = types r >>= \case
prettyType r = let ppe = PPE.declarationPPE pped r in types r >>= \case
Nothing -> pure $ "😶 Missing type source for: " <> typeName ppe r
Just ty -> pure . P.syntaxToColor $ P.group $ DP.prettyDecl ppe r (PPE.typeName ppe r) ty

View File

@ -832,29 +832,31 @@ formatMissingStuff terms types =
<> P.column2 [ (P.syntaxToColor $ prettyHashQualified name, fromString (show ref)) | (name, ref) <- types ])
displayDefinitions' :: Var v => Ord a1
=> PPE.PrettyPrintEnv
=> PPE.PrettyPrintEnvDecl
-> Map Reference.Reference (DisplayThing (DD.Decl v a1))
-> Map Reference.Reference (DisplayThing (Unison.Term.AnnotatedTerm v a1))
-> Pretty
displayDefinitions' ppe types terms = P.syntaxToColor $ P.sep "\n\n" (prettyTypes <> prettyTerms)
displayDefinitions' ppe0 types terms = P.syntaxToColor $ P.sep "\n\n" (prettyTypes <> prettyTerms)
where
ppeBody r = PPE.declarationPPE ppe0 r
ppeDecl = PPE.unsuffixifiedPPE ppe0
prettyTerms = map go . Map.toList
-- sort by name
$ Map.mapKeys (first (PPE.termName ppe . Referent.Ref) . dupe) terms
$ Map.mapKeys (first (PPE.termName ppeDecl . Referent.Ref) . dupe) terms
prettyTypes = map go2 . Map.toList
$ Map.mapKeys (first (PPE.typeName ppe) . dupe) types
$ Map.mapKeys (first (PPE.typeName ppeDecl) . dupe) types
go ((n, r), dt) =
case dt of
MissingThing r -> missing n r
BuiltinThing -> builtin n
RegularThing tm -> TermPrinter.prettyBinding ppe n tm
RegularThing tm -> TermPrinter.prettyBinding (ppeBody r) n tm
go2 ((n, r), dt) =
case dt of
MissingThing r -> missing n r
BuiltinThing -> builtin n
RegularThing decl -> case decl of
Left d -> DeclPrinter.prettyEffectDecl ppe r n d
Right d -> DeclPrinter.prettyDataDecl ppe r n d
Left d -> DeclPrinter.prettyEffectDecl (ppeBody r) r n d
Right d -> DeclPrinter.prettyDataDecl (ppeBody r) r n d
builtin n = P.wrap $ "--" <> prettyHashQualified n <> " is built-in."
missing n r = P.wrap (
"-- The name " <> prettyHashQualified n <> " is assigned to the "
@ -888,7 +890,7 @@ displayRendered outputLoc pp =
displayDefinitions :: Var v => Ord a1 =>
Maybe FilePath
-> PPE.PrettyPrintEnv
-> PPE.PrettyPrintEnvDecl
-> Map Reference.Reference (DisplayThing (DD.Decl v a1))
-> Map Reference.Reference (DisplayThing (Unison.Term.AnnotatedTerm v a1))
-> IO Pretty
@ -1067,7 +1069,7 @@ renderEditConflicts ppe Patch{..} =
P.oxfordCommas [ termName r | TermEdit.Replace r _ <- es ]
formatConflict = either formatTypeEdits formatTermEdits
todoOutput :: Var v => PPE.PrettyPrintEnv -> TO.TodoOutput v a -> IO Pretty
todoOutput :: Var v => PPE.PrettyPrintEnvDecl -> TO.TodoOutput v a -> IO Pretty
todoOutput ppe todo =
if noConflicts && noEdits
then pure $ P.okCallout "No conflicts or edits in progress."
@ -1076,16 +1078,18 @@ todoOutput ppe todo =
noConflicts = TO.nameConflicts todo == mempty
&& TO.editConflicts todo == Patch.empty
noEdits = TO.todoScore todo == 0
ppeu = PPE.unsuffixifiedPPE ppe
ppes = PPE.suffixifiedPPE ppe
(frontierTerms, frontierTypes) = TO.todoFrontier todo
(dirtyTerms, dirtyTypes) = TO.todoFrontierDependents todo
corruptTerms =
[ (PPE.termName ppe (Referent.Ref r), r) | (r, Nothing) <- frontierTerms ]
[ (PPE.termName ppeu (Referent.Ref r), r) | (r, Nothing) <- frontierTerms ]
corruptTypes =
[ (PPE.typeName ppe r, r) | (r, MissingThing _) <- frontierTypes ]
[ (PPE.typeName ppeu r, r) | (r, MissingThing _) <- frontierTypes ]
goodTerms ts =
[ (PPE.termName ppe (Referent.Ref r), typ) | (r, Just typ) <- ts ]
[ (PPE.termName ppeu (Referent.Ref r), typ) | (r, Just typ) <- ts ]
todoConflicts = if noConflicts then mempty else P.lines . P.nonEmpty $
[ renderEditConflicts ppe (TO.editConflicts todo)
[ renderEditConflicts ppeu (TO.editConflicts todo)
, renderNameConflicts conflictedTypeNames conflictedTermNames ]
where
-- If a conflict is both an edit and a name conflict, we show it in the edit
@ -1125,15 +1129,15 @@ todoOutput ppe todo =
<> "transitive dependent(s) left to upgrade."
<> "Your edit frontier is the dependents of these definitions:")
, P.indentN 2 . P.lines $ (
(prettyDeclPair ppe <$> toList frontierTypes) ++
TypePrinter.prettySignatures' ppe (goodTerms frontierTerms)
(prettyDeclPair ppeu <$> toList frontierTypes) ++
TypePrinter.prettySignatures' ppes (goodTerms frontierTerms)
)
, P.wrap "I recommend working on them in the following order:"
, P.numberedList $
let unscore (_score,a,b) = (a,b)
in (prettyDeclPair ppe . unscore <$> toList dirtyTypes) ++
in (prettyDeclPair ppeu . unscore <$> toList dirtyTypes) ++
TypePrinter.prettySignatures'
ppe
ppes
(goodTerms $ unscore <$> dirtyTerms)
, formatMissingStuff corruptTerms corruptTypes
]

View File

@ -4,6 +4,7 @@ module Unison.HashQualified where
import Unison.Prelude hiding (fromString)
import Data.List ( sortOn )
import Data.Maybe ( fromJust
)
import qualified Data.Text as Text
@ -40,6 +41,21 @@ toName = \case
HashQualified name _ -> Just name
HashOnly _ -> Nothing
-- Sort the list of names by length of segments: smaller number of
-- segments is listed first. NameOnly < Hash qualified < Hash only
--
-- Examples:
-- [foo.bar.baz, bar.baz] -> [bar.baz, foo.bar.baz]
-- [#a29dj2k91, foo.bar.baz] -> [foo.bar.baz, #a29dj2k91]
-- [foo.bar#abc, foo.bar] -> [foo.bar, foo.bar#abc]
-- [.foo.bar, foo.bar] -> [foo.bar, .foo.bar]
sortByLength :: [HashQualified' Name] -> [HashQualified' Name]
sortByLength hs = sortOn f hs where
f (NameOnly n) = (countDots n, 0, Left n)
f (HashQualified n _h) = (countDots n, 1, Left n)
f (HashOnly h) = (maxBound, 0, Right h)
countDots n = Text.count "." (Text.dropEnd 1 (Name.toText n))
hasName, hasHash :: HashQualified -> Bool
hasName = isJust . toName
hasHash = isJust . toHash

View File

@ -11,6 +11,7 @@ module Unison.Name
, sortNamed
, stripNamePrefix
, stripPrefixes
, suffixes
, toString
, toVar
, unqualified
@ -29,7 +30,7 @@ import qualified Unison.Hashable as H
import Unison.Var ( Var )
import qualified Unison.Var as Var
import qualified Data.RFC5051 as RFC5051
import Data.List ( sortBy )
import Data.List ( sortBy, tails )
newtype Name = Name { toText :: Text } deriving (Eq, Ord)
@ -103,6 +104,12 @@ parent (Name txt) = case unsnoc (Text.splitOn "." txt) of
Just ([],_) -> Nothing
Just (init,_) -> Just $ Name (Text.intercalate "." init)
suffixes :: Name -> [Name]
suffixes (Name n) =
fmap up . tails . dropWhile (== "") $ Text.splitOn "." n
where
up ns = Name (Text.intercalate "." ns)
unqualified' :: Text -> Text
unqualified' = last . Text.splitOn "."

View File

@ -1,10 +1,12 @@
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
module Unison.Names3 where
import Unison.Prelude
import Data.List.Extra (nubOrd)
import Unison.HashQualified (HashQualified)
import qualified Unison.HashQualified as HQ
import qualified Unison.HashQualified' as HQ'
@ -15,9 +17,11 @@ import Unison.Referent (Referent)
import Unison.Referent as Referent
import Unison.Util.Relation (Relation)
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Unison.Name as Name
import qualified Unison.Names2
import qualified Unison.Names2 as Names
import qualified Unison.Util.List as List
import qualified Unison.Util.Relation as R
import qualified Unison.ConstructorType as CT
@ -33,6 +37,22 @@ data ResolutionFailure v a
type ResolutionResult v a r = Either (Seq (ResolutionFailure v a)) r
-- For all names in `ns`, (ex: foo.bar.baz), generate the list of suffixes
-- of that name [[foo.bar.baz], [bar.baz], [baz]]. Insert these suffixes
-- into a multimap map along with their corresponding refs. Any suffix
-- which is unique is added as an entry to `ns`.
suffixify0 :: Names0 -> Names0
suffixify0 ns = ns <> suffixNs
where
suffixNs = names0 (R.fromList uniqueTerms) (R.fromList uniqueTypes)
terms = List.multimap [ (n,ref) | (n0,ref) <- R.toList (terms0 ns), n <- Name.suffixes n0 ]
types = List.multimap [ (n,ref) | (n0,ref) <- R.toList (types0 ns), n <- Name.suffixes n0 ]
uniqueTerms = [ (n,ref) | (n, nubOrd -> [ref]) <- Map.toList terms ]
uniqueTypes = [ (n,ref) | (n, nubOrd -> [ref]) <- Map.toList types ]
suffixify :: Names -> Names
suffixify ns = Names (suffixify0 (currentNames ns)) (oldNames ns)
filterTypes :: (Name -> Bool) -> Names0 -> Names0
filterTypes = Unison.Names2.filterTypes

View File

@ -240,12 +240,13 @@ rootFile :: Ord v => P v a -> P v a
rootFile p = p <* P.eof
run' :: Ord v => P v a -> String -> String -> ParsingEnv -> Either (Err v) a
run' p s name =
run' p s name env =
let lex = if debug
then L.lexer name (trace (L.debugLex''' "lexer receives" s) s)
else L.lexer name s
pTraced = traceRemainingTokens "parser receives" *> p
in runParserT pTraced name (Input lex)
env' = env { names = Names.suffixify (names env) }
in runParserT pTraced name (Input lex) env'
run :: Ord v => P v a -> String -> ParsingEnv -> Either (Err v) a
run p s = run' p s ""

View File

@ -15,6 +15,7 @@ import qualified Data.Map as Map
import qualified Unison.HashQualified as HQ
import qualified Unison.Name as Name
import qualified Unison.Names3 as Names
import qualified Unison.Reference as Reference
import qualified Unison.Referent as Referent
import qualified Unison.ConstructorType as CT
import qualified Unison.HashQualified' as HQ'
@ -34,10 +35,48 @@ instance Show PrettyPrintEnv where
show _ = "PrettyPrintEnv"
fromNames :: Int -> Names -> PrettyPrintEnv
fromNames length names = PrettyPrintEnv terms' types' where
terms' r = safeHead . Set.map HQ'.toHQ $ (Names.termName length r names)
types' r = safeHead . Set.map HQ'.toHQ $ (Names.typeName length r names)
fromNames len names = PrettyPrintEnv terms' types' where
terms' r = shortestName . Set.map HQ'.toHQ $ (Names.termName len r names)
types' r = shortestName . Set.map HQ'.toHQ $ (Names.typeName len r names)
shortestName ns = safeHead $ HQ.sortByLength (toList ns)
fromSuffixNames :: Int -> Names -> PrettyPrintEnv
fromSuffixNames len names = fromNames len (Names.suffixify names)
fromNamesDecl :: Int -> Names -> PrettyPrintEnvDecl
fromNamesDecl len names =
PrettyPrintEnvDecl (fromNames len names) (fromSuffixNames len names)
-- A pair of PrettyPrintEnvs:
-- - suffixifiedPPE uses the shortest unique suffix
-- - unsuffixifiedPPE uses the shortest full name
--
-- Generally, we want declarations LHS (the `x` in `x = 23`) to use the
-- unsuffixified names, so the LHS is an accurate description of where in the
-- namespace the definition lives. For everywhere else, we can use the
-- suffixified version.
data PrettyPrintEnvDecl = PrettyPrintEnvDecl {
unsuffixifiedPPE :: PrettyPrintEnv,
suffixifiedPPE :: PrettyPrintEnv
} deriving Show
-- declarationPPE uses the full name for references that are
-- part the same cycle as the input reference, used to ensures
-- recursive definitions are printed properly, for instance:
--
-- foo.bar x = foo.bar x
-- and not
-- foo.bar x = bar x
declarationPPE :: PrettyPrintEnvDecl -> Reference -> PrettyPrintEnv
declarationPPE ppe rd = PrettyPrintEnv tm ty where
comp = Reference.members (Reference.componentFor rd)
tm r0@(Referent.Ref r) = if Set.member r comp
then terms (unsuffixifiedPPE ppe) r0
else terms (suffixifiedPPE ppe) r0
tm r = terms (suffixifiedPPE ppe) r
ty r = if Set.member r comp then types (unsuffixifiedPPE ppe) r
else types (suffixifiedPPE ppe) r
-- Left-biased union of environments
unionLeft :: PrettyPrintEnv -> PrettyPrintEnv -> PrettyPrintEnv
unionLeft e1 e2 = PrettyPrintEnv

View File

@ -28,6 +28,7 @@ import qualified Unison.Test.Var as Var
import qualified Unison.Test.Codebase as Codebase
import qualified Unison.Test.Codebase.FileCodebase as FileCodebase
import qualified Unison.Test.UriParser as UriParser
import qualified Unison.Test.Git as Git
test :: Test ()
test = tests
@ -54,6 +55,7 @@ test = tests
, Typechecker.test
, UriParser.test
, Context.test
, Git.test
]
main :: IO ()

View File

@ -0,0 +1,56 @@
{-# Language OverloadedStrings #-}
{-# Language QuasiQuotes #-}
module Unison.Test.Git where
import EasyTest
import Data.String.Here (iTrim)
import Unison.Prelude
import Data.Text (Text)
import qualified Data.Text as Text
import qualified System.IO.Temp as Temp
import Shellmet ()
import System.FilePath ((</>))
import System.Directory (getCurrentDirectory)
import Unison.Codebase.FileCodebase as FC
import qualified Unison.Codebase.TranscriptParser as TR
test :: Test ()
test = scope "git" . tests $ [testBareRepo]
testBareRepo :: Test ()
testBareRepo = scope "testBareRepo" $ do
io . Temp.withSystemTempDirectory "testBareRepo" $ \tmp -> do
-- create a git repo and a transcript that references it
let repo = tmp </> "repo.git"
"git" ["init", "--bare", Text.pack repo]
let transcript = makeTranscript repo
-- initialize an fresh codebase
let codebase = tmp </> "codebase"
FC.initCodebase codebase
case TR.parse "transcript" transcript of
Left err -> error $ "Parse error: \n" <> show err
Right stanzas -> void $ do
currentDir <- getCurrentDirectory
theCodebase <- FC.getCodebaseOrExit $ Just codebase
TR.run currentDir stanzas theCodebase
ok
makeTranscript :: FilePath -> Text
makeTranscript repoPath = Text.pack $ [iTrim|
```unison
x = 3
```
```ucm
.foo> add
.foo> push ${repoPath}
```
Now we pull what we pushed
```ucm
.foo2> pull ${repoPath}
.foo2> ls
```
|]

View File

@ -40,6 +40,7 @@ library
Unison.Codecs
Unison.Codebase
Unison.Codebase.Branch
Unison.Codebase.BranchLoadMode
Unison.Codebase.BranchUtil
Unison.Codebase.Causal
Unison.Codebase.Classes
@ -290,6 +291,7 @@ executable tests
Unison.Test.Common
Unison.Test.DataDeclaration
Unison.Test.FileParser
Unison.Test.Git
Unison.Test.Lexer
Unison.Test.Range
Unison.Test.Referent
@ -317,10 +319,13 @@ executable tests
extra,
filepath,
filemanip,
here,
lens,
megaparsec,
mtl,
raw-strings-qq,
shellmet,
temporary,
text,
transformers,
unison-parser-typechecker

View File

@ -0,0 +1,23 @@
-- This file shows that any unique suffix can be used to refer
-- to a definition.
-- no imports needed here, even though FQN is builtin.Int
foo : Int
foo = +1
-- no imports needed here, even though FQNs are builtin.Optional.{None,Some}
ex1 o = case o of
None -> 0
Some a -> a + 1
-- you can still use the
ex2 o = case o of
Optional.None -> 99
Optional.Some _ -> 0
ex3 = builtin.Optional.None
-- TDNR would have handled this one before, but TDNR can't do
-- type resolution or pattern resolution
zoink = Some 42

View File

@ -12,7 +12,7 @@ See [this ticket](https://github.com/unisonweb/unison/issues/873); the point bei
⍟ These new definitions are ok to `add`:
- : builtin.Nat -> builtin.Nat -> builtin.Int
- : Nat -> Nat -> Int
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -23,7 +23,7 @@ See [this ticket](https://github.com/unisonweb/unison/issues/873); the point bei
⍟ I've added these definitions:
- : builtin.Nat -> builtin.Nat -> builtin.Int
- : Nat -> Nat -> Int
```
```unison
@ -38,7 +38,7 @@ baz x = x - 1
⍟ These new definitions are ok to `add`:
baz : builtin.Nat -> builtin.Int
baz : Nat -> Int
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.

View File

@ -6,12 +6,12 @@ Unison documentation is written in Unison. Documentation is a value of the follo
.> view builtin.Doc
unique type builtin.Doc
= Link builtin.Link
| Source builtin.Link
| Blob builtin.Text
= Link Link
| Source Link
| Blob Text
| Join [builtin.Doc]
| Signature builtin.Link.Term
| Evaluate builtin.Link.Term
| Signature Term
| Evaluate Term
```
You can create these `Doc` values with ordinary code, or you can use the special syntax. A value of type `Doc` can be created via syntax like:
@ -36,7 +36,7 @@ Can link to definitions like @List.drop or @List
⍟ These new definitions are ok to `add`:
doc1 : builtin.Doc
doc1 : Doc
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -69,8 +69,8 @@ List.take.ex2 = take 2 [1,2,3,4,5]
⍟ These new definitions are ok to `add`:
List.take.ex1 : [builtin.Nat]
List.take.ex2 : [builtin.Nat]
List.take.ex1 : [Nat]
List.take.ex2 : [Nat]
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -81,8 +81,8 @@ List.take.ex2 = take 2 [1,2,3,4,5]
⍟ I've added these definitions:
List.take.ex1 : [builtin.Nat]
List.take.ex2 : [builtin.Nat]
List.take.ex1 : [Nat]
List.take.ex2 : [Nat]
```
And now let's write our docs and reference these examples:
@ -115,7 +115,7 @@ docs.List.take = [:
⍟ These new definitions are ok to `add`:
docs.List.take : builtin.Doc
docs.List.take : Doc
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -128,7 +128,7 @@ Let's add it to the codebase, and link it to the definition:
⍟ I've added these definitions:
docs.List.take : builtin.Doc
docs.List.take : Doc
.> link builtin.List.take docs.List.take
@ -140,7 +140,7 @@ Now that documentation is linked to the definition. We can view it if we like:
```ucm
.> links builtin.List.take builtin.Doc
1. docs.List.take : builtin.Doc
1. docs.List.take : Doc
Tip: Try using `display 1` to display the first result or
`view 1` to view its source.

View File

@ -16,7 +16,7 @@ hey = "yello"
⍟ These new definitions are ok to `add`:
hey : builtin.Text
hey : Text
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -27,7 +27,7 @@ hey = "yello"
⍟ I've added these definitions:
hey : builtin.Text
hey : Text
```
Update
@ -49,7 +49,7 @@ hey = "hello"
⍟ These new definitions will replace existing ones of the
same name and are ok to `update`:
hey : builtin.Text
hey : Text
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.

View File

@ -15,7 +15,7 @@ x = 42
⍟ These new definitions are ok to `add`:
x : builtin.Nat
x : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.

View File

@ -14,9 +14,9 @@ z = y + 2
⍟ These new definitions are ok to `add`:
x : builtin.Nat
y : builtin.Nat
z : builtin.Nat
x : Nat
y : Nat
z : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -27,9 +27,9 @@ z = y + 2
⍟ I've added these definitions:
x : builtin.Nat
y : builtin.Nat
z : builtin.Nat
x : Nat
y : Nat
z : Nat
```
Now we edit `x` to be `7`, which should make `z` equal `10`:
@ -47,7 +47,7 @@ x = 7
⍟ These new definitions will replace existing ones of the
same name and are ok to `update`:
x : builtin.Nat
x : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -66,17 +66,17 @@ x = 7
.> view x y z
x : builtin.Nat
x : Nat
x = 7
y : builtin.Nat
y : Nat
y =
use builtin.Nat +
use Nat +
x + 1
z : builtin.Nat
z : Nat
z =
use builtin.Nat +
use Nat +
y + 2
```
@ -94,7 +94,7 @@ test> t1 = if z == 3 then [Fail "nooo!!!"] else [Ok "great"]
⍟ These new definitions are ok to `add`:
t1 : [builtin.Test.Result]
t1 : [Result]
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -109,7 +109,7 @@ test> t1 = if z == 3 then [Fail "nooo!!!"] else [Ok "great"]
⍟ I've added these definitions:
t1 : [builtin.Test.Result]
t1 : [Result]
.> test

View File

@ -38,7 +38,7 @@ x = 42
⍟ These new definitions are ok to `add`:
x : builtin.Nat
x : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -51,11 +51,11 @@ Let's go ahead and add that to the codebase, then make sure it's there:
⍟ I've added these definitions:
x : builtin.Nat
x : Nat
.> view x
x : builtin.Nat
x : Nat
x = 42
```

View File

@ -14,7 +14,7 @@ x = 42
⍟ These new definitions are ok to `add`:
x : builtin.Nat
x : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -25,7 +25,7 @@ x = 42
⍟ I've added these definitions:
x : builtin.Nat
x : Nat
```
Let's move `x` into a new namespace, `master`:
@ -63,7 +63,7 @@ y = "hello"
⍟ These new definitions are ok to `add`:
y : builtin.Text
y : Text
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -76,7 +76,7 @@ y = "hello"
⍟ I've added these definitions:
y : .builtin.Text
y : Text
.master> merge .feature1
@ -92,7 +92,7 @@ y = "hello"
.master> view y
y : .builtin.Text
y : Text
y = "hello"
```
@ -189,7 +189,7 @@ z = 99
⍟ These new definitions are ok to `add`:
z : builtin.Nat
z : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -200,7 +200,7 @@ z = 99
⍟ I've added these definitions:
z : .builtin.Nat
z : Nat
.feature2> delete.term x
@ -220,8 +220,8 @@ master.frobnicate n = n + 1
⍟ These new definitions are ok to `add`:
master.frobnicate : .builtin.Nat -> .builtin.Nat
master.y : .builtin.Text
master.frobnicate : Nat -> Nat
master.y : Text
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -244,14 +244,14 @@ master.frobnicate n = n + 1
.> view master.y
feature2.y : builtin.Text
feature2.y : Text
feature2.y = "updated y"
.> view master.frobnicate
master.frobnicate : builtin.Nat -> builtin.Nat
master.frobnicate : Nat -> Nat
master.frobnicate n =
use builtin.Nat +
use Nat +
n + 1
```
@ -291,19 +291,19 @@ And notice that `y` has the most recent value, and that `z` and `frobnicate` bot
```ucm
.> view master.y
feature2.y : builtin.Text
feature2.y : Text
feature2.y = "updated y"
.> view master.z
feature2.z : builtin.Nat
feature2.z : Nat
feature2.z = 99
.> view master.frobnicate
master.frobnicate : builtin.Nat -> builtin.Nat
master.frobnicate : Nat -> Nat
master.frobnicate n =
use builtin.Nat +
use Nat +
n + 1
```

View File

@ -19,12 +19,12 @@ corge = "corge"
⍟ These new definitions are ok to `add`:
bar : builtin.Text
baz : builtin.Text
corge : builtin.Text
foo : builtin.Text
quux : builtin.Text
qux : builtin.Text
bar : Text
baz : Text
corge : Text
foo : Text
quux : Text
qux : Text
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -37,12 +37,12 @@ corge = "corge"
⍟ I've added these definitions:
bar : .builtin.Text
baz : .builtin.Text
corge : .builtin.Text
foo : .builtin.Text
quux : .builtin.Text
qux : .builtin.Text
bar : Text
baz : Text
corge : Text
foo : Text
quux : Text
qux : Text
```
We can get the list of things in the namespace, and UCM will give us a numbered
@ -51,12 +51,12 @@ list:
```ucm
.temp> find
1. bar : .builtin.Text
2. baz : .builtin.Text
3. corge : .builtin.Text
4. foo : .builtin.Text
5. quux : .builtin.Text
6. qux : .builtin.Text
1. bar : Text
2. baz : Text
3. corge : Text
4. foo : Text
5. quux : Text
6. qux : Text
```
@ -65,17 +65,17 @@ We can ask to `view` the second element of this list:
```ucm
.temp> find
1. bar : .builtin.Text
2. baz : .builtin.Text
3. corge : .builtin.Text
4. foo : .builtin.Text
5. quux : .builtin.Text
6. qux : .builtin.Text
1. bar : Text
2. baz : Text
3. corge : Text
4. foo : Text
5. quux : Text
6. qux : Text
.temp> view 2
baz : .builtin.Text
baz : Text
baz = "baz"
```
@ -84,23 +84,23 @@ And we can `view` multiple elements by separating with spaces:
```ucm
.temp> find
1. bar : .builtin.Text
2. baz : .builtin.Text
3. corge : .builtin.Text
4. foo : .builtin.Text
5. quux : .builtin.Text
6. qux : .builtin.Text
1. bar : Text
2. baz : Text
3. corge : Text
4. foo : Text
5. quux : Text
6. qux : Text
.temp> view 2 3 5
baz : .builtin.Text
baz : Text
baz = "baz"
corge : .builtin.Text
corge : Text
corge = "corge"
quux : .builtin.Text
quux : Text
quux = "quux"
```
@ -109,23 +109,23 @@ We can also ask for a range:
```ucm
.temp> find
1. bar : .builtin.Text
2. baz : .builtin.Text
3. corge : .builtin.Text
4. foo : .builtin.Text
5. quux : .builtin.Text
6. qux : .builtin.Text
1. bar : Text
2. baz : Text
3. corge : Text
4. foo : Text
5. quux : Text
6. qux : Text
.temp> view 2-4
baz : .builtin.Text
baz : Text
baz = "baz"
corge : .builtin.Text
corge : Text
corge = "corge"
foo : .builtin.Text
foo : Text
foo = "foo"
```
@ -134,32 +134,32 @@ And we can ask for multiple ranges and use mix of ranges and numbers:
```ucm
.temp> find
1. bar : .builtin.Text
2. baz : .builtin.Text
3. corge : .builtin.Text
4. foo : .builtin.Text
5. quux : .builtin.Text
6. qux : .builtin.Text
1. bar : Text
2. baz : Text
3. corge : Text
4. foo : Text
5. quux : Text
6. qux : Text
.temp> view 1-3 4 5-6
bar : .builtin.Text
bar : Text
bar = "bar"
baz : .builtin.Text
baz : Text
baz = "baz"
corge : .builtin.Text
corge : Text
corge = "corge"
foo : .builtin.Text
foo : Text
foo = "foo"
quux : .builtin.Text
quux : Text
quux = "quux"
qux : .builtin.Text
qux : Text
qux = "qux"
```

View File

@ -20,7 +20,7 @@ fooToInt _ = +42
⍟ These new definitions are ok to `add`:
unique type Foo
fooToInt : Foo -> builtin.Int
fooToInt : Foo -> Int
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -36,7 +36,7 @@ And then we add it.
⍟ I've added these definitions:
unique type Foo
fooToInt : Foo -> .builtin.Int
fooToInt : Foo -> Int
.subpath> find.verbose
@ -47,13 +47,13 @@ And then we add it.
Foo.Foo : Foo
3. -- #o9q6anf4873hbnsaiifh5b46q8fdli18cu8cudu0ti8ort1gm253120uq8ijk24l52ecf62bm1rmq4tgnu7ip8apireh1oq97e042jg
fooToInt : Foo -> .builtin.Int
fooToInt : Foo -> Int
.subpath> view fooToInt
fooToInt : Foo -> .builtin.Int
fooToInt : Foo -> Int
fooToInt _ = +42
```
@ -97,7 +97,7 @@ and update the codebase to use the new type `Foo`...
```ucm
.subpath> view fooToInt
fooToInt : Foo -> .builtin.Int
fooToInt : Foo -> Int
fooToInt _ = +42
```
@ -124,8 +124,8 @@ otherTerm y = someTerm y
⍟ These new definitions are ok to `add`:
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
someTerm : .builtin.Optional foo -> .builtin.Optional foo
otherTerm : Optional baz -> Optional baz
someTerm : Optional foo -> Optional foo
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -140,8 +140,8 @@ Add that to the codebase:
⍟ I've added these definitions:
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
someTerm : .builtin.Optional foo -> .builtin.Optional foo
otherTerm : Optional baz -> Optional baz
someTerm : Optional foo -> Optional foo
```
Let's now edit the dependency:
@ -162,7 +162,7 @@ someTerm _ = None
⍟ These new definitions will replace existing ones of the
same name and are ok to `update`:
someTerm : .builtin.Optional x -> .builtin.Optional x
someTerm : Optional x -> Optional x
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -188,12 +188,12 @@ type of `otherTerm` should remain the same.
```ucm
.subpath.preserve> view someTerm
someTerm : .builtin.Optional x -> .builtin.Optional x
someTerm _ = .builtin.Optional.None
someTerm : Optional x -> Optional x
someTerm _ = None
.subpath.preserve> view otherTerm
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
otherTerm : Optional baz -> Optional baz
otherTerm y = someTerm y
```
@ -236,8 +236,8 @@ otherTerm y = someTerm y
⍟ These new definitions are ok to `add`:
otherTerm : builtin.Optional baz -> builtin.Optional baz
someTerm : builtin.Optional foo -> builtin.Optional foo
otherTerm : Optional baz -> Optional baz
someTerm : Optional foo -> Optional foo
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -252,8 +252,8 @@ We'll make two copies of this namespace.
⍟ I've added these definitions:
otherTerm : .builtin.Optional baz -> .builtin.Optional baz
someTerm : .builtin.Optional foo -> .builtin.Optional foo
otherTerm : Optional baz -> Optional baz
someTerm : Optional foo -> Optional foo
.subpath> fork one two
@ -277,7 +277,7 @@ someTerm _ = None
⍟ These new definitions are ok to `add`:
someTerm : .builtin.Optional x -> .builtin.Optional x
someTerm : Optional x -> Optional x
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -302,7 +302,7 @@ The other namespace should be left alone.
```ucm
.subpath.two> view someTerm
someTerm : .builtin.Optional foo -> .builtin.Optional foo
someTerm : Optional foo -> Optional foo
someTerm x = x
```

View File

@ -13,7 +13,7 @@ x = 1
⍟ These new definitions are ok to `add`:
x : builtin.Nat
x : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -24,7 +24,7 @@ x = 1
⍟ I've added these definitions:
x : builtin.Nat
x : Nat
```
```unison
@ -39,7 +39,7 @@ y = 2
⍟ These new definitions are ok to `add`:
y : builtin.Nat
y : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -50,11 +50,11 @@ y = 2
⍟ I've added these definitions:
y : builtin.Nat
y : Nat
.> view y
y : builtin.Nat
y : Nat
y = 2
```

View File

@ -24,7 +24,7 @@ a.foo = 42
⍟ These new definitions are ok to `add`:
a.foo : .builtin.Nat
a.foo : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -35,7 +35,7 @@ a.foo = 42
⍟ I've added these definitions:
a.foo : .builtin.Nat
a.foo : Nat
```
We'll fork the namespace `a` into a new namespace `b`, so we can edit the two concurrently.
@ -73,7 +73,7 @@ foo = 43
⍟ These new definitions will replace existing ones of the
same name and are ok to `update`:
foo : .builtin.Nat
foo : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
@ -106,7 +106,7 @@ foo = 44
⍟ These new definitions will replace existing ones of the
same name and are ok to `update`:
foo : .builtin.Nat
foo : Nat
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.

View File

@ -0,0 +1,28 @@
# Suffix-based resolution of names
Any unique name suffix can be used to refer to a definition. For instance:
```unison
-- No imports needed even though FQN is `builtin.{Int,Nat}`
foo.bar.a : Int
foo.bar.a = +99
-- No imports needed even though FQN is `builtin.Optional.{None,Some}`
optional.isNone o = case o of
None -> true
Some _ -> false
```
This also affects commands like find. Notice lack of qualified names in output:
```ucm
.> find take
```
In the signature, we don't see `base.Nat`, just `Nat`. The full declaration name is still shown for each search result though.
Type-based search also benefits from this, we can just say `Nat` rather than `.base.Nat`:
```ucm
.> find : Nat -> [a] -> [a]
```

View File

@ -0,0 +1,53 @@
# Suffix-based resolution of names
Any unique name suffix can be used to refer to a definition. For instance:
```unison
-- No imports needed even though FQN is `builtin.{Int,Nat}`
foo.bar.a : Int
foo.bar.a = +99
-- No imports needed even though FQN is `builtin.Optional.{None,Some}`
optional.isNone o = case o of
None -> true
Some _ -> false
```
```ucm
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.bar.a : Int
optional.isNone : Optional a -> Boolean
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
```
This also affects commands like find. Notice lack of qualified names in output:
```ucm
.> find take
1. builtin.Bytes.take : Nat -> Bytes -> Bytes
2. builtin.List.take : Nat -> [a] -> [a]
3. builtin.Text.take : Nat -> Text -> Text
```
In the signature, we don't see `base.Nat`, just `Nat`. The full declaration name is still shown for each search result though.
Type-based search also benefits from this, we can just say `Nat` rather than `.base.Nat`:
```ucm
.> find : Nat -> [a] -> [a]
1. builtin.List.drop : Nat -> [a] -> [a]
2. builtin.List.take : Nat -> [a] -> [a]
```