diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 130d0312e0..52aabb3287 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,6 +15,8 @@ on: - trunk tags: - release/* + workflow_dispatch: + jobs: @@ -229,11 +231,7 @@ jobs: - name: unison-util-relation tests run: stack --no-terminal build --fast --test unison-util-relation - name: round-trip-tests - if: runner.os == 'macOS' run: | - mkdir -p /private/tmp - touch /private/tmp/roundtrip.u - touch /private/tmp/rewrite-tmp.u stack --no-terminal exec unison transcript unison-src/transcripts-round-trip/main.md git add unison-src/transcripts-round-trip/main.output.md # Fail if any transcripts cause git diffs. diff --git a/.github/workflows/pre-release.yaml b/.github/workflows/pre-release.yaml index eba0d39bf7..6852cfb979 100644 --- a/.github/workflows/pre-release.yaml +++ b/.github/workflows/pre-release.yaml @@ -162,7 +162,7 @@ jobs: - uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" - automatic_release_tag: "pre-release" + automatic_release_tag: "trunk-build" prerelease: true title: "Development Build" files: | diff --git a/.github/workflows/update-transcripts.yaml b/.github/workflows/update-transcripts.yaml new file mode 100644 index 0000000000..e0a7b23576 --- /dev/null +++ b/.github/workflows/update-transcripts.yaml @@ -0,0 +1,89 @@ +name: update-transcripts + +on: + workflow_dispatch: + +jobs: + update_transcripts: + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash + strategy: + matrix: + os: + - macOS-12 + steps: + - uses: actions/checkout@v4 + - id: stackage-resolver + name: record stackage resolver + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files + # looks for `resolver: nightly-yyyy-mm-dd` or `resolver: lts-xx.yy` in `stack.yaml` and splits it into + # `nightly` or `lts-xx`. the whole resolver string is put into resolver_long as a backup cache key + # ${{ steps.stackage-resolver.outputs.resolver_short }} + # ${{ steps.stackage-resolver.outputs.resolver_long }} + run: | + grep resolver stack.yaml | awk '{ x="resolver_short="; if (split($2,a,"-") > 2) print x a[1]; else {split($2,b,"."); print x b[1]}}' >> "$GITHUB_OUTPUT" + grep resolver stack.yaml | awk '{print "resolver_long="$2}' >> "$GITHUB_OUTPUT" + # Cache ~/.stack, keyed by the contents of 'stack.yaml'. + - uses: actions/cache@v3 + name: cache ~/.stack (unix) + if: runner.os != 'Windows' + with: + path: ~/.stack + key: stack-1_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_long }}-${{hashFiles('**/stack.yaml')}}-${{github.sha}} + # Fall-back to use the most recent cache for the stack.yaml, or failing that the OS + restore-keys: | + stack-1_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_long }}-${{hashFiles('**/stack.yaml')}}- + stack-1_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_long }}- + stack-1_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_short }}- + stack-1_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_short }}. + stack-1_${{matrix.os}}- + + # Cache each local package's ~/.stack-work for fast incremental builds in CI. + - uses: actions/cache@v3 + name: cache .stack-work + with: + path: | + **/.stack-work + # Main cache key: commit hash. This should always result in a cache miss... + # So when loading a cache we'll always fall back to the restore-keys, + # which should load the most recent cache via a prefix search on the most + # recent branch cache. + # Then it will save a new cache at this commit sha, which should be used by + # the next build on this branch. + key: stack-work-4_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_short }}-${{hashFiles('**/stack.yaml')}}-${{github.sha}} + restore-keys: | + stack-work-4_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_long }}-${{hashFiles('**/stack.yaml')}}- + stack-work-4_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_long }}- + stack-work-4_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_short }}- + stack-work-4_${{matrix.os}}-${{ steps.stackage-resolver.outputs.resolver_short }}. + stack-work-4_${{matrix.os}}- + + # Install stack by downloading the binary from GitHub. + # The installation process differs by OS. + - name: install stack (Linux) + if: runner.os == 'Linux' + working-directory: ${{ runner.temp }} + run: | + mkdir stack && cd stack + curl -L https://github.com/commercialhaskell/stack/releases/download/v2.9.1/stack-2.9.1-linux-x86_64.tar.gz | tar -xz + echo "$PWD/stack-"* >> $GITHUB_PATH + + # One of the transcripts fails if the user's git name hasn't been set. + - name: set git user info + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + - name: build + run: stack --no-terminal build --fast --no-run-tests --test + - name: round-trip-tests + run: | + stack --no-terminal exec unison transcript unison-src/transcripts-round-trip/main.md + stack --no-terminal exec unison transcript unison-src/transcripts-manual/rewrites.md + - name: transcripts + run: stack --no-terminal exec transcripts + - name: save transcript changes + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: rerun transcripts (reminder to rerun CI!) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..14aa55ca46 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM debian:stable + +RUN adduser --home /unison --disabled-password unison + +RUN apt-get update && \ + apt-get install -y git libncurses5 less locales fzf && \ + echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \ + dpkg-reconfigure --frontend=noninteractive locales && \ + update-locale LANG=en_US.UTF-8 + + +COPY tmp/ucm/ucm /usr/local/bin/ucm +COPY tmp/ucm/ui /usr/local/share/ucm + +ENV UCM_WEB_UI=/usr/local/share/ucm +ENV UCM_PORT=8080 +ENV UCM_TOKEN=pub + +RUN chmod 555 /usr/local/bin/ucm + +EXPOSE 8080 +ENTRYPOINT ["/usr/local/bin/ucm"] +CMD ["--codebase","/unison"] diff --git a/codebase2/codebase-sqlite-hashing-v2/package.yaml b/codebase2/codebase-sqlite-hashing-v2/package.yaml index d2301bd918..9e32e8546b 100644 --- a/codebase2/codebase-sqlite-hashing-v2/package.yaml +++ b/codebase2/codebase-sqlite-hashing-v2/package.yaml @@ -20,6 +20,7 @@ dependencies: - unison-hashing-v2 - unison-prelude - unison-sqlite + - unison-syntax - unison-util-base32hex - unison-util-term - vector diff --git a/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Decl/Hashing.hs b/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Decl/Hashing.hs new file mode 100644 index 0000000000..c16b0d931e --- /dev/null +++ b/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Decl/Hashing.hs @@ -0,0 +1,54 @@ +module U.Codebase.Decl.Hashing where + +import Control.Lens +import Data.Foldable qualified as Foldable +import Data.Map qualified as Map +import U.Codebase.Decl qualified as C +import U.Codebase.Decl qualified as C.Decl +import U.Codebase.HashTags +import U.Codebase.Reference qualified as Reference +import U.Codebase.Sqlite.Decl.Format qualified as DeclFormat +import U.Codebase.Sqlite.HashHandle (HashMismatch (..)) +import U.Codebase.Sqlite.HashHandle qualified as HH +import U.Codebase.Sqlite.LocalIds qualified as LocalIds +import U.Codebase.Sqlite.Queries qualified as Q +import U.Codebase.Sqlite.Symbol qualified as S +import U.Codebase.Sqlite.Symbol qualified as Sqlite +import Unison.Hash32 +import Unison.Hash32 qualified as Hash32 +import Unison.Hashing.V2 qualified as H2 +import Unison.Hashing.V2.Convert2 qualified as H2 +import Unison.Prelude +import Unison.Symbol qualified as Unison +import Unison.Syntax.Name qualified as Name +import Unison.Var qualified as Var + +verifyDeclFormatHash :: ComponentHash -> DeclFormat.HashDeclFormat -> Maybe HH.DeclHashingError +verifyDeclFormatHash (ComponentHash hash) (DeclFormat.Decl (DeclFormat.LocallyIndexedComponent elements)) = + Foldable.toList elements + & fmap s2cDecl + & Reference.component hash + & fmap (\(decl, refId) -> (refId, (C.Decl.vmap symbol2to1 decl, ()))) + & Map.fromList + & C.Decl.unhashComponent hash Var.unnamedRef + & Map.toList + & fmap (\(_refId, (v, decl, ())) -> (v, either H2.toDataDecl id $ H2.v2ToH2Decl decl)) + & Map.fromList + & H2.hashDecls Name.unsafeFromVar + & \case + Left _err -> Just HH.DeclHashResolutionFailure + Right m -> + m + & altMap \(_, H2.ReferenceId hash' _, _) -> + if hash == hash' + then Nothing + else Just (HH.DeclHashMismatch $ HashMismatch hash hash') + where + symbol2to1 :: S.Symbol -> Unison.Symbol + symbol2to1 (S.Symbol i t) = Unison.Symbol i (Var.User t) + +s2cDecl :: (LocalIds.LocalIds' Text Hash32, DeclFormat.Decl Sqlite.Symbol) -> C.Decl Sqlite.Symbol +s2cDecl (ids, decl) = + let Identity (substText, substHash) = Q.localIdsToLookups Identity pure (bimap id Hash32.toHash ids) + refmap = (bimap substText (fmap substHash)) + in Q.x2cDecl refmap decl diff --git a/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Sqlite/V2/HashHandle.hs b/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Sqlite/V2/HashHandle.hs index d08f2906e3..be5030e386 100644 --- a/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Sqlite/V2/HashHandle.hs +++ b/codebase2/codebase-sqlite-hashing-v2/src/U/Codebase/Sqlite/V2/HashHandle.hs @@ -7,13 +7,15 @@ import Data.Function ((&)) import Data.Set qualified as Set import U.Codebase.Branch.Hashing qualified as H2 import U.Codebase.Causal.Hashing qualified as H2 -import U.Codebase.HashTags (BranchHash (..)) +import U.Codebase.Decl.Hashing qualified as H2 +import U.Codebase.HashTags (BranchHash (..), PatchHash (..)) import U.Codebase.Sqlite.Branch.Format qualified as BranchFormat import U.Codebase.Sqlite.HashHandle +import U.Codebase.Sqlite.Patch.Format qualified as PatchFormat import U.Codebase.Term.Hashing as H2 import U.Util.Type (removeAllEffectVars) import Unison.Hashing.V2 qualified as H2 -import Unison.Hashing.V2.Convert2 (h2ToV2Reference, hashBranchFormatToH2Branch, v2ToH2Type, v2ToH2TypeD) +import Unison.Hashing.V2.Convert2 (h2ToV2Reference, hashBranchFormatToH2Branch, hashPatchFormatToH2Patch, v2ToH2Type, v2ToH2TypeD) v2HashHandle :: HashHandle v2HashHandle = @@ -25,10 +27,19 @@ v2HashHandle = hashBranch = H2.hashBranch, hashBranchV3 = H2.hashBranchV3, hashCausal = H2.hashCausal, - hashBranchFormatFull = \localIds localBranch -> - BranchFormat.localToHashBranch localIds localBranch - & hashBranchFormatToH2Branch - & H2.contentHash - & BranchHash, - verifyTermFormatHash = H2.verifyTermFormatHash + hashBranchFormatFull, + hashPatchFormatFull, + verifyTermFormatHash = H2.verifyTermFormatHash, + verifyDeclFormatHash = H2.verifyDeclFormatHash } + where + hashBranchFormatFull localIds localBranch = + BranchFormat.localToHashBranch localIds localBranch + & hashBranchFormatToH2Branch + & H2.contentHash + & BranchHash + hashPatchFormatFull localIds localPatch = + PatchFormat.localPatchToHashPatch localIds localPatch + & hashPatchFormatToH2Patch + & H2.contentHash + & PatchHash diff --git a/codebase2/codebase-sqlite-hashing-v2/src/Unison/Hashing/V2/Convert2.hs b/codebase2/codebase-sqlite-hashing-v2/src/Unison/Hashing/V2/Convert2.hs index 2c6c51c66a..f89a952770 100644 --- a/codebase2/codebase-sqlite-hashing-v2/src/Unison/Hashing/V2/Convert2.hs +++ b/codebase2/codebase-sqlite-hashing-v2/src/Unison/Hashing/V2/Convert2.hs @@ -4,24 +4,32 @@ module Unison.Hashing.V2.Convert2 v2ToH2Type, v2ToH2TypeD, h2ToV2Reference, + v2ToH2Referent, v2ToH2Branch, v2ToH2Term, + v2ToH2Decl, hashBranchFormatToH2Branch, + hashPatchFormatToH2Patch, ) where import Data.Map qualified as Map import Data.Set qualified as Set +import Data.Text qualified as Text import U.Codebase.Branch qualified as V2 import U.Codebase.Branch qualified as V2Branch import U.Codebase.BranchV3 (BranchV3 (..)) import U.Codebase.Causal qualified as Causal +import U.Codebase.Decl qualified as V2.Decl import U.Codebase.HashTags import U.Codebase.Kind qualified as V2 import U.Codebase.Reference qualified as V2 import U.Codebase.Reference qualified as V2Reference import U.Codebase.Referent qualified as V2Referent import U.Codebase.Sqlite.Branch.Full qualified as Memory.BranchFull +import U.Codebase.Sqlite.Patch.Full qualified as Memory.PatchFull +import U.Codebase.Sqlite.Patch.TermEdit qualified as Memory.TermEdit +import U.Codebase.Sqlite.Patch.TypeEdit qualified as Memory.TypeEdit import U.Codebase.Term qualified as V2 (TypeRef) import U.Codebase.Term qualified as V2.Term import U.Codebase.Type qualified as V2.Type @@ -30,6 +38,7 @@ import Unison.Hash (Hash) import Unison.Hashing.V2 qualified as H2 import Unison.NameSegment (NameSegment (..)) import Unison.Prelude +import Unison.Symbol qualified as Unison import Unison.Util.Map qualified as Map -- | Convert a V3 branch to a hashing branch. @@ -135,6 +144,29 @@ hashBranchFormatToH2Branch Memory.BranchFull.Branch {terms, types, patches, chil V2Referent.Con typeRef conId -> do (H2.ReferentCon (v2ToH2Reference $ second unComponentHash typeRef) conId) +hashPatchFormatToH2Patch :: Memory.PatchFull.HashPatch -> H2.Patch +hashPatchFormatToH2Patch Memory.PatchFull.Patch {termEdits, typeEdits} = + H2.Patch + { termEdits = Map.bimap cvreferent (Set.map cvTermEdit) termEdits, + typeEdits = Map.bimap cvreference (Set.map cvTypeEdit) typeEdits + } + where + cvTermEdit :: Memory.TermEdit.HashTermEdit -> H2.TermEdit + cvTermEdit = \case + Memory.TermEdit.Replace ref _typing -> H2.TermEditReplace (v2ToH2Referent . coerce $ ref) + Memory.TermEdit.Deprecate -> H2.TermEditDeprecate + cvTypeEdit :: Memory.TypeEdit.HashTypeEdit -> H2.TypeEdit + cvTypeEdit = \case + Memory.TypeEdit.Replace ref -> H2.TypeEditReplace (v2ToH2Reference . coerce $ ref) + Memory.TypeEdit.Deprecate -> H2.TypeEditDeprecate + cvreference :: V2Reference.Reference' Text ComponentHash -> H2.Reference + cvreference = v2ToH2Reference . second unComponentHash + cvreferent :: Memory.BranchFull.Referent'' Text ComponentHash -> H2.Referent + cvreferent = \case + V2Referent.Ref ref -> (H2.ReferentRef (v2ToH2Reference $ second unComponentHash ref)) + V2Referent.Con typeRef conId -> do + (H2.ReferentCon (v2ToH2Reference $ second unComponentHash typeRef) conId) + v2ToH2Term :: forall v. Ord v => V2.Term.HashableTerm v -> H2.Term v () v2ToH2Term = ABT.transform convertF where @@ -189,3 +221,27 @@ v2ToH2Term = ABT.transform convertF V2.Term.PCons -> H2.Cons V2.Term.PSnoc -> H2.Snoc V2.Term.PConcat -> H2.Concat + +v2ToH2Decl :: V2.Decl.HashableDecl Unison.Symbol -> H2.Decl Unison.Symbol () +v2ToH2Decl (V2.Decl.DataDeclaration {declType, modifier, bound, constructorTypes}) = + let tag = case declType of + V2.Decl.Effect -> Left . H2.EffectDeclaration + V2.Decl.Data -> Right + in tag $ + H2.DataDeclaration + { modifier = v2ToH2Modifier modifier, + annotation = (), + bound = bound, + constructors' = + constructorTypes + & zip [0 ..] + & fmap mkCtor + } + where + mkCtor :: (Int, V2.Type.TypeR V2.Decl.HashableTypeRef Unison.Symbol) -> ((), Unison.Symbol, H2.Type Unison.Symbol ()) + mkCtor (n, t) = ((), Unison.symbol . Text.pack $ "Constructor" ++ show n, v2ToH2Type t) + + v2ToH2Modifier :: V2.Decl.Modifier -> H2.Modifier + v2ToH2Modifier = \case + V2.Decl.Structural -> H2.Structural + V2.Decl.Unique t -> H2.Unique t diff --git a/codebase2/codebase-sqlite-hashing-v2/unison-codebase-sqlite-hashing-v2.cabal b/codebase2/codebase-sqlite-hashing-v2/unison-codebase-sqlite-hashing-v2.cabal index 0bdc069dc8..67e88874b7 100644 --- a/codebase2/codebase-sqlite-hashing-v2/unison-codebase-sqlite-hashing-v2.cabal +++ b/codebase2/codebase-sqlite-hashing-v2/unison-codebase-sqlite-hashing-v2.cabal @@ -21,6 +21,7 @@ library other-modules: U.Codebase.Branch.Hashing U.Codebase.Causal.Hashing + U.Codebase.Decl.Hashing U.Codebase.Term.Hashing Unison.Hashing.V2.Convert2 hs-source-dirs: @@ -69,6 +70,7 @@ library , unison-hashing-v2 , unison-prelude , unison-sqlite + , unison-syntax , unison-util-base32hex , unison-util-term , vector diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Format.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Format.hs index c64ac0f53c..ce07a487fb 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Format.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Format.hs @@ -11,6 +11,7 @@ module U.Codebase.Sqlite.Branch.Format localToDbBranch, localToDbDiff, localToHashBranch, + localToBranch, -- dbToLocalDiff, ) where diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Full.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Full.hs index f14d2325cd..7fbd2b77da 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Full.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Full.hs @@ -3,8 +3,8 @@ module U.Codebase.Sqlite.Branch.Full where import Control.Lens +import Data.Bitraversable import Data.Map.Strict qualified as Map -import Data.Set qualified as Set import U.Codebase.HashTags import U.Codebase.Reference (Reference', TermReference', TypeReference') import U.Codebase.Reference qualified as Reference @@ -91,13 +91,33 @@ metadataSetFormatReferences_ :: metadataSetFormatReferences_ f (Inline refs) = Inline <$> Set.traverse f refs quadmap :: forall t h p c t' h' p' c'. (Ord t', Ord h') => (t -> t') -> (h -> h') -> (p -> p') -> (c -> c') -> Branch' t h p c -> Branch' t' h' p' c' -quadmap ft fh fp fc (Branch terms types patches children) = +quadmap ft fh fp fc branch = + runIdentity $ quadmapM (Identity . ft) (Identity . fh) (Identity . fp) (Identity . fc) branch + +quadmapM :: forall t h p c t' h' p' c' m. (Ord t', Ord h', Applicative m) => (t -> m t') -> (h -> m h') -> (p -> m p') -> (c -> m c') -> Branch' t h p c -> m (Branch' t' h' p' c') +quadmapM ft fh fp fc (Branch terms types patches children) = Branch - (Map.bimap ft doTerms terms) - (Map.bimap ft doTypes types) - (Map.bimap ft fp patches) - (Map.bimap ft fc children) + <$> (Map.bitraverse ft doTerms terms) + <*> (Map.bitraverse ft doTypes types) + <*> (Map.bitraverse ft fp patches) + <*> (Map.bitraverse ft fc children) where - doTerms = Map.bimap (bimap (bimap ft fh) (bimap ft fh)) doMetadata - doTypes = Map.bimap (bimap ft fh) doMetadata - doMetadata (Inline s) = Inline . Set.map (bimap ft fh) $ s + doTerms = Map.bitraverse (bitraverse (bitraverse ft fh) (bitraverse ft fh)) doMetadata + doTypes = Map.bitraverse (bitraverse ft fh) doMetadata + doMetadata (Inline s) = Inline <$> Set.traverse (bitraverse ft fh) s + +-- | Traversal over text references in a branch +t_ :: (Ord t', Ord h) => Traversal (Branch' t h p c) (Branch' t' h p c) t t' +t_ f = quadmapM f pure pure pure + +-- | Traversal over hash references in a branch +h_ :: (Ord t, Ord h') => Traversal (Branch' t h p c) (Branch' t h' p c) h h' +h_ f = quadmapM pure f pure pure + +-- | Traversal over patch references in a branch +p_ :: (Ord t, Ord h) => Traversal (Branch' t h p c) (Branch' t h p' c) p p' +p_ f = quadmapM pure pure f pure + +-- | Traversal over child references in a branch +c_ :: (Ord t, Ord h) => Traversal (Branch' t h p c) (Branch' t h p c') c c' +c_ f = quadmapM pure pure pure f diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decl/Format.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decl/Format.hs index 76a3d1069d..5a6f401964 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decl/Format.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decl/Format.hs @@ -10,12 +10,18 @@ import U.Codebase.Sqlite.LocalIds (LocalDefnId, LocalIds', LocalTextId) import U.Codebase.Sqlite.Symbol (Symbol) import U.Codebase.Type qualified as Type import U.Core.ABT qualified as ABT +import Unison.Hash32 (Hash32) import Unison.Prelude -- | Add new formats here -data DeclFormat = Decl LocallyIndexedComponent +data DeclFormat' text defn = Decl (LocallyIndexedComponent' text defn) deriving (Show) +type DeclFormat = DeclFormat' TextId ObjectId + +-- | A DeclFormat which uses hash references instead of database ids. +type HashDeclFormat = DeclFormat' Text Hash32 + -- | V1: Decls included `Hash`es inline -- V2: Instead of `Hash`, we use a smaller index. type LocallyIndexedComponent = diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decode.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decode.hs index 4e31e66e89..afb2a54c26 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decode.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Decode.hs @@ -1,6 +1,6 @@ -- | This module contains decoders for blobs stored in SQLite. module U.Codebase.Sqlite.Decode - ( DecodeError, + ( DecodeError (..), -- * @object.bytes@ decodeBranchFormat, diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/HashHandle.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/HashHandle.hs index cd73192a30..028c4d827f 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/HashHandle.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/HashHandle.hs @@ -1,6 +1,7 @@ module U.Codebase.Sqlite.HashHandle ( HashHandle (..), HashMismatch (..), + DeclHashingError (..), ) where @@ -10,6 +11,9 @@ import U.Codebase.HashTags import U.Codebase.Reference qualified as C import U.Codebase.Sqlite.Branch.Format (HashBranchLocalIds) import U.Codebase.Sqlite.Branch.Full (LocalBranch) +import U.Codebase.Sqlite.Decl.Format qualified as DeclFormat +import U.Codebase.Sqlite.Patch.Format (HashPatchLocalIds) +import U.Codebase.Sqlite.Patch.Full (LocalPatch) import U.Codebase.Sqlite.Symbol (Symbol) import U.Codebase.Sqlite.Term.Format qualified as TermFormat import U.Codebase.Term qualified as C.Term @@ -22,6 +26,10 @@ data HashMismatch = HashMismatch actualHash :: Hash } +data DeclHashingError + = DeclHashMismatch HashMismatch + | DeclHashResolutionFailure + data HashHandle = HashHandle { -- | Hash type toReference :: C.Term.Type Symbol -> C.Reference, @@ -43,5 +51,16 @@ data HashHandle = HashHandle HashBranchLocalIds -> LocalBranch -> BranchHash, - verifyTermFormatHash :: ComponentHash -> TermFormat.HashTermFormat -> Maybe (HashMismatch) + hashPatchFormatFull :: + HashPatchLocalIds -> + LocalPatch -> + PatchHash, + verifyTermFormatHash :: + ComponentHash -> + TermFormat.HashTermFormat -> + Maybe (HashMismatch), + verifyDeclFormatHash :: + ComponentHash -> + DeclFormat.HashDeclFormat -> + Maybe DeclHashingError } diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalIds.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalIds.hs index 842d1a66a8..1cfd697365 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalIds.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalIds.hs @@ -2,8 +2,8 @@ module U.Codebase.Sqlite.LocalIds where +import Control.Lens import Data.Bifoldable (Bifoldable (bifoldMap)) -import Data.Bifunctor (Bifunctor (bimap)) import Data.Bitraversable (Bitraversable (bitraverse)) import Data.Bits (Bits) import Data.Vector (Vector) @@ -48,3 +48,9 @@ instance Bifoldable LocalIds' where instance Bifunctor LocalIds' where bimap f g (LocalIds t d) = LocalIds (f <$> t) (g <$> d) + +t_ :: Traversal (LocalIds' t h) (LocalIds' t' h) t t' +t_ f (LocalIds t d) = LocalIds <$> traverse f t <*> pure d + +h_ :: Traversal (LocalIds' t h) (LocalIds' t h') h h' +h_ f (LocalIds t d) = LocalIds <$> pure t <*> traverse f d diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalizeObject.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalizeObject.hs index 7524638dbc..74228c5d9b 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalizeObject.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalizeObject.hs @@ -1,3 +1,6 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} + -- | This module facilitates the creation of "localized" versions of objects, suitable for storage. -- -- Localization is a stateful process in which the real database identifiers contained within an object, e.g. 'DbBranch', are canonicalized @@ -24,21 +27,24 @@ -- where all terms, types, etc. within the @branch@ structure refer to offsets in the associated vectors. module U.Codebase.Sqlite.LocalizeObject ( localizeBranch, + localizeBranchG, localizePatch, + localizePatchG, ) where import Control.Lens -import Control.Monad.Trans.State.Strict (StateT) +import Control.Monad.State.Strict import Control.Monad.Trans.State.Strict qualified as State import Data.Bitraversable (bitraverse) -import Data.Generics.Product.Typed (HasType (typed)) +import Data.Generics.Product (HasField (..)) import Data.Map.Strict qualified as Map +import U.Codebase.Reference (Reference') +import U.Codebase.Referent (Referent') import U.Codebase.Sqlite.Branch.Format (BranchLocalIds) import U.Codebase.Sqlite.Branch.Format qualified as Branch import U.Codebase.Sqlite.Branch.Full (Branch' (..), DbBranch, LocalBranch) import U.Codebase.Sqlite.Branch.Full qualified as Branch -import U.Codebase.Sqlite.DbId (BranchObjectId, CausalHashId, HashId, ObjectId, PatchObjectId, TextId) import U.Codebase.Sqlite.LocalIds ( LocalBranchChildId (..), LocalDefnId (..), @@ -46,13 +52,13 @@ import U.Codebase.Sqlite.LocalIds LocalPatchObjectId (..), LocalTextId (..), ) -import U.Codebase.Sqlite.Patch.Format (PatchLocalIds) +import U.Codebase.Sqlite.Patch.Format (PatchLocalIds, PatchLocalIds') import U.Codebase.Sqlite.Patch.Format qualified as Patch import U.Codebase.Sqlite.Patch.Full (LocalPatch, Patch, Patch' (..)) -import U.Codebase.Sqlite.Patch.TermEdit (LocalTermEdit, TermEdit) -import U.Codebase.Sqlite.Patch.TypeEdit (LocalTypeEdit, TypeEdit) -import U.Codebase.Sqlite.Reference (LocalReference, LocalReferenceH, Reference, ReferenceH) -import U.Codebase.Sqlite.Referent (LocalReferent, LocalReferentH, Referent, ReferentH) +import U.Codebase.Sqlite.Patch.TermEdit (LocalTermEdit, TermEdit') +import U.Codebase.Sqlite.Patch.TypeEdit (LocalTypeEdit, TypeEdit') +import U.Codebase.Sqlite.Reference (LocalReference, LocalReferenceH) +import U.Codebase.Sqlite.Referent (LocalReferent, LocalReferentH) import Unison.Prelude import Unison.Util.Map qualified as Map import Unison.Util.Set qualified as Set @@ -62,7 +68,11 @@ import Unison.Util.Set qualified as Set -- | Localize a branch object. localizeBranch :: DbBranch -> (BranchLocalIds, LocalBranch) -localizeBranch (Branch terms types patches children) = +localizeBranch = localizeBranchG + +-- | Generalized form of 'localizeBranch'. +localizeBranchG :: forall t d p c. (Ord t, Ord d, Ord p, Ord c) => Branch' t d p c -> (Branch.BranchLocalIds' t d p c, LocalBranch) +localizeBranchG (Branch terms types patches children) = (runIdentity . runLocalizeBranch) do Branch <$> Map.bitraverse localizeText (Map.bitraverse localizeReferent localizeBranchMetadata) terms @@ -70,23 +80,28 @@ localizeBranch (Branch terms types patches children) = <*> Map.bitraverse localizeText localizePatchReference patches <*> Map.bitraverse localizeText localizeBranchReference children where - localizeBranchMetadata :: (ContainsDefns s, ContainsText s, Monad m) => Branch.DbMetadataSet -> StateT s m Branch.LocalMetadataSet + localizeBranchMetadata :: + Branch.MetadataSetFormat' t d -> + State (LocalizeBranchState t d p c) (Branch.MetadataSetFormat' LocalTextId LocalDefnId) localizeBranchMetadata (Branch.Inline refs) = Branch.Inline <$> Set.traverse localizeReference refs -- | Localize a patch object. localizePatch :: Patch -> (PatchLocalIds, LocalPatch) -localizePatch (Patch termEdits typeEdits) = +localizePatch = localizePatchG + +localizePatchG :: forall t h d. (Ord t, Ord h, Ord d) => Patch' t h d -> (PatchLocalIds' t h d, LocalPatch) +localizePatchG (Patch termEdits typeEdits) = (runIdentity . runLocalizePatch) do Patch <$> Map.bitraverse localizeReferentH (Set.traverse localizeTermEdit) termEdits <*> Map.bitraverse localizeReferenceH (Set.traverse localizeTypeEdit) typeEdits where - localizeTermEdit :: (ContainsText s, ContainsDefns s, Monad m) => TermEdit -> StateT s m LocalTermEdit + localizeTermEdit :: (TermEdit' t d) -> State (LocalizePatchState t h d) LocalTermEdit localizeTermEdit = bitraverse localizeText localizeDefn - localizeTypeEdit :: (ContainsText s, ContainsDefns s, Monad m) => TypeEdit -> StateT s m LocalTypeEdit + localizeTypeEdit :: TypeEdit' t d -> State (LocalizePatchState t h d) LocalTypeEdit localizeTypeEdit = bitraverse localizeText localizeDefn @@ -94,38 +109,51 @@ localizePatch (Patch termEdits typeEdits) = -- General-purpose localization -- Contains references to branch objects. -type ContainsBranches s = - HasType (Map (BranchObjectId, CausalHashId) LocalBranchChildId) s +class Ord c => ContainsBranches c s where + branches_ :: Lens' s (Map c LocalBranchChildId) -- Contains references to definition objects i.e. term/decl component objects. -type ContainsDefns s = - HasType (Map ObjectId LocalDefnId) s +class Ord d => ContainsDefns d s where + defns_ :: Lens' s (Map d LocalDefnId) -- Contains references to objects by their hash. -type ContainsHashes = - HasType (Map HashId LocalHashId) +class Ord h => ContainsHashes h s where + hashes_ :: Lens' s (Map h LocalHashId) -- Contains references to patch objects. -type ContainsPatches = - HasType (Map PatchObjectId LocalPatchObjectId) +class Ord p => ContainsPatches p s where + patches_ :: Lens' s (Map p LocalPatchObjectId) -- Contains text. -type ContainsText = - HasType (Map TextId LocalTextId) +class Ord t => ContainsText t s where + texts_ :: Lens' s (Map t LocalTextId) -- The inner state of the localization of a branch object. -type LocalizeBranchState = - ( Map TextId LocalTextId, - Map ObjectId LocalDefnId, - Map PatchObjectId LocalPatchObjectId, - Map (BranchObjectId, CausalHashId) LocalBranchChildId - ) +data LocalizeBranchState t d p c = LocalizeBranchState + { texts :: Map t LocalTextId, + defns :: Map d LocalDefnId, + patches :: Map p LocalPatchObjectId, + branches :: Map c LocalBranchChildId + } + deriving (Show, Generic) + +instance Ord t => ContainsText t (LocalizeBranchState t d p c) where + texts_ = field @"texts" + +instance Ord d => ContainsDefns d (LocalizeBranchState t d p c) where + defns_ = field @"defns" --- Run a computation that localizes a branch object, returning the local ids recorded within. -runLocalizeBranch :: (Monad m) => StateT LocalizeBranchState m a -> m (BranchLocalIds, a) +instance Ord p => ContainsPatches p (LocalizeBranchState t d p c) where + patches_ = field @"patches" + +instance Ord c => ContainsBranches c (LocalizeBranchState t d p c) where + branches_ = field @"branches" + +-- | Run a computation that localizes a branch object, returning the local ids recorded within. +runLocalizeBranch :: forall m t d p c a. (Monad m, Ord t, Ord d, Ord p, Ord c) => StateT (LocalizeBranchState t d p c) m a -> m (Branch.BranchLocalIds' t d p c, a) runLocalizeBranch action = do - (result, (localTexts, localDefns, localPatches, localChildren)) <- State.runStateT action (mempty @LocalizeBranchState) - let branchLocalIds :: BranchLocalIds + (result, (LocalizeBranchState localTexts localDefns localPatches localChildren)) <- State.runStateT action (LocalizeBranchState mempty mempty mempty mempty) + let branchLocalIds :: Branch.BranchLocalIds' t d p c branchLocalIds = Branch.LocalIds { Branch.branchTextLookup = Map.valuesVector (Map.swap localTexts), @@ -136,17 +164,27 @@ runLocalizeBranch action = do pure (branchLocalIds, result) -- The inner state of the localization of a patch object. -type LocalizePatchState = - ( Map TextId LocalTextId, - Map HashId LocalHashId, - Map ObjectId LocalDefnId - ) +data LocalizePatchState t h d = LocalizePatchState + { texts :: Map t LocalTextId, + hashes :: Map h LocalHashId, + defns :: Map d LocalDefnId + } + deriving (Show, Generic) + +instance Ord t => ContainsText t (LocalizePatchState t h d) where + texts_ = field @"texts" + +instance Ord h => ContainsHashes h (LocalizePatchState t h d) where + hashes_ = field @"hashes" + +instance Ord d => ContainsDefns d (LocalizePatchState t h d) where + defns_ = field @"defns" -- Run a computation that localizes a patch object, returning the local ids recorded within. -runLocalizePatch :: (Monad m) => StateT LocalizePatchState m a -> m (PatchLocalIds, a) +runLocalizePatch :: forall t h d a m. (Monad m, Ord t, Ord h, Ord d) => StateT (LocalizePatchState t h d) m a -> m (PatchLocalIds' t h d, a) runLocalizePatch action = do - (result, (localTexts, localHashes, localDefns)) <- State.runStateT action (mempty @LocalizePatchState) - let patchLocalIds :: PatchLocalIds + (result, (LocalizePatchState localTexts localHashes localDefns)) <- State.runStateT action (LocalizePatchState mempty mempty mempty) + let patchLocalIds :: PatchLocalIds' t h d patchLocalIds = Patch.LocalIds { Patch.patchTextLookup = Map.valuesVector (Map.swap localTexts), @@ -156,52 +194,52 @@ runLocalizePatch action = do pure (patchLocalIds, result) -- Localize a branch object reference in any monad that encapsulates the stateful localization of an object that contains branch references. -localizeBranchReference :: (ContainsBranches s, Monad m) => (BranchObjectId, CausalHashId) -> StateT s m LocalBranchChildId +localizeBranchReference :: (ContainsBranches c s, Monad m) => c -> StateT s m LocalBranchChildId localizeBranchReference = - zoom typed . localize + zoom branches_ . localize -- Localize a definition object reference in any monad that encapsulates the stateful localization of an object that contains definition -- references. -localizeDefn :: (ContainsDefns s, Monad m) => ObjectId -> StateT s m LocalDefnId +localizeDefn :: (ContainsDefns d s, Monad m) => d -> StateT s m LocalDefnId localizeDefn = - zoom typed . localize + zoom defns_ . localize -- Localize a hash reference in any monad that encapsulates the stateful localization of an object that contains hash references. -localizeHash :: (ContainsHashes s, Monad m) => HashId -> StateT s m LocalHashId +localizeHash :: (ContainsHashes h s, Monad m) => h -> StateT s m LocalHashId localizeHash = - zoom typed . localize + zoom hashes_ . localize -- Localize a patch object reference in any monad that encapsulates the stateful localization of an object that contains patch references. -localizePatchReference :: (ContainsPatches s, Monad m) => PatchObjectId -> StateT s m LocalPatchObjectId +localizePatchReference :: (ContainsPatches p s, Monad m) => p -> StateT s m LocalPatchObjectId localizePatchReference = - zoom typed . localize + zoom patches_ . localize -- Localize a reference in any monad that encapsulates the stateful localization of an object that contains references. -localizeReference :: (ContainsDefns s, ContainsText s, Monad m) => Reference -> StateT s m LocalReference +localizeReference :: (ContainsDefns d s, ContainsText t s, Monad m) => Reference' t d -> StateT s m LocalReference localizeReference = bitraverse localizeText localizeDefn -- Localize a possibly-missing reference in any monad that encapsulates the stateful localization of an object that contains -- possibly-missing references. -localizeReferenceH :: (ContainsHashes s, ContainsText s, Monad m) => ReferenceH -> StateT s m LocalReferenceH +localizeReferenceH :: (ContainsHashes h s, ContainsText t s, Monad m) => Reference' t h -> StateT s m LocalReferenceH localizeReferenceH = bitraverse localizeText localizeHash -- Localize a referent in any monad that encapsulates the stateful localization of an object that contains referents. -localizeReferent :: (ContainsDefns s, ContainsText s, Monad m) => Referent -> StateT s m LocalReferent +localizeReferent :: forall d t s m. (ContainsDefns d s, ContainsText t s, Monad m) => (Referent' (Reference' t d) (Reference' t d)) -> StateT s m LocalReferent localizeReferent = bitraverse localizeReference localizeReference -- Localize a possibly-missing referent in any monad that encapsulates the stateful localization of an object that contains possibly-missing -- referents. -localizeReferentH :: (ContainsHashes s, ContainsText s, Monad m) => ReferentH -> StateT s m LocalReferentH +localizeReferentH :: (ContainsHashes h s, ContainsText t s, Monad m, r ~ Reference' t h) => Referent' r r -> StateT s m LocalReferentH localizeReferentH = bitraverse localizeReferenceH localizeReferenceH -- Localize a text reference in any monad that encapsulates the stateful localization of an object that contains text. -localizeText :: (ContainsText s, Monad m) => TextId -> StateT s m LocalTextId +localizeText :: (ContainsText t s, Monad m) => t -> StateT s m LocalTextId localizeText = - zoom typed . localize + zoom texts_ . localize -- Resolve a real id to its corresponding local id, either by looking it up in a map, or else using the next available local id, which is -- recorded for next time. diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Format.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Format.hs index 263fec4bb9..7defa50234 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Format.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Format.hs @@ -2,11 +2,14 @@ module U.Codebase.Sqlite.Patch.Format ( PatchFormat (..), PatchLocalIds, PatchLocalIds' (..), + HashPatchLocalIds, SyncPatchFormat, SyncPatchFormat' (..), applyPatchDiffs, localPatchToPatch, + localPatchToPatch', localPatchDiffToPatchDiff, + localPatchToHashPatch, ) where @@ -14,11 +17,12 @@ import Data.Map.Strict qualified as Map import Data.Set qualified as Set import Data.Vector (Vector) import Data.Vector qualified as Vector +import U.Codebase.HashTags import U.Codebase.Sqlite.DbId (HashId, ObjectId, PatchObjectId, TextId) import U.Codebase.Sqlite.LocalIds (LocalDefnId (LocalDefnId), LocalHashId (LocalHashId), LocalTextId (LocalTextId)) import U.Codebase.Sqlite.Patch.Diff (LocalPatchDiff, PatchDiff, PatchDiff' (..)) import U.Codebase.Sqlite.Patch.Diff qualified as Patch.Diff -import U.Codebase.Sqlite.Patch.Full (LocalPatch, Patch, Patch' (..)) +import U.Codebase.Sqlite.Patch.Full (HashPatch, LocalPatch, Patch, Patch' (..)) import U.Codebase.Sqlite.Patch.Full qualified as Patch.Full import Unison.Prelude @@ -28,6 +32,9 @@ data PatchFormat type PatchLocalIds = PatchLocalIds' TextId HashId ObjectId +-- | LocalIds type which can be used in hashing the Patch. +type HashPatchLocalIds = PatchLocalIds' Text ComponentHash ComponentHash + data PatchLocalIds' t h d = LocalIds { patchTextLookup :: Vector t, patchHashLookup :: Vector h, @@ -64,10 +71,26 @@ applyPatchDiffs = let diff = Set.difference src del in if Set.null diff then Nothing else Just diff -localPatchToPatch :: PatchLocalIds -> LocalPatch -> Patch -localPatchToPatch li = +localToPatch' :: (Ord t, Ord h, Ord d) => PatchLocalIds' t h d -> (Patch' LocalTextId LocalHashId LocalDefnId) -> Patch' t h d +localToPatch' li = + Patch.Full.trimap (lookupPatchLocalText li) (lookupPatchLocalHash li) (lookupPatchLocalDefn li) + +-- | Generic version of `localPatchToPatch` that works with any `PatchLocalIds'`. +localPatchToPatch' :: + (Ord t, Ord h, Ord d) => + PatchLocalIds' t h d -> + Patch' LocalTextId LocalHashId LocalDefnId -> + Patch' t h d +localPatchToPatch' li = Patch.Full.trimap (lookupPatchLocalText li) (lookupPatchLocalHash li) (lookupPatchLocalDefn li) +-- | Type specialized version of `localToPatch'`. +localPatchToPatch :: PatchLocalIds -> LocalPatch -> Patch +localPatchToPatch = localToPatch' + +localPatchToHashPatch :: HashPatchLocalIds -> LocalPatch -> HashPatch +localPatchToHashPatch = localToPatch' + localPatchDiffToPatchDiff :: PatchLocalIds -> LocalPatchDiff -> PatchDiff localPatchDiffToPatchDiff li = Patch.Diff.trimap @@ -75,11 +98,11 @@ localPatchDiffToPatchDiff li = (lookupPatchLocalHash li) (lookupPatchLocalDefn li) -lookupPatchLocalText :: PatchLocalIds -> LocalTextId -> TextId +lookupPatchLocalText :: PatchLocalIds' t h d -> LocalTextId -> t lookupPatchLocalText li (LocalTextId w) = patchTextLookup li Vector.! fromIntegral w -lookupPatchLocalHash :: PatchLocalIds -> LocalHashId -> HashId +lookupPatchLocalHash :: PatchLocalIds' t h d -> LocalHashId -> h lookupPatchLocalHash li (LocalHashId w) = patchHashLookup li Vector.! fromIntegral w -lookupPatchLocalDefn :: PatchLocalIds -> LocalDefnId -> ObjectId +lookupPatchLocalDefn :: PatchLocalIds' t h d -> LocalDefnId -> d lookupPatchLocalDefn li (LocalDefnId w) = patchDefnLookup li Vector.! fromIntegral w diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Full.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Full.hs index 7f3252848b..b2f1366932 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Full.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Full.hs @@ -1,9 +1,12 @@ module U.Codebase.Sqlite.Patch.Full where import Control.Lens +import Data.Bitraversable (Bitraversable, bitraverse) import Data.Map (Map) import Data.Set (Set) import Data.Set qualified as Set +import Data.Text (Text) +import U.Codebase.HashTags import U.Codebase.Reference (Reference') import U.Codebase.Reference qualified as Reference import U.Codebase.Referent (Referent') @@ -26,6 +29,9 @@ import Unison.Util.Set qualified as Set -- @ type Patch = Patch' Db.TextId Db.HashId Db.ObjectId +-- | A version of Patch' which can be used for hashing. +type HashPatch = Patch' Text ComponentHash ComponentHash + -- | -- @ -- LocalPatch @@ -42,6 +48,16 @@ data Patch' t h o = Patch typeEdits :: Map (Reference' t h) (Set (TypeEdit' t o)) } +patchT_ :: (Ord t', Ord h, Ord o) => Traversal (Patch' t h o) (Patch' t' h o) t t' +patchT_ f Patch {termEdits, typeEdits} = do + newTermEdits <- + traverseOf (Map.bitraversed (Referent.refs_ . Reference.t_) (Set.traverse . traverseFirst)) f termEdits + newTypeEdits <- traverseOf (Map.bitraversed (Reference.t_) (Set.traverse . traverseFirst)) f typeEdits + pure Patch {termEdits = newTermEdits, typeEdits = newTypeEdits} + where + traverseFirst :: Bitraversable b => Traversal (b a c) (b a' c) a a' + traverseFirst f = bitraverse f pure + patchH_ :: (Ord t, Ord h') => Traversal (Patch' t h o) (Patch' t h' o) h h' patchH_ f Patch {termEdits, typeEdits} = do newTermEdits <- termEdits & Map.traverseKeys . Referent.refs_ . Reference.h_ %%~ f diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TermEdit.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TermEdit.hs index 4b07b975b0..bc93dd166c 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TermEdit.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TermEdit.hs @@ -3,6 +3,8 @@ module U.Codebase.Sqlite.Patch.TermEdit where import Control.Lens import Data.Bifoldable (Bifoldable (bifoldMap)) import Data.Bitraversable (Bitraversable (bitraverse)) +import Data.Text (Text) +import U.Codebase.HashTags import U.Codebase.Reference (Reference') import U.Codebase.Reference qualified as Reference import U.Codebase.Referent qualified as Referent @@ -11,6 +13,8 @@ import U.Codebase.Sqlite.LocalIds (LocalDefnId, LocalTextId) type TermEdit = TermEdit' Db.TextId Db.ObjectId +type HashTermEdit = TermEdit' Text ComponentHash + type LocalTermEdit = TermEdit' LocalTextId LocalDefnId type Referent' t h = Referent.Referent' (Reference' t h) (Reference' t h) diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TypeEdit.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TypeEdit.hs index 9223812532..6b8d3ea48c 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TypeEdit.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/TypeEdit.hs @@ -3,6 +3,8 @@ module U.Codebase.Sqlite.Patch.TypeEdit where import Control.Lens import Data.Bifoldable (Bifoldable (bifoldMap)) import Data.Bitraversable (Bitraversable (bitraverse)) +import Data.Text (Text) +import U.Codebase.HashTags import U.Codebase.Reference (Reference') import U.Codebase.Reference qualified as Reference import U.Codebase.Sqlite.DbId qualified as Db @@ -12,6 +14,8 @@ type LocalTypeEdit = TypeEdit' LocalTextId LocalDefnId type TypeEdit = TypeEdit' Db.TextId Db.ObjectId +type HashTypeEdit = TypeEdit' Text ComponentHash + data TypeEdit' t h = Replace (Reference' t h) | Deprecate deriving (Eq, Ord, Show) diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Queries.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Queries.hs index 98e645b367..f96ce2517b 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Queries.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Queries.hs @@ -273,6 +273,7 @@ module U.Codebase.Sqlite.Queries schemaVersion, x2cTType, x2cTerm, + x2cDecl, checkBranchExistsForCausalHash, -- * Types @@ -2791,6 +2792,7 @@ data EntityLocation EntityInMainStorage | -- | `temp_entity` EntityInTempStorage + deriving (Eq, Show, Ord) -- | Where is an entity stored? entityLocation :: Hash32 -> Transaction (Maybe EntityLocation) @@ -3045,9 +3047,12 @@ saveTermComponent hh@HashHandle {toReference, toReferenceMentions} maybeEncodedT -- | Unlocalize a decl. s2cDecl :: LocalIds -> S.Decl.Decl Symbol -> Transaction (C.Decl Symbol) -s2cDecl ids (C.Decl.DataDeclaration dt m b ct) = do +s2cDecl ids decl = do substTypeRef <- localIdsToTypeRefLookup ids - pure (C.Decl.DataDeclaration dt m b (C.Type.rmap substTypeRef <$> ct)) + pure $ x2cDecl substTypeRef decl + +x2cDecl :: (r -> r1) -> (C.Decl.DeclR r Symbol -> C.Decl.DeclR r1 Symbol) +x2cDecl substTypeRef (C.Decl.DataDeclaration dt m b ct) = C.Decl.DataDeclaration dt m b (C.Type.rmap substTypeRef <$> ct) saveDeclComponent :: HashHandle -> diff --git a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Serialization.hs b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Serialization.hs index e04ac9b5bc..b6207ef2d6 100644 --- a/codebase2/codebase-sqlite/U/Codebase/Sqlite/Serialization.hs +++ b/codebase2/codebase-sqlite/U/Codebase/Sqlite/Serialization.hs @@ -12,12 +12,14 @@ module U.Codebase.Sqlite.Serialization getDeclElementNumConstructors, getDeclFormat, getPatchFormat, + getLocalPatch, getTempCausalFormat, getTempDeclFormat, getTempNamespaceFormat, getTempPatchFormat, getTempTermFormat, getTermAndType, + getTypeFromTermAndType, getTermFormat, getWatchResultFormat, lookupDeclElement, @@ -36,6 +38,16 @@ module U.Codebase.Sqlite.Serialization recomposePatchFormat, recomposeTermFormat, recomposeWatchFormat, + + -- * Exported for Share + putTermAndType, + putSingleTerm, + putDeclElement, + getSingleTerm, + putLocalIdsWith, + getLocalIdsWith, + putLocalBranch, + putLocalPatch, ) where @@ -153,7 +165,7 @@ putLocalIdsWith putText putDefn LocalIds {textLookup, defnLookup} = do putFoldable putText textLookup putFoldable putDefn defnLookup -getLocalIds :: (MonadGet m) => m LocalIds +getLocalIds :: (MonadGet m, Num t, Bits t, Num h, Bits h) => m (LocalIds' t h) getLocalIds = getLocalIdsWith getVarInt getVarInt skipLocalIds :: (MonadGet m) => m () @@ -182,12 +194,12 @@ putWatchResultFormat = \case TermFormat.WatchResult ids t -> do putWord8 0 putLocalIds ids - putTerm t + putSingleTerm t getWatchResultFormat :: (MonadGet m) => m TermFormat.WatchResultFormat getWatchResultFormat = getWord8 >>= \case - 0 -> TermFormat.WatchResult <$> getWatchLocalIds <*> getTerm + 0 -> TermFormat.WatchResult <$> getWatchLocalIds <*> getSingleTerm other -> unknownTag "getWatchResultFormat" other putTermFormat :: (MonadPut m) => TermFormat.TermFormat -> m () @@ -208,13 +220,18 @@ putTermComponent t | debug && trace ("putTermComponent " ++ show t) False = unde putTermComponent (TermFormat.LocallyIndexedComponent v) = putFramedArray ( \(localIds, term, typ) -> - putLocalIds localIds >> putFramed putTerm term >> putTType typ + putLocalIds localIds >> putTermAndType (term, typ) ) v -putTerm :: (MonadPut m) => TermFormat.Term -> m () -putTerm _t | debug && trace "putTerm" False = undefined -putTerm t = putABT putSymbol putUnit putF t +putTermAndType :: (MonadPut m) => (TermFormat.Term, TermFormat.Type) -> m () +putTermAndType (term, typ) = putFramed putSingleTerm term >> putTType typ + +-- | Encode a single term without its type or component. +-- Don't use this on its own unless you're encoding a watch result. +putSingleTerm :: (MonadPut m) => TermFormat.Term -> m () +putSingleTerm _t | debug && trace "putSingleTerm" False = undefined +putSingleTerm t = putABT putSymbol putUnit putF t where putF :: (MonadPut m) => (a -> m ()) -> TermFormat.F a -> m () putF putChild = \case @@ -303,13 +320,19 @@ putTerm t = putABT putSymbol putUnit putF t getTermComponent :: (MonadGet m) => m TermFormat.LocallyIndexedComponent getTermComponent = TermFormat.LocallyIndexedComponent - <$> getFramedArray (getTuple3 getLocalIds (getFramed getTerm) getTType) + <$> getFramedArray (getTuple3 getLocalIds (getFramed getSingleTerm) getTermElementType) getTermAndType :: (MonadGet m) => m (TermFormat.Term, TermFormat.Type) -getTermAndType = (,) <$> getFramed getTerm <*> getTType +getTermAndType = (,) <$> getFramed getSingleTerm <*> getTermElementType + +-- | Decode ONLY the type of a term-component element. +-- This is useful during sync and when we need the type of a term component element but don't +-- want to decode the whole term (which can be expensive). +getTypeFromTermAndType :: (MonadGet m) => m (TermFormat.Type) +getTypeFromTermAndType = skipFramed *> getTermElementType -getTerm :: (MonadGet m) => m TermFormat.Term -getTerm = getABT getSymbol getUnit getF +getSingleTerm :: (MonadGet m) => m TermFormat.Term +getSingleTerm = getABT getSymbol getUnit getF where getF :: (MonadGet m) => m a -> m (TermFormat.F a) getF getChild = @@ -340,7 +363,7 @@ getTerm = getABT getSymbol getUnit getF 19 -> Term.Char <$> getChar 20 -> Term.TermLink <$> getReferent 21 -> Term.TypeLink <$> getReference - tag -> unknownTag "getTerm" tag + tag -> unknownTag "getSingleTerm" tag where getReferent :: (MonadGet m) => m (Referent' TermFormat.TermRef TermFormat.TypeRef) getReferent = @@ -387,23 +410,24 @@ getTerm = getABT getSymbol getUnit getF lookupTermElement :: (MonadGet m) => Reference.Pos -> m (LocalIds, TermFormat.Term, TermFormat.Type) lookupTermElement i = getWord8 >>= \case - 0 -> unsafeFramedArrayLookup (getTuple3 getLocalIds (getFramed getTerm) getTType) $ fromIntegral i + 0 -> unsafeFramedArrayLookup (getTuple3 getLocalIds (getFramed getSingleTerm) getTermElementType) $ fromIntegral i tag -> unknownTag "lookupTermElement" tag lookupTermElementDiscardingType :: (MonadGet m) => Reference.Pos -> m (LocalIds, TermFormat.Term) lookupTermElementDiscardingType i = getWord8 >>= \case - 0 -> unsafeFramedArrayLookup ((,) <$> getLocalIds <*> getFramed getTerm) $ fromIntegral i + 0 -> unsafeFramedArrayLookup ((,) <$> getLocalIds <*> getFramed getSingleTerm) $ fromIntegral i tag -> unknownTag "lookupTermElementDiscardingType" tag lookupTermElementDiscardingTerm :: (MonadGet m) => Reference.Pos -> m (LocalIds, TermFormat.Type) lookupTermElementDiscardingTerm i = getWord8 >>= \case - 0 -> unsafeFramedArrayLookup ((,) <$> getLocalIds <* skipFramed <*> getTType) $ fromIntegral i + 0 -> unsafeFramedArrayLookup ((,) <$> getLocalIds <* skipFramed <*> getTermElementType) $ fromIntegral i tag -> unknownTag "lookupTermElementDiscardingTerm" tag -getTType :: (MonadGet m) => m TermFormat.Type -getTType = getType getReference +-- | Decode a type which is stored alongisde a term-component element. +getTermElementType :: (MonadGet m) => m TermFormat.Type +getTermElementType = getType getReference getType :: forall m r. (MonadGet m) => m r -> m (Type.TypeR r Symbol) getType getReference = getABT getSymbol getUnit go @@ -436,16 +460,18 @@ putDeclFormat = \case putDeclComponent t | debug && trace ("putDeclComponent " ++ show t) False = undefined putDeclComponent (DeclFormat.LocallyIndexedComponent v) = putFramedArray (putPair putLocalIds putDeclElement) v - where - putDeclElement Decl.DataDeclaration {..} = do - putDeclType declType - putModifier modifier - putFoldable putSymbol bound - putFoldable putDType constructorTypes - putDeclType Decl.Data = putWord8 0 - putDeclType Decl.Effect = putWord8 1 - putModifier Decl.Structural = putWord8 0 - putModifier (Decl.Unique t) = putWord8 1 *> putText t + +putDeclElement :: MonadPut m => Decl.DeclR DeclFormat.TypeRef Symbol -> m () +putDeclElement Decl.DataDeclaration {..} = do + putDeclType declType + putModifier modifier + putFoldable putSymbol bound + putFoldable putDType constructorTypes + where + putDeclType Decl.Data = putWord8 0 + putDeclType Decl.Effect = putWord8 1 + putModifier Decl.Structural = putWord8 0 + putModifier (Decl.Unique t) = putWord8 1 *> putText t getDeclFormat :: (MonadGet m) => m DeclFormat.DeclFormat getDeclFormat = @@ -512,21 +538,13 @@ putBranchFormat b = case b of BranchFormat.Full li b -> do putWord8 0 putBranchLocalIds li - putBranchFull b + putLocalBranch b BranchFormat.Diff r li d -> do putWord8 1 putVarInt r putBranchLocalIds li putBranchDiff d where - putBranchFull (BranchFull.Branch terms types patches children) = do - putMap putVarInt (putMap putReferent putMetadataSetFormat) terms - putMap putVarInt (putMap putReference putMetadataSetFormat) types - putMap putVarInt putVarInt patches - putMap putVarInt putVarInt children - where - putMetadataSetFormat (BranchFull.Inline s) = - putWord8 0 *> putFoldable putReference s putBranchDiff (BranchDiff.Diff terms types patches children) = do putMap putVarInt (putMap putReferent putDiffOp) terms putMap putVarInt (putMap putReference putDiffOp) types @@ -548,6 +566,16 @@ putBranchFormat b = case b of BranchDiff.ChildRemove -> putWord8 0 BranchDiff.ChildAddReplace b -> putWord8 1 *> putVarInt b +putLocalBranch :: (MonadPut m) => BranchFull.LocalBranch -> m () +putLocalBranch (BranchFull.Branch terms types patches children) = do + putMap putVarInt (putMap putReferent putMetadataSetFormat) terms + putMap putVarInt (putMap putReference putMetadataSetFormat) types + putMap putVarInt putVarInt patches + putMap putVarInt putVarInt children + where + putMetadataSetFormat (BranchFull.Inline s) = + putWord8 0 *> putFoldable putReference s + putBranchLocalIds :: (MonadPut m) => BranchFormat.BranchLocalIds -> m () putBranchLocalIds (BranchFormat.LocalIds ts os ps cs) = do putFoldable putVarInt ts @@ -560,7 +588,7 @@ putPatchFormat = \case PatchFormat.Full ids p -> do putWord8 0 putPatchLocalIds ids - putPatchFull p + putLocalPatch p PatchFormat.Diff r ids p -> do putWord8 1 putVarInt r @@ -570,15 +598,10 @@ putPatchFormat = \case getPatchFormat :: (MonadGet m) => m PatchFormat.PatchFormat getPatchFormat = getWord8 >>= \case - 0 -> PatchFormat.Full <$> getPatchLocalIds <*> getPatchFull + 0 -> PatchFormat.Full <$> getPatchLocalIds <*> getLocalPatch 1 -> PatchFormat.Diff <$> getVarInt <*> getPatchLocalIds <*> getPatchDiff x -> unknownTag "getPatchFormat" x where - getPatchFull :: (MonadGet m) => m PatchFull.LocalPatch - getPatchFull = - PatchFull.Patch - <$> getMap getReferent (getSet getTermEdit) - <*> getMap getReference (getSet getTypeEdit) getPatchDiff :: (MonadGet m) => m PatchDiff.LocalPatchDiff getPatchDiff = PatchDiff.PatchDiff @@ -586,25 +609,34 @@ getPatchFormat = <*> getMap getReference (getSet getTypeEdit) <*> getMap getReferent (getSet getTermEdit) <*> getMap getReference (getSet getTypeEdit) - getTermEdit :: (MonadGet m) => m TermEdit.LocalTermEdit - getTermEdit = - getWord8 >>= \case - 0 -> pure TermEdit.Deprecate - 1 -> TermEdit.Replace <$> getReferent <*> getTyping - x -> unknownTag "getTermEdit" x - getTyping :: (MonadGet m) => m TermEdit.Typing - getTyping = - getWord8 >>= \case - 0 -> pure TermEdit.Same - 1 -> pure TermEdit.Subtype - 2 -> pure TermEdit.Different - x -> unknownTag "getTyping" x - getTypeEdit :: (MonadGet m) => m TypeEdit.LocalTypeEdit - getTypeEdit = - getWord8 >>= \case - 0 -> pure TypeEdit.Deprecate - 1 -> TypeEdit.Replace <$> getReference - x -> unknownTag "getTypeEdit" x + +getLocalPatch :: (MonadGet m) => m PatchFull.LocalPatch +getLocalPatch = + PatchFull.Patch + <$> getMap getReferent (getSet getTermEdit) + <*> getMap getReference (getSet getTypeEdit) + +getTermEdit :: (MonadGet m) => m TermEdit.LocalTermEdit +getTermEdit = + getWord8 >>= \case + 0 -> pure TermEdit.Deprecate + 1 -> TermEdit.Replace <$> getReferent <*> getTyping + x -> unknownTag "getTermEdit" x + +getTyping :: (MonadGet m) => m TermEdit.Typing +getTyping = + getWord8 >>= \case + 0 -> pure TermEdit.Same + 1 -> pure TermEdit.Subtype + 2 -> pure TermEdit.Different + x -> unknownTag "getTyping" x + +getTypeEdit :: (MonadGet m) => m TypeEdit.LocalTypeEdit +getTypeEdit = + getWord8 >>= \case + 0 -> pure TypeEdit.Deprecate + 1 -> TypeEdit.Replace <$> getReference + x -> unknownTag "getTypeEdit" x getPatchLocalIds :: (MonadGet m) => m PatchFormat.PatchLocalIds getPatchLocalIds = @@ -613,8 +645,8 @@ getPatchLocalIds = <*> getVector getVarInt <*> getVector getVarInt -putPatchFull :: (MonadPut m) => PatchFull.LocalPatch -> m () -putPatchFull (PatchFull.Patch termEdits typeEdits) = do +putLocalPatch :: (MonadPut m) => PatchFull.LocalPatch -> m () +putLocalPatch (PatchFull.Patch termEdits typeEdits) = do putMap putReferent (putFoldable putTermEdit) termEdits putMap putReference (putFoldable putTypeEdit) typeEdits diff --git a/codebase2/codebase/U/Codebase/Branch/Type.hs b/codebase2/codebase/U/Codebase/Branch/Type.hs index 17ddbd4474..0944f0fd6b 100644 --- a/codebase2/codebase/U/Codebase/Branch/Type.hs +++ b/codebase2/codebase/U/Codebase/Branch/Type.hs @@ -1,5 +1,3 @@ -{-# LANGUAGE RecordWildCards #-} - module U.Codebase.Branch.Type ( Branch (..), CausalBranch, @@ -12,8 +10,6 @@ module U.Codebase.Branch.Type childAt, hoist, hoistCausalBranch, - termMetadata, - typeMetadata, U.Codebase.Branch.Type.empty, ) where @@ -105,26 +101,3 @@ hoistCausalBranch f cb = cb & Causal.hoist f & Causal.emap (hoist f) (hoist f) - --- | Returns all the metadata value references that are attached to a term with the provided name in the --- provided branch. --- --- If only name is specified, metadata will be returned for all terms at that name. -termMetadata :: (Monad m) => Branch m -> NameSegment -> Maybe Referent -> m [Map MetadataValue MetadataType] -termMetadata Branch {terms} = metadataHelper terms - --- | Returns all the metadata value references that are attached to a type with the provided name in the --- provided branch. --- --- If only name is specified, metadata will be returned for all types at that name. -typeMetadata :: (Monad m) => Branch m -> NameSegment -> Maybe Reference -> m [Map MetadataValue MetadataType] -typeMetadata Branch {types} = metadataHelper types - -metadataHelper :: (Monad m, Ord ref) => Map NameSegment (Map ref (m MdValues)) -> NameSegment -> Maybe ref -> m [Map MetadataValue MetadataType] -metadataHelper t ns mayQualifier = do - case Map.lookup ns t of - Nothing -> pure [] - Just allRefsAtName -> do - case mayQualifier of - Nothing -> (fmap . fmap) unMdValues . sequenceA $ Map.elems allRefsAtName - Just qualifier -> (fmap . fmap) unMdValues . sequenceA . maybeToList $ Map.lookup qualifier allRefsAtName diff --git a/codebase2/codebase/U/Codebase/Decl.hs b/codebase2/codebase/U/Codebase/Decl.hs index e725150041..26172ed1db 100644 --- a/codebase2/codebase/U/Codebase/Decl.hs +++ b/codebase2/codebase/U/Codebase/Decl.hs @@ -1,8 +1,15 @@ module U.Codebase.Decl where +import Control.Lens hiding (List) +import Control.Monad.State +import Data.Map qualified as Map +import Data.Set qualified as Set import U.Codebase.Reference (Reference') +import U.Codebase.Reference qualified as Reference import U.Codebase.Type (TypeR) import U.Codebase.Type qualified as Type +import U.Core.ABT qualified as ABT +import U.Core.ABT.Var qualified as ABT import Unison.Hash (Hash) import Unison.Prelude @@ -13,10 +20,16 @@ data DeclType = Data | Effect type Decl v = DeclR TypeRef v +type HashableDecl v = DeclR HashableTypeRef v + type TypeRef = Reference' Text (Maybe Hash) +type HashableTypeRef = Reference' Text Hash + type Type v = TypeR TypeRef v +type HashableType v = TypeR HashableTypeRef v + data Modifier = Structural | Unique Text deriving (Eq, Ord, Show) @@ -28,6 +41,28 @@ data DeclR r v = DataDeclaration } deriving (Show) +allVars :: Ord v => DeclR r v -> Set v +allVars (DataDeclaration _ _ bound constructorTypes) = + (Set.fromList $ foldMap ABT.allVars constructorTypes) <> Set.fromList bound + +vmap :: Ord v' => (v -> v') -> DeclR r v -> DeclR r v' +vmap f (DataDeclaration {declType, modifier, bound, constructorTypes}) = + DataDeclaration + { declType, + modifier, + bound = f <$> bound, + constructorTypes = ABT.vmap f <$> constructorTypes + } + +rmap :: (Ord v) => (r -> r') -> DeclR r v -> DeclR r' v +rmap f (DataDeclaration {declType, modifier, bound, constructorTypes}) = + DataDeclaration + { declType, + modifier, + bound, + constructorTypes = Type.rmap f <$> constructorTypes + } + -- * Hashing stuff dependencies :: (Ord r, Ord v) => DeclR r v -> Set r @@ -41,3 +76,71 @@ data F a | Constructors [a] | Modified DeclType Modifier a deriving (Functor, Foldable, Show) + +-- | Given the pieces of a single decl component, +-- replaces all 'Nothing' self-referential hashes with a variable reference +-- to the relevant piece of the component in the component map. +unhashComponent :: + forall v extra. + ABT.Var v => + Hash -> + -- | A function to convert a reference to a variable. The actual var names aren't important. + (Reference.Id -> v) -> + -- A SINGLE decl component. Self references should have a 'Nothing' hash in term + -- references/term links + Map Reference.Id (Decl v, extra) -> + -- | The component with all self-references replaced with variable references. + Map Reference.Id (v, HashableDecl v, extra) +unhashComponent componentHash refToVar m = + withGeneratedVars + & traversed . _2 %~ fillSelfReferences + where + usedVars :: Set v + usedVars = foldMapOf (folded . _1) allVars m + withGeneratedVars :: Map Reference.Id (v, Decl v, extra) + withGeneratedVars = evalState (Map.traverseWithKey assignVar m) usedVars + assignVar :: Reference.Id -> (trm, extra) -> StateT (Set v) Identity (v, trm, extra) + assignVar r (trm, extra) = (,trm,extra) <$> ABT.freshenS (refToVar r) + fillSelfReferences :: Decl v -> HashableDecl v + fillSelfReferences DataDeclaration {declType, modifier, bound, constructorTypes} = + DataDeclaration + { declType, + modifier, + bound, + constructorTypes = ABT.cata alg <$> constructorTypes + } + where + rewriteTypeReference :: Reference.Id' (Maybe Hash) -> Either v Reference.Reference + rewriteTypeReference rid@(Reference.Id mayH pos) = + case mayH of + Just h -> + case Map.lookup (Reference.Id h pos) withGeneratedVars of + -- No entry in the component map, so this is NOT a self-reference, keep it but + -- replace the 'Maybe Hash' with a 'Hash'. + Nothing -> Right (Reference.ReferenceDerived (Reference.Id h pos)) + -- Entry in the component map, so this is a self-reference, replace it with a + -- Var. + Just (v, _, _) -> Left v + Nothing -> + -- This is a self-reference, so we expect to find it in the component map. + case Map.lookup (fromMaybe componentHash <$> rid) withGeneratedVars of + Nothing -> error "unhashComponent: self-reference not found in component map" + Just (v, _, _) -> Left v + alg :: () -> ABT.ABT (Type.F' TypeRef) v (HashableType v) -> HashableType v + alg () = \case + ABT.Var v -> ABT.var () v + ABT.Cycle body -> ABT.cycle () body + ABT.Abs v body -> ABT.abs () v body + ABT.Tm t -> case t of + Type.Ref (Reference.ReferenceDerived rid) -> + rewriteTypeReference rid + & either (ABT.var ()) (ABT.tm () . Type.Ref) + Type.Ref (Reference.ReferenceBuiltin t) -> + ABT.tm () $ Type.Ref (Reference.ReferenceBuiltin t) + Type.Arrow a b -> ABT.tm () $ Type.Arrow a b + Type.Ann a k -> ABT.tm () $ Type.Ann a k + Type.App a b -> ABT.tm () $ Type.App a b + Type.Effect a b -> ABT.tm () $ Type.Effect a b + Type.Effects as -> ABT.tm () $ Type.Effects as + Type.Forall a -> ABT.tm () $ Type.Forall a + Type.IntroOuter a -> ABT.tm () $ Type.IntroOuter a diff --git a/codebase2/codebase/U/Codebase/Referent.hs b/codebase2/codebase/U/Codebase/Referent.hs index 292e189e7b..0b7fb0233a 100644 --- a/codebase2/codebase/U/Codebase/Referent.hs +++ b/codebase2/codebase/U/Codebase/Referent.hs @@ -31,11 +31,11 @@ data Referent' termRef typeRef refs_ :: Traversal (Referent' ref ref) (Referent' ref' ref') ref ref' refs_ f r = bitraverse f f r -typeRef_ :: Traversal (Referent' typeRef termRef) (Referent' typeRef' termRef) typeRef typeRef' -typeRef_ f = bitraverse f pure +typeRef_ :: Traversal (Referent' termRef typeRef) (Referent' termRef typeRef') typeRef typeRef' +typeRef_ f = bitraverse pure f -termRef_ :: Traversal (Referent' typeRef termRef) (Referent' typeRef termRef') termRef termRef' -termRef_ f = bitraverse pure f +termRef_ :: Traversal (Referent' termRef typeRef) (Referent' termRef' typeRef) termRef termRef' +termRef_ f = bitraverse f pure _Ref :: Prism (Referent' tmr tyr) (Referent' tmr' tyr) tmr tmr' _Ref = _Ctor @"Ref" diff --git a/codebase2/codebase/U/Codebase/Term.hs b/codebase2/codebase/U/Codebase/Term.hs index fc7f55cc73..3af9a5faff 100644 --- a/codebase2/codebase/U/Codebase/Term.hs +++ b/codebase2/codebase/U/Codebase/Term.hs @@ -144,55 +144,87 @@ extraMap :: (vt -> vt') -> ABT.Term (F' text termRef typeRef termLink typeLink vt) v a -> ABT.Term (F' text' termRef' typeRef' termLink' typeLink' vt') v a -extraMap ftext ftermRef ftypeRef ftermLink ftypeLink fvt = go' +extraMap ftext ftermRef ftypeRef ftermLink ftypeLink fvt t = + runIdentity $ extraMapM (pure . ftext) (pure . ftermRef) (pure . ftypeRef) (pure . ftermLink) (pure . ftypeLink) (pure . fvt) t + +extraMapM :: + forall + m + text + termRef + typeRef + termLink + typeLink + vt + text' + termRef' + typeRef' + termLink' + typeLink' + vt' + v + a. + (Ord v, Ord vt', Monad m) => + (text -> m text') -> + (termRef -> m termRef') -> + (typeRef -> m typeRef') -> + (termLink -> m termLink') -> + (typeLink -> m typeLink') -> + (vt -> m vt') -> + ABT.Term (F' text termRef typeRef termLink typeLink vt) v a -> + m (ABT.Term (F' text' termRef' typeRef' termLink' typeLink' vt') v a) +extraMapM ftext ftermRef ftypeRef ftermLink ftypeLink fvt = go' where - go' = ABT.transform go - go :: forall x. F' text termRef typeRef termLink typeLink vt x -> F' text' termRef' typeRef' termLink' typeLink' vt' x + go' = ABT.transformM go + go :: forall x. F' text termRef typeRef termLink typeLink vt x -> m (F' text' termRef' typeRef' termLink' typeLink' vt' x) go = \case - Int i -> Int i - Nat n -> Nat n - Float d -> Float d - Boolean b -> Boolean b - Text t -> Text (ftext t) - Char c -> Char c - Ref r -> Ref (ftermRef r) - Constructor r cid -> Constructor (ftypeRef r) cid - Request r cid -> Request (ftypeRef r) cid - Handle e h -> Handle e h - App f a -> App f a - Ann a typ -> Ann a (Type.rmap ftypeRef $ ABT.vmap fvt typ) - List s -> List s - If c t f -> If c t f - And p q -> And p q - Or p q -> Or p q - Lam b -> Lam b - LetRec bs b -> LetRec bs b - Let a b -> Let a b - Match s cs -> Match s (goCase <$> cs) - TermLink r -> TermLink (ftermLink r) - TypeLink r -> TypeLink (ftypeLink r) - goCase :: MatchCase text typeRef x -> MatchCase text' typeRef' x - goCase (MatchCase p g b) = MatchCase (goPat p) g b - goPat = rmapPattern ftext ftypeRef + Int i -> pure $ Int i + Nat n -> pure $ Nat n + Float d -> pure $ Float d + Boolean b -> pure $ Boolean b + Text t -> Text <$> ftext t + Char c -> pure $ Char c + Ref r -> Ref <$> ftermRef r + Constructor r cid -> Constructor <$> (ftypeRef r) <*> pure cid + Request r cid -> Request <$> ftypeRef r <*> pure cid + Handle e h -> pure $ Handle e h + App f a -> pure $ App f a + Ann a typ -> Ann a <$> (ABT.vmapM fvt typ >>= Type.rmapM ftypeRef) + List s -> pure $ List s + If c t f -> pure $ If c t f + And p q -> pure $ And p q + Or p q -> pure $ Or p q + Lam b -> pure $ Lam b + LetRec bs b -> pure $ LetRec bs b + Let a b -> pure $ Let a b + Match s cs -> Match s <$> (traverse goCase cs) + TermLink r -> TermLink <$> ftermLink r + TypeLink r -> TypeLink <$> ftypeLink r + goCase :: MatchCase text typeRef x -> m (MatchCase text' typeRef' x) + goCase (MatchCase p g b) = MatchCase <$> goPat p <*> pure g <*> pure b + goPat = rmapPatternM ftext ftypeRef rmapPattern :: (t -> t') -> (r -> r') -> Pattern t r -> Pattern t' r' -rmapPattern ft fr = go +rmapPattern ft fr p = runIdentity . rmapPatternM (pure . ft) (pure . fr) $ p + +rmapPatternM :: Applicative m => (t -> m t') -> (r -> m r') -> Pattern t r -> m (Pattern t' r') +rmapPatternM ft fr = go where go = \case - PUnbound -> PUnbound - PVar -> PVar - PBoolean b -> PBoolean b - PInt i -> PInt i - PNat n -> PNat n - PFloat d -> PFloat d - PText t -> PText (ft t) - PChar c -> PChar c - PConstructor r i ps -> PConstructor (fr r) i (go <$> ps) - PAs p -> PAs (go p) - PEffectPure p -> PEffectPure (go p) - PEffectBind r i ps p -> PEffectBind (fr r) i (go <$> ps) (go p) - PSequenceLiteral ps -> PSequenceLiteral (go <$> ps) - PSequenceOp p1 op p2 -> PSequenceOp (go p1) op (go p2) + PUnbound -> pure $ PUnbound + PVar -> pure $ PVar + PBoolean b -> pure $ PBoolean b + PInt i -> pure $ PInt i + PNat n -> pure $ PNat n + PFloat d -> pure $ PFloat d + PText t -> PText <$> ft t + PChar c -> pure $ PChar c + PConstructor r i ps -> PConstructor <$> fr r <*> pure i <*> (traverse go ps) + PAs p -> PAs <$> go p + PEffectPure p -> PEffectPure <$> go p + PEffectBind r i ps p -> PEffectBind <$> fr r <*> pure i <*> traverse go ps <*> go p + PSequenceLiteral ps -> PSequenceLiteral <$> traverse go ps + PSequenceOp p1 op p2 -> PSequenceOp <$> go p1 <*> pure op <*> go p2 dependencies :: (Ord termRef, Ord typeRef, Ord termLink, Ord typeLink, Ord v) => diff --git a/codebase2/codebase/U/Codebase/Type.hs b/codebase2/codebase/U/Codebase/Type.hs index 9b8f915187..d24179b89a 100644 --- a/codebase2/codebase/U/Codebase/Type.hs +++ b/codebase2/codebase/U/Codebase/Type.hs @@ -38,9 +38,16 @@ type TypeD v = ABT.Term FD v () type TypeR r v = ABT.Term (F' r) v () rmap :: (Ord v) => (r -> r') -> ABT.Term (F' r) v a -> ABT.Term (F' r') v a -rmap f = ABT.transform \case - Ref r -> Ref (f r) - x -> unsafeCoerce x +rmap f = runIdentity . rmapM (Identity . f) + +rmapM :: + (Ord v, Monad f) => + (r -> f r') -> + ABT.Term (F' r) v a -> + f (ABT.Term (F' r') v a) +rmapM f = ABT.transformM \case + Ref r -> Ref <$> f r + x -> pure $ unsafeCoerce x typeD2T :: (Ord v) => Hash -> TypeD v -> TypeT v typeD2T h = rmap $ bimap id $ Maybe.fromMaybe h diff --git a/codebase2/core/U/Codebase/HashTags.hs b/codebase2/core/U/Codebase/HashTags.hs index f5da75fb2c..5470f3009f 100644 --- a/codebase2/core/U/Codebase/HashTags.hs +++ b/codebase2/core/U/Codebase/HashTags.hs @@ -1,17 +1,25 @@ module U.Codebase.HashTags where import Unison.Hash (Hash) +import Unison.Hash32 (Hash32) +import Unison.Prelude -- | Represents a hash of a type or term component newtype ComponentHash = ComponentHash {unComponentHash :: Hash} - deriving stock (Eq, Ord, Show) + deriving stock (Eq, Ord) -newtype BranchHash = BranchHash {unBranchHash :: Hash} deriving (Eq, Ord) +newtype BranchHash = BranchHash {unBranchHash :: Hash} + deriving stock (Eq, Ord) -- | Represents a hash of a causal containing values of the provided type. -newtype CausalHash = CausalHash {unCausalHash :: Hash} deriving (Eq, Ord) +newtype CausalHash = CausalHash {unCausalHash :: Hash} + deriving stock (Eq, Ord) -newtype PatchHash = PatchHash {unPatchHash :: Hash} deriving (Eq, Ord) +newtype PatchHash = PatchHash {unPatchHash :: Hash} + deriving stock (Eq, Ord) + +instance Show ComponentHash where + show h = "ComponentHash (" ++ show (unComponentHash h) ++ ")" instance Show BranchHash where show h = "BranchHash (" ++ show (unBranchHash h) ++ ")" @@ -21,3 +29,55 @@ instance Show CausalHash where instance Show PatchHash where show h = "PatchHash (" ++ show (unPatchHash h) ++ ")" + +instance From ComponentHash Text where + from = from @Hash @Text . unComponentHash + +instance From BranchHash Text where + from = from @Hash @Text . unBranchHash + +instance From CausalHash Text where + from = from @Hash @Text . unCausalHash + +instance From PatchHash Text where + from = from @Hash @Text . unPatchHash + +instance From ComponentHash Hash + +instance From BranchHash Hash + +instance From CausalHash Hash + +instance From PatchHash Hash + +instance From Hash ComponentHash + +instance From Hash BranchHash + +instance From Hash CausalHash + +instance From Hash PatchHash + +instance From ComponentHash Hash32 where + from = from @Hash @Hash32 . unComponentHash + +instance From BranchHash Hash32 where + from = from @Hash @Hash32 . unBranchHash + +instance From CausalHash Hash32 where + from = from @Hash @Hash32 . unCausalHash + +instance From PatchHash Hash32 where + from = from @Hash @Hash32 . unPatchHash + +instance From Hash32 ComponentHash where + from = ComponentHash . from @Hash32 @Hash + +instance From Hash32 BranchHash where + from = BranchHash . from @Hash32 @Hash + +instance From Hash32 CausalHash where + from = CausalHash . from @Hash32 @Hash + +instance From Hash32 PatchHash where + from = PatchHash . from @Hash32 @Hash diff --git a/codebase2/core/U/Core/ABT.hs b/codebase2/core/U/Core/ABT.hs index 3dfb546002..690202d366 100644 --- a/codebase2/core/U/Core/ABT.hs +++ b/codebase2/core/U/Core/ABT.hs @@ -5,14 +5,11 @@ module U.Core.ABT where import Control.Lens (Lens', use, (.=)) import Control.Monad.State import Data.Foldable qualified as Foldable -import Data.Functor.Identity (Identity (runIdentity)) -import Data.Maybe (fromMaybe) -import Data.Set (Set) import Data.Set qualified as Set import Debug.RecoverRTTI qualified as RTTI -import GHC.Generics (Generic) import U.Core.ABT.Var (Var (freshIn)) import Unison.Debug qualified as Debug +import Unison.Prelude import Prelude hiding (abs, cycle) data ABT f v r @@ -20,7 +17,7 @@ data ABT f v r | Cycle r | Abs v r | Tm (f r) - deriving stock (Eq, Show, Functor, Foldable, Traversable) + deriving stock (Eq, Show, Functor, Foldable, Traversable, Generic) -- | At each level in the tree, we store the set of free variables and -- a value of type `a`. Variables are of type `v`. @@ -93,6 +90,13 @@ vmap f (Term _ a out) = case out of Cycle r -> cycle a (vmap f r) Abs v body -> abs a (f v) (vmap f body) +vmapM :: (Applicative m, Traversable f, Foldable f, Ord v2) => (v -> m v2) -> Term f v a -> m (Term f v2 a) +vmapM f (Term _ a out) = case out of + Var v -> var a <$> f v + Tm fa -> tm a <$> traverse (vmapM f) fa + Cycle r -> cycle a <$> vmapM f r + Abs v body -> abs a <$> f v <*> vmapM f body + cata :: (Functor f) => (a -> ABT f v x -> x) -> diff --git a/codebase2/util-serialization/U/Util/Serialization.hs b/codebase2/util-serialization/U/Util/Serialization.hs index 66869ae804..ecc90fe439 100644 --- a/codebase2/util-serialization/U/Util/Serialization.hs +++ b/codebase2/util-serialization/U/Util/Serialization.hs @@ -9,7 +9,7 @@ module U.Util.Serialization where import Control.Applicative (Applicative (liftA2), liftA3) -import Control.Monad (foldM, replicateM, when, replicateM_) +import Control.Monad (foldM, replicateM, replicateM_, when) import Data.Bits (Bits, clearBit, setBit, shiftL, shiftR, testBit, (.|.)) import Data.ByteString (ByteString, readFile, writeFile) import qualified Data.ByteString as BS diff --git a/docs/language-server.markdown b/docs/language-server.markdown index c2c39cf7f7..3a5b785ce9 100644 --- a/docs/language-server.markdown +++ b/docs/language-server.markdown @@ -2,12 +2,19 @@ [![asciicast](https://asciinema.org/a/Kwa7NscffA3R8KCHxq1OavRm0.svg)](https://asciinema.org/a/Kwa7NscffA3R8KCHxq1OavRm0) +* [Overview](#overview) +* [Installation and setup](#installation-and-setup) + * [Settings](#settings) + * [NeoVim](#neovim) + * [VSCode](#vscode) + ## Overview Supported features: * Autocompletion * Inline type and parser error messages +* Format on save (you can disable this in your editor if you like) * Show type on hover Notes: @@ -34,6 +41,17 @@ You can set this persistently in powershell using: See [this issue](https://github.com/unisonweb/unison/issues/3487) for more details. +### Settings + +Supported settings and their defaults. See information for your language server client about where to provide these. + +```json +{ + // A suggestion for the formatter about how wide (in columns) to print definitions. + "formattingWidth": 80 +} +``` + ### NeoVim Before configuring the LSP, install the Vim plugin for filetype detection and syntax highlighting. diff --git a/lib/unison-hash/package.yaml b/lib/unison-hash/package.yaml index 514fda17c1..977e823288 100644 --- a/lib/unison-hash/package.yaml +++ b/lib/unison-hash/package.yaml @@ -10,6 +10,7 @@ dependencies: - text - unison-prelude - unison-util-base32hex + - witch library: source-dirs: src diff --git a/lib/unison-hash/src/Unison/Hash.hs b/lib/unison-hash/src/Unison/Hash.hs index 77a7855ca4..c6b4b2d67e 100644 --- a/lib/unison-hash/src/Unison/Hash.hs +++ b/lib/unison-hash/src/Unison/Hash.hs @@ -37,6 +37,9 @@ instance Show Hash where newtype HashFor t = HashFor {genericHash :: Hash} deriving newtype (Show, Eq, Ord, Generic) +instance From Hash Text where + from = toBase32HexText + -- | Convert a hash to a byte string. toByteString :: Hash -> ByteString toByteString = B.Short.fromShort . toShort diff --git a/lib/unison-hash/src/Unison/Hash32.hs b/lib/unison-hash/src/Unison/Hash32.hs index 9d55c82a81..97e7c201ed 100644 --- a/lib/unison-hash/src/Unison/Hash32.hs +++ b/lib/unison-hash/src/Unison/Hash32.hs @@ -32,6 +32,15 @@ import Unison.Prelude newtype Hash32 = UnsafeFromBase32Hex Base32Hex deriving (Eq, Ord, Show) via (Text) +instance From Hash32 Text where + from = toText + +instance From Hash32 Hash where + from = toHash + +instance From Hash Hash32 where + from = fromHash + fromHash :: Hash -> Hash32 fromHash = unsafeFromBase32Hex . Hash.toBase32Hex diff --git a/lib/unison-hash/unison-hash.cabal b/lib/unison-hash/unison-hash.cabal index 281ca59fcd..afdc6cc89d 100644 --- a/lib/unison-hash/unison-hash.cabal +++ b/lib/unison-hash/unison-hash.cabal @@ -56,4 +56,5 @@ library , text , unison-prelude , unison-util-base32hex + , witch default-language: Haskell2010 diff --git a/lib/unison-prelude/package.yaml b/lib/unison-prelude/package.yaml index 4ffa469ba8..9e15dfc36b 100644 --- a/lib/unison-prelude/package.yaml +++ b/lib/unison-prelude/package.yaml @@ -15,6 +15,7 @@ dependencies: - generic-lens - either - extra + - filepath - generic-lens - lens - mtl @@ -36,15 +37,28 @@ default-extensions: - BangPatterns - BlockArguments - ConstraintKinds + - DeriveAnyClass - DeriveFunctor + - DeriveGeneric + - DeriveTraversable - DerivingStrategies + - DerivingVia - DoAndIfThenElse + - DuplicateRecordFields - FlexibleContexts - FlexibleInstances + - GeneralizedNewtypeDeriving - ImportQualifiedPost - LambdaCase - MultiParamTypeClasses - - ScopedTypeVariables + - NamedFieldPuns + - OverloadedLabels + - OverloadedStrings + - PatternSynonyms - RankNTypes + - ScopedTypeVariables + - StandaloneDeriving - TupleSections - TypeApplications + - TypeFamilies + - ViewPatterns diff --git a/lib/unison-prelude/src/Unison/Prelude.hs b/lib/unison-prelude/src/Unison/Prelude.hs index fd9a27ec18..dfc75d7cde 100644 --- a/lib/unison-prelude/src/Unison/Prelude.hs +++ b/lib/unison-prelude/src/Unison/Prelude.hs @@ -4,6 +4,7 @@ module Unison.Prelude safeReadUtf8, safeReadUtf8StdIn, writeUtf8, + prependUtf8, uncurry4, reportBug, tShow, @@ -81,10 +82,12 @@ import GHC.Generics as X (Generic, Generic1) import GHC.IO.Handle qualified as Handle import GHC.Stack as X (HasCallStack) import Safe as X (atMay, headMay, lastMay, readMay) +import System.FilePath qualified as FilePath import System.IO qualified as IO import Text.Read as X (readMaybe) import UnliftIO as X (MonadUnliftIO (..), askRunInIO, askUnliftIO, try, withUnliftIO) import UnliftIO qualified +import UnliftIO.Directory qualified as UnliftIO import Witch as X (From (from), TryFrom (tryFrom), TryFromException (TryFromException), into, tryInto) import Witherable as X (filterA, forMaybe, mapMaybe, wither, witherMap) @@ -233,6 +236,24 @@ writeUtf8 fileName txt = do Handle.hSetEncoding handle IO.utf8 Text.hPutStr handle txt +-- | Atomically prepend some text to a file +prependUtf8 :: FilePath -> Text -> IO () +prependUtf8 path txt = do + let withTempFile tmpFilePath tmpHandle = do + Text.hPutStrLn tmpHandle txt + IO.withFile path IO.ReadMode \currentScratchFile -> do + let copyLoop = do + chunk <- Text.hGetChunk currentScratchFile + case Text.length chunk == 0 of + True -> pure () + False -> do + Text.hPutStr tmpHandle chunk + copyLoop + copyLoop + IO.hClose tmpHandle + UnliftIO.renameFile tmpFilePath path + UnliftIO.withTempFile (FilePath.takeDirectory path) ".unison-scratch" withTempFile + reportBug :: String -> String -> String reportBug bugId msg = unlines diff --git a/lib/unison-prelude/unison-prelude.cabal b/lib/unison-prelude/unison-prelude.cabal index 2f963a9afb..874025db32 100644 --- a/lib/unison-prelude/unison-prelude.cabal +++ b/lib/unison-prelude/unison-prelude.cabal @@ -34,18 +34,31 @@ library BangPatterns BlockArguments ConstraintKinds + DeriveAnyClass DeriveFunctor + DeriveGeneric + DeriveTraversable DerivingStrategies + DerivingVia DoAndIfThenElse + DuplicateRecordFields FlexibleContexts FlexibleInstances + GeneralizedNewtypeDeriving ImportQualifiedPost LambdaCase MultiParamTypeClasses - ScopedTypeVariables + NamedFieldPuns + OverloadedLabels + OverloadedStrings + PatternSynonyms RankNTypes + ScopedTypeVariables + StandaloneDeriving TupleSections TypeApplications + TypeFamilies + ViewPatterns ghc-options: -Wall build-depends: base @@ -53,6 +66,7 @@ library , containers , either , extra + , filepath , generic-lens , lens , mtl diff --git a/lib/unison-util-relation/src/Unison/Util/BiMultimap.hs b/lib/unison-util-relation/src/Unison/Util/BiMultimap.hs index 349ebd8e1d..466424c912 100644 --- a/lib/unison-util-relation/src/Unison/Util/BiMultimap.hs +++ b/lib/unison-util-relation/src/Unison/Util/BiMultimap.hs @@ -243,4 +243,3 @@ deriveRangeFromDomain :: Ord b => a -> NESet b -> Map b a -> Map b a deriveRangeFromDomain x ys acc = foldr (flip Map.insert x) acc ys {-# INLINE deriveRangeFromDomain #-} - diff --git a/lib/unison-util-relation/src/Unison/Util/Relation.hs b/lib/unison-util-relation/src/Unison/Util/Relation.hs index e56557c6ef..060f990ad9 100644 --- a/lib/unison-util-relation/src/Unison/Util/Relation.hs +++ b/lib/unison-util-relation/src/Unison/Util/Relation.hs @@ -28,6 +28,7 @@ module Unison.Util.Relation -- ** Searches searchDom, + searchDomG, searchRan, -- ** Filters @@ -588,21 +589,24 @@ lookupDom a r = fromMaybe S.empty $ lookupDom' a r -- or empty, this function takes time logarithmic in the number of unique keys -- of the domain, `a`. searchDom :: (Ord a, Ord b) => (a -> Ordering) -> Relation a b -> Set b -searchDom f r = go (domain r) +searchDom = searchDomG (\_ set -> set) + +searchDomG :: (Ord a, Monoid c) => (a -> Set b -> c) -> (a -> Ordering) -> Relation a b -> c +searchDomG g f r = go (domain r) where go Map.Tip = mempty go (Map.Bin _ amid bs l r) = case f amid of - EQ -> bs <> goL l <> goR r + EQ -> goL l <> g amid bs <> goR r LT -> go r GT -> go l goL Map.Tip = mempty goL (Map.Bin _ amid bs l r) = case f amid of - EQ -> bs <> goL l <> S.unions (Map.elems r) + EQ -> goL l <> g amid bs <> Map.foldrWithKey (\k v acc -> g k v <> acc) mempty r LT -> goL r GT -> error "predicate not monotone with respect to ordering" goR Map.Tip = mempty goR (Map.Bin _ amid bs l r) = case f amid of - EQ -> bs <> goR r <> S.unions (Map.elems l) + EQ -> Map.foldrWithKey (\k v acc -> g k v <> acc) mempty l <> g amid bs <> goR r GT -> goR l LT -> error "predicate not monotone with respect to ordering" diff --git a/parser-typechecker/package.yaml b/parser-typechecker/package.yaml index a3273d20a9..db05325bd8 100644 --- a/parser-typechecker/package.yaml +++ b/parser-typechecker/package.yaml @@ -59,6 +59,7 @@ dependencies: - http-client - http-media - http-types + - IntervalMap - lens - lucid - megaparsec diff --git a/parser-typechecker/src/U/Codebase/Branch/Diff.hs b/parser-typechecker/src/U/Codebase/Branch/Diff.hs index e816daf034..c4a7291547 100644 --- a/parser-typechecker/src/U/Codebase/Branch/Diff.hs +++ b/parser-typechecker/src/U/Codebase/Branch/Diff.hs @@ -45,12 +45,10 @@ data Diff a = Diff -- | Represents the changes to definitions at a given path, not including child paths. -- --- Note: doesn't yet include any info on metadata or patch diffs. Feel free to add it. +-- Note: doesn't yet include any info on patch diffs. Feel free to add it. data DefinitionDiffs = DefinitionDiffs { termDiffs :: Map NameSegment (Diff Referent), typeDiffs :: Map NameSegment (Diff Reference) - -- termMetadataDiffs :: Map (NameSegment, Referent) (Diff Reference), - -- typeMetadataDiffs :: Map (NameSegment, Reference) (Diff Reference) -- patchDiffs :: Map NameSegment (Diff ()) } deriving stock (Show, Eq, Ord) diff --git a/parser-typechecker/src/Unison/Builtin/Terms.hs b/parser-typechecker/src/Unison/Builtin/Terms.hs index 60dfec49a8..49c98f7045 100644 --- a/parser-typechecker/src/Unison/Builtin/Terms.hs +++ b/parser-typechecker/src/Unison/Builtin/Terms.hs @@ -1,6 +1,3 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TypeApplications #-} - module Unison.Builtin.Terms ( builtinTermsRef, builtinTermsSrc, diff --git a/parser-typechecker/src/Unison/Codebase.hs b/parser-typechecker/src/Unison/Codebase.hs index 94c91270fb..3d81e99681 100644 --- a/parser-typechecker/src/Unison/Codebase.hs +++ b/parser-typechecker/src/Unison/Codebase.hs @@ -13,7 +13,6 @@ module Unison.Codebase isTerm, putTerm, putTermComponent, - termMetadata, -- ** Referents (sorta-termlike) getTypeOfReferent, @@ -45,6 +44,7 @@ module Unison.Codebase SqliteCodebase.Operations.before, getShallowBranchAtPath, getShallowCausalAtPath, + getBranchAtPath, Operations.expectCausalBranchByCausalHash, getShallowCausalFromRoot, getShallowRootBranch, @@ -116,14 +116,12 @@ where import Control.Monad.Except (ExceptT (ExceptT), runExceptT) import Control.Monad.Trans.Except (throwE) -import Data.List as List import Data.Map qualified as Map import Data.Set qualified as Set import U.Codebase.Branch qualified as V2 import U.Codebase.Branch qualified as V2Branch import U.Codebase.Causal qualified as V2Causal import U.Codebase.HashTags (CausalHash) -import U.Codebase.Referent qualified as V2 import U.Codebase.Sqlite.Operations qualified as Operations import U.Codebase.Sqlite.Queries qualified as Queries import Unison.Builtin qualified as Builtin @@ -153,7 +151,6 @@ import Unison.DataDeclaration (Decl) import Unison.DataDeclaration qualified as DD import Unison.Hash (Hash) import Unison.Hashing.V2.Convert qualified as Hashing -import Unison.NameSegment qualified as NameSegment import Unison.Parser.Ann (Ann) import Unison.Parser.Ann qualified as Parser import Unison.Prelude @@ -245,23 +242,15 @@ getShallowBranchAtPath path mayBranch = do childBranch <- V2Causal.value childCausal getShallowBranchAtPath p (Just childBranch) --- | Get a branch from the codebase. -getBranchForHash :: (Monad m) => Codebase m v a -> CausalHash -> m (Maybe (Branch m)) -getBranchForHash codebase h = - -- Attempt to find the Branch in the current codebase cache and root up to 3 levels deep - -- If not found, attempt to find it in the Codebase (sqlite) - let nestedChildrenForDepth :: Int -> Branch m -> [Branch m] - nestedChildrenForDepth depth b = - if depth == 0 - then [] - else b : (Map.elems (Branch._children (Branch.head b)) >>= nestedChildrenForDepth (depth - 1)) - - headHashEq = (h ==) . Branch.headHash - - find rb = List.find headHashEq (nestedChildrenForDepth 3 rb) - in do - rootBranch <- getRootBranch codebase - maybe (getBranchForHashImpl codebase h) (pure . Just) (find rootBranch) +-- | Get a v1 branch from the root following the given path. +getBranchAtPath :: + (MonadIO m) => + Codebase m v a -> + Path.Absolute -> + m (Branch m) +getBranchAtPath codebase path = do + V2Causal.Causal {causalHash} <- runTransaction codebase $ getShallowCausalAtPath (Path.unabsolute path) Nothing + expectBranchForHash codebase causalHash -- | Like 'getBranchForHash', but for when the hash is known to be in the codebase. expectBranchForHash :: (Monad m) => Codebase m v a -> CausalHash -> m (Branch m) @@ -270,19 +259,6 @@ expectBranchForHash codebase hash = Just branch -> pure branch Nothing -> error $ reportBug "E412939" ("expectBranchForHash: " ++ show hash ++ " not found in codebase") --- | Get the metadata attached to the term at a given path and name relative to the given branch. -termMetadata :: - -- | The branch to search inside. Use the current root if 'Nothing'. - Maybe (V2Branch.Branch Sqlite.Transaction) -> - Split -> - -- | There may be multiple terms at the given name. You can specify a Referent to - -- disambiguate if desired. - Maybe V2.Referent -> - Sqlite.Transaction [Map V2Branch.MetadataValue V2Branch.MetadataType] -termMetadata mayBranch (path, nameSeg) ref = do - b <- getShallowBranchAtPath path mayBranch - V2Branch.termMetadata b (coerce @NameSegment.NameSegment nameSeg) ref - -- | Get the lowest common ancestor of two branches, i.e. the most recent branch that is an ancestor of both branches. lca :: (MonadIO m) => Codebase m v a -> Branch m -> Branch m -> m (Maybe (Branch m)) lca code b1@(Branch.headHash -> h1) b2@(Branch.headHash -> h2) = do diff --git a/parser-typechecker/src/Unison/Codebase/Branch.hs b/parser-typechecker/src/Unison/Codebase/Branch.hs index 29fbdaa01e..2c1dd569f7 100644 --- a/parser-typechecker/src/Unison/Codebase/Branch.hs +++ b/parser-typechecker/src/Unison/Codebase/Branch.hs @@ -1,7 +1,4 @@ -{-# LANGUAGE PatternSynonyms #-} -{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-orphans #-} module Unison.Codebase.Branch @@ -131,7 +128,6 @@ import Unison.Util.List qualified as List import Unison.Util.Monoid qualified as Monoid import Unison.Util.Relation qualified as R import Unison.Util.Relation qualified as Relation -import Unison.Util.Relation4 qualified as R4 import Unison.Util.Set qualified as Set import Unison.Util.Star3 qualified as Star3 import Witherable (FilterableWithIndex (imapMaybe)) @@ -192,7 +188,6 @@ terms = \branch terms -> branch {_terms = terms} & deriveDeepTerms - & deriveDeepTermMetadata types :: Lens' (Branch0 m) (Star TypeReference NameSegment) types = @@ -201,7 +196,6 @@ types = \branch types -> branch {_types = types} & deriveDeepTypes - & deriveDeepTypeMetadata children :: Lens' (Branch0 m) (Map NameSegment (Branch m)) children = lens _children (\Branch0 {..} x -> branch0 _terms _types x _edits) @@ -242,15 +236,11 @@ branch0 terms types children edits = -- These are all overwritten immediately deepTerms = R.empty, deepTypes = R.empty, - deepTermMetadata = R4.empty, - deepTypeMetadata = R4.empty, deepPaths = Set.empty, deepEdits = Map.empty } & deriveDeepTerms & deriveDeepTypes - & deriveDeepTermMetadata - & deriveDeepTypeMetadata & deriveDeepPaths & deriveDeepEdits @@ -299,50 +289,6 @@ deriveDeepTypes branch = children <- deepChildrenHelper e go (work <> children) (types <> acc) --- | Derive the 'deepTermMetadata' field of a branch. -deriveDeepTermMetadata :: forall m. Branch0 m -> Branch0 m -deriveDeepTermMetadata branch = - branch {deepTermMetadata = R4.fromList (makeDeepTermMetadata branch)} - where - makeDeepTermMetadata :: Branch0 m -> [(Referent, Name, Metadata.Type, Metadata.Value)] - makeDeepTermMetadata branch = State.evalState (go (Seq.singleton ([], 0, branch)) mempty) Set.empty - where - go :: - Seq (DeepChildAcc m) -> - [(Referent, Name, Metadata.Type, Metadata.Value)] -> - DeepState m [(Referent, Name, Metadata.Type, Metadata.Value)] - go Seq.Empty acc = pure acc - go (e@(reversePrefix, _, b0) Seq.:<| work) acc = do - let termMetadata :: [(Referent, Name, Metadata.Type, Metadata.Value)] - termMetadata = - map - (\(r, n, t, v) -> (r, Name.fromReverseSegments (n NonEmpty.:| reversePrefix), t, v)) - (Metadata.starToR4List (_terms b0)) - children <- deepChildrenHelper e - go (work <> children) (termMetadata <> acc) - --- | Derive the 'deepTypeMetadata' field of a branch. -deriveDeepTypeMetadata :: forall m. Branch0 m -> Branch0 m -deriveDeepTypeMetadata branch = - branch {deepTypeMetadata = R4.fromList (makeDeepTypeMetadata branch)} - where - makeDeepTypeMetadata :: Branch0 m -> [(TypeReference, Name, Metadata.Type, Metadata.Value)] - makeDeepTypeMetadata branch = State.evalState (go (Seq.singleton ([], 0, branch)) mempty) Set.empty - where - go :: - Seq (DeepChildAcc m) -> - [(TypeReference, Name, Metadata.Type, Metadata.Value)] -> - DeepState m [(TypeReference, Name, Metadata.Type, Metadata.Value)] - go Seq.Empty acc = pure acc - go (e@(reversePrefix, _, b0) Seq.:<| work) acc = do - let typeMetadata :: [(TypeReference, Name, Metadata.Type, Metadata.Value)] - typeMetadata = - map - (\(r, n, t, v) -> (r, Name.fromReverseSegments (n NonEmpty.:| reversePrefix), t, v)) - (Metadata.starToR4List (_types b0)) - children <- deepChildrenHelper e - go (work <> children) (typeMetadata <> acc) - -- | Derive the 'deepPaths' field of a branch. deriveDeepPaths :: forall m. Branch0 m -> Branch0 m deriveDeepPaths branch = @@ -483,7 +429,17 @@ one = Branch . Causal.one empty0 :: Branch0 m empty0 = - Branch0 mempty mempty mempty mempty True mempty mempty mempty mempty mempty mempty + Branch0 + { _terms = mempty, + _types = mempty, + _children = Map.empty, + _edits = Map.empty, + isEmpty0 = True, + deepTerms = Relation.empty, + deepTypes = Relation.empty, + deepPaths = Set.empty, + deepEdits = Map.empty + } -- | Checks whether a branch is empty AND has no history. isEmpty :: Branch m -> Bool @@ -718,15 +674,13 @@ batchUpdatesM (toList -> actions) curBranch = foldM execActions curBranch (group pathLocation _ = ChildActions -- todo: consider inlining these into Actions2 -addTermName :: - Referent -> NameSegment -> Metadata.Metadata -> Branch0 m -> Branch0 m -addTermName r new md = - over terms (Metadata.insertWithMetadata (r, md) . Star3.insertD1 (r, new)) - -addTypeName :: - TypeReference -> NameSegment -> Metadata.Metadata -> Branch0 m -> Branch0 m -addTypeName r new md = - over types (Metadata.insertWithMetadata (r, md) . Star3.insertD1 (r, new)) +addTermName :: Referent -> NameSegment -> Branch0 m -> Branch0 m +addTermName r new = + over terms (Star3.insertD1 (r, new)) + +addTypeName :: TypeReference -> NameSegment -> Branch0 m -> Branch0 m +addTypeName r new = + over types (Star3.insertD1 (r, new)) deleteTermName :: Referent -> NameSegment -> Branch0 m -> Branch0 m deleteTermName r n b diff --git a/parser-typechecker/src/Unison/Codebase/Branch/Names.hs b/parser-typechecker/src/Unison/Codebase/Branch/Names.hs index 88da47b6d8..d8157d63e2 100644 --- a/parser-typechecker/src/Unison/Codebase/Branch/Names.hs +++ b/parser-typechecker/src/Unison/Codebase/Branch/Names.hs @@ -1,15 +1,26 @@ module Unison.Codebase.Branch.Names ( namesDiff, toNames, + toPrettyPrintEnvDecl, ) where import Unison.Codebase.Branch import Unison.Names (Names (..)) import Unison.NamesWithHistory qualified as Names +import Unison.PrettyPrintEnv.Names qualified as PPE +import Unison.PrettyPrintEnvDecl qualified as PPED +import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Util.Relation qualified as R import Prelude hiding (head, read, subtract) +-- | Get the pretty-printing environment for names in the provided branch. +toPrettyPrintEnvDecl :: Int -> Branch0 m -> PPED.PrettyPrintEnvDecl +toPrettyPrintEnvDecl hashLength b = + let names = toNames b + in PPED.makePPED (PPE.hqNamer hashLength names) (PPE.suffixifyByHash names) + +-- | Get the names in the provided branch. toNames :: Branch0 m -> Names toNames b = Names diff --git a/parser-typechecker/src/Unison/Codebase/Branch/Type.hs b/parser-typechecker/src/Unison/Codebase/Branch/Type.hs index c93a9ae0d5..93a41cd3a6 100644 --- a/parser-typechecker/src/Unison/Codebase/Branch/Type.hs +++ b/parser-typechecker/src/Unison/Codebase/Branch/Type.hs @@ -70,12 +70,9 @@ data Branch0 m = Branch0 -- | True if a branch and its children have no definitions or edits in them. -- (Computed recursively, and small enough to justify storing here to avoid computing more than once.) isEmpty0 :: Bool, - -- names and metadata for this branch and its children - -- (ref, (name, value)) iff ref has metadata `value` at name `name` + -- names for this branch and its children deepTerms :: Relation Referent Name, deepTypes :: Relation Reference Name, - deepTermMetadata :: Metadata.R4 Referent Name, - deepTypeMetadata :: Metadata.R4 Reference Name, deepPaths :: Set Path, deepEdits :: Map Name PatchHash } diff --git a/parser-typechecker/src/Unison/Codebase/BranchDiff.hs b/parser-typechecker/src/Unison/Codebase/BranchDiff.hs index aece833cad..c846a17757 100644 --- a/parser-typechecker/src/Unison/Codebase/BranchDiff.hs +++ b/parser-typechecker/src/Unison/Codebase/BranchDiff.hs @@ -5,37 +5,23 @@ import Data.Set qualified as Set import U.Codebase.HashTags (PatchHash) import Unison.Codebase.Branch (Branch0 (..)) import Unison.Codebase.Branch qualified as Branch -import Unison.Codebase.Metadata qualified as Metadata import Unison.Codebase.Patch (Patch, PatchDiff) import Unison.Codebase.Patch qualified as Patch import Unison.Name (Name) import Unison.Prelude import Unison.Reference (Reference) import Unison.Referent (Referent) -import Unison.Runtime.IOSource (isPropagatedValue) import Unison.Util.Relation (Relation) import Unison.Util.Relation qualified as R -import Unison.Util.Relation3 (Relation3) -import Unison.Util.Relation3 qualified as R3 -import Unison.Util.Relation4 qualified as R4 data DiffType a = Create a | Delete a | Modify a deriving (Show) --- todo: maybe simplify this file using Relation3? -data NamespaceSlice r = NamespaceSlice - { names :: Relation r Name, - metadata :: Relation3 r Name Metadata.Value - } - deriving (Show) - data DiffSlice r = DiffSlice { -- tpatchUpdates :: Relation r r, -- old new tallnamespaceUpdates :: Map Name (Set r, Set r), talladds :: Relation r Name, tallremoves :: Relation r Name, - trenames :: Map r (Set Name, Set Name), -- ref (old, new) - taddedMetadata :: Relation3 r Name Metadata.Value, - tremovedMetadata :: Relation3 r Name Metadata.Value + trenames :: Map r (Set Name, Set Name) } deriving stock (Generic, Show) @@ -51,10 +37,10 @@ diff0 old new = BranchDiff terms types <$> patchDiff old new where (terms, types) = computeSlices - (deepr4ToSlice (Branch.deepTerms old) (Branch.deepTermMetadata old)) - (deepr4ToSlice (Branch.deepTerms new) (Branch.deepTermMetadata new)) - (deepr4ToSlice (Branch.deepTypes old) (Branch.deepTypeMetadata old)) - (deepr4ToSlice (Branch.deepTypes new) (Branch.deepTypeMetadata new)) + (Branch.deepTerms old) + (Branch.deepTerms new) + (Branch.deepTypes old) + (Branch.deepTypes new) patchDiff :: forall m. (Monad m) => Branch0 m -> Branch0 m -> m (Map Name (DiffType PatchDiff)) patchDiff old new = do @@ -79,48 +65,33 @@ patchDiff old new = do modified <- foldM f mempty (Set.intersection (Map.keysSet oldDeepEdits) (Map.keysSet newDeepEdits)) pure $ added <> removed <> modified -deepr4ToSlice :: - (Ord r) => - R.Relation r Name -> - Metadata.R4 r Name -> - NamespaceSlice r -deepr4ToSlice deepNames deepMetadata = - NamespaceSlice deepNames (R4.d124 deepMetadata) - computeSlices :: - NamespaceSlice Referent -> - NamespaceSlice Referent -> - NamespaceSlice Reference -> - NamespaceSlice Reference -> + Relation Referent Name -> + Relation Referent Name -> + Relation Reference Name -> + Relation Reference Name -> (DiffSlice Referent, DiffSlice Reference) computeSlices oldTerms newTerms oldTypes newTypes = (termsOut, typesOut) where termsOut = - let nc = allNames oldTerms newTerms + let nc = R.outerJoinDomMultimaps oldTerms newTerms nu = allNamespaceUpdates oldTerms newTerms in DiffSlice { tallnamespaceUpdates = nu, talladds = allAdds nc nu, tallremoves = allRemoves nc nu, - trenames = remainingNameChanges nc, - taddedMetadata = addedMetadata oldTerms newTerms, - tremovedMetadata = removedMetadata oldTerms newTerms + trenames = remainingNameChanges nc } typesOut = - let nc = allNames oldTypes newTypes + let nc = R.outerJoinDomMultimaps oldTypes newTypes nu = allNamespaceUpdates oldTypes newTypes in DiffSlice { tallnamespaceUpdates = nu, talladds = allAdds nc nu, tallremoves = allRemoves nc nu, - trenames = remainingNameChanges nc, - taddedMetadata = addedMetadata oldTypes newTypes, - tremovedMetadata = removedMetadata oldTypes newTypes + trenames = remainingNameChanges nc } - allNames :: (Ord r) => NamespaceSlice r -> NamespaceSlice r -> Map r (Set Name, Set Name) - allNames old new = R.outerJoinDomMultimaps (names old) (names new) - allAdds, allRemoves :: forall r. @@ -153,33 +124,14 @@ computeSlices oldTerms newTerms oldTypes newTypes = (termsOut, typesOut) remainingNameChanges = Map.filter (\(old, new) -> not (null old) && not (null new) && old /= new) - allNamespaceUpdates :: (Ord r) => NamespaceSlice r -> NamespaceSlice r -> Map Name (Set r, Set r) + allNamespaceUpdates :: (Ord r) => Relation r Name -> Relation r Name -> Map Name (Set r, Set r) allNamespaceUpdates old new = - Map.filter f $ R.innerJoinRanMultimaps (names old) (names new) + Map.filter f $ R.innerJoinRanMultimaps old new where f (old, new) = old /= new - addedMetadata :: (Ord r) => NamespaceSlice r -> NamespaceSlice r -> Relation3 r Name Metadata.Value - addedMetadata old new = metadata new `R3.difference` metadata old - - removedMetadata :: (Ord r) => NamespaceSlice r -> NamespaceSlice r -> Relation3 r Name Metadata.Value - removedMetadata old new = metadata old `R3.difference` metadata new - --- the namespace updates that aren't propagated namespaceUpdates :: (Ord r) => DiffSlice r -> Map Name (Set r, Set r) -namespaceUpdates s = Map.mapMaybeWithKey f (tallnamespaceUpdates s) +namespaceUpdates s = Map.mapMaybe f (tallnamespaceUpdates s) where - f name (olds, news) = - let news' = Set.difference news (Map.findWithDefault mempty name propagated) - in if null news' then Nothing else Just (olds, news') - propagated = propagatedUpdates s - -propagatedUpdates :: (Ord r) => DiffSlice r -> Map Name (Set r) -propagatedUpdates s = - Map.fromList - [ (name, news) - | (name, (_olds0, news0)) <- Map.toList $ tallnamespaceUpdates s, - let news = Set.filter propagated news0 - propagated rnew = R3.member rnew name isPropagatedValue (taddedMetadata s), - not (null news) - ] + f (olds, news) = + if null news then Nothing else Just (olds, news) diff --git a/parser-typechecker/src/Unison/Codebase/BranchUtil.hs b/parser-typechecker/src/Unison/Codebase/BranchUtil.hs index 85f8dbc40c..6245b592ac 100644 --- a/parser-typechecker/src/Unison/Codebase/BranchUtil.hs +++ b/parser-typechecker/src/Unison/Codebase/BranchUtil.hs @@ -6,10 +6,6 @@ module Unison.Codebase.BranchUtil getBranch, getTerm, getType, - getTermMetadataAt, - getTypeMetadataAt, - getTermMetadataHQNamed, - getTypeMetadataHQNamed, -- * Branch modifications makeSetBranch, @@ -28,14 +24,10 @@ import Data.Map qualified as Map import Data.Set qualified as Set import Unison.Codebase.Branch (Branch, Branch0) import Unison.Codebase.Branch qualified as Branch -import Unison.Codebase.Metadata (Metadata) -import Unison.Codebase.Metadata qualified as Metadata import Unison.Codebase.Patch (Patch) import Unison.Codebase.Path (Path) import Unison.Codebase.Path qualified as Path import Unison.HashQualified' (HashQualified (HashQualified, NameOnly)) -import Unison.HashQualified' qualified as HQ' -import Unison.NameSegment (NameSegment) import Unison.Names (Names) import Unison.Names qualified as Names import Unison.Prelude @@ -44,9 +36,7 @@ import Unison.Reference qualified as Reference import Unison.Referent (Referent) import Unison.Referent qualified as Referent import Unison.ShortHash qualified as SH -import Unison.Util.List qualified as List import Unison.Util.Relation qualified as R -import Unison.Util.Relation4 qualified as R4 import Unison.Util.Star3 qualified as Star3 -- | Creates a branch containing all of the given names, with a single history node. @@ -55,10 +45,8 @@ fromNames names0 = Branch.stepManyAt (typeActions <> termActions) Branch.empty where typeActions = map doType . R.toList $ Names.types names0 termActions = map doTerm . R.toList $ Names.terms names0 - -- doTerm :: (Name, Referent) -> (Path, Branch0 m -> Branch0 m) - doTerm (n, r) = makeAddTermName (Path.splitFromName n) r mempty -- no metadata - -- doType :: (Name, Reference) -> (Path, Branch0 m -> Branch0 m) - doType (n, r) = makeAddTypeName (Path.splitFromName n) r mempty -- no metadata + doTerm (n, r) = makeAddTermName (Path.splitFromName n) r + doType (n, r) = makeAddTypeName (Path.splitFromName n) r getTerm :: Path.HQSplit -> Branch0 m -> Set Referent getTerm (p, hq) b = case hq of @@ -68,31 +56,6 @@ getTerm (p, hq) b = case hq of filter sh = Set.filter (SH.isPrefixOf sh . Referent.toShortHash) terms = Branch._terms (Branch.getAt0 p b) -getTermMetadataHQNamed :: - (Path.Path, HQ'.HQSegment) -> Branch0 m -> Metadata.R4 Referent NameSegment -getTermMetadataHQNamed (path, hqseg) b = - R4.filter (\(r, n, _t, _v) -> HQ'.matchesNamedReferent n r hqseg) terms - where - terms = Metadata.starToR4 . Branch._terms $ Branch.getAt0 path b - -getTypeMetadataHQNamed :: - (Path.Path, HQ'.HQSegment) -> - Branch0 m -> - Metadata.R4 Reference NameSegment -getTypeMetadataHQNamed (path, hqseg) b = - R4.filter (\(r, n, _t, _v) -> HQ'.matchesNamedReference n r hqseg) types - where - types = Metadata.starToR4 . Branch._types $ Branch.getAt0 path b - --- todo: audit usages and maybe eliminate! --- Only returns metadata for the term at the exact level given -getTermMetadataAt :: (Path.Path, a) -> Referent -> Branch0 m -> Metadata -getTermMetadataAt (path, _) r b = Set.fromList <$> List.multimap mdList - where - mdList :: [(Metadata.Type, Metadata.Value)] - mdList = Set.toList . R.ran . Star3.d3 . Star3.selectFact (Set.singleton r) $ terms - terms = Branch._terms $ Branch.getAt0 path b - getType :: Path.HQSplit -> Branch0 m -> Set Reference.TypeReference getType (p, hq) b = case hq of NameOnly n -> Star3.lookupD1 n types @@ -101,13 +64,6 @@ getType (p, hq) b = case hq of filter sh = Set.filter (SH.isPrefixOf sh . Reference.toShortHash) types = Branch._types (Branch.getAt0 p b) -getTypeMetadataAt :: (Path.Path, a) -> Reference -> Branch0 m -> Metadata -getTypeMetadataAt (path, _) r b = Set.fromList <$> List.multimap mdList - where - mdList :: [(Metadata.Type, Metadata.Value)] - mdList = Set.toList . R.ran . Star3.d3 . Star3.selectFact (Set.singleton r) $ types - types = Branch._types $ Branch.getAt0 path b - getBranch :: Path.Split -> Branch0 m -> Maybe (Branch m) getBranch (p, seg) b = case Path.toList p of [] -> Map.lookup seg (Branch._children b) @@ -115,8 +71,8 @@ getBranch (p, seg) b = case Path.toList p of (Branch.head <$> Map.lookup h (Branch._children b)) >>= getBranch (Path.fromList p, seg) -makeAddTermName :: Path.Split -> Referent -> Metadata -> (Path, Branch0 m -> Branch0 m) -makeAddTermName (p, name) r md = (p, Branch.addTermName r name md) +makeAddTermName :: Path.Split -> Referent -> (Path, Branch0 m -> Branch0 m) +makeAddTermName (p, name) r = (p, Branch.addTermName r name) makeDeleteTermName :: Path.Split -> Referent -> (Path, Branch0 m -> Branch0 m) makeDeleteTermName (p, name) r = (p, Branch.deleteTermName r name) @@ -133,12 +89,11 @@ makeReplacePatch (p, name) patch = (p, Branch.replacePatch name patch) makeDeletePatch :: Path.Split -> (Path, Branch0 m -> Branch0 m) makeDeletePatch (p, name) = (p, Branch.deletePatch name) -makeAddTypeName :: Path.Split -> Reference -> Metadata -> (Path, Branch0 m -> Branch0 m) -makeAddTypeName (p, name) r md = (p, Branch.addTypeName r name md) +makeAddTypeName :: Path.Split -> Reference -> (Path, Branch0 m -> Branch0 m) +makeAddTypeName (p, name) r = (p, Branch.addTypeName r name) makeDeleteTypeName :: Path.Split -> Reference -> (Path, Branch0 m -> Branch0 m) makeDeleteTypeName (p, name) r = (p, Branch.deleteTypeName r name) -makeSetBranch :: - Path.Split -> Branch m -> (Path, Branch0 m -> Branch0 m) +makeSetBranch :: Path.Split -> Branch m -> (Path, Branch0 m -> Branch0 m) makeSetBranch (p, name) b = (p, Branch.setChildBranch name b) diff --git a/parser-typechecker/src/Unison/Codebase/Metadata.hs b/parser-typechecker/src/Unison/Codebase/Metadata.hs index 3a00e0ab04..f181b6ecb5 100644 --- a/parser-typechecker/src/Unison/Codebase/Metadata.hs +++ b/parser-typechecker/src/Unison/Codebase/Metadata.hs @@ -52,11 +52,6 @@ hasMetadataWithType a t = Set.member t . R.lookupDom a . Star3.d2 inserts :: (Ord a, Ord n) => [(a, Type, Value)] -> Star a n -> Star a n inserts tups s = foldl' (flip insert) s tups -insertWithMetadata :: - (Ord a, Ord n) => (a, Metadata) -> Star a n -> Star a n -insertWithMetadata (a, md) = - inserts [(a, ty, v) | (ty, vs) <- Map.toList md, v <- toList vs] - insert :: (Ord a, Ord n) => (a, Type, Value) -> Star a n -> Star a n insert (a, ty, v) = Star3.insertD23 (a, ty, (ty, v)) diff --git a/parser-typechecker/src/Unison/Codebase/SqliteCodebase.hs b/parser-typechecker/src/Unison/Codebase/SqliteCodebase.hs index 90755b4496..0c6de213a2 100644 --- a/parser-typechecker/src/Unison/Codebase/SqliteCodebase.hs +++ b/parser-typechecker/src/Unison/Codebase/SqliteCodebase.hs @@ -381,7 +381,7 @@ sqliteCodebase debugName root localOrRemote lockOption migrationStrategy action getTermComponentWithTypes, getRootBranch, putRootBranch, - getBranchForHashImpl = getBranchForHash, + getBranchForHash, putBranch, syncFromDirectory, syncToDirectory, diff --git a/parser-typechecker/src/Unison/Codebase/SqliteCodebase/Operations.hs b/parser-typechecker/src/Unison/Codebase/SqliteCodebase/Operations.hs index 9cc0964de3..129eade195 100644 --- a/parser-typechecker/src/Unison/Codebase/SqliteCodebase/Operations.hs +++ b/parser-typechecker/src/Unison/Codebase/SqliteCodebase/Operations.hs @@ -50,7 +50,6 @@ import Unison.Name qualified as Name import Unison.NameSegment (NameSegment (..)) import Unison.Names (Names (Names)) import Unison.Names qualified as Names -import Unison.Names.Scoped (ScopedNames (..)) import Unison.Parser.Ann (Ann) import Unison.Prelude import Unison.Reference (Reference) @@ -518,7 +517,7 @@ filterReferentsHavingTypeImpl :: filterReferentsHavingTypeImpl doGetDeclType typRef termRefs = Ops.filterTermsByReferentHavingType (Cv.reference1to2 typRef) (Cv.referentid1to2 <$> toList termRefs) >>= traverse (Cv.referentid2to1 doGetDeclType) - <&> Set.fromList + <&> Set.fromList -- | The number of base32 characters needed to distinguish any two references in the codebase. hashLength :: Transaction Int @@ -588,7 +587,7 @@ namesAtPath :: BranchHash -> -- Include names from the project which contains this path. Path -> - Transaction ScopedNames + Transaction Names namesAtPath bh path = do let namesRoot = PathSegments . coerce . Path.toList $ path namesPerspective@Ops.NamesPerspective {relativePerspective} <- Ops.namesPerspectiveForRootAndPath bh namesRoot @@ -596,22 +595,15 @@ namesAtPath bh path = do NamesInPerspective {termNamesInPerspective, typeNamesInPerspective} <- Ops.allNamesInPerspective namesPerspective let termsInPath = convertTerms termNamesInPerspective let typesInPath = convertTypes typeNamesInPerspective - let rootTerms = Rel.fromList termsInPath - let rootTypes = Rel.fromList typesInPath - let absoluteRootNames = Names.makeAbsolute $ Names {terms = rootTerms, types = rootTypes} let relativeScopedNames = case relativePath of - Path.Empty -> (Names.makeRelative $ absoluteRootNames) + Path.Empty -> (Names {terms = Rel.fromList termsInPath, types = Rel.fromList typesInPath}) p -> let reversedPathSegments = reverse . Path.toList $ p relativeTerms = mapMaybe (stripPathPrefix reversedPathSegments) termsInPath relativeTypes = mapMaybe (stripPathPrefix reversedPathSegments) typesInPath in (Names {terms = Rel.fromList relativeTerms, types = Rel.fromList relativeTypes}) - pure $ - ScopedNames - { relativeScopedNames, - absoluteRootNames - } + pure $ relativeScopedNames where convertTypes names = names <&> \(S.NamedRef {reversedSegments, ref}) -> diff --git a/parser-typechecker/src/Unison/Codebase/Type.hs b/parser-typechecker/src/Unison/Codebase/Type.hs index fe2cb52458..3ac6ac91aa 100644 --- a/parser-typechecker/src/Unison/Codebase/Type.hs +++ b/parser-typechecker/src/Unison/Codebase/Type.hs @@ -79,7 +79,7 @@ data Codebase m v a = Codebase Text -> -- Reason for the change, will be recorded in the reflog Branch m -> m (), - getBranchForHashImpl :: CausalHash -> m (Maybe (Branch m)), + getBranchForHash :: CausalHash -> m (Maybe (Branch m)), -- | Put a branch into the codebase, which includes its children, its patches, and the branch itself, if they don't -- already exist. -- diff --git a/parser-typechecker/src/Unison/DataDeclaration/Dependencies.hs b/parser-typechecker/src/Unison/DataDeclaration/Dependencies.hs index 92995dfce8..4eb6c67007 100644 --- a/parser-typechecker/src/Unison/DataDeclaration/Dependencies.hs +++ b/parser-typechecker/src/Unison/DataDeclaration/Dependencies.hs @@ -83,7 +83,7 @@ hashFieldAccessors :: ) hashFieldAccessors ppe declName vars declRef dd = do let accessors :: [(v, (), Term.Term v ())] - accessors = DD.generateRecordAccessors (map (,()) vars) declName declRef + accessors = DD.generateRecordAccessors mempty (map (,()) vars) declName declRef let typeLookup :: TypeLookup v () typeLookup = TypeLookup diff --git a/parser-typechecker/src/Unison/FileParsers.hs b/parser-typechecker/src/Unison/FileParsers.hs index 39c02dea41..7cf18b08f3 100644 --- a/parser-typechecker/src/Unison/FileParsers.hs +++ b/parser-typechecker/src/Unison/FileParsers.hs @@ -143,11 +143,7 @@ synthesizeFile env0 uf = do let term = UF.typecheckingTerm uf -- substitute Blanks for any remaining free vars in UF body tdnrTerm = Term.prepareTDNR term - unisonFilePPE = - ( PPE.fromNames - 10 - (Names.shadowing (UF.toNames uf) Builtin.names) - ) + unisonFilePPE = PPE.makePPE (PPE.hqNamer 10 (Names.shadowing (UF.toNames uf) Builtin.names)) PPE.dontSuffixify Result notes mayType = evalStateT (Typechecker.synthesizeAndResolve unisonFilePPE env0) tdnrTerm -- If typechecking succeeded, reapply the TDNR decisions to user's term: diff --git a/parser-typechecker/src/Unison/KindInference.hs b/parser-typechecker/src/Unison/KindInference.hs index 5e252c263d..7041146bf6 100644 --- a/parser-typechecker/src/Unison/KindInference.hs +++ b/parser-typechecker/src/Unison/KindInference.hs @@ -13,7 +13,6 @@ -- Afterwards, the 'SolveState' holds the kinds of all decls and we -- can check that type annotations in terms that may mention the -- decls are well-kinded with 'kindCheckAnnotations'. - module Unison.KindInference ( inferDecls, kindCheckAnnotations, @@ -28,7 +27,7 @@ import Data.Map.Strict qualified as Map import Unison.Codebase.BuiltinAnnotation (BuiltinAnnotation) import Unison.DataDeclaration import Unison.KindInference.Generate (declComponentConstraints, termConstraints) -import Unison.KindInference.Solve (KindError, verify, initialState, step, defaultUnconstrainedVars) +import Unison.KindInference.Solve (KindError, defaultUnconstrainedVars, initialState, step, verify) import Unison.KindInference.Solve.Monad (Env (..), SolveState, run, runGen) import Unison.Prelude import Unison.PrettyPrintEnv qualified as PrettyPrintEnv diff --git a/parser-typechecker/src/Unison/KindInference/Constraint/Context.hs b/parser-typechecker/src/Unison/KindInference/Constraint/Context.hs index e48761bc2a..5739cdebef 100644 --- a/parser-typechecker/src/Unison/KindInference/Constraint/Context.hs +++ b/parser-typechecker/src/Unison/KindInference/Constraint/Context.hs @@ -1,6 +1,7 @@ module Unison.KindInference.Constraint.Context - ( ConstraintContext(..) - ) where + ( ConstraintContext (..), + ) +where import Unison.KindInference.UVar (UVar) import Unison.Type (Type) diff --git a/parser-typechecker/src/Unison/KindInference/Constraint/Unsolved.hs b/parser-typechecker/src/Unison/KindInference/Constraint/Unsolved.hs index a1f8818d0f..92ad1fc4ca 100644 --- a/parser-typechecker/src/Unison/KindInference/Constraint/Unsolved.hs +++ b/parser-typechecker/src/Unison/KindInference/Constraint/Unsolved.hs @@ -6,7 +6,7 @@ module Unison.KindInference.Constraint.Unsolved ) where -import Control.Lens (Traversal, Lens, Lens') +import Control.Lens (Lens, Lens', Traversal) import Unison.KindInference.Constraint.Provenance (Provenance) import Unison.KindInference.Constraint.Provenance qualified as Provenance diff --git a/parser-typechecker/src/Unison/KindInference/Generate.hs b/parser-typechecker/src/Unison/KindInference/Generate.hs index 86267ef07e..c9841800d5 100644 --- a/parser-typechecker/src/Unison/KindInference/Generate.hs +++ b/parser-typechecker/src/Unison/KindInference/Generate.hs @@ -20,7 +20,7 @@ import Unison.KindInference.Constraint.Context (ConstraintContext (..)) import Unison.KindInference.Constraint.Provenance (Provenance (..)) import Unison.KindInference.Constraint.Provenance qualified as Provenance import Unison.KindInference.Constraint.Unsolved (Constraint (..)) -import Unison.KindInference.Generate.Monad (Gen, GeneratedConstraint, freshVar, pushType, lookupType, scopedType) +import Unison.KindInference.Generate.Monad (Gen, GeneratedConstraint, freshVar, lookupType, pushType, scopedType) import Unison.KindInference.UVar (UVar) import Unison.Prelude import Unison.Reference (Reference) @@ -241,41 +241,42 @@ declComponentConstraintTree decls = do -- Add a kind variable for every datatype declKind <- pushType (Type.ref (DD.annotation $ asDataDecl decl) ref) pure (ref, decl, declKind) - (declConstraints, constructorConstraints) <- unzip <$> for decls \(ref, decl, declKind) -> do - let declAnn = DD.annotation $ asDataDecl decl - let declType = Type.ref declAnn ref - -- Unify the datatype with @k_1 -> ... -> k_n -> *@ where @n@ is - -- the number of type parameters - let tyVars = map (\tyVar -> Type.var declAnn tyVar) (DD.bound $ asDataDecl decl) - tyvarKinds <- for tyVars \tyVar -> do - -- it would be nice to annotate these type vars with their - -- precise location, but that information doesn't seem to be - -- available via "DataDeclaration", so we currently settle for - -- the whole decl annotation. - k <- freshVar tyVar - pure (k, tyVar) + (declConstraints, constructorConstraints) <- + unzip <$> for decls \(ref, decl, declKind) -> do + let declAnn = DD.annotation $ asDataDecl decl + let declType = Type.ref declAnn ref + -- Unify the datatype with @k_1 -> ... -> k_n -> *@ where @n@ is + -- the number of type parameters + let tyVars = map (\tyVar -> Type.var declAnn tyVar) (DD.bound $ asDataDecl decl) + tyvarKinds <- for tyVars \tyVar -> do + -- it would be nice to annotate these type vars with their + -- precise location, but that information doesn't seem to be + -- available via "DataDeclaration", so we currently settle for + -- the whole decl annotation. + k <- freshVar tyVar + pure (k, tyVar) - let tyvarKindsOnly = map fst tyvarKinds - constructorConstraints <- - Node <$> for (DD.constructors' $ asDataDecl decl) \(constructorAnn, _, constructorType) -> do - withInstantiatedConstructorType declType tyvarKindsOnly constructorType \constructorType -> do - constructorKind <- freshVar constructorType - ct <- typeConstraintTree constructorKind constructorType - pure $ ParentConstraint (IsType constructorKind (Provenance DeclDefinition constructorAnn)) ct + let tyvarKindsOnly = map fst tyvarKinds + constructorConstraints <- + Node <$> for (DD.constructors' $ asDataDecl decl) \(constructorAnn, _, constructorType) -> do + withInstantiatedConstructorType declType tyvarKindsOnly constructorType \constructorType -> do + constructorKind <- freshVar constructorType + ct <- typeConstraintTree constructorKind constructorType + pure $ ParentConstraint (IsType constructorKind (Provenance DeclDefinition constructorAnn)) ct - (fullyAppliedKind, _fullyAppliedType, declConstraints) <- - let phi (dk, dt, cts) (ak, at) = do - -- introduce a kind uvar for each app node - let t' = Type.app declAnn dt at - v <- freshVar t' - let cts' = Constraint (IsArr dk (Provenance DeclDefinition declAnn) ak v) cts - pure (v, t', cts') - in foldlM phi (declKind, declType, Node []) tyvarKinds + (fullyAppliedKind, _fullyAppliedType, declConstraints) <- + let phi (dk, dt, cts) (ak, at) = do + -- introduce a kind uvar for each app node + let t' = Type.app declAnn dt at + v <- freshVar t' + let cts' = Constraint (IsArr dk (Provenance DeclDefinition declAnn) ak v) cts + pure (v, t', cts') + in foldlM phi (declKind, declType, Node []) tyvarKinds - let finalDeclConstraints = case decl of - Left _effectDecl -> Constraint (IsAbility fullyAppliedKind (Provenance DeclDefinition declAnn)) declConstraints - Right _dataDecl -> Constraint (IsType fullyAppliedKind (Provenance DeclDefinition declAnn)) declConstraints - pure (finalDeclConstraints, constructorConstraints) + let finalDeclConstraints = case decl of + Left _effectDecl -> Constraint (IsAbility fullyAppliedKind (Provenance DeclDefinition declAnn)) declConstraints + Right _dataDecl -> Constraint (IsType fullyAppliedKind (Provenance DeclDefinition declAnn)) declConstraints + pure (finalDeclConstraints, constructorConstraints) pure (Node declConstraints `StrictOrder` Node constructorConstraints) -- | This is a helper to unify the kind constraints on type variables diff --git a/parser-typechecker/src/Unison/KindInference/Solve.hs b/parser-typechecker/src/Unison/KindInference/Solve.hs index 2c19289173..cdda14228d 100644 --- a/parser-typechecker/src/Unison/KindInference/Solve.hs +++ b/parser-typechecker/src/Unison/KindInference/Solve.hs @@ -8,7 +8,6 @@ module Unison.KindInference.Solve ) where -import Unison.KindInference.Error (KindError(..), ConstraintConflict(..), improveError) import Control.Lens (Prism', prism', review, (%~)) import Control.Monad.Reader (asks) import Control.Monad.Reader qualified as M @@ -22,6 +21,7 @@ import Unison.KindInference.Constraint.Provenance (Provenance (..)) import Unison.KindInference.Constraint.Solved qualified as Solved import Unison.KindInference.Constraint.StarProvenance (StarProvenance (..)) import Unison.KindInference.Constraint.Unsolved qualified as Unsolved +import Unison.KindInference.Error (ConstraintConflict (..), KindError (..), improveError) import Unison.KindInference.Generate (builtinConstraints) import Unison.KindInference.Generate.Monad (Gen (..), GeneratedConstraint) import Unison.KindInference.Solve.Monad @@ -123,9 +123,9 @@ markVisiting x = do OccCheckState {visitingSet, visitingStack} <- M.get case Set.member x visitingSet of True -> do - OccCheckState{solvedConstraints} <- M.get + OccCheckState {solvedConstraints} <- M.get let loc = case U.lookupCanon x solvedConstraints of - Just (_, _, Descriptor { descriptorConstraint = Just (Solved.IsArr (Provenance _ loc) _ _ )}, _) -> loc + Just (_, _, Descriptor {descriptorConstraint = Just (Solved.IsArr (Provenance _ loc) _ _)}, _) -> loc _ -> error "cycle without IsArr constraint" addError (CycleDetected loc x solvedConstraints) pure Cycle diff --git a/parser-typechecker/src/Unison/PatternMatchCoverage/Solve.hs b/parser-typechecker/src/Unison/PatternMatchCoverage/Solve.hs index e6a548648a..59ffa3d865 100644 --- a/parser-typechecker/src/Unison/PatternMatchCoverage/Solve.hs +++ b/parser-typechecker/src/Unison/PatternMatchCoverage/Solve.hs @@ -718,7 +718,7 @@ union v0 v1 nc@NormalizedConstraints {constraintMap} = IsEffectful -> [C.Effectful chosenCanon] in addConstraints constraints nc {constraintMap = m} where - noMerge m = pure nc { constraintMap = m } + noMerge m = pure nc {constraintMap = m} modifyListC :: forall vt v loc m. diff --git a/parser-typechecker/src/Unison/PatternMatchCoverage/UFMap.hs b/parser-typechecker/src/Unison/PatternMatchCoverage/UFMap.hs index ea9f48381f..d9a6d3a3f0 100644 --- a/parser-typechecker/src/Unison/PatternMatchCoverage/UFMap.hs +++ b/parser-typechecker/src/Unison/PatternMatchCoverage/UFMap.hs @@ -14,8 +14,8 @@ module Unison.PatternMatchCoverage.UFMap ) where -import Control.Monad.Trans.Class import Control.Monad.Fix (MonadFix) +import Control.Monad.Trans.Class import Control.Monad.Trans.Except (ExceptT (..)) import Data.Foldable (foldl') import Data.Functor ((<&>)) diff --git a/parser-typechecker/src/Unison/PrettyPrintEnv.hs b/parser-typechecker/src/Unison/PrettyPrintEnv.hs index 158b4d3016..2038666bc2 100644 --- a/parser-typechecker/src/Unison/PrettyPrintEnv.hs +++ b/parser-typechecker/src/Unison/PrettyPrintEnv.hs @@ -1,5 +1,3 @@ -{-# LANGUAGE OverloadedStrings #-} - module Unison.PrettyPrintEnv ( PrettyPrintEnv (..), patterns, diff --git a/parser-typechecker/src/Unison/PrettyPrintEnv/Names.hs b/parser-typechecker/src/Unison/PrettyPrintEnv/Names.hs index a9ae758d52..fe34067742 100644 --- a/parser-typechecker/src/Unison/PrettyPrintEnv/Names.hs +++ b/parser-typechecker/src/Unison/PrettyPrintEnv/Names.hs @@ -1,8 +1,19 @@ module Unison.PrettyPrintEnv.Names - ( fromNames, - fromSuffixNames, - prioritize, - shortestUniqueSuffixes, + ( -- * Namer + Namer (..), + hqNamer, + namer, + + -- * Suffixifier + Suffixifier, + dontSuffixify, + suffixifyByHash, + suffixifyByName, + + -- * Pretty-print env + makePPE, + makeTermNames, + makeTypeNames, ) where @@ -15,21 +26,73 @@ import Unison.Names qualified as Names import Unison.NamesWithHistory qualified as Names import Unison.Prelude import Unison.PrettyPrintEnv (PrettyPrintEnv (PrettyPrintEnv)) -import Unison.Util.Relation qualified as Rel - -fromNames :: Int -> Names -> PrettyPrintEnv -fromNames len names = PrettyPrintEnv terms' types' - where - terms' r = - Names.termName len r names - & Set.toList - & fmap (\n -> (n, n)) - & prioritize - types' r = - Names.typeName len r names - & Set.toList - & fmap (\n -> (n, n)) - & prioritize +import Unison.Reference (TypeReference) +import Unison.Referent (Referent) + +------------------------------------------------------------------------------------------------------------------------ +-- Namer + +data Namer = Namer + { nameTerm :: Referent -> Set (HQ'.HashQualified Name), + nameType :: TypeReference -> Set (HQ'.HashQualified Name) + } + +namer :: Names -> Namer +namer names = + Namer + { nameTerm = Set.map HQ'.fromName . Names.namesForReferent names, + nameType = Set.map HQ'.fromName . Names.namesForReference names + } + +hqNamer :: Int -> Names -> Namer +hqNamer hashLen names = + Namer + { nameTerm = \ref -> Names.termName hashLen ref names, + nameType = \ref -> Names.typeName hashLen ref names + } + +------------------------------------------------------------------------------------------------------------------------ +-- Suffixifier + +data Suffixifier = Suffixifier + { suffixifyTerm :: Name -> Name, + suffixifyType :: Name -> Name + } + +dontSuffixify :: Suffixifier +dontSuffixify = + Suffixifier id id + +suffixifyByName :: Names -> Suffixifier +suffixifyByName names = + Suffixifier + { suffixifyTerm = \name -> Name.suffixifyByName name (Names.terms names), + suffixifyType = \name -> Name.suffixifyByName name (Names.types names) + } + +suffixifyByHash :: Names -> Suffixifier +suffixifyByHash names = + Suffixifier + { suffixifyTerm = \name -> Name.suffixifyByHash name (Names.terms names), + suffixifyType = \name -> Name.suffixifyByHash name (Names.types names) + } + +------------------------------------------------------------------------------------------------------------------------ +-- Pretty-print env + +makePPE :: Namer -> Suffixifier -> PrettyPrintEnv +makePPE namer suffixifier = + PrettyPrintEnv + (makeTermNames namer suffixifier) + (makeTypeNames namer suffixifier) + +makeTermNames :: Namer -> Suffixifier -> Referent -> [(HQ'.HashQualified Name, HQ'.HashQualified Name)] +makeTermNames Namer {nameTerm} Suffixifier {suffixifyTerm} = + prioritize . map (\name -> (name, suffixifyTerm <$> name)) . Set.toList . nameTerm + +makeTypeNames :: Namer -> Suffixifier -> TypeReference -> [(HQ'.HashQualified Name, HQ'.HashQualified Name)] +makeTypeNames Namer {nameType} Suffixifier {suffixifyType} = + prioritize . map (\name -> (name, suffixifyType <$> name)) . Set.toList . nameType -- | Sort the names for a given ref by the following factors (in priority order): -- @@ -42,24 +105,3 @@ prioritize = sortOn \case (fqn, HQ'.NameOnly name) -> (Name.isAbsolute name, Nothing, Name.countSegments (HQ'.toName fqn), Name.countSegments name) (fqn, HQ'.HashQualified name hash) -> (Name.isAbsolute name, Just hash, Name.countSegments (HQ'.toName fqn), Name.countSegments name) - -fromSuffixNames :: Int -> Names -> PrettyPrintEnv -fromSuffixNames len names = PrettyPrintEnv terms' types' - where - terms' r = - Names.termName len r names - & Set.toList - & fmap (\n -> (n, n)) - & shortestUniqueSuffixes (Names.terms names) - & prioritize - types' r = - Names.typeName len r names - & Set.toList - & fmap (\n -> (n, n)) - & shortestUniqueSuffixes (Names.types names) - & prioritize - --- | Reduce the provided names to their minimal unique suffix within the scope of the given --- relation. -shortestUniqueSuffixes :: (Ord ref) => Rel.Relation Name ref -> [(a, HQ'.HashQualified Name)] -> [(a, HQ'.HashQualified Name)] -shortestUniqueSuffixes rel names = names <&> second (fmap (\name -> Name.shortestUniqueSuffix name rel)) diff --git a/parser-typechecker/src/Unison/PrettyPrintEnvDecl.hs b/parser-typechecker/src/Unison/PrettyPrintEnvDecl.hs index 88a6fecc5b..81a9b08b21 100644 --- a/parser-typechecker/src/Unison/PrettyPrintEnvDecl.hs +++ b/parser-typechecker/src/Unison/PrettyPrintEnvDecl.hs @@ -37,6 +37,8 @@ biasTo targets PrettyPrintEnvDecl {unsuffixifiedPPE, suffixifiedPPE} = empty :: PrettyPrintEnvDecl empty = PrettyPrintEnvDecl PPE.empty PPE.empty +-- | Will use names from the fallback pped if no names were found in the primary. +-- @addFallback primary fallback@ addFallback :: PrettyPrintEnvDecl -> PrettyPrintEnvDecl -> PrettyPrintEnvDecl addFallback (PrettyPrintEnvDecl unsuff1 suff1) (PrettyPrintEnvDecl unsuff2 suff2) = PrettyPrintEnvDecl (unsuff1 `PPE.addFallback` unsuff2) (suff1 `PPE.addFallback` suff2) diff --git a/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Names.hs b/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Names.hs index 2ee6c6c44c..274f418049 100644 --- a/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Names.hs +++ b/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Names.hs @@ -1,11 +1,13 @@ -{-# LANGUAGE OverloadedStrings #-} +module Unison.PrettyPrintEnvDecl.Names + ( makePPED, + ) +where -module Unison.PrettyPrintEnvDecl.Names where - -import Unison.Names (Names) -import Unison.PrettyPrintEnv.Names (fromNames, fromSuffixNames) +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl (PrettyPrintEnvDecl (PrettyPrintEnvDecl)) -fromNamesDecl :: Int -> Names -> PrettyPrintEnvDecl -fromNamesDecl hashLength names = - PrettyPrintEnvDecl (fromNames hashLength names) (fromSuffixNames hashLength names) +makePPED :: PPE.Namer -> PPE.Suffixifier -> PrettyPrintEnvDecl +makePPED namer suffixifier = + PrettyPrintEnvDecl + (PPE.makePPE namer PPE.dontSuffixify) + (PPE.makePPE namer suffixifier) diff --git a/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Sqlite.hs b/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Sqlite.hs index c26c3675c3..633be7a5ed 100644 --- a/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Sqlite.hs +++ b/parser-typechecker/src/Unison/PrettyPrintEnvDecl/Sqlite.hs @@ -16,6 +16,7 @@ import Unison.Name qualified as Name import Unison.NameSegment (NameSegment (..)) import Unison.Names qualified as Names import Unison.Prelude +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Reference (Reference) @@ -50,7 +51,8 @@ ppedForReferences namesPerspective refs = do pure result let allTermNamesToConsider = termNames <> longestTermSuffixMatches let allTypeNamesToConsider = typeNames <> longestTypeSuffixMatches - pure . PPED.fromNamesDecl hashLen $ Names.fromTermsAndTypes allTermNamesToConsider allTypeNamesToConsider + let names = Names.fromTermsAndTypes allTermNamesToConsider allTypeNamesToConsider + pure (PPED.makePPED (PPE.hqNamer hashLen names) (PPE.suffixifyByHash names)) where namesForReference :: Ops.NamesPerspective -> LabeledDependency -> Sqlite.Transaction ([(Name, Referent)], [(Name, Reference)]) namesForReference namesPerspective = \case diff --git a/parser-typechecker/src/Unison/PrintError.hs b/parser-typechecker/src/Unison/PrintError.hs index 029e2ce57c..d3174ce657 100644 --- a/parser-typechecker/src/Unison/PrintError.hs +++ b/parser-typechecker/src/Unison/PrintError.hs @@ -20,11 +20,13 @@ import Unison.Builtin.Decls (unitRef, pattern TupleType') import Unison.Codebase.Path qualified as Path import Unison.ConstructorReference (ConstructorReference, GConstructorReference (..)) import Unison.HashQualified (HashQualified) +import Unison.HashQualified' qualified as HQ' import Unison.Kind (Kind) import Unison.Kind qualified as Kind import Unison.KindInference.Error.Pretty (prettyKindError) import Unison.Name (Name) import Unison.Name qualified as Name +import Unison.NameSegment (NameSegment (..)) import Unison.Names qualified as Names import Unison.Names.ResolutionResult qualified as Names import Unison.Parser.Ann (Ann (..)) @@ -1218,16 +1220,18 @@ rangeToEnglish (Range (L.Pos l c) (L.Pos l' c')) = then "line " ++ show l else "lines " ++ show l ++ "—" ++ show l' -annotatedToEnglish :: (Annotated a, IsString s) => a -> s +annotatedToEnglish :: (Annotated a, IsString s, Semigroup s) => a -> s annotatedToEnglish a = case ann a of - Intrinsic -> "an intrinsic" - External -> "an external" + Intrinsic -> "" + External -> "" + GeneratedFrom a -> "generated from: " <> annotatedToEnglish a Ann start end -> rangeToEnglish $ Range start end rangeForAnnotated :: (Annotated a) => a -> Maybe Range rangeForAnnotated a = case ann a of Intrinsic -> Nothing External -> Nothing + GeneratedFrom a -> rangeForAnnotated a Ann start end -> Just $ Range start end showLexerOutput :: Bool @@ -1629,16 +1633,17 @@ renderParseErrors s = \case then unknownTypesMsg else unknownTypesMsg <> "\n\n" <> dupDataAndAbilitiesMsg in (msgs, allRanges) - go (Parser.DidntExpectExpression _tok (Just t@(L.payload -> L.SymbolyId "::" Nothing))) = - let msg = - mconcat - [ "This looks like the start of an expression here but I was expecting a binding.", - "\nDid you mean to use a single " <> style Code ":", - " here for a type signature?", - "\n\n", - tokenAsErrorSite s t - ] - in (msg, [rangeForToken t]) + go (Parser.DidntExpectExpression _tok (Just t@(L.payload -> L.SymbolyId (HQ'.NameOnly name)))) + | name == Name.fromSegment (NameSegment "::") = + let msg = + mconcat + [ "This looks like the start of an expression here but I was expecting a binding.", + "\nDid you mean to use a single " <> style Code ":", + " here for a type signature?", + "\n\n", + tokenAsErrorSite s t + ] + in (msg, [rangeForToken t]) go (Parser.DidntExpectExpression tok _nextTok) = let msg = mconcat @@ -1938,8 +1943,8 @@ prettyResolutionFailures s allFailures = (Names.TypeResolutionFailure v _ Names.NotFound) -> (v, Nothing) ppeFromNames :: Names.Names -> PPE.PrettyPrintEnv - ppeFromNames = - PPE.fromNames PPE.todoHashLength + ppeFromNames names = + PPE.makePPE (PPE.hqNamer PPE.todoHashLength names) PPE.dontSuffixify prettyRow :: (v, Maybe (NESet String)) -> [(Pretty ColorText, Pretty ColorText)] prettyRow (v, mSet) = case mSet of diff --git a/parser-typechecker/src/Unison/Runtime/IOSource.hs b/parser-typechecker/src/Unison/Runtime/IOSource.hs index 22931be6d8..8286a525c4 100644 --- a/parser-typechecker/src/Unison/Runtime/IOSource.hs +++ b/parser-typechecker/src/Unison/Runtime/IOSource.hs @@ -1005,4 +1005,4 @@ showNotes source env = intercalateMap "\n\n" $ PrintError.renderNoteAsANSI 60 env source Path.absoluteEmpty ppEnv :: PPE.PrettyPrintEnv -ppEnv = PPE.fromNames 10 Builtin.names +ppEnv = PPE.makePPE (PPE.hqNamer 10 Builtin.names) PPE.dontSuffixify diff --git a/parser-typechecker/src/Unison/Syntax/DeclParser.hs b/parser-typechecker/src/Unison/Syntax/DeclParser.hs index 07e4c1b272..438d09981b 100644 --- a/parser-typechecker/src/Unison/Syntax/DeclParser.hs +++ b/parser-typechecker/src/Unison/Syntax/DeclParser.hs @@ -5,8 +5,8 @@ where import Control.Lens import Control.Monad.Reader (MonadReader (..)) +import Data.List.NonEmpty qualified as NonEmpty import Data.Map qualified as Map -import Data.Text qualified as Text import Text.Megaparsec qualified as P import Unison.ABT qualified as ABT import Unison.DataDeclaration (DataDeclaration, EffectDeclaration) @@ -93,9 +93,18 @@ resolveUnresolvedModifier unresolvedModifier var = UnresolvedModifier'Structural -> pure (DD.Structural <$ unresolvedModifier) UnresolvedModifier'UniqueWithGuid guid -> pure (DD.Unique guid <$ unresolvedModifier) UnresolvedModifier'UniqueWithoutGuid guid0 -> do - ParsingEnv {uniqueTypeGuid} <- ask - guid <- fromMaybe guid0 <$> lift (lift (uniqueTypeGuid (Name.unsafeFromVar var))) - pure (DD.Unique guid <$ unresolvedModifier) + unique <- resolveUniqueModifier var guid0 + pure $ unique <$ unresolvedModifier + +resolveUniqueModifier :: (Monad m, Var v) => v -> Text -> P v m DD.Modifier +resolveUniqueModifier var guid0 = do + ParsingEnv {uniqueTypeGuid} <- ask + guid <- fromMaybe guid0 <$> lift (lift (uniqueTypeGuid (Name.unsafeFromVar var))) + pure $ DD.Unique guid + +defaultUniqueModifier :: (Monad m, Var v) => v -> P v m DD.Modifier +defaultUniqueModifier var = + uniqueName 32 >>= resolveUniqueModifier var -- unique[someguid] type Blah = ... modifier :: (Monad m, Var v) => P v m (Maybe (L.Token UnresolvedModifier)) @@ -104,11 +113,11 @@ modifier = do where unique = do tok <- openBlockWith "unique" - optional (openBlockWith "[" *> wordyIdString <* closeBlock) >>= \case + optional (openBlockWith "[" *> importWordyId <* closeBlock) >>= \case Nothing -> do guid <- uniqueName 32 pure (UnresolvedModifier'UniqueWithoutGuid guid <$ tok) - Just guid -> pure (UnresolvedModifier'UniqueWithGuid (Text.pack (L.payload guid)) <$ tok) + Just guid -> pure (UnresolvedModifier'UniqueWithGuid (Name.toText (L.payload guid)) <$ tok) structural = do tok <- openBlockWith "structural" pure (UnresolvedModifier'Structural <$ tok) @@ -132,7 +141,7 @@ dataDeclaration :: Maybe (L.Token UnresolvedModifier) -> P v m (v, DataDeclaration v Ann, Accessors v) dataDeclaration maybeUnresolvedModifier = do - keywordTok <- fmap void (reserved "type") <|> openBlockWith "type" + typeToken <- fmap void (reserved "type") <|> openBlockWith "type" (name, typeArgs) <- (,) <$> TermParser.verifyRelativeVarName prefixDefinitionName @@ -158,7 +167,7 @@ dataDeclaration maybeUnresolvedModifier = do prefixVar = TermParser.verifyRelativeVarName prefixDefinitionName dataConstructor :: P v m (Ann, v, Type v Ann) dataConstructor = go <$> prefixVar <*> many TypeParser.valueTypeLeaf - record :: P v m ([(Ann, v, Type v Ann)], [(L.Token v, [(L.Token v, Type v Ann)])]) + record :: P v m ([(Ann, v, Type v Ann)], [(L.Token v, [(L.Token v, Type v Ann)])], Ann) record = do _ <- openBlockWith "{" let field :: P v m [(L.Token v, Type v Ann)] @@ -170,23 +179,35 @@ dataDeclaration maybeUnresolvedModifier = do Just _ -> maybe [f] (f :) <$> (optional semi *> optional field) ) fields <- field - _ <- closeBlock + closingToken <- closeBlock let lastSegment = name <&> (\v -> Var.named (Name.toText $ Name.unqualified (Name.unsafeFromVar v))) - pure ([go lastSegment (snd <$> fields)], [(name, fields)]) - (constructors, accessors) <- - msum [record, (,[]) <$> sepBy (reserved "|") dataConstructor] + pure ([go lastSegment (snd <$> fields)], [(name, fields)], ann closingToken) + (constructors, accessors, closingAnn) <- + msum [Left <$> record, Right <$> sepBy (reserved "|") dataConstructor] <&> \case + Left (constructors, accessors, closingAnn) -> (constructors, accessors, closingAnn) + Right constructors -> + let closingAnn :: Ann + closingAnn = NonEmpty.last (ann eq NonEmpty.:| ((\(_, _, t) -> ann t) <$> constructors)) + in (constructors, [], closingAnn) _ <- closeBlock - let -- the annotation of the last constructor if present, - -- otherwise ann of name - closingAnn :: Ann - closingAnn = last (ann eq : ((\(_, _, t) -> ann t) <$> constructors)) case maybeUnresolvedModifier of - Nothing -> P.customFailure $ MissingTypeModifier ("type" <$ keywordTok) name + Nothing -> do + modifier <- defaultUniqueModifier (L.payload name) + -- ann spanning the whole Decl. + let declSpanAnn = ann typeToken <> closingAnn + pure + ( L.payload name, + DD.mkDataDecl' modifier declSpanAnn typeArgVs constructors, + accessors + ) Just unresolvedModifier -> do modifier <- resolveUnresolvedModifier unresolvedModifier (L.payload name) + -- ann spanning the whole Decl. + -- Technically the typeToken is redundant here, but this is more future proof. + let declSpanAnn = ann typeToken <> ann modifier <> closingAnn pure ( L.payload name, - DD.mkDataDecl' (L.payload modifier) (ann modifier <> closingAnn) typeArgVs constructors, + DD.mkDataDecl' (L.payload modifier) declSpanAnn typeArgVs constructors, accessors ) @@ -196,7 +217,7 @@ effectDeclaration :: Maybe (L.Token UnresolvedModifier) -> P v m (v, EffectDeclaration v Ann) effectDeclaration maybeUnresolvedModifier = do - keywordTok <- fmap void (reserved "ability") <|> openBlockWith "ability" + abilityToken <- fmap void (reserved "ability") <|> openBlockWith "ability" name <- TermParser.verifyRelativeVarName prefixDefinitionName typeArgs <- many (TermParser.verifyRelativeVarName prefixDefinitionName) let typeArgVs = L.payload <$> typeArgs @@ -208,14 +229,24 @@ effectDeclaration maybeUnresolvedModifier = do last $ ann blockStart : ((\(_, _, t) -> ann t) <$> constructors) case maybeUnresolvedModifier of - Nothing -> P.customFailure $ MissingTypeModifier ("ability" <$ keywordTok) name + Nothing -> do + modifier <- defaultUniqueModifier (L.payload name) + -- ann spanning the whole ability declaration. + let abilitySpanAnn = ann abilityToken <> closingAnn + pure + ( L.payload name, + DD.mkEffectDecl' modifier abilitySpanAnn typeArgVs constructors + ) Just unresolvedModifier -> do modifier <- resolveUnresolvedModifier unresolvedModifier (L.payload name) + -- ann spanning the whole ability declaration. + -- Technically the abilityToken is redundant here, but this is more future proof. + let abilitySpanAnn = ann abilityToken <> ann modifier <> closingAnn pure ( L.payload name, DD.mkEffectDecl' (L.payload modifier) - (ann modifier <> closingAnn) + abilitySpanAnn typeArgVs constructors ) diff --git a/parser-typechecker/src/Unison/Syntax/DeclPrinter.hs b/parser-typechecker/src/Unison/Syntax/DeclPrinter.hs index 9b3011bba9..ed86480ab6 100644 --- a/parser-typechecker/src/Unison/Syntax/DeclPrinter.hs +++ b/parser-typechecker/src/Unison/Syntax/DeclPrinter.hs @@ -83,7 +83,7 @@ prettyGADT env ctorType r name dd = constructor (n, (_, _, t)) = prettyPattern (PPED.unsuffixifiedPPE env) ctorType name (ConstructorReference r n) <> fmt S.TypeAscriptionColon " :" - `P.hang` TypePrinter.prettySyntax (PPED.suffixifiedPPE env) t + `P.hang` TypePrinter.prettySyntax (PPED.suffixifiedPPE env) t header = prettyEffectHeader name (DD.EffectDeclaration dd) <> fmt S.ControlKeyword " where" prettyPattern :: @@ -112,11 +112,12 @@ prettyDataDecl :: DataDeclaration v a -> Writer [AccessorName] (Pretty SyntaxText) prettyDataDecl (PrettyPrintEnvDecl unsuffixifiedPPE suffixifiedPPE) r name dd = - (header <>) . P.sep (fmt S.DelimiterChar (" | " `P.orElse` "\n | ")) + (header <>) + . P.sep (fmt S.DelimiterChar (" | " `P.orElse` "\n | ")) <$> constructor - `traverse` zip - [0 ..] - (DD.constructors' dd) + `traverse` zip + [0 ..] + (DD.constructors' dd) where constructor (n, (_, _, Type.ForallsNamed' _ t)) = constructor' n t constructor (n, (_, _, t)) = constructor' n t @@ -147,7 +148,7 @@ prettyDataDecl (PrettyPrintEnvDecl unsuffixifiedPPE suffixifiedPPE) r name dd = P.group $ styleHashQualified'' (fmt (S.TypeReference r)) fname <> fmt S.TypeAscriptionColon " :" - `P.hang` runPretty suffixifiedPPE (TypePrinter.prettyRaw Map.empty (-1) typ) + `P.hang` runPretty suffixifiedPPE (TypePrinter.prettyRaw Map.empty (-1) typ) header = prettyDataHeader name dd <> fmt S.DelimiterChar (" = " `P.orElse` "\n = ") -- Comes up with field names for a data declaration which has the form of a @@ -199,8 +200,9 @@ fieldNames env r name dd = do prettyModifier :: DD.Modifier -> Pretty SyntaxText prettyModifier DD.Structural = fmt S.DataTypeModifier "structural" -prettyModifier (DD.Unique _uid) = - fmt S.DataTypeModifier "unique" -- <> ("[" <> P.text uid <> "] ") +prettyModifier (DD.Unique _uid) = mempty -- don't print anything since 'unique' is the default +-- leaving this comment for the historical record so the syntax for uid is not forgotten +-- fmt S.DataTypeModifier "unique" -- <> ("[" <> P.text uid <> "] ") prettyDataHeader :: (Var v) => HQ.HashQualified Name -> DD.DataDeclaration v a -> Pretty SyntaxText diff --git a/parser-typechecker/src/Unison/Syntax/FileParser.hs b/parser-typechecker/src/Unison/Syntax/FileParser.hs index 9390053e49..ead8f3b15e 100644 --- a/parser-typechecker/src/Unison/Syntax/FileParser.hs +++ b/parser-typechecker/src/Unison/Syntax/FileParser.hs @@ -9,14 +9,16 @@ import Unison.ABT qualified as ABT import Unison.DataDeclaration (DataDeclaration) import Unison.DataDeclaration qualified as DD import Unison.Name qualified as Name +import Unison.NameSegment (NameSegment (..)) import Unison.Names qualified as Names import Unison.Names.ResolutionResult qualified as Names import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann) +import Unison.Parser.Ann qualified as Ann import Unison.Prelude import Unison.Syntax.DeclParser (declarations) import Unison.Syntax.Lexer qualified as L -import Unison.Syntax.Name qualified as Name (unsafeFromVar) +import Unison.Syntax.Name qualified as Name (toString, unsafeFromVar) import Unison.Syntax.Parser import Unison.Syntax.TermParser qualified as TermParser import Unison.Term (Term) @@ -47,7 +49,7 @@ file = do Left es -> resolutionFailures (toList es) let accessors :: [[(v, Ann, Term v Ann)]] accessors = - [ DD.generateRecordAccessors (toPair <$> fields) (L.payload typ) r + [ DD.generateRecordAccessors Ann.GeneratedFrom (toPair <$> fields) (L.payload typ) r | (typ, fields) <- parsedAccessors, Just (r, _) <- [Map.lookup (L.payload typ) (UF.datas env)] ] @@ -193,9 +195,10 @@ stanza = watchExpression <|> unexpectedAction <|> binding (kind, guid, ann) <- watched _ <- guardEmptyWatch ann msum - [ WatchBinding kind ann <$> TermParser.binding, - WatchExpression kind guid ann <$> TermParser.blockTerm + [ TermParser.binding <&> (\trm@(((trmSpanAnn, _), _)) -> WatchBinding kind (ann <> trmSpanAnn) trm), + TermParser.blockTerm <&> (\trm -> WatchExpression kind guid (ann <> ABT.annotation trm) trm) ] + guardEmptyWatch ann = P.try $ do op <- optional (L.payload <$> P.lookAhead closeBlock) @@ -216,10 +219,10 @@ stanza = watchExpression <|> unexpectedAction <|> binding watched :: (Monad m, Var v) => P v m (UF.WatchKind, Text, Ann) watched = P.try do - kind <- optional wordyIdString + kind <- (fmap . fmap . fmap) Name.toString (optional importWordyId) guid <- uniqueName 10 - op <- optional (L.payload <$> P.lookAhead symbolyIdString) - guard (op == Just ">") + op <- optional (L.payload <$> P.lookAhead importSymbolyId) + guard (op == Just (Name.fromSegment (NameSegment ">"))) tok <- anyToken guard $ maybe True (`L.touches` tok) kind pure (maybe UF.RegularWatch L.payload kind, guid, maybe mempty ann kind <> ann tok) diff --git a/parser-typechecker/src/Unison/Syntax/TermParser.hs b/parser-typechecker/src/Unison/Syntax/TermParser.hs index c6c27de716..e4173dad5a 100644 --- a/parser-typechecker/src/Unison/Syntax/TermParser.hs +++ b/parser-typechecker/src/Unison/Syntax/TermParser.hs @@ -30,8 +30,11 @@ import Unison.Builtin.Decls qualified as DD import Unison.ConstructorReference (ConstructorReference, GConstructorReference (..)) import Unison.ConstructorType qualified as CT import Unison.HashQualified qualified as HQ +import Unison.HashQualified' qualified as HQ' import Unison.Name (Name) import Unison.Name qualified as Name +import Unison.NameSegment (NameSegment (..)) +import Unison.NameSegment qualified as NameSegment import Unison.Names (Names) import Unison.Names qualified as Names import Unison.NamesWithHistory qualified as Names @@ -256,7 +259,9 @@ parsePattern = label "pattern" root text = (\t -> Pattern.Text (ann t) (L.payload t)) <$> string char = (\c -> Pattern.Char (ann c) (L.payload c)) <$> character parenthesizedOrTuplePattern :: P v m (Pattern Ann, [(Ann, v)]) - parenthesizedOrTuplePattern = tupleOrParenthesized parsePattern unit pair + parenthesizedOrTuplePattern = do + (_spanAnn, (pat, pats)) <- tupleOrParenthesized parsePattern unit pair + pure (pat, pats) unit ann = (Pattern.Constructor ann (ConstructorReference DD.unitRef 0) [], []) pair (p1, v1) (p2, v2) = ( Pattern.Constructor (ann p1 <> ann p2) (ConstructorReference DD.pairRef 0) [p1, p2], @@ -402,16 +407,22 @@ hashQualifiedPrefixTerm = resolveHashQualified =<< hqPrefixId hashQualifiedInfixTerm :: (Monad m, Var v) => TermP v m hashQualifiedInfixTerm = resolveHashQualified =<< hqInfixId -quasikeyword :: (Ord v) => String -> P v m (L.Token ()) +quasikeyword :: Ord v => Text -> P v m (L.Token ()) quasikeyword kw = queryToken \case - L.WordyId s Nothing | s == kw -> Just () + L.WordyId (HQ'.NameOnly n) | nameIsKeyword n kw -> Just () _ -> Nothing -symbolyQuasikeyword :: (Ord v) => String -> P v m (L.Token ()) +symbolyQuasikeyword :: (Ord v) => Text -> P v m (L.Token ()) symbolyQuasikeyword kw = queryToken \case - L.SymbolyId s Nothing | s == kw -> Just () + L.SymbolyId (HQ'.NameOnly n) | nameIsKeyword n kw -> Just () _ -> Nothing +nameIsKeyword :: Name -> Text -> Bool +nameIsKeyword name keyword = + case (Name.isRelative name, Name.reverseSegments name) of + (True, segment NonEmpty.:| []) -> NameSegment.toText segment == keyword + _ -> False + -- If the hash qualified is name only, it is treated as a var, if it -- has a short hash, we resolve that short hash immediately and fail -- committed if that short hash can't be found in the current environment @@ -960,9 +971,9 @@ bang = P.label "bang" do seqOp :: (Ord v) => P v m Pattern.SeqOp seqOp = - (Pattern.Snoc <$ matchToken (L.SymbolyId ":+" Nothing)) - <|> (Pattern.Cons <$ matchToken (L.SymbolyId "+:" Nothing)) - <|> (Pattern.Concat <$ matchToken (L.SymbolyId "++" Nothing)) + Pattern.Snoc <$ matchToken (L.SymbolyId (HQ'.fromName (Name.fromSegment (NameSegment ":+")))) + <|> Pattern.Cons <$ matchToken (L.SymbolyId (HQ'.fromName (Name.fromSegment (NameSegment "+:")))) + <|> Pattern.Concat <$ matchToken (L.SymbolyId (HQ'.fromName (Name.fromSegment (NameSegment "++")))) term4 :: (Monad m, Var v) => TermP v m term4 = f <$> some termLeaf @@ -1064,7 +1075,9 @@ binding = label "binding" do (lhsLoc, name, args) <- P.try (lhs <* P.lookAhead (openBlockWith "=")) body <- block "=" verifyRelativeName' (fmap Name.unsafeFromVar name) - pure $ mkBinding (lhsLoc <> ann body) (L.payload name) args body + let binding = mkBinding lhsLoc args body + let spanAnn = ann lhsLoc <> ann binding + pure $ ((spanAnn, (L.payload name)), binding) Just (nameT, typ) -> do (lhsLoc, name, args) <- lhs verifyRelativeName' (fmap Name.unsafeFromVar name) @@ -1072,14 +1085,14 @@ binding = label "binding" do customFailure $ SignatureNeedsAccompanyingBody nameT body <- block "=" - pure $ - fmap - (\e -> Term.ann (ann nameT <> ann e) e typ) - (mkBinding (ann lhsLoc <> ann body) (L.payload name) args body) + let binding = mkBinding lhsLoc args body + let spanAnn = ann nameT <> ann binding + pure $ ((spanAnn, L.payload name), Term.ann (ann nameT <> ann binding) binding typ) where - mkBinding loc f [] body = ((loc, f), body) - mkBinding loc f args body = - ((loc, f), Term.lam' (loc <> ann body) (L.payload <$> args) body) + mkBinding :: Ann -> [L.Token v] -> Term.Term v Ann -> Term.Term v Ann + mkBinding _lhsLoc [] body = body + mkBinding lhsLoc args body = + (Term.lam' (lhsLoc <> ann body) (L.payload <$> args) body) customFailure :: (P.MonadParsec e s m) => e -> m a customFailure = P.customFailure @@ -1247,7 +1260,9 @@ number' i u f = fmap go numeric | otherwise = u (read <$> num) tupleOrParenthesizedTerm :: (Monad m, Var v) => TermP v m -tupleOrParenthesizedTerm = label "tuple" $ tupleOrParenthesized term DD.unitTerm pair +tupleOrParenthesizedTerm = label "tuple" $ do + (spanAnn, tm) <- tupleOrParenthesized term DD.unitTerm pair + pure $ tm {ABT.annotation = spanAnn} where pair t1 t2 = Term.app diff --git a/parser-typechecker/src/Unison/Syntax/TypeParser.hs b/parser-typechecker/src/Unison/Syntax/TypeParser.hs index 5fc1525382..f1b4786e0c 100644 --- a/parser-typechecker/src/Unison/Syntax/TypeParser.hs +++ b/parser-typechecker/src/Unison/Syntax/TypeParser.hs @@ -3,8 +3,12 @@ module Unison.Syntax.TypeParser where import Control.Monad.Reader (asks) import Data.Set qualified as Set import Text.Megaparsec qualified as P +import Unison.ABT qualified as ABT import Unison.Builtin.Decls qualified as DD import Unison.HashQualified qualified as HQ +import Unison.HashQualified' qualified as HQ' +import Unison.Name qualified as Name +import Unison.NameSegment (NameSegment (NameSegment)) import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann (..)) import Unison.Prelude @@ -93,8 +97,10 @@ sequenceTyp = do let a = ann open <> ann close pure $ Type.app a (Type.list a) t -tupleOrParenthesizedType :: (Var v) => TypeP v m -> TypeP v m -tupleOrParenthesizedType rec = tupleOrParenthesized rec DD.unitType pair +tupleOrParenthesizedType :: Var v => TypeP v m -> TypeP v m +tupleOrParenthesizedType rec = do + (spanAnn, ty) <- tupleOrParenthesized rec DD.unitType pair + pure (ty {ABT.annotation = ABT.annotation ty <> spanAnn}) where pair t1 t2 = let a = ann t1 <> ann t2 @@ -113,6 +119,6 @@ forall :: (Var v) => TypeP v m -> TypeP v m forall rec = do kw <- reserved "forall" <|> reserved "∀" vars <- fmap (fmap L.payload) . some $ prefixDefinitionName - _ <- matchToken $ L.SymbolyId "." Nothing + _ <- matchToken $ L.SymbolyId (HQ'.fromName (Name.fromSegment (NameSegment "."))) t <- rec pure $ Type.foralls (ann kw <> ann t) vars t diff --git a/parser-typechecker/src/Unison/Typechecker/Components.hs b/parser-typechecker/src/Unison/Typechecker/Components.hs index 848201a3f4..ccef8995d3 100644 --- a/parser-typechecker/src/Unison/Typechecker/Components.hs +++ b/parser-typechecker/src/Unison/Typechecker/Components.hs @@ -47,9 +47,10 @@ minimize (Term.LetRecNamedAnnotatedTop' isTop blockAnn bs e) = (compare `on` fst) grouped = group bindings dupes = filter ok grouped - where - ok (v, as) | Var.name v == "_" = False - | otherwise = length as > 1 + where + ok (v, as) + | Var.name v == "_" = False + | otherwise = length as > 1 in if not $ null dupes then Left $ Nel.fromList dupes else diff --git a/parser-typechecker/src/Unison/Typechecker/Extractor.hs b/parser-typechecker/src/Unison/Typechecker/Extractor.hs index 0da268534a..7e977f4367 100644 --- a/parser-typechecker/src/Unison/Typechecker/Extractor.hs +++ b/parser-typechecker/src/Unison/Typechecker/Extractor.hs @@ -1,12 +1,12 @@ module Unison.Typechecker.Extractor where -import Unison.KindInference (KindError) import Control.Monad.Reader import Data.List qualified as List import Data.List.NonEmpty (NonEmpty) import Data.Set qualified as Set import Unison.Blank qualified as B import Unison.ConstructorReference (ConstructorReference) +import Unison.KindInference (KindError) import Unison.Pattern (Pattern) import Unison.Prelude hiding (whenM) import Unison.Term qualified as Term diff --git a/parser-typechecker/src/Unison/UnisonFile/Names.hs b/parser-typechecker/src/Unison/UnisonFile/Names.hs index a77309b474..667e0016f6 100644 --- a/parser-typechecker/src/Unison/UnisonFile/Names.hs +++ b/parser-typechecker/src/Unison/UnisonFile/Names.hs @@ -9,20 +9,21 @@ import Unison.DataDeclaration (DataDeclaration, EffectDeclaration (..)) import Unison.DataDeclaration qualified as DD import Unison.DataDeclaration.Names qualified as DD.Names import Unison.Hashing.V2.Convert qualified as Hashing +import Unison.Name qualified as Name import Unison.Names (Names (..)) import Unison.Names.ResolutionResult qualified as Names +import Unison.NamesWithHistory qualified as Names import Unison.Prelude import Unison.Reference qualified as Reference import Unison.Referent qualified as Referent -import Unison.Name qualified as Name import Unison.Syntax.Name qualified as Name import Unison.Term qualified as Term import Unison.UnisonFile qualified as UF import Unison.UnisonFile.Env (Env (..)) import Unison.UnisonFile.Error (Error (DupDataAndAbility, UnknownType)) import Unison.UnisonFile.Type (TypecheckedUnisonFile (TypecheckedUnisonFileId), UnisonFile (UnisonFileId)) -import Unison.Util.Relation qualified as Relation import Unison.Util.List qualified as List +import Unison.Util.Relation qualified as Relation import Unison.Var (Var) import Unison.Var qualified as Var import Unison.WatchKind qualified as WK @@ -33,6 +34,9 @@ toNames uf = datas <> effects datas = foldMap (DD.Names.dataDeclToNames' Name.unsafeFromVar) (Map.toList (UF.dataDeclarationsId uf)) effects = foldMap (DD.Names.effectDeclToNames' Name.unsafeFromVar) (Map.toList (UF.effectDeclarationsId uf)) +addNamesFromUnisonFile :: (Var v) => UnisonFile v a -> Names -> Names +addNamesFromUnisonFile unisonFile names = Names.shadowing (toNames unisonFile) names + typecheckedToNames :: (Var v) => TypecheckedUnisonFile v a -> Names typecheckedToNames uf = Names (terms <> ctors) types where @@ -57,6 +61,9 @@ typecheckedToNames uf = Names (terms <> ctors) types . UF.hashConstructors $ uf +addNamesFromTypeCheckedUnisonFile :: (Var v) => TypecheckedUnisonFile v a -> Names -> Names +addNamesFromTypeCheckedUnisonFile unisonFile names = Names.shadowing (typecheckedToNames unisonFile) names + typecheckedUnisonFile0 :: (Ord v) => TypecheckedUnisonFile v a typecheckedUnisonFile0 = TypecheckedUnisonFileId Map.empty Map.empty mempty mempty mempty @@ -86,21 +93,21 @@ bindNames names (UnisonFileId d e ts ws) = do -- | Given the set of fully-qualified variable names, this computes -- a Map from unique suffixes to the fully qualified name. --- +-- -- Example, given [foo.bar, qux.bar, baz.quaffle], this returns: -- -- Map [ foo.bar -> foo.bar -- , qux.bar -> qux.bar -- , baz.quaffle -> baz.quaffle --- , quaffle -> baz.quaffle --- ] --- --- This is used to replace variable references with their canonical +-- , quaffle -> baz.quaffle +-- ] +-- +-- This is used to replace variable references with their canonical -- fully qualified variables. --- +-- -- It's used below in `environmentFor` and also during the term resolution -- process. -variableCanonicalizer :: forall v . Var v => [v] -> Map v v +variableCanonicalizer :: forall v. Var v => [v] -> Map v v variableCanonicalizer vs = done $ List.multimap do v <- vs @@ -108,7 +115,7 @@ variableCanonicalizer vs = suffix <- Name.suffixes n pure (Var.named (Name.toText suffix), v) where - done xs = Map.fromList [ (k, v) | (k, nubOrd -> [v]) <- Map.toList xs ] <> Map.fromList [(v,v) | v <- vs] + done xs = Map.fromList [(k, v) | (k, nubOrd -> [v]) <- Map.toList xs] <> Map.fromList [(v, v) | v <- vs] -- This function computes hashes for data and effect declarations, and -- also returns a function for resolving strings to (Reference, ConstructorId) diff --git a/parser-typechecker/src/Unison/UnisonFile/Summary.hs b/parser-typechecker/src/Unison/UnisonFile/Summary.hs new file mode 100644 index 0000000000..4fb92d4878 --- /dev/null +++ b/parser-typechecker/src/Unison/UnisonFile/Summary.hs @@ -0,0 +1,153 @@ +module Unison.UnisonFile.Summary + ( FileSummary (..), + allWatches, + allTypeDecls, + mkFileSummary, + fileDefLocations, + ) +where + +import Control.Lens +import Data.Foldable +import Data.Map qualified as Map +import Data.Set qualified as Set +import Unison.DataDeclaration qualified as DD +import Unison.Names (Names) +import Unison.Parser.Ann +import Unison.Prelude +import Unison.Reference qualified as Reference +import Unison.Symbol +import Unison.Symbol qualified as Symbol +import Unison.Term (Term) +import Unison.Term qualified as Term +import Unison.Type (Type) +import Unison.UnisonFile qualified as UF +import Unison.UnisonFile.Names qualified as UF +import Unison.Var qualified as Var +import Unison.WatchKind (pattern TestWatch) +import Unison.WatchKind qualified as WK + +-- | A file that parses might not always type-check, but often we just want to get as much +-- information as we have available. This provides a type where we can summarize the +-- information available in a Unison file. +-- +-- If the file typechecked then all the Ref Ids and types will be filled in, otherwise +-- they will be Nothing. +data FileSummary = FileSummary + { dataDeclsBySymbol :: Map Symbol (Reference.Id, DD.DataDeclaration Symbol Ann), + dataDeclsByReference :: Map Reference.Id (Map Symbol (DD.DataDeclaration Symbol Ann)), + effectDeclsBySymbol :: Map Symbol (Reference.Id, DD.EffectDeclaration Symbol Ann), + effectDeclsByReference :: Map Reference.Id (Map Symbol (DD.EffectDeclaration Symbol Ann)), + termsBySymbol :: Map Symbol (Ann, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann)), + termsByReference :: Map (Maybe Reference.Id) (Map Symbol (Ann, Term Symbol Ann, Maybe (Type Symbol Ann))), + testWatchSummary :: [(Ann, Maybe Symbol, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann))], + exprWatchSummary :: [(Ann, Maybe Symbol, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann), Maybe WK.WatchKind)], + fileNames :: Names + } + deriving stock (Show) + +allWatches :: FileSummary -> [(Ann, Maybe Symbol, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann), Maybe WK.WatchKind)] +allWatches FileSummary {testWatchSummary, exprWatchSummary} = + exprWatchSummary + <> (testWatchSummary <&> \(ann, sym, refId, tm, typ) -> (ann, sym, refId, tm, typ, Just WK.TestWatch)) + +allTypeDecls :: FileSummary -> Map Symbol (Reference.Id, Either (DD.EffectDeclaration Symbol Ann) (DD.DataDeclaration Symbol Ann)) +allTypeDecls FileSummary {dataDeclsBySymbol, effectDeclsBySymbol} = + let dataDecls = dataDeclsBySymbol <&> \(refId, dd) -> (refId, Right dd) + effectDecls = effectDeclsBySymbol <&> \(refId, ed) -> (refId, Left ed) + in dataDecls <> effectDecls + +-- | Summarize the information available to us from the current state of the file. +-- See 'FileSummary' for more information. +mkFileSummary :: Maybe (UF.UnisonFile Symbol Ann) -> Maybe (UF.TypecheckedUnisonFile Symbol Ann) -> Maybe FileSummary +mkFileSummary parsed typechecked = case (parsed, typechecked) of + (Nothing, Nothing) -> Nothing + (_, Just tf@(UF.TypecheckedUnisonFileId {dataDeclarationsId', effectDeclarationsId', hashTermsId})) -> + let (trms, testWatches, exprWatches) = + hashTermsId & ifoldMap \sym (ann, ref, wk, trm, typ) -> + case wk of + Nothing -> (Map.singleton sym (ann, Just ref, trm, getUserTypeAnnotation sym <|> Just typ), mempty, mempty) + Just TestWatch -> (mempty, [(ann, assertUserSym sym, Just ref, trm, getUserTypeAnnotation sym <|> Just typ)], mempty) + Just wk -> (mempty, mempty, [(ann, assertUserSym sym, Just ref, trm, getUserTypeAnnotation sym <|> Just typ, Just wk)]) + in Just $ + FileSummary + { dataDeclsBySymbol = dataDeclarationsId', + dataDeclsByReference = declsRefMap dataDeclarationsId', + effectDeclsBySymbol = effectDeclarationsId', + effectDeclsByReference = declsRefMap effectDeclarationsId', + termsBySymbol = trms, + termsByReference = termsRefMap trms, + testWatchSummary = testWatches, + exprWatchSummary = exprWatches, + fileNames = UF.typecheckedToNames tf + } + (Just uf@(UF.UnisonFileId {dataDeclarationsId, effectDeclarationsId, terms, watches}), _) -> + let trms = + terms & foldMap \(sym, ann, trm) -> + (Map.singleton sym (ann, Nothing, trm, Nothing)) + (testWatches, exprWatches) = + watches & ifoldMap \wk tms -> + tms & foldMap \(v, ann, trm) -> + case wk of + TestWatch -> ([(ann, assertUserSym v, Nothing, trm, Nothing)], mempty) + _ -> (mempty, [(ann, assertUserSym v, Nothing, trm, Nothing, Just wk)]) + in Just $ + FileSummary + { dataDeclsBySymbol = dataDeclarationsId, + dataDeclsByReference = declsRefMap dataDeclarationsId, + effectDeclsBySymbol = effectDeclarationsId, + effectDeclsByReference = declsRefMap effectDeclarationsId, + termsBySymbol = trms, + termsByReference = termsRefMap trms, + testWatchSummary = testWatches, + exprWatchSummary = exprWatches, + fileNames = UF.toNames uf + } + where + declsRefMap :: (Ord v, Ord r) => Map v (r, a) -> Map r (Map v a) + declsRefMap m = + m + & Map.toList + & fmap (\(v, (r, a)) -> (r, Map.singleton v a)) + & Map.fromListWith (<>) + termsRefMap :: (Ord v, Ord r) => Map v (ann, r, a, b) -> Map r (Map v (ann, a, b)) + termsRefMap m = + m + & Map.toList + & fmap (\(v, (ann, r, a, b)) -> (r, Map.singleton v (ann, a, b))) + & Map.fromListWith (<>) + -- Gets the user provided type annotation for a term if there is one. + -- This type sig will have Ann's within the file if it exists. + getUserTypeAnnotation :: Symbol -> Maybe (Type Symbol Ann) + getUserTypeAnnotation v = do + UF.UnisonFileId {terms, watches} <- parsed + trm <- (terms <> fold watches) ^? folded . filteredBy (_1 . only v) . _3 + typ <- Term.getTypeAnnotation trm + pure typ + + -- \| If a symbol is a 'User' symbol, return (Just sym), otherwise return Nothing. + assertUserSym :: Symbol -> Maybe Symbol + assertUserSym sym = case sym of + Symbol.Symbol _ (Var.User {}) -> Just sym + _ -> Nothing + +-- | Compute the location of user defined definitions within the file +fileDefLocations :: FileSummary -> Map Symbol (Set Ann) +fileDefLocations fs@FileSummary {dataDeclsBySymbol, effectDeclsBySymbol, termsBySymbol} = + fold + [ dataDeclsBySymbol <&> \(_, decl) -> + decl + & DD.annotation + & Set.singleton, + effectDeclsBySymbol <&> \(_, decl) -> + decl + & DD.toDataDecl + & DD.annotation + & Set.singleton, + (allWatches fs) + & foldMap \(ann, maySym, _id, _trm, _typ, _wk) -> + case maySym of + Nothing -> mempty + Just sym -> Map.singleton sym (Set.singleton ann), + termsBySymbol <&> \(ann, _id, _trm, _typ) -> Set.singleton ann + ] diff --git a/parser-typechecker/tests/Unison/Core/Test/Name.hs b/parser-typechecker/tests/Unison/Core/Test/Name.hs index 0776d9bc3e..fbf7cc8205 100644 --- a/parser-typechecker/tests/Unison/Core/Test/Name.hs +++ b/parser-typechecker/tests/Unison/Core/Test/Name.hs @@ -92,24 +92,24 @@ testSuffixSearch = (Name.searchBySuffix (n "map") rel) expectEqual' (n "List.map") - (Name.shortestUniqueSuffix (n "base.List.map") rel) + (Name.suffixifyByHash (n "base.List.map") rel) expectEqual' (n "Set.map") - (Name.shortestUniqueSuffix (n "base.Set.map") rel) + (Name.suffixifyByHash (n "base.Set.map") rel) expectEqual' (n "baz") - (Name.shortestUniqueSuffix (n "foo.bar.baz") rel) + (Name.suffixifyByHash (n "foo.bar.baz") rel) expectEqual' (n "a.b.c") - (Name.shortestUniqueSuffix (n "a.b.c") rel) + (Name.suffixifyByHash (n "a.b.c") rel) expectEqual' (n "a1.b.c") - (Name.shortestUniqueSuffix (n "a1.b.c") rel) + (Name.suffixifyByHash (n "a1.b.c") rel) note . show $ Name.reverseSegments (n ".") note . show $ Name.reverseSegments (n "..") tests [ scope "(.) shortest unique suffix" $ - expectEqual' (n ".") (Name.shortestUniqueSuffix (n "..") rel), + expectEqual' (n ".") (Name.suffixifyByHash (n "..") rel), scope "(.) search by suffix" $ expectEqual' (Set.fromList [6]) (Name.searchBySuffix (n ".") rel) ] diff --git a/parser-typechecker/tests/Unison/Test/Syntax/TypePrinter.hs b/parser-typechecker/tests/Unison/Test/Syntax/TypePrinter.hs index 4b5fb29abc..69a09a6874 100644 --- a/parser-typechecker/tests/Unison/Test/Syntax/TypePrinter.hs +++ b/parser-typechecker/tests/Unison/Test/Syntax/TypePrinter.hs @@ -21,7 +21,7 @@ import Unison.Util.Pretty qualified as PP tc_diff_rtt :: Bool -> String -> String -> PP.Width -> Test () tc_diff_rtt rtt s expected width = let input_type = Common.t s - get_names = PPE.fromNames Common.hqLength Unison.Builtin.names + get_names = PPE.makePPE (PPE.hqNamer Common.hqLength Unison.Builtin.names) PPE.dontSuffixify prettied = fmap toPlain $ PP.syntaxToColor . runPretty get_names $ prettyRaw Map.empty (-1) input_type actual = if width == 0 diff --git a/parser-typechecker/tests/Unison/Test/UnisonSources.hs b/parser-typechecker/tests/Unison/Test/UnisonSources.hs index 5849684327..e63945d3ce 100644 --- a/parser-typechecker/tests/Unison/Test/UnisonSources.hs +++ b/parser-typechecker/tests/Unison/Test/UnisonSources.hs @@ -1,6 +1,3 @@ -{-# LANGUAGE PatternSynonyms #-} -{-# LANGUAGE RankNTypes #-} - module Unison.Test.UnisonSources where import Control.Exception (throwIO) @@ -46,7 +43,7 @@ type SynthResult = type EitherResult = Either String TFile ppEnv :: PPE.PrettyPrintEnv -ppEnv = PPE.fromNames Common.hqLength Builtin.names +ppEnv = PPE.makePPE (PPE.hqNamer Common.hqLength Builtin.names) PPE.dontSuffixify expectRight' :: Either String a -> Test a expectRight' (Left e) = crash e @@ -103,9 +100,9 @@ decodeResult source (Result notes (Just (Left uf))) = in Left $ showNotes source - ( PPE.fromNames - Common.hqLength - (Names.shadowing errNames Builtin.names) + ( PPE.makePPE + (PPE.hqNamer Common.hqLength (Names.shadowing errNames Builtin.names)) + PPE.dontSuffixify ) notes decodeResult _source (Result _notes (Just (Right uf))) = diff --git a/parser-typechecker/unison-parser-typechecker.cabal b/parser-typechecker/unison-parser-typechecker.cabal index 340c52d0b5..096e339c02 100644 --- a/parser-typechecker/unison-parser-typechecker.cabal +++ b/parser-typechecker/unison-parser-typechecker.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.36.0. +-- This file has been generated from package.yaml by hpack version 0.35.2. -- -- see: https://github.com/sol/hpack @@ -177,6 +177,7 @@ library Unison.UnisonFile Unison.UnisonFile.Env Unison.UnisonFile.Names + Unison.UnisonFile.Summary Unison.UnisonFile.Type Unison.Util.Convert Unison.Util.CycleTable @@ -226,7 +227,8 @@ library ViewPatterns ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures build-depends: - ListLike + IntervalMap + , ListLike , NanoID , aeson , ansi-terminal @@ -416,7 +418,8 @@ test-suite parser-typechecker-tests ViewPatterns ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 build-depends: - ListLike + IntervalMap + , ListLike , NanoID , aeson , ansi-terminal diff --git a/scripts/check.sh b/scripts/check.sh index 9832d7d4fb..7d55fbc789 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -5,4 +5,5 @@ true \ && stack build --fast --test \ && stack exec transcripts \ && stack exec unison transcript unison-src/transcripts-round-trip/main.md \ + && stack exec unison transcript unison-src/transcripts-manual/rewrites.md \ && stack exec integration-tests diff --git a/scripts/make-release.sh b/scripts/make-release.sh index 0ab5dfb8b8..a8cba3b7aa 100755 --- a/scripts/make-release.sh +++ b/scripts/make-release.sh @@ -18,7 +18,7 @@ usage() { echo "E.g." echo "$0 M4a" echo "" - echo "The latest release is: $(git tag --list 'release/*' | sort -r | head -n 1 | sed 's/release\///')" + echo "I think the latest release is: $(git tag --list 'release/*' | grep -v M | sort -rV | head -n 1 | sed 's/release\///')" } if [[ -z "$1" ]] ; then diff --git a/unison-cli/src/Unison/Cli/Monad.hs b/unison-cli/src/Unison/Cli/Monad.hs index 6301ae0611..22d03dfb96 100644 --- a/unison-cli/src/Unison/Cli/Monad.hs +++ b/unison-cli/src/Unison/Cli/Monad.hs @@ -36,6 +36,7 @@ module Unison.Cli.Monad -- * Communicating output to the user respond, respondNumbered, + setNumberedArgs, -- * Debug-timing actions time, @@ -157,9 +158,6 @@ data Env = Env credentialManager :: CredentialManager, -- | Generate a unique name. generateUniqueName :: IO Parser.UniqueName, - -- | Are we currently running a transcript? Sometimes, it is convenient to know this fact, so we can put more - -- information to the terminal to be captured in transcript output. - isTranscript :: Bool, -- | How to load source code. loadSource :: SourceName -> IO LoadSourceResult, -- | How to write source code. @@ -415,6 +413,11 @@ respondNumbered :: NumberedOutput -> Cli () respondNumbered output = do Env {notifyNumbered} <- ask args <- liftIO (notifyNumbered output) + setNumberedArgs args + +-- | Updates the numbered args, but only if the new args are non-empty. +setNumberedArgs :: NumberedArgs -> Cli () +setNumberedArgs args = do unless (null args) do #numberedArgs .= args diff --git a/unison-cli/src/Unison/Cli/MonadUtils.hs b/unison-cli/src/Unison/Cli/MonadUtils.hs index 525e97fa5e..551f51c9f4 100644 --- a/unison-cli/src/Unison/Cli/MonadUtils.hs +++ b/unison-cli/src/Unison/Cli/MonadUtils.hs @@ -75,7 +75,7 @@ module Unison.Cli.MonadUtils -- * Latest touched Unison file getLatestFile, getLatestParsedFile, - getNamesFromLatestParsedFile, + getNamesFromLatestFile, getTermFromLatestParsedFile, expectLatestFile, expectLatestParsedFile, @@ -258,7 +258,8 @@ modifyRootBranch f = do getCurrentBranch :: Cli (Branch IO) getCurrentBranch = do path <- getCurrentPath - getBranchAt path + Cli.Env {codebase} <- ask + liftIO $ Codebase.getBranchAtPath codebase path -- | Get the current branch0. getCurrentBranch0 :: Cli (Branch0 IO) @@ -573,12 +574,14 @@ getTermFromLatestParsedFile (HQ.NameOnly n) = do _ -> Nothing getTermFromLatestParsedFile _ = pure Nothing -getNamesFromLatestParsedFile :: Cli Names -getNamesFromLatestParsedFile = do - uf <- getLatestParsedFile - pure $ case uf of +-- | Gets the names from the latest typechecked unison file, or latest parsed file if it +-- didn't typecheck. +getNamesFromLatestFile :: Cli Names +getNamesFromLatestFile = do + use #latestTypecheckedFile <&> \case + Just (Right tf) -> UFN.typecheckedToNames tf + Just (Left uf) -> UFN.toNames uf Nothing -> mempty - Just uf -> UFN.toNames uf -- | Get the latest typechecked unison file, or return early if there isn't one. expectLatestTypecheckedFile :: Cli (TypecheckedUnisonFile Symbol Ann) diff --git a/unison-cli/src/Unison/Cli/NamesUtils.hs b/unison-cli/src/Unison/Cli/NamesUtils.hs index bfca470609..8e36020459 100644 --- a/unison-cli/src/Unison/Cli/NamesUtils.hs +++ b/unison-cli/src/Unison/Cli/NamesUtils.hs @@ -1,65 +1,15 @@ -- | Utilities that have to do with constructing names objects. module Unison.Cli.NamesUtils - ( basicParseNames, - basicPrettyPrintNamesA, - displayNames, - getBasicPrettyPrintNames, - makePrintNamesFromLabeled', - makeShadowedPrintNamesFromHQ, + ( currentNames, ) where import Unison.Cli.Monad (Cli) -import Unison.Cli.MonadUtils qualified as Cli -import Unison.Codebase.Path (Path) -import Unison.Codebase.Path qualified as Path +import Unison.Cli.MonadUtils (getCurrentBranch0) +import Unison.Codebase.Branch.Names qualified as Branch import Unison.Names (Names) -import Unison.NamesWithHistory qualified as Names -import Unison.Server.Backend qualified as Backend -import Unison.UnisonFile (TypecheckedUnisonFile) -import Unison.UnisonFile.Names qualified as UF -import Unison.Var (Var) -basicParseNames :: Cli Names -basicParseNames = - fst <$> basicNames' Backend.Within - -basicPrettyPrintNamesA :: Cli Names -basicPrettyPrintNamesA = snd <$> basicNames' Backend.AllNames - --- implementation detail of basicParseNames and basicPrettyPrintNames -basicNames' :: (Path -> Backend.NameScoping) -> Cli (Names, Names) -basicNames' nameScoping = do - root' <- Cli.getRootBranch - currentPath' <- Cli.getCurrentPath - let (parse, pretty, _local) = Backend.namesForBranch root' (nameScoping $ Path.unabsolute currentPath') - pure (parse, pretty) - --- | Produce a `Names` needed to display all the hashes used in the given file. -displayNames :: - (Var v) => - TypecheckedUnisonFile v a -> - Cli Names -displayNames unisonFile = - -- voodoo - makeShadowedPrintNamesFromLabeled - (UF.typecheckedToNames unisonFile) - -getBasicPrettyPrintNames :: Cli Names -getBasicPrettyPrintNames = do - rootBranch <- Cli.getRootBranch - currentPath <- Cli.getCurrentPath - pure (Backend.prettyNamesForBranch rootBranch (Backend.AllNames (Path.unabsolute currentPath))) - -makePrintNamesFromLabeled' :: Cli Names -makePrintNamesFromLabeled' = - basicPrettyPrintNamesA - -makeShadowedPrintNamesFromHQ :: Names -> Cli Names -makeShadowedPrintNamesFromHQ shadowing = do - basicNames <- basicPrettyPrintNamesA - pure $ Names.shadowing shadowing basicNames - -makeShadowedPrintNamesFromLabeled :: Names -> Cli Names -makeShadowedPrintNamesFromLabeled shadowing = - Names.shadowing shadowing <$> makePrintNamesFromLabeled' +-- | Produce a 'Names' object which contains names for the current branch. +currentNames :: Cli Names +currentNames = do + Branch.toNames <$> getCurrentBranch0 diff --git a/unison-cli/src/Unison/Cli/Pretty.hs b/unison-cli/src/Unison/Cli/Pretty.hs index 9957b472a8..a8773ad4d2 100644 --- a/unison-cli/src/Unison/Cli/Pretty.hs +++ b/unison-cli/src/Unison/Cli/Pretty.hs @@ -437,7 +437,7 @@ prettyUnisonFile ppe uf@(UF.UnisonFileId datas effects terms watches) = sppe = PPED.suffixifiedPPE ppe' pb v tm = st $ TermPrinter.prettyBinding sppe v tm ppe' = PPED.PrettyPrintEnvDecl dppe dppe `PPED.addFallback` ppe - dppe = PPE.fromNames 8 (UF.toNames uf) + dppe = PPE.makePPE (PPE.hqNamer 8 (UF.toNames uf)) PPE.dontSuffixify rd = Reference.DerivedId hqv v = HQ.unsafeFromVar v diff --git a/unison-cli/src/Unison/Cli/PrettyPrintUtils.hs b/unison-cli/src/Unison/Cli/PrettyPrintUtils.hs index 0ab1a30ba2..17abdd49c5 100644 --- a/unison-cli/src/Unison/Cli/PrettyPrintUtils.hs +++ b/unison-cli/src/Unison/Cli/PrettyPrintUtils.hs @@ -1,31 +1,32 @@ -- | Utilities that have to do with constructing pretty-print environments, given stateful information in the Cli monad -- state/environment, such as the current path. module Unison.Cli.PrettyPrintUtils - ( prettyPrintEnvDecl, + ( prettyPrintEnvDeclFromNames, currentPrettyPrintEnvDecl, ) where import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli -import Unison.Cli.MonadUtils qualified as Cli +import Unison.Cli.NamesUtils qualified as Cli import Unison.Codebase qualified as Codebase -import Unison.Codebase.Path (Path) -import Unison.Codebase.Path qualified as Path import Unison.Names (Names) import Unison.Prelude +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPE hiding (biasTo) -import Unison.PrettyPrintEnvDecl.Names qualified as PPE -import Unison.Server.Backend qualified as Backend +import Unison.PrettyPrintEnvDecl.Names qualified as PPED -prettyPrintEnvDecl :: Names -> Cli PPE.PrettyPrintEnvDecl -prettyPrintEnvDecl ns = - Cli.runTransaction Codebase.hashLength <&> (`PPE.fromNamesDecl` ns) +-- | Builds a pretty print env decl from a names object. +prettyPrintEnvDeclFromNames :: Names -> Cli PPE.PrettyPrintEnvDecl +prettyPrintEnvDeclFromNames ns = + Cli.runTransaction Codebase.hashLength <&> \hashLen -> + PPED.makePPED (PPE.hqNamer hashLen ns) (PPE.suffixifyByHash ns) -- | Get a pretty print env decl for the current names at the current path. -currentPrettyPrintEnvDecl :: (Path -> Backend.NameScoping) -> Cli PPE.PrettyPrintEnvDecl -currentPrettyPrintEnvDecl scoping = do - root' <- Cli.getRootBranch - currentPath <- Cli.getCurrentPath - hqLen <- Cli.runTransaction Codebase.hashLength - pure $ Backend.getCurrentPrettyNames hqLen (scoping (Path.unabsolute currentPath)) root' +-- +-- Prefer using 'prettyPrintEnvDeclFromNames' when you've already got +-- a 'Names' value around, since using 'currentPrettyPrintEnvDecl' rebuilds the underlying +-- names object. +currentPrettyPrintEnvDecl :: Cli PPE.PrettyPrintEnvDecl +currentPrettyPrintEnvDecl = do + Cli.currentNames >>= prettyPrintEnvDeclFromNames diff --git a/unison-cli/src/Unison/Cli/ProjectUtils.hs b/unison-cli/src/Unison/Cli/ProjectUtils.hs index aa2c839efe..2a19ad25c4 100644 --- a/unison-cli/src/Unison/Cli/ProjectUtils.hs +++ b/unison-cli/src/Unison/Cli/ProjectUtils.hs @@ -3,6 +3,7 @@ module Unison.Cli.ProjectUtils ( -- * Project/path helpers getCurrentProject, expectCurrentProject, + expectCurrentProjectIds, getCurrentProjectIds, getCurrentProjectBranch, getProjectBranchForPath, @@ -12,6 +13,8 @@ module Unison.Cli.ProjectUtils projectBranchPath, projectBranchSegment, projectBranchPathPrism, + resolveBranchRelativePath, + branchRelativePathToAbsolute, -- * Name hydration hydrateNames, @@ -49,12 +52,47 @@ import Unison.Codebase.Editor.Output (Output (LocalProjectBranchDoesntExist)) import Unison.Codebase.Editor.Output qualified as Output import Unison.Codebase.Path (Path') import Unison.Codebase.Path qualified as Path +import Unison.CommandLine.BranchRelativePath (BranchRelativePath, ResolvedBranchRelativePath) +import Unison.CommandLine.BranchRelativePath qualified as BranchRelativePath import Unison.Prelude import Unison.Project (ProjectAndBranch (..), ProjectBranchName, ProjectName) import Unison.Project.Util import Unison.Sqlite qualified as Sqlite import Witch (unsafeFrom) +branchRelativePathToAbsolute :: BranchRelativePath -> Cli Path.Absolute +branchRelativePathToAbsolute brp = resolveBranchRelativePath brp <&> \case + BranchRelativePath.ResolvedLoosePath p -> p + BranchRelativePath.ResolvedBranchRelative projectBranch mRel -> + let projectBranchIds = getIds projectBranch + handleRel = case mRel of + Nothing -> id + Just rel -> flip Path.resolve rel + in handleRel (projectBranchPath projectBranchIds) + where + getIds = \case + ProjectAndBranch project branch -> ProjectAndBranch (view #projectId project) (view #branchId branch) + +resolveBranchRelativePath :: BranchRelativePath -> Cli ResolvedBranchRelativePath +resolveBranchRelativePath = \case + BranchRelativePath.BranchRelative brp -> case brp of + This projectBranch -> do + projectBranch <- expectProjectAndBranchByTheseNames (toThese projectBranch) + pure (BranchRelativePath.ResolvedBranchRelative projectBranch Nothing) + That path -> do + (projectBranch, _) <- expectCurrentProjectBranch + pure (BranchRelativePath.ResolvedBranchRelative projectBranch (Just path)) + These projectBranch path -> do + projectBranch <- expectProjectAndBranchByTheseNames (toThese projectBranch) + pure (BranchRelativePath.ResolvedBranchRelative projectBranch (Just path)) + BranchRelativePath.LoosePath path -> + BranchRelativePath.ResolvedLoosePath <$> Cli.resolvePath' path + where + toThese = \case + Left branchName -> That branchName + Right (projectName, branchName) -> These projectName branchName + + -- | Get the current project that a user is on. getCurrentProject :: Cli (Maybe Sqlite.Project) getCurrentProject = do @@ -76,6 +114,11 @@ getCurrentProjectIds :: Cli (Maybe (ProjectAndBranch ProjectId ProjectBranchId)) getCurrentProjectIds = fmap fst . preview projectBranchPathPrism <$> Cli.getCurrentPath +-- | Like 'getCurrentProjectIds', but fails with a message if the user is not on a project branch. +expectCurrentProjectIds :: Cli (ProjectAndBranch ProjectId ProjectBranchId) +expectCurrentProjectIds = + getCurrentProjectIds & onNothingM (Cli.returnEarly Output.NotOnProjectBranch) + -- | Get the current project+branch+branch path that a user is on. getCurrentProjectBranch :: Cli (Maybe (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch, Path.Path)) getCurrentProjectBranch = do diff --git a/unison-cli/src/Unison/Cli/UnisonConfigUtils.hs b/unison-cli/src/Unison/Cli/UnisonConfigUtils.hs index 991d6177be..b1dafa02f4 100644 --- a/unison-cli/src/Unison/Cli/UnisonConfigUtils.hs +++ b/unison-cli/src/Unison/Cli/UnisonConfigUtils.hs @@ -1,7 +1,6 @@ -- | @.unisonConfig@ file utilities module Unison.Cli.UnisonConfigUtils - ( defaultMetadataKey, - gitUrlKey, + ( gitUrlKey, remoteMappingKey, resolveConfiguredUrl, ) @@ -34,9 +33,6 @@ configKey k p = NameSegment.toText (Path.toSeq $ Path.unabsolute p) -defaultMetadataKey :: Path.Absolute -> Text -defaultMetadataKey = configKey "DefaultMetadata" - gitUrlKey :: Path.Absolute -> Text gitUrlKey = configKey "GitUrl" diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs index 30c2de7b71..9b1df2917a 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs @@ -11,7 +11,7 @@ where import Control.Error.Util qualified as ErrorUtil import Control.Exception (catch) -import Control.Lens +import Control.Lens hiding (from) import Control.Monad.Reader (ask) import Control.Monad.State (StateT) import Control.Monad.State qualified as State @@ -43,13 +43,12 @@ import U.Codebase.Sqlite.ProjectBranch qualified as Sqlite import U.Codebase.Sqlite.Queries qualified as Queries import Unison.ABT qualified as ABT import Unison.Builtin qualified as Builtin -import Unison.Builtin.Decls qualified as DD import Unison.Builtin.Terms qualified as Builtin import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils (basicParseNames, displayNames, getBasicPrettyPrintNames, makePrintNamesFromLabeled') -import Unison.Cli.PrettyPrintUtils (currentPrettyPrintEnvDecl, prettyPrintEnvDecl) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Cli.ProjectUtils qualified as ProjectUtils import Unison.Cli.TypeCheck (typecheckTerm) import Unison.Codebase (Codebase) @@ -72,8 +71,8 @@ import Unison.Codebase.Editor.HandleInput.DeleteBranch (handleDeleteBranch) import Unison.Codebase.Editor.HandleInput.DeleteProject (handleDeleteProject) import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace) import Unison.Codebase.Editor.HandleInput.FindAndReplace (handleStructuredFindI, handleStructuredFindReplaceI) +import Unison.Codebase.Editor.HandleInput.FormatFile qualified as Format import Unison.Codebase.Editor.HandleInput.Load (EvalMode (Sandboxed), evalUnisonFile, handleLoad, loadUnisonFile) -import Unison.Codebase.Editor.HandleInput.MetadataUtils (addDefaultMetadata, manageLinks) import Unison.Codebase.Editor.HandleInput.MoveAll (handleMoveAll) import Unison.Codebase.Editor.HandleInput.MoveBranch (doMoveBranch) import Unison.Codebase.Editor.HandleInput.MoveTerm (doMoveTerm) @@ -125,6 +124,7 @@ import Unison.Codebase.TermEdit.Typing qualified as TermEdit import Unison.Codebase.TypeEdit (TypeEdit) import Unison.Codebase.TypeEdit qualified as TypeEdit import Unison.Codebase.Verbosity qualified as Verbosity +import Unison.CommandLine.BranchRelativePath (BranchRelativePath) import Unison.CommandLine.Completion qualified as Completion import Unison.CommandLine.DisplayValues qualified as DisplayValues import Unison.CommandLine.InputPattern qualified as IP @@ -136,7 +136,6 @@ import Unison.Hash qualified as Hash import Unison.HashQualified qualified as HQ import Unison.HashQualified' qualified as HQ' import Unison.HashQualified' qualified as HashQualified -import Unison.Hashing.V2.Convert qualified as Hashing import Unison.JitInfo qualified as JitInfo import Unison.LabeledDependency (LabeledDependency) import Unison.LabeledDependency qualified as LD @@ -199,7 +198,6 @@ import Unison.Util.Pretty qualified as P import Unison.Util.Pretty qualified as Pretty import Unison.Util.Relation qualified as R import Unison.Util.Relation qualified as Relation -import Unison.Util.Relation4 qualified as R4 import Unison.Util.Set qualified as Set import Unison.Util.Star3 qualified as Star3 import Unison.Util.TransitiveClosure (transitiveClosure) @@ -282,9 +280,11 @@ loop e = do void $ propagatePatch description patch' currentPath Cli.respond Success previewResponse sourceName sr uf = do - names <- displayNames uf - ppe <- PPE.suffixifiedPPE <$> prettyPrintEnvDecl names - Cli.respond $ Typechecked (Text.pack sourceName) ppe sr uf + names <- Cli.currentNames + let namesWithDefinitionsFromFile = UF.addNamesFromTypeCheckedUnisonFile uf names + filePPED <- Cli.prettyPrintEnvDeclFromNames namesWithDefinitionsFromFile + let suffixifiedPPE = PPE.suffixifiedPPE filePPED + Cli.respond $ Typechecked (Text.pack sourceName) suffixifiedPPE sr uf in Cli.time "InputPattern" case input of ApiI -> do Cli.Env {serverBaseUrl} <- ask @@ -309,7 +309,7 @@ loop e = do let moreEntriesToLoad = length entries == numEntriesToShow let expandedEntries = List.unfoldr expandEntries (entries, Nothing, moreEntriesToLoad) let numberedEntries = expandedEntries <&> \(_time, hash, _reason) -> "#" <> SCH.toString hash - #numberedArgs .= numberedEntries + Cli.setNumberedArgs numberedEntries Cli.respond $ ShowReflog expandedEntries where expandEntries :: @@ -423,20 +423,21 @@ loop e = do Cli.updateRoot newRoot description Cli.respond Success ForkLocalBranchI src0 dest0 -> do - srcb <- + (srcb, branchEmpty) <- case src0 of - Left hash -> Cli.resolveShortCausalHash hash - Right path' -> Cli.expectBranchAtPath' path' - Cli.assertNoBranchAtPath' dest0 + Left hash -> (,WhichBranchEmptyHash hash) <$> Cli.resolveShortCausalHash hash + Right path' -> do + absPath <- ProjectUtils.branchRelativePathToAbsolute path' + let srcp = Path.convert absPath + srcb <- Cli.expectBranchAtPath' srcp + pure (srcb, WhichBranchEmptyPath srcp) description <- inputDescription input - dest <- Cli.resolvePath' dest0 + dest <- ProjectUtils.branchRelativePathToAbsolute dest0 ok <- Cli.updateAtM description dest (const $ pure srcb) Cli.respond if ok then Success - else BranchEmpty case src0 of - Left hash -> WhichBranchEmptyHash hash - Right path -> WhichBranchEmptyPath path + else BranchEmpty branchEmpty MergeLocalBranchI src0 dest0 mergeMode -> do description <- inputDescription input src0 <- ProjectUtils.expectLooseCodeOrProjectBranch src0 @@ -547,11 +548,10 @@ loop e = do Cli.respondNumbered (Output.ShowDiffAfterUndo ppe diff) UiI path' -> openUI path' DocToMarkdownI docName -> do - basicPrettyPrintNames <- getBasicPrettyPrintNames + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names hqLength <- Cli.runTransaction Codebase.hashLength - let pped = PPED.fromNamesDecl hqLength basicPrettyPrintNames - basicPrettyPrintNames <- basicParseNames - let nameSearch = NameSearch.makeNameSearch hqLength basicPrettyPrintNames + let nameSearch = NameSearch.makeNameSearch hqLength names Cli.Env {codebase, runtime} <- ask mdText <- liftIO $ do docRefs <- Backend.docsForDefinitionName codebase nameSearch Names.IncludeSuffixes docName @@ -587,15 +587,7 @@ loop e = do when (not (Set.null destTerms)) do Cli.returnEarly (TermAlreadyExists dest' destTerms) description <- inputDescription input - srcMetadata <- - case src of - Left _ -> pure Metadata.empty - Right (path, _) -> do - root0 <- Cli.getRootBranch0 - pure (BranchUtil.getTermMetadataAt (Path.convert path, ()) srcTerm root0) - Cli.stepAt - description - (BranchUtil.makeAddTermName (Path.convert dest) srcTerm srcMetadata) + Cli.stepAt description (BranchUtil.makeAddTermName (Path.convert dest) srcTerm) Cli.respond Success AliasTypeI src' dest' -> do src <- traverseOf _Right Cli.resolveSplit' src' @@ -618,15 +610,7 @@ loop e = do when (not (Set.null destTypes)) do Cli.returnEarly (TypeAlreadyExists dest' destTypes) description <- inputDescription input - srcMetadata <- - case src of - Left _ -> pure Metadata.empty - Right (path, _) -> do - root0 <- Cli.getRootBranch0 - pure (BranchUtil.getTypeMetadataAt (Path.convert path, ()) srcType root0) - Cli.stepAt - description - (BranchUtil.makeAddTypeName (Path.convert dest) srcType srcMetadata) + Cli.stepAt description (BranchUtil.makeAddTypeName (Path.convert dest) srcType) Cli.respond Success -- this implementation will happily produce name conflicts, @@ -654,9 +638,7 @@ loop e = do Path.HQSplit -> ([Path.HQSplit], [(Path, Branch0 m -> Branch0 m)]) go root0 currentBranch0 dest (missingSrcs, actions) hqsrc = - let src :: Path.Split - src = second HQ'.toName hqsrc - proposedDest :: Path.Split + let proposedDest :: Path.Split proposedDest = second HQ'.toName hqProposedDest hqProposedDest :: Path.HQSplit hqProposedDest = first Path.unabsolute $ Path.resolve dest hqsrc @@ -670,8 +652,7 @@ loop e = do -- happy path Just . map addAlias . toList $ Set.difference rsrcs existing where - addAlias r = BranchUtil.makeAddTypeName proposedDest r (oldMD r) - oldMD r = BranchUtil.getTypeMetadataAt src r currentBranch0 + addAlias r = BranchUtil.makeAddTypeName proposedDest r doTerm :: Maybe [(Path, Branch0 m -> Branch0 m)] doTerm = case ( BranchUtil.getTerm hqsrc currentBranch0, BranchUtil.getTerm hqProposedDest root0 @@ -680,8 +661,7 @@ loop e = do (rsrcs, existing) -> Just . map addAlias . toList $ Set.difference rsrcs existing where - addAlias r = BranchUtil.makeAddTermName proposedDest r (oldMD r) - oldMD r = BranchUtil.getTermMetadataAt src r currentBranch0 + addAlias r = BranchUtil.makeAddTermName proposedDest r in case (doType, doTerm) of (Nothing, Nothing) -> (missingSrcs :> hqsrc, actions) (Just as, Nothing) -> (missingSrcs, actions ++ as) @@ -691,22 +671,20 @@ loop e = do fixupOutput :: Path.HQSplit -> HQ.HashQualified Name fixupOutput = fmap Path.unsafeToName . HQ'.toHQ . Path.unsplitHQ NamesI global query -> do - currentPath' <- Path.unabsolute <$> Cli.getCurrentPath hqLength <- Cli.runTransaction Codebase.hashLength root <- Cli.getRootBranch (names, pped) <- if global || any Name.isAbsolute query then do let root0 = Branch.head root - let names = Names.makeAbsolute $ Branch.toNames root0 -- Use an absolutely qualified ppe for view.global - let pped = PPED.fromNamesDecl hqLength names + let names = Names.makeAbsolute $ Branch.toNames root0 + let pped = PPED.makePPED (PPE.hqNamer hqLength names) (PPE.suffixifyByHash names) pure (names, pped) else do - currentBranch <- Cli.getCurrentBranch0 - let currentNames = Branch.toNames currentBranch - let pped = Backend.getCurrentPrettyNames hqLength (Backend.Within currentPath') root - pure (currentNames, pped) + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + pure (names, pped) let unsuffixifiedPPE = PPED.unsuffixifiedPPE pped terms = Names.lookupHQTerm Names.IncludeSuffixes query names @@ -716,26 +694,8 @@ loop e = do types' :: [(Reference, [HQ'.HashQualified Name])] types' = map (\r -> (r, PPE.allTypeNames unsuffixifiedPPE r)) (Set.toList types) Cli.respond $ ListNames global hqLength types' terms' - LinkI mdValue srcs -> do - description <- inputDescription input - manageLinks False srcs [mdValue] Metadata.insert - Cli.syncRoot description - UnlinkI mdValue srcs -> do - description <- inputDescription input - manageLinks False srcs [mdValue] Metadata.delete - Cli.syncRoot description - - -- > links List.map (.Docs .English) - -- > links List.map -- give me all the - -- > links Optional License - LinksI src mdTypeStr -> do - (ppe, out) <- getLinks (show input) src (Right mdTypeStr) - #numberedArgs .= fmap (HQ.toString . view _1) out - let biasedPPE = (PPE.biasTo (maybeToList . Path.toName' . HQ'.toName $ Path.unsplitHQ' src) ppe) - Cli.respond $ ListOfLinks biasedPPE out DocsI srcs -> do - basicPrettyPrintNames <- getBasicPrettyPrintNames - for_ srcs (docsI (show input) basicPrettyPrintNames) + for_ srcs docsI CreateAuthorI authorNameSegment authorFullName -> do Cli.Env {codebase} <- ask initialBranch <- Cli.getCurrentBranch @@ -752,9 +712,9 @@ loop e = do guidPath <- Cli.resolveSplit' (authorPath' |> "guid") Cli.stepManyAt description - [ BranchUtil.makeAddTermName (Path.convert authorPath) (d authorRef) mempty, - BranchUtil.makeAddTermName (Path.convert copyrightHolderPath) (d copyrightHolderRef) mempty, - BranchUtil.makeAddTermName (Path.convert guidPath) (d guidRef) mempty + [ BranchUtil.makeAddTermName (Path.convert authorPath) (d authorRef), + BranchUtil.makeAddTermName (Path.convert copyrightHolderPath) (d copyrightHolderRef), + BranchUtil.makeAddTermName (Path.convert guidPath) (d guidRef) ] currentPath <- Cli.getCurrentPath finalBranch <- Cli.getCurrentBranch0 @@ -811,12 +771,12 @@ loop e = do case (null endangerments, insistence) of (True, _) -> pure (Cli.respond Success) (False, Force) -> do - ppeDecl <- currentPrettyPrintEnvDecl Backend.Within + ppeDecl <- Cli.currentPrettyPrintEnvDecl pure do Cli.respond Success Cli.respondNumbered $ DeletedDespiteDependents ppeDecl endangerments (False, Try) -> do - ppeDecl <- currentPrettyPrintEnvDecl Backend.Within + ppeDecl <- Cli.currentPrettyPrintEnvDecl Cli.respondNumbered $ CantDeleteNamespace ppeDecl endangerments Cli.returnEarlyWithoutOutput parentPathAbs <- Cli.resolvePath' parentPath @@ -828,9 +788,8 @@ loop e = do afterDelete DeleteTarget'ProjectBranch name -> handleDeleteBranch name DeleteTarget'Project name -> handleDeleteProject name - DisplayI outputLoc names -> do - basicPrettyPrintNames <- getBasicPrettyPrintNames - traverse_ (displayI basicPrettyPrintNames outputLoc) names + DisplayI outputLoc namesToDisplay -> do + traverse_ (displayI outputLoc) namesToDisplay ShowDefinitionI outputLoc showDefinitionScope query -> handleShowDefinition outputLoc showDefinitionScope query EditNamespaceI paths -> handleEditNamespace LatestFileLocation paths FindPatchI -> do @@ -841,22 +800,21 @@ loop e = do (seg, _) <- Map.toList (Branch._edits b) ] Cli.respond $ ListOfPatches $ Set.fromList patches - #numberedArgs .= fmap Name.toString patches + Cli.setNumberedArgs $ fmap Name.toString patches FindShallowI pathArg -> do Cli.Env {codebase} <- ask pathArgAbs <- Cli.resolvePath' pathArg entries <- liftIO (Backend.lsAtPath codebase Nothing pathArgAbs) - -- caching the result as an absolute path, for easier jumping around - #numberedArgs .= fmap entryToHQString entries - currentBranch <- Cli.getCurrentBranch - let buildPPE = do - schLength <- Codebase.runTransaction codebase Codebase.branchHashLength - pure $ - Backend.basicSuffixifiedNames - schLength - currentBranch - (Backend.AllNames (Path.unabsolute pathArgAbs)) + Cli.setNumberedArgs $ fmap entryToHQString entries + pped <- Cli.currentPrettyPrintEnvDecl + let suffixifiedPPE = PPED.suffixifiedPPE pped + -- This used to be a delayed action which only forced the loading of the root + -- branch when it was necessary for printing the results, but that got wiped out + -- when we ported to the new Cli monad. + -- It would be nice to restore it, but it's pretty rare that it actually results + -- in an improvement, so perhaps it's not worth the effort. + let buildPPE = pure suffixifiedPPE Cli.respond $ ListShallow buildPPE entries where entryToHQString :: ShallowListEntry v Ann -> String @@ -980,9 +938,9 @@ loop e = do let adds = SlurpResult.adds sr Cli.stepAtNoSync (Path.unabsolute currentPath, doSlurpAdds adds uf) Cli.runTransaction . Codebase.addDefsToCodebase codebase . SlurpResult.filterUnisonFile sr $ uf - ppe <- prettyPrintEnvDecl =<< displayNames uf - Cli.respond $ SlurpOutput input (PPE.suffixifiedPPE ppe) sr - addDefaultMetadata adds + pped <- Cli.prettyPrintEnvDeclFromNames $ UF.addNamesFromTypeCheckedUnisonFile uf currentNames + let suffixifiedPPE = PPED.suffixifiedPPE pped + Cli.respond $ SlurpOutput input suffixifiedPPE sr Cli.syncRoot description SaveExecuteResultI resultName -> handleAddRun input resultName PreviewAddI requestedNames -> do @@ -1071,8 +1029,9 @@ loop e = do Cli.respond Success ListEditsI maybePath -> do patch <- Cli.getPatchAt (fromMaybe Cli.defaultPatchPath maybePath) - ppe <- suffixifiedPPE =<< makePrintNamesFromLabeled' - Cli.respondNumbered $ ListEdits patch ppe + pped <- Cli.currentPrettyPrintEnvDecl + let suffixifiedPPE = PPED.suffixifiedPPE pped + Cli.respondNumbered $ ListEdits patch suffixifiedPPE PullRemoteBranchI sourceTarget sMode pMode verbosity -> doPullRemoteBranch sourceTarget sMode pMode verbosity PushRemoteBranchI pushRemoteBranchInput -> handlePushRemoteBranch pushRemoteBranchInput ListDependentsI hq -> handleDependents hq @@ -1111,6 +1070,25 @@ loop e = do _ -> pure () Nothing -> do Cli.respond DebugFuzzyOptionsNoResolver + DebugFormatI -> do + Cli.Env {writeSource, loadSource} <- ask + void $ runMaybeT do + (filePath, _) <- MaybeT Cli.getLatestFile + pf <- lift Cli.getLatestParsedFile + tf <- lift Cli.getLatestTypecheckedFile + names <- lift Cli.currentNames + let buildPPED uf tf = + Cli.prettyPrintEnvDeclFromNames $ (fromMaybe mempty $ (UF.typecheckedToNames <$> tf) <|> (UF.toNames <$> uf)) `Names.shadowing` names + let formatWidth = 80 + currentPath <- lift $ Cli.getCurrentPath + updates <- MaybeT $ Format.formatFile buildPPED formatWidth currentPath pf tf Nothing + source <- + liftIO (loadSource (Text.pack filePath)) >>= \case + Cli.InvalidSourceNameError -> lift $ Cli.returnEarly $ Output.InvalidSourceName filePath + Cli.LoadError -> lift $ Cli.returnEarly $ Output.SourceLoadFailed filePath + Cli.LoadSuccess contents -> pure contents + let updatedSource = Format.applyFormatUpdates updates source + liftIO $ writeSource (Text.pack filePath) updatedSource DebugDumpNamespacesI -> do let seen h = State.gets (Set.member h) set h = State.modify (Set.insert h) @@ -1125,12 +1103,12 @@ loop e = do Causal.Merge h _bh b (Map.toList -> tails) -> goBranch h b (map fst tails) (tails ++ queue) goBranch :: forall m. (Monad m) => CausalHash -> Branch0 m -> [CausalHash] -> [(CausalHash, m (Branch.UnwrappedBranch m))] -> StateT (Set CausalHash) m () goBranch h b (Set.fromList -> causalParents) queue = case b of - Branch0 terms0 types0 children0 patches0 _ _ _ _ _ _ _ -> - let wrangleMetadata :: (Ord r, Ord n) => Metadata.Star r n -> r -> (r, (Set n, Set Metadata.Value)) - wrangleMetadata s r = - (r, (R.lookupDom r $ Star3.d1 s, Set.map snd . R.lookupDom r $ Star3.d3 s)) - terms = Map.fromList . map (wrangleMetadata terms0) . Foldable.toList $ Star3.fact terms0 - types = Map.fromList . map (wrangleMetadata types0) . Foldable.toList $ Star3.fact types0 + Branch0 terms0 types0 children0 patches0 _ _ _ _ _ -> + let ignoreMetadata :: (Ord r, Ord n) => Metadata.Star r n -> r -> (r, Set n) + ignoreMetadata s r = + (r, R.lookupDom r $ Star3.d1 s) + terms = Map.fromList . map (ignoreMetadata terms0) . Foldable.toList $ Star3.fact terms0 + types = Map.fromList . map (ignoreMetadata types0) . Foldable.toList $ Star3.fact types0 patches = fmap fst patches0 children = fmap Branch.headHash children0 in do @@ -1153,10 +1131,9 @@ loop e = do ] ) where - prettyLinks renderR r [] = P.indentN 2 $ P.text (renderR r) - prettyLinks renderR r links = P.indentN 2 (P.lines (P.text (renderR r) : (links <&> \r -> "+ " <> P.text (Reference.toText r)))) - prettyDefn renderR (r, (Foldable.toList -> names, Foldable.toList -> links)) = - P.lines (P.text . NameSegment.toText <$> if null names then [NameSegment ""] else names) <> P.newline <> prettyLinks renderR r links + prettyRef renderR r = P.indentN 2 $ P.text (renderR r) + prettyDefn renderR (r, Foldable.toList -> names) = + P.lines (P.text . NameSegment.toText <$> if null names then [NameSegment ""] else names) <> P.newline <> prettyRef renderR r rootBranch <- Cli.getRootBranch void . liftIO . flip State.execStateT mempty $ goCausal [getCausal rootBranch] DebugDumpNamespaceSimpleI -> do @@ -1220,9 +1197,10 @@ loop e = do inputDescription :: Input -> Cli Text inputDescription input = case input of + SaveExecuteResultI _str -> pure "save-execute-result" ForkLocalBranchI src0 dest0 -> do - src <- hp' src0 - dest <- p' dest0 + src <- either (pure . Text.pack . show) brp src0 + dest <- brp dest0 pure ("fork " <> src <> " " <> dest) MergeLocalBranchI src0 dest0 mode -> do src <- looseCodeOrProjectToText src0 @@ -1339,12 +1317,6 @@ inputDescription input = ExecuteI s args -> pure ("execute " <> Text.unwords (fmap Text.pack (s : args))) IOTestI hq -> pure ("io.test " <> HQ.toText hq) IOTestAllI -> pure "io.test.all" - LinkI md defs0 -> do - defs <- traverse hqs' defs0 - pure ("link " <> HQ.toText md <> " " <> Text.intercalate " " defs) - UnlinkI md defs0 -> do - defs <- traverse hqs' defs0 - pure ("unlink " <> HQ.toText md <> " " <> Text.intercalate " " defs) UpdateBuiltinsI -> pure "builtins.update" MergeBuiltinsI -> pure "builtins.merge" MergeIOBuiltinsI -> pure "builtins.mergeio" @@ -1388,6 +1360,7 @@ inputDescription input = DebugNumberedArgsI {} -> wat DebugTabCompletionI _input -> wat DebugFuzzyOptionsI cmd input -> pure . Text.pack $ "debug.fuzzy-completions " <> unwords (cmd : toList input) + DebugFormatI -> pure "debug.format" DebugTypecheckedUnisonFileI {} -> wat DeprecateTermI {} -> wat DeprecateTypeI {} -> wat @@ -1402,7 +1375,6 @@ inputDescription input = StructuredFindReplaceI {} -> wat GistI {} -> wat HistoryI {} -> wat - LinksI {} -> wat ListDependenciesI {} -> wat ListDependentsI {} -> wat ListEditsI {} -> wat @@ -1421,7 +1393,6 @@ inputDescription input = PushRemoteBranchI {} -> wat QuitI {} -> wat ReleaseDraftI {} -> wat - SaveExecuteResultI {} -> wat ShowDefinitionByPrefixI {} -> wat ShowDefinitionI {} -> wat EditNamespaceI paths -> @@ -1438,6 +1409,8 @@ inputDescription input = hp' = either (pure . Text.pack . show) p' p' :: Path' -> Cli Text p' = fmap tShow . Cli.resolvePath' + brp :: BranchRelativePath -> Cli Text + brp = fmap from . ProjectUtils.resolveBranchRelativePath ops' :: Maybe Path.Split' -> Cli Text ops' = maybe (pure ".") ps' opatch :: Maybe Path.Split' -> Cli Text @@ -1468,31 +1441,25 @@ handleFindI :: Cli () handleFindI isVerbose fscope ws input = do Cli.Env {codebase} <- ask - root' <- Cli.getRootBranch - currentPath' <- Cli.getCurrentPath currentBranch0 <- Cli.getCurrentBranch0 - let getNames :: FindScope -> Names - getNames findScope = - let cp = Path.unabsolute currentPath' - nameScope = case findScope of - FindLocal -> Backend.Within cp - FindLocalAndDeps -> Backend.Within cp - FindGlobal -> Backend.AllNames cp - scopeFilter = case findScope of - FindLocal -> - let f n = - case Name.segments n of - "lib" Nel.:| _ : _ -> False - _ -> True - in Names.filter f - FindGlobal -> id - FindLocalAndDeps -> - let f n = - case Name.segments n of - "lib" Nel.:| (_ : "lib" : _) -> False - _ -> True - in Names.filter f - in scopeFilter (Backend.prettyNamesForBranch root' nameScope) + (pped, names) <- case fscope of + FindLocal -> do + let names = Branch.toNames (Branch.withoutLib currentBranch0) + -- Don't exclude anything from the pretty printer, since the type signatures we print for + -- results may contain things in lib. + pped <- Cli.currentPrettyPrintEnvDecl + pure (pped, names) + FindLocalAndDeps -> do + let names = Branch.toNames (Branch.withoutTransitiveLibs currentBranch0) + -- Don't exclude anything from the pretty printer, since the type signatures we print for + -- results may contain things in lib. + pped <- Cli.currentPrettyPrintEnvDecl + pure (pped, names) + FindGlobal -> do + globalNames <- Names.makeAbsolute . Branch.toNames <$> Cli.getRootBranch0 + pped <- Cli.prettyPrintEnvDeclFromNames globalNames + pure (pped, globalNames) + let suffixifiedPPE = PPED.suffixifiedPPE pped let getResults :: Names -> Cli [SearchResult] getResults names = case ws of @@ -1520,15 +1487,22 @@ handleFindI isVerbose fscope ws input = do let srs = searchBranchScored names fuzzyNameDistance qs pure $ uniqueBy SR.toReferent srs let respondResults results = do - #numberedArgs .= fmap searchResultToHQString results + Cli.setNumberedArgs $ fmap searchResultToHQString results results' <- Cli.runTransaction (Backend.loadSearchResults codebase results) - ppe <- suffixifiedPPE =<< makePrintNamesFromLabeled' - Cli.respond $ ListOfDefinitions fscope ppe isVerbose results' - results <- getResults (getNames fscope) + Cli.respond $ ListOfDefinitions fscope suffixifiedPPE isVerbose results' + results <- getResults names case (results, fscope) of ([], FindLocal) -> do Cli.respond FindNoLocalMatches - respondResults =<< getResults (getNames FindLocalAndDeps) + -- We've already searched everything else, so now we search JUST the + -- names in lib. + let mayOnlyLibBranch = currentBranch0 & Branch.children %%~ (\cs -> Map.singleton "lib" <$> Map.lookup "lib" cs) + case mayOnlyLibBranch of + Nothing -> respondResults [] + Just onlyLibBranch -> do + let onlyLibNames = Branch.toNames onlyLibBranch + results <- getResults onlyLibNames + respondResults results _ -> respondResults results handleDependencies :: HQ.HashQualified Name -> Cli () @@ -1536,7 +1510,8 @@ handleDependencies hq = do Cli.Env {codebase} <- ask -- todo: add flag to handle transitive efficiently lds <- resolveHQToLabeledDependencies hq - ppe <- PPE.suffixifiedPPE <$> currentPrettyPrintEnvDecl Backend.WithinStrict + pped <- Cli.currentPrettyPrintEnvDecl + let suffixifiedPPE = PPED.suffixifiedPPE pped when (null lds) do Cli.returnEarly (LabeledReferenceNotFound hq) results <- for (toList lds) \ld -> do @@ -1561,15 +1536,15 @@ handleDependencies hq = do Just tp -> Type.labeledDependencies tp tm _ = pure mempty in LD.fold tp tm ld - let types = [(PPE.typeName ppe r, r) | LabeledDependency.TypeReference r <- toList dependencies] - let terms = [(PPE.termName ppe r, r) | LabeledDependency.TermReferent r <- toList dependencies] + let types = [(PPE.typeName suffixifiedPPE r, r) | LabeledDependency.TypeReference r <- toList dependencies] + let terms = [(PPE.termName suffixifiedPPE r, r) | LabeledDependency.TermReferent r <- toList dependencies] pure (types, terms) let types = nubOrdOn snd . Name.sortByText (HQ.toText . fst) $ (join $ fst <$> results) let terms = nubOrdOn snd . Name.sortByText (HQ.toText . fst) $ (join $ snd <$> results) - #numberedArgs - .= map (Text.unpack . Reference.toText . snd) types - <> map (Text.unpack . Reference.toText . Referent.toReference . snd) terms - Cli.respond $ ListDependencies ppe lds (fst <$> types) (fst <$> terms) + Cli.setNumberedArgs $ + map (Text.unpack . Reference.toText . snd) types + <> map (Text.unpack . Reference.toText . Referent.toReference . snd) terms + Cli.respond $ ListDependencies suffixifiedPPE lds (fst <$> types) (fst <$> terms) handleDependents :: HQ.HashQualified Name -> Cli () handleDependents hq = do @@ -1577,7 +1552,7 @@ handleDependents hq = do lds <- resolveHQToLabeledDependencies hq -- Use an unsuffixified PPE here, so we display full names (relative to the current path), -- rather than the shortest possible unambiguous name. - pped <- currentPrettyPrintEnvDecl Backend.WithinStrict + pped <- Cli.currentPrettyPrintEnvDecl let fqppe = PPE.unsuffixifiedPPE pped let ppe = PPE.suffixifiedPPE pped when (null lds) do @@ -1605,7 +1580,7 @@ handleDependents hq = do let sort = nubOrdOn snd . Name.sortByText (HQ.toText . fst) let types = sort [(n, r) | (False, n, r) <- join results] let terms = sort [(n, r) | (True, n, r) <- join results] - #numberedArgs .= map (Text.unpack . Reference.toText . view _2) (types <> terms) + Cli.setNumberedArgs $ map (Text.unpack . Reference.toText . view _2) (types <> terms) Cli.respond (ListDependents ppe lds (fst <$> types) (fst <$> terms)) handleDiffNamespaceToPatch :: Text -> DiffNamespaceToPatchInput -> Cli () @@ -1640,8 +1615,8 @@ handleDiffNamespaceToPatch description input = do } -- Display the patch that we are about to create. - ppe <- suffixifiedPPE =<< makePrintNamesFromLabeled' - Cli.respondNumbered (ListEdits patch ppe) + suffixifiedPPE <- PPED.suffixifiedPPE <$> Cli.currentPrettyPrintEnvDecl + Cli.respondNumbered (ListEdits patch suffixifiedPPE) (patchPath, patchName) <- Cli.resolveSplit' (input ^. #patch) @@ -1680,27 +1655,26 @@ handleShowDefinition :: OutputLocation -> ShowDefinitionScope -> NonEmpty (HQ.Ha handleShowDefinition outputLoc showDefinitionScope query = do Cli.Env {codebase} <- ask hqLength <- Cli.runTransaction Codebase.hashLength - -- If the query is empty, run a fuzzy search. - root <- Cli.getRootBranch - let root0 = Branch.head root - currentPath' <- Path.unabsolute <$> Cli.getCurrentPath let hasAbsoluteQuery = any (any Name.isAbsolute) query (names, unbiasedPPED) <- case (hasAbsoluteQuery, showDefinitionScope) of + -- If any of the queries are absolute, use global names. + -- TODO: We should instead print each definition using the names from its project-branch root. (True, _) -> do - let namingScope = Backend.AllNames currentPath' - let parseNames = Backend.parseNamesForBranch root namingScope - let ppe = Backend.getCurrentPrettyNames hqLength (Backend.Within currentPath') root - pure (parseNames, ppe) + root <- Cli.getRootBranch + let root0 = Branch.head root + let names = Names.makeAbsolute $ Branch.toNames root0 + pped <- Cli.prettyPrintEnvDeclFromNames names + pure (names, pped) (_, ShowDefinitionGlobal) -> do + root <- Cli.getRootBranch + let root0 = Branch.head root let names = Names.makeAbsolute $ Branch.toNames root0 - -- Use an absolutely qualified ppe for view.global - let ppe = PPED.fromNamesDecl hqLength names - pure (names, ppe) + pped <- Cli.prettyPrintEnvDeclFromNames names + pure (names, pped) (_, ShowDefinitionLocal) -> do - currentBranch <- Cli.getCurrentBranch0 - let currentNames = Branch.toNames currentBranch - let ppe = Backend.getCurrentPrettyNames hqLength (Backend.Within currentPath') root - pure (currentNames, ppe) + currentNames <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames currentNames + pure (currentNames, pped) let pped = PPED.biasTo (mapMaybe HQ.toName (toList query)) unbiasedPPED Backend.DefinitionResults terms types misses <- do let nameSearch = NameSearch.makeNameSearch hqLength names @@ -1718,10 +1692,10 @@ handleShowDefinition outputLoc showDefinitionScope query = do resolveHQToLabeledDependencies :: HQ.HashQualified Name -> Cli (Set LabeledDependency) resolveHQToLabeledDependencies = \case HQ.NameOnly n -> do - parseNames <- basicParseNames + names <- Cli.currentNames let terms, types :: Set LabeledDependency - terms = Set.map LD.referent . Name.searchBySuffix n $ Names.terms parseNames - types = Set.map LD.typeRef . Name.searchBySuffix n $ Names.types parseNames + terms = Set.map LD.referent . Name.searchBySuffix n $ Names.terms names + types = Set.map LD.typeRef . Name.searchBySuffix n $ Names.types names pure $ terms <> types -- rationale: the hash should be unique enough that the name never helps HQ.HashQualified _n sh -> resolveHashOnly sh @@ -1740,13 +1714,13 @@ doDisplay :: OutputLocation -> Names -> Term Symbol () -> Cli () doDisplay outputLoc names tm = do Cli.Env {codebase} <- ask loopState <- State.get - - ppe <- prettyPrintEnvDecl names + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped (tms, typs) <- maybe mempty UF.indexByReference <$> Cli.getLatestTypecheckedFile let useCache = True evalTerm tm = fmap ErrorUtil.hush . fmap (fmap Term.unannotate) $ - RuntimeUtils.evalUnisonTermE True (PPE.suffixifiedPPE ppe) useCache (Term.amap (const External) tm) + RuntimeUtils.evalUnisonTermE True suffixifiedPPE useCache (Term.amap (const External) tm) loadTerm (Reference.DerivedId r) = case Map.lookup r tms of Nothing -> fmap (fmap Term.unannotate) $ Cli.runTransaction (Codebase.getTerm codebase r) Just (_, tm, _) -> pure (Just $ Term.unannotate tm) @@ -1758,7 +1732,7 @@ doDisplay outputLoc names tm = do loadTypeOfTerm' (Referent.Ref (Reference.DerivedId r)) | Just (_, _, ty) <- Map.lookup r tms = pure $ Just (void ty) loadTypeOfTerm' r = fmap (fmap void) . Cli.runTransaction . Codebase.getTypeOfReferent codebase $ r - rendered <- DisplayValues.displayTerm ppe loadTerm loadTypeOfTerm' evalTerm loadDecl tm + rendered <- DisplayValues.displayTerm pped loadTerm loadTypeOfTerm' evalTerm loadDecl tm mayFP <- case outputLoc of ConsoleLocation -> pure Nothing FileLocation path -> Just <$> Directory.canonicalizePath path @@ -1777,49 +1751,6 @@ doDisplay outputLoc names tm = do else do writeUtf8 filePath txt -getLinks :: - SrcLoc -> - Path.HQSplit' -> - Either (Set Reference) (Maybe String) -> - Cli - ( PPE.PrettyPrintEnv, - -- e.g. ("Foo.doc", #foodoc, Just (#builtin.Doc) - [(HQ.HashQualified Name, Reference, Maybe (Type Symbol Ann))] - ) -getLinks srcLoc src = - getLinks' src <=< \case - Left s -> pure (Just s) - Right Nothing -> pure Nothing - Right (Just mdTypeStr) -> do - typ <- parseType srcLoc mdTypeStr - pure (Just (Set.singleton (Hashing.typeToReference typ))) - -getLinks' :: - Path.HQSplit' -> -- definition to print metadata of - Maybe (Set Reference) -> -- return all metadata if empty - Cli - ( PPE.PrettyPrintEnv, - -- e.g. ("Foo.doc", #foodoc, Just (#builtin.Doc) - [(HQ.HashQualified Name, Reference, Maybe (Type Symbol Ann))] - ) -getLinks' src selection0 = do - Cli.Env {codebase} <- ask - root0 <- Cli.getRootBranch0 - p <- Path.convert <$> Cli.resolveSplit' src -- ex: the (parent,hqsegment) of `List.map` - `List` - let -- all metadata (type+value) associated with name `src` - allMd = - R4.d34 (BranchUtil.getTermMetadataHQNamed p root0) - <> R4.d34 (BranchUtil.getTypeMetadataHQNamed p root0) - allMd' = maybe allMd (`R.restrictDom` allMd) selection0 - -- then list the values after filtering by type - allRefs :: Set Reference = R.ran allMd' - sigs <- Cli.runTransaction (for (toList allRefs) (Codebase.getTypeOfReferent codebase . Referent.Ref)) - ppe <- prettyPrintEnvDecl =<< makePrintNamesFromLabeled' - let ppeDecl = PPE.unsuffixifiedPPE ppe - let sortedSigs = sortOn snd (toList allRefs `zip` sigs) - let out = [(PPE.termName ppeDecl (Referent.Ref r), r, t) | (r, t) <- sortedSigs] - pure (PPE.suffixifiedPPE ppe, out) - -- | Show todo output if there are any conflicts or edits. doShowTodoOutput :: Patch -> Path.Absolute -> Cli () doShowTodoOutput patch scopePath = do @@ -1829,15 +1760,12 @@ doShowTodoOutput patch scopePath = do if TO.noConflicts todo && TO.noEdits todo then Cli.respond NoConflictsOrEdits else do - #numberedArgs - .= ( Text.unpack . Reference.toText . view _2 - <$> fst (TO.todoFrontierDependents todo) - ) - -- only needs the local references to check for obsolete defs - ppe <- do - names <- makePrintNamesFromLabeled' - prettyPrintEnvDecl names - Cli.respondNumbered $ TodoOutput ppe todo + Cli.setNumberedArgs + ( Text.unpack . Reference.toText . view _2 + <$> fst (TO.todoFrontierDependents todo) + ) + pped <- Cli.currentPrettyPrintEnvDecl + Cli.respondNumbered $ TodoOutput pped todo checkTodo :: Codebase m Symbol Ann -> Patch -> Names -> Sqlite.Transaction (TO.TodoOutput Symbol Ann) checkTodo codebase patch names0 = do @@ -1975,10 +1903,6 @@ searchBranchScored names0 score queries = pair qn = (\score -> (Just score, result)) <$> score qn name -basicPPE :: Cli PPE.PrettyPrintEnv -basicPPE = - basicParseNames >>= suffixifiedPPE - compilerPath :: Path.Path' compilerPath = Path.Path' {Path.unPath' = Left abs} where @@ -2026,7 +1950,7 @@ getSchemeStaticLibDir = doGenerateSchemeBoot :: Bool -> Maybe PPE.PrettyPrintEnv -> Maybe String -> Cli () doGenerateSchemeBoot force mppe mdir = do - ppe <- maybe basicPPE pure mppe + ppe <- maybe (PPED.suffixifiedPPE <$> Cli.currentPrettyPrintEnvDecl) pure mppe dir <- maybe getSchemeGenLibDir pure mdir let bootf = dir "unison" "boot-generated.ss" swrapf = dir "unison" "simple-wrappers.ss" @@ -2243,6 +2167,8 @@ checkDeletes typesTermsTuples doutput inputs = do toRel setRef name = R.fromList (fmap (name,) (toList setRef)) let toDelete = fmap (\(_, names, types, terms) -> Names (toRel terms names) (toRel types names)) splitsNames -- make sure endangered is compeletely contained in paths + -- TODO: We should just check for endangerments from the project root, not the + -- global root! rootNames <- Branch.toNames <$> Cli.getRootBranch0 -- get only once for the entire deletion set let allTermsToDelete :: Set LabeledDependency @@ -2265,18 +2191,18 @@ checkDeletes typesTermsTuples doutput inputs = do (map (BranchUtil.makeDeleteTypeName split) . Set.toList $ types) ++ (map (BranchUtil.makeDeleteTermName split) . Set.toList $ terms) ) - before <- Cli.getRootBranch0 + before <- Cli.getCurrentBranch0 description <- inputDescription inputs Cli.stepManyAt description deleteTypesTerms case doutput of DeleteOutput'Diff -> do - after <- Cli.getRootBranch0 + after <- Cli.getCurrentBranch0 (ppe, diff) <- diffHelper before after Cli.respondNumbered (ShowDiffAfterDeleteDefinitions ppe diff) DeleteOutput'NoDiff -> do Cli.respond Success else do - ppeDecl <- currentPrettyPrintEnvDecl Backend.Within + ppeDecl <- Cli.prettyPrintEnvDeclFromNames rootNames let combineRefs = List.foldl (Map.unionWith NESet.union) Map.empty endangeredDeletions Cli.respondNumbered (CantDeleteDefinitions ppeDecl combineRefs) @@ -2291,7 +2217,7 @@ getEndangeredDependents :: Names -> -- | All entities we want to delete (including the target) Set LabeledDependency -> - -- | All names from the root branch + -- | Names from the current branch Names -> -- | map from references going extinct to the set of endangered dependents Sqlite.Transaction (Map LabeledDependency (NESet LabeledDependency)) @@ -2329,41 +2255,54 @@ getEndangeredDependents targetToDelete otherDesiredDeletions rootNames = do pure extinctToEndangered displayI :: - Names -> OutputLocation -> HQ.HashQualified Name -> Cli () -displayI names outputLoc hq = do +displayI outputLoc hq = do + let useRoot = any Name.isAbsolute hq + (names, pped) <- + if useRoot + then do + root <- Cli.getRootBranch + let root0 = Branch.head root + let names = Names.makeAbsolute $ Branch.toNames root0 + pped <- Cli.prettyPrintEnvDeclFromNames names + pure (names, pped) + else do + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + pure (names, pped) + let suffixifiedPPE = PPE.suffixifiedPPE pped let bias = maybeToList $ HQ.toName hq latestTypecheckedFile <- Cli.getLatestTypecheckedFile case addWatch (HQ.toString hq) latestTypecheckedFile of Nothing -> do let results = Names.lookupHQTerm Names.IncludeSuffixes hq names - pped <- prettyPrintEnvDecl names ref <- Set.asSingleton results & onNothing do Cli.returnEarly if Set.null results then SearchTermsNotFound [hq] - else TermAmbiguous (PPE.suffixifiedPPE pped) hq results + else TermAmbiguous suffixifiedPPE hq results let tm = Term.fromReferent External ref - tm <- RuntimeUtils.evalUnisonTerm True (PPE.biasTo bias $ PPE.suffixifiedPPE pped) True tm + tm <- RuntimeUtils.evalUnisonTerm True (PPE.biasTo bias $ suffixifiedPPE) True tm doDisplay outputLoc names (Term.unannotate tm) Just (toDisplay, unisonFile) -> do - ppe <- PPE.biasTo bias <$> executePPE unisonFile - (_, watches) <- evalUnisonFile Sandboxed ppe unisonFile [] + let namesWithDefinitionsFromFile = UF.addNamesFromTypeCheckedUnisonFile unisonFile names + filePPED <- Cli.prettyPrintEnvDeclFromNames namesWithDefinitionsFromFile + let suffixifiedFilePPE = PPE.biasTo bias $ PPE.suffixifiedPPE filePPED + (_, watches) <- evalUnisonFile Sandboxed suffixifiedFilePPE unisonFile [] (_, _, _, _, tm, _) <- Map.lookup toDisplay watches & onNothing (error $ "Evaluation dropped a watch expression: " <> HQ.toString hq) - ns <- displayNames unisonFile + let ns = UF.addNamesFromTypeCheckedUnisonFile unisonFile names doDisplay outputLoc ns tm -docsI :: SrcLoc -> Names -> Path.HQSplit' -> Cli () -docsI srcLoc names src = - fileByName +docsI :: Path.HQSplit' -> Cli () +docsI src = do + findInScratchfileByName where {- Given `docs foo`, we look for docs in 3 places, in this order: (fileByName) First check the file for `foo.doc`, and if found do `display foo.doc` - (codebaseByMetadata) Next check for doc metadata linked to `foo` in the codebase (codebaseByName) Lastly check for `foo.doc` in the codebase and if found do `display foo.doc` -} hq :: HQ.HashQualified Name @@ -2375,39 +2314,15 @@ docsI srcLoc names src = dotDoc :: HQ.HashQualified Name dotDoc = hq <&> \n -> Name.joinDot n "doc" - fileByName :: Cli () - fileByName = do - ns <- maybe mempty UF.typecheckedToNames <$> Cli.getLatestTypecheckedFile - case Names.lookupHQTerm Names.IncludeSuffixes dotDoc ns of + findInScratchfileByName :: Cli () + findInScratchfileByName = do + namesInFile <- Cli.getNamesFromLatestFile + case Names.lookupHQTerm Names.IncludeSuffixes dotDoc namesInFile of s | Set.size s == 1 -> do -- the displayI command expects full term names, so we resolve -- the hash back to its full name in the file - displayI names ConsoleLocation $ Names.longestTermName 10 (Set.findMin s) ns - _ -> codebaseByMetadata - - codebaseByMetadata :: Cli () - codebaseByMetadata = do - (ppe, out) <- getLinks srcLoc src (Left $ Set.fromList [DD.docRef, IOSource.doc2Ref]) - case out of - [] -> codebaseByName - [(_name, ref, _tm)] -> do - len <- Cli.runTransaction Codebase.branchHashLength - let tm = Term.ref External ref - tm <- RuntimeUtils.evalUnisonTerm True (PPE.fromNames len names) True tm - doDisplay ConsoleLocation names (Term.unannotate tm) - out -> do - #numberedArgs .= fmap (HQ.toString . view _1) out - Cli.respond $ ListOfLinks ppe out - - codebaseByName :: Cli () - codebaseByName = do - parseNames <- basicParseNames - case Names.lookupHQTerm Names.IncludeSuffixes dotDoc parseNames of - s - | Set.size s == 1 -> displayI names ConsoleLocation dotDoc - | Set.size s == 0 -> Cli.respond $ ListOfLinks PPE.empty [] - -- todo: return a list of links here too - | otherwise -> Cli.respond $ ListOfLinks PPE.empty [] + displayI ConsoleLocation (Names.longestTermName 10 (Set.findMin s) namesInFile) + _ -> displayI ConsoleLocation dotDoc loadDisplayInfo :: Codebase m Symbol Ann -> @@ -2430,15 +2345,10 @@ loadTypeDisplayObject codebase = \case maybe (MissingObject $ Reference.idToShortHash id) UserObject <$> Codebase.getTypeDeclaration codebase id -lexedSource :: Text -> Text -> Cli (Names, (Text, [L.Token L.Lexeme])) +lexedSource :: Text -> Text -> Cli (Text, [L.Token L.Lexeme]) lexedSource name src = do let tokens = L.lexer (Text.unpack name) (Text.unpack src) - parseNames <- basicParseNames - pure (parseNames, (src, tokens)) - -suffixifiedPPE :: Names -> Cli PPE.PrettyPrintEnv -suffixifiedPPE ns = - Cli.runTransaction Codebase.hashLength <&> (`PPE.fromSuffixNames` ns) + pure (src, tokens) parseSearchType :: SrcLoc -> String -> Cli (Type Symbol Ann) parseSearchType srcLoc typ = Type.removeAllEffectVars <$> parseType srcLoc typ @@ -2449,9 +2359,8 @@ type SrcLoc = String parseType :: SrcLoc -> String -> Cli (Type Symbol Ann) parseType input src = do -- `show Input` is the name of the "file" being lexed - (names0, lexed) <- lexedSource (Text.pack input) (Text.pack src) - parseNames <- basicParseNames - let names = Names.push names0 parseNames + lexed <- lexedSource (Text.pack input) (Text.pack src) + names <- Cli.currentNames let parsingEnv = Parser.ParsingEnv { uniqueNames = mempty, @@ -2493,22 +2402,13 @@ addWatch watchName (Just uf) = do ) _ -> addWatch watchName Nothing -executePPE :: - (Var v) => - TypecheckedUnisonFile v a -> - Cli PPE.PrettyPrintEnv -executePPE unisonFile = - suffixifiedPPE =<< displayNames unisonFile - hqNameQuery :: Names.SearchType -> [HQ.HashQualified Name] -> Cli QueryResult hqNameQuery searchType query = do Cli.Env {codebase} <- ask - root' <- Cli.getRootBranch - currentPath <- Cli.getCurrentPath + names <- Cli.currentNames Cli.runTransaction do hqLength <- Codebase.hashLength - let parseNames = Backend.parseNamesForBranch root' (Backend.AllNames (Path.unabsolute currentPath)) - let nameSearch = NameSearch.makeNameSearch hqLength parseNames + let nameSearch = NameSearch.makeNameSearch hqLength names Backend.hqNameQuery codebase nameSearch searchType query looseCodeOrProjectToPath :: Either Path' (ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch) -> Path' diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/AddRun.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/AddRun.hs index 5521fa89ac..e9d396cb29 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/AddRun.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/AddRun.hs @@ -11,10 +11,9 @@ import Data.Text qualified as Text import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils (displayNames) -import Unison.Cli.PrettyPrintUtils (prettyPrintEnvDecl) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Codebase qualified as Codebase -import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.Editor.HandleInput.Update (doSlurpAdds) import Unison.Codebase.Editor.Input (Input) import Unison.Codebase.Editor.Output (Output (NoLastRunResult, SaveTermNameConflict, SlurpOutput)) @@ -31,6 +30,7 @@ import Unison.Symbol (Symbol) import Unison.Syntax.Name qualified as Name import Unison.UnisonFile (TypecheckedUnisonFile) import Unison.UnisonFile qualified as UF +import Unison.UnisonFile.Names qualified as UF handleAddRun :: Input -> Name -> Cli () handleAddRun input resultName = do @@ -38,14 +38,16 @@ handleAddRun input resultName = do uf <- addSavedTermToUnisonFile resultName Cli.Env {codebase} <- ask currentPath <- Cli.getCurrentPath - currentNames <- Branch.toNames <$> Cli.getCurrentBranch0 + currentNames <- Cli.currentNames let sr = Slurp.slurpFile uf (Set.singleton resultVar) Slurp.AddOp currentNames let adds = SlurpResult.adds sr Cli.stepAtNoSync (Path.unabsolute currentPath, doSlurpAdds adds uf) Cli.runTransaction . Codebase.addDefsToCodebase codebase . SlurpResult.filterUnisonFile sr $ uf - ppe <- prettyPrintEnvDecl =<< displayNames uf + let namesWithDefinitionsFromFile = UF.addNamesFromTypeCheckedUnisonFile uf currentNames + pped <- Cli.prettyPrintEnvDeclFromNames namesWithDefinitionsFromFile + let suffixifiedPPE = PPE.suffixifiedPPE pped Cli.syncRoot (Text.pack (InputPattern.patternName InputPatterns.saveExecuteResult) <> " " <> Name.toText resultName) - Cli.respond $ SlurpOutput input (PPE.suffixifiedPPE ppe) sr + Cli.respond $ SlurpOutput input suffixifiedPPE sr addSavedTermToUnisonFile :: Name -> Cli (TypecheckedUnisonFile Symbol Ann) addSavedTermToUnisonFile resultName = do diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/EditNamespace.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/EditNamespace.hs index 7fcd2c9dc0..45db6ada4c 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/EditNamespace.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/EditNamespace.hs @@ -16,7 +16,6 @@ import Unison.Codebase.Path (Path) import Unison.Codebase.Path qualified as Path import Unison.Names qualified as Names import Unison.Prelude -import Unison.Server.Backend (NameScoping (Within)) import Unison.Server.Backend qualified as Backend import Unison.Util.Monoid (foldMapM) @@ -24,7 +23,7 @@ handleEditNamespace :: OutputLocation -> [Path] -> Cli () handleEditNamespace outputLoc inputPaths = do Cli.Env {codebase} <- ask currentBranch <- Cli.getCurrentBranch0 - ppe <- NamesUtils.currentPrettyPrintEnvDecl Within + ppe <- NamesUtils.currentPrettyPrintEnvDecl let paths = if null inputPaths then [Path.empty] diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs index 8983a3b41d..ce81492cbb 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/FindAndReplace.hs @@ -28,6 +28,7 @@ import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann (..)) import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPE hiding (biasTo, empty) import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.PrettyPrintEnvDecl.Names qualified as PPED @@ -86,7 +87,7 @@ handleStructuredFindI rule = do results0 <- traverse ok results let results = Alphabetical.sortAlphabeticallyOn fst [(hq, r) | ((hq, r), True) <- results0] let toNumArgs = Text.unpack . Reference.toText . Referent.toReference . view _2 - #numberedArgs .= map toNumArgs results + Cli.setNumberedArgs $ map toNumArgs results Cli.respond (ListStructuredFind (fst <$> results)) lookupRewrite :: @@ -98,9 +99,9 @@ lookupRewrite onErr prepare rule = do Cli.Env {codebase} <- ask currentBranch <- Cli.getCurrentBranch0 hqLength <- Cli.runTransaction Codebase.hashLength - fileNames <- Cli.getNamesFromLatestParsedFile + fileNames <- Cli.getNamesFromLatestFile let currentNames = fileNames <> Branch.toNames currentBranch - let ppe = PPED.fromNamesDecl hqLength currentNames + let ppe = PPED.makePPED (PPE.hqNamer hqLength currentNames) (PPE.suffixifyByHash currentNames) ot <- Cli.getTermFromLatestParsedFile rule ot <- case ot of Just _ -> pure ot @@ -141,7 +142,4 @@ renderRewrittenFile ppe msg (vs, uf) = do let prettyVar = P.text . Var.name modifiedDefs = P.sep " " (P.blue . prettyVar <$> vs) header = "-- " <> P.string msg <> "\n" <> "-- | Modified definition(s): " <> modifiedDefs - in (header <> "\n\n" <> P.prettyUnisonFile ppe uf <> foldLine) - where - foldLine :: (IsString s) => P.Pretty s - foldLine = "\n\n---- Anything below this line is ignored by Unison.\n\n" + in (header <> "\n\n" <> P.prettyUnisonFile ppe uf) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/FormatFile.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/FormatFile.hs new file mode 100644 index 0000000000..e81da987db --- /dev/null +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/FormatFile.hs @@ -0,0 +1,234 @@ +module Unison.Codebase.Editor.HandleInput.FormatFile + ( formatFile, + applyFormatUpdates, + TextReplacement (..), + ) +where + +import Control.Lens hiding (List) +import Data.IntervalMap.Interval qualified as Interval +import Data.List qualified as List +import Data.List.NonEmpty.Extra qualified as NEL +import Data.Map qualified as Map +import Data.Text qualified as Text +import Unison.Codebase.Path qualified as Path +import Unison.DataDeclaration qualified as Decl +import Unison.HashQualified qualified as HQ +import Unison.Lexer.Pos qualified as Pos +import Unison.Name qualified as Name +import Unison.Parser.Ann qualified as Ann +import Unison.Prelude +import Unison.PrettyPrintEnv.Util qualified as PPE +import Unison.PrettyPrintEnvDecl qualified as PPED +import Unison.Reference qualified as Reference +import Unison.Symbol (Symbol) +import Unison.Syntax.DeclPrinter qualified as DeclPrinter +import Unison.Syntax.Name qualified as Name +import Unison.Syntax.TermPrinter qualified as TermPrinter +import Unison.Term qualified as Term +import Unison.UnisonFile (TypecheckedUnisonFile, UnisonFile) +import Unison.UnisonFile qualified as UF +import Unison.UnisonFile.Summary qualified as FileSummary +import Unison.Util.Pretty qualified as Pretty +import Unison.Util.Range (Range (..)) + +-- | Format a file, returning a list of Text replacements to apply to the file. +formatFile :: + Monad m => + (Maybe (UnisonFile Symbol Ann.Ann) -> Maybe (TypecheckedUnisonFile Symbol Ann.Ann) -> m PPED.PrettyPrintEnvDecl) -> + Int -> + Path.Absolute -> + Maybe (UnisonFile Symbol Ann.Ann) -> + Maybe (TypecheckedUnisonFile Symbol Ann.Ann) -> + Maybe (Set Range) -> + m (Maybe [TextReplacement]) +formatFile makePPEDForFile formattingWidth currentPath inputParsedFile inputTypecheckedFile mayRangesToFormat = runMaybeT $ do + let (mayParsedFile, mayTypecheckedFile) = mkUnisonFilesDeterministic inputParsedFile inputTypecheckedFile + fileSummary <- hoistMaybe $ FileSummary.mkFileSummary mayParsedFile mayTypecheckedFile + filePPED <- lift $ makePPEDForFile mayParsedFile mayTypecheckedFile + parsedFile <- hoistMaybe mayParsedFile + formattedDecls <- + (FileSummary.allTypeDecls fileSummary) + & fmap + ( \(ref, decl) -> + let tldAnn = either (Decl.annotation . Decl.toDataDecl) (Decl.annotation) decl + in (tldAnn, ref, decl) + ) + & Map.filter (\(tldAnn, _, _) -> shouldFormatTLD tldAnn) + & itraverse \sym (tldAnn, ref, decl) -> do + symName <- hoistMaybe (Name.fromVar sym) + let declNameSegments = NEL.appendr (Path.toList (Path.unabsolute currentPath)) (Name.segments symName) + let declName = Name.fromSegments declNameSegments + let hqName = HQ.fromName symName + let biasedPPED = PPED.biasTo [declName] filePPED + -- If it's a unique type the parser will re-order constructors arbitrarily because + -- the random unique seed gets mixed in and then things are ordered by hash. + -- + -- The constructor order will always be re-ordered on definition Add anyways, so we + -- just force alphabetical order for unique types for sanity reasons. + -- Doesn't work unless we alter it before building the pped + -- let deterministicDecl = decl & Decl.declAsDataDecl_ . Decl.constructors_ %~ sortOn (view _1) + pure $ + (tldAnn, DeclPrinter.prettyDecl biasedPPED (Reference.DerivedId ref) hqName decl) + & over _2 Pretty.syntaxToColor + formattedTerms <- + (FileSummary.termsBySymbol fileSummary) + & Map.filterWithKey + ( \sym (tldAnn, _, _, _) -> + shouldFormatTLD tldAnn + -- TODO: Fix printing of docs using {{ }} syntax. + -- For now we just skip them. + && (Name.lastSegment <$> Name.fromVar sym) /= Just "doc" + ) + & itraverse \sym (tldAnn, mayRefId, trm, _typ) -> do + symName <- hoistMaybe (Name.fromVar sym) + let defNameSegments = NEL.appendr (Path.toList (Path.unabsolute currentPath)) (Name.segments symName) + let defName = Name.fromSegments defNameSegments + let hqName = HQ.NameOnly symName + let biasedPPED = PPED.biasTo [defName] filePPED + let definitionPPE = case mayRefId of + Just refId -> PPE.declarationPPE biasedPPED (Reference.DerivedId refId) + Nothing -> PPED.suffixifiedPPE biasedPPED + let formattedTerm = Pretty.syntaxToColor $ TermPrinter.prettyBinding definitionPPE hqName (removeGeneratedTypeAnnotations parsedFile sym trm) + -- TODO: format watch expressions and test watches + -- let formattedWatches = + -- allWatches fileSummary & map \(_tldAnn, maySym, _mayRef, trm, _mayType, mayWatchKind) -> do + -- case (mayWatchKind, maySym) of + -- (Just wk, Just (Symbol.Symbol _ (Var.User {}))) -> + -- -- Watch with binding + -- Pretty.syntaxToColor $ Pretty.string wk <> "> " <> TermPrinter.prettyBindingWithoutTypeSignature definitionPPE hqName (stripTypeAnnotation trm) + -- (Just wk, _) -> Pretty.string wk <> "> " <> TermPrinter.prettyBlock False definitionPPE (stripTypeAnnotation trm) + -- (Nothing, _) -> "> " <> TermPrinter.prettyBlock False definitionPPE (stripTypeAnnotation trm) + pure (tldAnn, formattedTerm) + + -- Only keep definitions which are _actually_ in the file, skipping generated accessors + -- and such. + let nonGeneratedDefs = + (formattedTerms <> formattedDecls) + & mapMaybe + ( \case + (Ann.Ann {start, end}, txt) -> Just ((start, end), txt) + _ -> Nothing + ) + -- when (null filteredDefs) empty {- Don't format if we have no definitions or it wipes out the fold! -} + let textEdits = + nonGeneratedDefs & foldMap \((start, end), txt) -> do + range <- maybeToList $ annToRange (Ann.Ann start end) + pure $ (TextReplacement (Text.pack $ Pretty.toPlain (Pretty.Width formattingWidth) txt) range) + pure textEdits + where + shouldFormatTLD :: Ann.Ann -> Bool + shouldFormatTLD ann = + case mayRangesToFormat of + Nothing -> True + Just rangesToFormat -> any (annRangeOverlap ann) rangesToFormat + -- Does the given range overlap with the given annotation? + annRangeOverlap :: Ann.Ann -> Range -> Bool + annRangeOverlap a r = + annToInterval a & \case + Nothing -> False + Just annI -> rangeToInterval r `Interval.overlaps` annI + + -- Typechecking ALWAYS adds a type-signature, but we don't want to add ones that didn't + -- already exist in the source file. + removeGeneratedTypeAnnotations :: + UnisonFile Symbol a -> Symbol -> (Term.Term Symbol a) -> (Term.Term Symbol a) + removeGeneratedTypeAnnotations uf v = \case + Term.Ann' tm _annotation | not (hasUserTypeSignature uf v) -> tm + x -> x + + -- This is a bit of a hack. + -- The file parser uses a different unique ID for unique types on every parse, + -- that id changes hashes, and constructors are ordered by that hash. + -- This means that pretty-printing isn't deterministic and constructors will re-order + -- themselves on every save :| + -- + -- It's difficult and a bad idea to change the parser to use a deterministic unique ID, + -- so instead we just re-sort the constructors by their source-file annotation AFTER + -- parsing. This is fine for pretty-printing, but don't use this for anything other than + -- formatting since the Decls it produces aren't technically valid. + mkUnisonFilesDeterministic :: Maybe (UnisonFile Symbol Ann.Ann) -> Maybe (TypecheckedUnisonFile Symbol Ann.Ann) -> (Maybe (UnisonFile Symbol Ann.Ann), Maybe (TypecheckedUnisonFile Symbol Ann.Ann)) + mkUnisonFilesDeterministic mayUnisonFile mayTypecheckedFile = + let sortedUF = + mayUnisonFile + & _Just . #dataDeclarationsId . traversed . _2 %~ sortConstructors + & _Just . #effectDeclarationsId . traversed . _2 . Decl.asDataDecl_ %~ sortConstructors + sortedTF = + mayTypecheckedFile + & _Just . #dataDeclarationsId' . traversed . _2 %~ sortConstructors + & _Just . #effectDeclarationsId' . traversed . _2 . Decl.asDataDecl_ %~ sortConstructors + in (sortedUF, sortedTF) + + -- ppedForFileHelper + sortConstructors :: Decl.DataDeclaration v Ann.Ann -> Decl.DataDeclaration v Ann.Ann + sortConstructors dd = + -- Sort by their Ann so we keep the order they were in the original file. + dd & Decl.constructors_ %~ sortOn @Ann.Ann (view _1) + +annToRange :: Ann.Ann -> Maybe Range +annToRange = \case + Ann.Intrinsic -> Nothing + Ann.External -> Nothing + Ann.GeneratedFrom a -> annToRange a + Ann.Ann start end -> Just $ Range start end + +rangeToInterval :: Range -> Interval.Interval Pos.Pos +rangeToInterval (Range start end) = + Interval.ClosedInterval start end + +annToInterval :: Ann.Ann -> Maybe (Interval.Interval Pos.Pos) +annToInterval ann = annToRange ann <&> rangeToInterval + +-- | Returns 'True' if the given symbol is a term with a user provided type signature in the +-- parsed file, false otherwise. +hasUserTypeSignature :: Eq v => UnisonFile v a -> v -> Bool +hasUserTypeSignature parsedFile sym = + UF.terms parsedFile + & any (\(v, _, trm) -> v == sym && isJust (Term.getTypeAnnotation trm)) + +data TextReplacement = TextReplacement + { -- The new new text to replace the old text in the range with. w + replacementText :: Text, + -- The range to replace. + replacementRange :: Range + } + deriving (Eq, Show) + +-- | Apply a list of range replacements to a text, returning the updated text. +-- +-- This isn't terribly efficient, but is fine for debugging and testing. +-- +-- TODO: rewrite to sort replacements and run them in a single pass. +-- +-- >>> applyFormatUpdates [TextReplacement "hello" (Range (Pos.Pos 2 3) (Pos.Pos 2 6))] "abcdefghijk\nlmnopqrstuv\nwxyz" +-- "abcdefghijk\nlmhelloqrstuv\nwxyz" +-- +-- >>> applyFormatUpdates [TextReplacement "hello" (Range (Pos.Pos 2 3) (Pos.Pos 3 2))] "abcdefghijk\nlmnopqrstuv\nwxyz\n1234567890" +-- "abcdefghijk\nlmhelloxyz\n1234567890" +-- +-- >>> applyFormatUpdates [TextReplacement "hello" (Range (Pos.Pos 2 3) (Pos.Pos 2 6)), TextReplacement "world" (Range (Pos.Pos 3 3) (Pos.Pos 4 3))] "abcdefghijk\nlmnopqrstuv\nwxyz\n1234567890" +-- "abcdefghijk\nlmhelloqrstuv\nwxworld34567890" +applyFormatUpdates :: [TextReplacement] -> Text -> Text +applyFormatUpdates updates txt = foldl' applyUpdate txt updates + where + applyUpdate :: Text -> TextReplacement -> Text + applyUpdate txt (TextReplacement newText (Range (Pos.Pos startLine' startCol') (Pos.Pos endLine' endCol'))) = fromMaybe txt $ do + -- Convert from 1-based indexing + let startLine = startLine' - 1 + let startCol = startCol' - 1 + let endLine = endLine' - 1 + let endCol = endCol' - 1 + let ls = Text.lines txt + (beforeLines, afterLines) = List.splitAt startLine (ls) + if startLine == endLine + then do + (theLine NEL.:| rest) <- NEL.nonEmpty afterLines + let (prefix, _) = Text.splitAt startCol theLine + let (_, suffix) = Text.splitAt endCol theLine + pure $ Text.intercalate "\n" $ beforeLines <> [prefix <> newText <> suffix] <> rest + else do + let (relevantLines', rest) = List.splitAt ((endLine + 1) - startLine) afterLines + relevantLines <- NEL.nonEmpty relevantLines' + let prefix = Text.take startCol (NEL.head relevantLines) + let (_, suffix) = Text.splitAt endCol (NEL.last relevantLines) + pure $ Text.intercalate "\n" $ beforeLines <> [prefix <> newText <> suffix] <> rest diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Load.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Load.hs index 3b7cd98af8..12d121c487 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Load.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Load.hs @@ -15,28 +15,26 @@ import System.Environment (withArgs) import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils (displayNames, makeShadowedPrintNamesFromHQ) -import Unison.Cli.PrettyPrintUtils (prettyPrintEnvDecl) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Cli.TypeCheck (computeTypecheckingEnvironment) import Unison.Cli.UniqueTypeGuidLookup qualified as Cli import Unison.Codebase qualified as Codebase -import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.Editor.HandleInput.RuntimeUtils qualified as RuntimeUtils import Unison.Codebase.Editor.Output qualified as Output import Unison.Codebase.Editor.Slurp qualified as Slurp -import Unison.Codebase.Path qualified as Path import Unison.Codebase.Runtime qualified as Runtime import Unison.FileParsers qualified as FileParsers +import Unison.Names (Names) import Unison.Parser.Ann (Ann) import Unison.Parser.Ann qualified as Ann import Unison.Parsers qualified as Parsers import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE -import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPE +import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Reference qualified as Reference import Unison.Result qualified as Result -import Unison.Server.Backend qualified as Backend import Unison.Symbol (Symbol) import Unison.Syntax.Parser qualified as Parser import Unison.Term (Term) @@ -60,11 +58,11 @@ handleLoad maybePath = do loadUnisonFile :: Text -> Text -> Cli () loadUnisonFile sourceName text = do Cli.respond $ Output.LoadingFile sourceName - unisonFile <- withFile sourceName text - currentNames <- Branch.toNames <$> Cli.getCurrentBranch0 + currentNames <- Cli.currentNames + unisonFile <- withFile currentNames sourceName text let sr = Slurp.slurpFile unisonFile mempty Slurp.CheckOp currentNames - names <- displayNames unisonFile - pped <- prettyPrintEnvDecl names + let names = UF.addNamesFromTypeCheckedUnisonFile unisonFile currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names let ppe = PPE.suffixifiedPPE pped Cli.respond $ Output.Typechecked sourceName ppe sr unisonFile (bindings, e) <- evalUnisonFile Permissive ppe unisonFile [] @@ -75,13 +73,12 @@ loadUnisonFile sourceName text = do #latestTypecheckedFile .= Just (Right unisonFile) where withFile :: + Names -> Text -> Text -> Cli (TypecheckedUnisonFile Symbol Ann) - withFile sourceName text = do - rootBranch <- Cli.getRootBranch + withFile names sourceName text = do currentPath <- Cli.getCurrentPath - let parseNames = Backend.getCurrentParseNames (Backend.Within (Path.unabsolute currentPath)) rootBranch State.modify' \loopState -> loopState & #latestFile .~ Just (Text.unpack sourceName, False) @@ -92,7 +89,7 @@ loadUnisonFile sourceName text = do Parser.ParsingEnv { uniqueNames = uniqueName, uniqueTypeGuid = Cli.loadUniqueTypeGuid currentPath, - names = parseNames + names } unisonFile <- Cli.runTransaction (Parsers.parseFile (Text.unpack sourceName) (Text.unpack text) parsingEnv) @@ -104,8 +101,9 @@ loadUnisonFile sourceName text = do computeTypecheckingEnvironment (FileParsers.ShouldUseTndr'Yes parsingEnv) codebase [] unisonFile let Result.Result notes maybeTypecheckedUnisonFile = FileParsers.synthesizeFile typecheckingEnv unisonFile maybeTypecheckedUnisonFile & onNothing do - ns <- makeShadowedPrintNamesFromHQ (UF.toNames unisonFile) - ppe <- Cli.runTransaction Codebase.hashLength <&> (`PPE.fromSuffixNames` ns) + let namesWithFileDefinitions = UF.addNamesFromUnisonFile unisonFile names + pped <- Cli.prettyPrintEnvDeclFromNames namesWithFileDefinitions + let suffixifiedPPE = PPED.suffixifiedPPE pped let tes = [err | Result.TypeError err <- toList notes] cbs = [ bug @@ -114,9 +112,9 @@ loadUnisonFile sourceName text = do ] when (not (null tes)) do currentPath <- Cli.getCurrentPath - Cli.respond (Output.TypeErrors currentPath text ppe tes) + Cli.respond (Output.TypeErrors currentPath text suffixifiedPPE tes) when (not (null cbs)) do - Cli.respond (Output.CompilerBugs text ppe cbs) + Cli.respond (Output.CompilerBugs text suffixifiedPPE cbs) Cli.returnEarlyWithoutOutput data EvalMode = Sandboxed | Permissive | Native diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/MetadataUtils.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/MetadataUtils.hs deleted file mode 100644 index ec4fbc43bd..0000000000 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/MetadataUtils.hs +++ /dev/null @@ -1,176 +0,0 @@ --- | Helpers/utils that have to do with term/type metadata. -module Unison.Codebase.Editor.HandleInput.MetadataUtils - ( addDefaultMetadata, - manageLinks, - ) -where - -import Control.Lens -import Control.Monad.Except -import Control.Monad.Reader (ask) -import Data.Set qualified as Set -import Unison.Cli.Monad (Cli) -import Unison.Cli.Monad qualified as Cli -import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.UnisonConfigUtils (defaultMetadataKey) -import Unison.Codebase qualified as Codebase -import Unison.Codebase.Branch qualified as Branch -import Unison.Codebase.Editor.HandleInput.NamespaceDiffUtils (diffHelper) -import Unison.Codebase.Editor.Output -import Unison.Codebase.Editor.Output.BranchDiff qualified as OBranchDiff -import Unison.Codebase.Editor.SlurpComponent (SlurpComponent (..)) -import Unison.Codebase.Editor.SlurpComponent qualified as SC -import Unison.Codebase.Metadata qualified as Metadata -import Unison.Codebase.Path qualified as Path -import Unison.CommandLine.InputPatterns qualified as InputPatterns -import Unison.HashQualified qualified as HQ -import Unison.Hashing.V2.Convert qualified as Hashing -import Unison.Name (Name) -import Unison.NameSegment (NameSegment (..)) -import Unison.Prelude -import Unison.PrettyPrintEnv qualified as PPE -import Unison.Referent (Referent) -import Unison.Referent qualified as Referent -import Unison.Server.Backend qualified as Backend -import Unison.Syntax.Name qualified as Name (unsafeFromVar) -import Unison.Util.Monoid qualified as Monoid -import Unison.Util.Relation qualified as R -import Unison.Util.Set qualified as Set - --- Add default metadata to all added types and terms in a slurp component. --- --- No-op if the slurp component is empty. -addDefaultMetadata :: SlurpComponent -> Cli () -addDefaultMetadata adds = - when (not (SC.isEmpty adds)) do - Cli.time "add-default-metadata" do - currentPath' <- Cli.getCurrentPath - - let addedVs = Set.toList $ SC.types adds <> SC.terms adds - addedNs = traverse (Path.hqSplitFromName' . Name.unsafeFromVar) addedVs - case addedNs of - Nothing -> - error $ - "I couldn't parse a name I just added to the codebase! " - <> "-- Added names: " - <> show addedVs - Just addedNames -> - resolveDefaultMetadata currentPath' >>= \case - [] -> pure () - dm -> do - traverse InputPatterns.parseHashQualifiedName dm & \case - Left err -> do - Cli.respond $ - ConfiguredMetadataParseError - (Path.absoluteToPath' currentPath') - (show dm) - err - Right defaultMeta -> do - manageLinks True addedNames defaultMeta Metadata.insert - --- | Add/remove links between definitions and metadata. --- `silent` controls whether this produces any output to the user. --- `srcs` is (names of the) definitions to pass to `op` --- `mdValues` is (names of the) metadata to pass to `op` --- `op` is the operation to add/remove/alter metadata mappings. --- e.g. `Metadata.insert` is passed to add metadata links. -manageLinks :: - Bool -> - [Path.HQSplit'] -> - [HQ.HashQualified Name] -> - ( forall r. - (Ord r) => - (r, Metadata.Type, Metadata.Value) -> - Branch.Star r NameSegment -> - Branch.Star r NameSegment - ) -> - Cli () -manageLinks silent srcs' metadataNames op = do - metadatas <- traverse resolveMetadata metadataNames - before <- Cli.getRootBranch0 - srcs <- traverse Cli.resolveSplit' srcs' - srcle <- Monoid.foldMapM Cli.getTermsAt srcs - srclt <- Monoid.foldMapM Cli.getTypesAt srcs - for_ metadatas \case - Left errOutput -> Cli.respond errOutput - Right (mdType, mdValue) -> do - let step = - let tmUpdates terms = foldl' go terms srcle - where - go terms src = op (src, mdType, mdValue) terms - tyUpdates types = foldl' go types srclt - where - go types src = op (src, mdType, mdValue) types - in over Branch.terms tmUpdates . over Branch.types tyUpdates - let steps = map (\(path, _hq) -> (Path.unabsolute path, step)) srcs - Cli.stepManyAtNoSync steps - if silent - then Cli.respond DefaultMetadataNotification - else do - after <- Cli.getRootBranch0 - (ppe, diff) <- diffHelper before after - if OBranchDiff.isEmpty diff - then Cli.respond NoOp - else - Cli.respondNumbered $ - ShowDiffNamespace - (Right Path.absoluteEmpty) - (Right Path.absoluteEmpty) - ppe - diff - --- | Resolve a metadata name to its type/value, or fail if it's missing or ambiguous. -resolveMetadata :: HQ.HashQualified Name -> Cli (Either Output (Metadata.Type, Metadata.Value)) -resolveMetadata name = do - Cli.Env {codebase} <- ask - root' <- Cli.getRootBranch - currentPath' <- Cli.getCurrentPath - schLength <- Cli.runTransaction Codebase.branchHashLength - - let ppe :: PPE.PrettyPrintEnv - ppe = - Backend.basicSuffixifiedNames schLength root' (Backend.Within $ Path.unabsolute currentPath') - - terms <- getHQTerms name - runExceptT $ do - ref <- - case Set.asSingleton terms of - Just (Referent.Ref ref) -> pure ref - -- FIXME: we want a different error message if the given name is associated with a data constructor (`Con`). - _ -> throwError (MetadataAmbiguous name ppe (Set.toList terms)) - lift (Cli.runTransaction ((Codebase.getTypeOfTerm codebase ref))) >>= \case - Just ty -> pure (Hashing.typeToReference ty, ref) - Nothing -> throwError (MetadataMissingType ppe (Referent.Ref ref)) - -resolveDefaultMetadata :: Path.Absolute -> Cli [String] -resolveDefaultMetadata path = do - let superpaths = Path.ancestors path - xs <- - for - superpaths - ( \path -> do - mayNames <- Cli.getConfig @[String] (defaultMetadataKey path) - pure . join $ toList mayNames - ) - pure . join $ toList xs - --- | Get the set of terms related to a hash-qualified name. -getHQTerms :: HQ.HashQualified Name -> Cli (Set Referent) -getHQTerms = \case - HQ.NameOnly n -> do - root0 <- Cli.getRootBranch0 - currentPath' <- Cli.getCurrentPath - -- absolute-ify the name, then lookup in deepTerms of root - let path = - n - & Path.fromName' - & Path.resolve currentPath' - & Path.unabsolute - & Path.unsafeToName - pure $ R.lookupRan path (Branch.deepTerms root0) - HQ.HashOnly sh -> hashOnly sh - HQ.HashQualified _ sh -> hashOnly sh - where - hashOnly sh = do - Cli.Env {codebase} <- ask - Cli.runTransaction (Backend.termReferentsByShortHash codebase sh) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveTerm.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveTerm.hs index c423519199..fc57ff768f 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveTerm.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveTerm.hs @@ -30,13 +30,10 @@ moveTermSteps src' dest' = do when (not (Set.null destTerms)) do Cli.returnEarly (Output.TermAlreadyExists dest' destTerms) let p = Path.convert src - srcMetadata <- do - root0 <- Cli.getRootBranch0 - pure (BranchUtil.getTermMetadataAt p srcTerm root0) pure [ -- Mitchell: throwing away any hash-qualification here seems wrong! BranchUtil.makeDeleteTermName (over _2 HQ'.toName p) srcTerm, - BranchUtil.makeAddTermName (Path.convert dest) srcTerm srcMetadata + BranchUtil.makeAddTermName (Path.convert dest) srcTerm ] doMoveTerm :: (Path', HQ'.HQSegment) -> (Path', NameSegment) -> Text -> Cli () diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveType.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveType.hs index d535406892..b9da6747be 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveType.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/MoveType.hs @@ -30,13 +30,10 @@ moveTypeSteps src' dest' = do when (not (Set.null destTypes)) do Cli.returnEarly (Output.TypeAlreadyExists dest' destTypes) let p = Path.convert src - srcMetadata <- do - root0 <- Cli.getRootBranch0 - pure (BranchUtil.getTypeMetadataAt p srcType root0) pure [ -- Mitchell: throwing away any hash-qualification here seems wrong! BranchUtil.makeDeleteTypeName (over _2 HQ'.toName p) srcType, - BranchUtil.makeAddTypeName (Path.convert dest) srcType srcMetadata + BranchUtil.makeAddTypeName (Path.convert dest) srcType ] doMoveType :: (Path', HQ'.HQSegment) -> (Path', NameSegment) -> Text -> Cli () diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDependencies.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDependencies.hs index 95bf27ed84..6760210e3d 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDependencies.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDependencies.hs @@ -10,11 +10,12 @@ import Data.Map qualified as Map import Data.Set qualified as Set import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.PrettyPrintUtils (currentPrettyPrintEnvDecl) +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Codebase (Codebase) import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch (Branch0) import Unison.Codebase.Branch qualified as Branch +import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.Editor.Output qualified as Output import Unison.Codebase.Path qualified as Path import Unison.DataDeclaration qualified as DD @@ -22,11 +23,11 @@ import Unison.LabeledDependency (LabeledDependency) import Unison.LabeledDependency qualified as LD import Unison.Name (Name) import Unison.Name qualified as Name +import Unison.Names qualified as Names import Unison.Prelude import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Reference qualified as Reference import Unison.Referent qualified as Referent -import Unison.Server.Backend qualified as Backend import Unison.Sqlite qualified as Sqlite import Unison.Symbol (Symbol) import Unison.Term qualified as Term @@ -41,10 +42,15 @@ handleNamespaceDependencies namespacePath' = do Cli.returnEarly (Output.BranchEmpty (Output.WhichBranchEmptyPath (Path.absoluteToPath' path))) externalDependencies <- Cli.runTransaction (namespaceDependencies codebase branch) - ppe <- PPED.unsuffixifiedPPE <$> currentPrettyPrintEnvDecl Backend.Within - Cli.respondNumbered $ Output.ListNamespaceDependencies ppe path externalDependencies + currentPPED <- Cli.currentPrettyPrintEnvDecl + globalNames <- Names.makeAbsolute . Branch.toNames <$> Cli.getRootBranch0 + globalPPED <- Cli.prettyPrintEnvDeclFromNames globalNames + -- We explicitly include a global unsuffixified fallback on namespace dependencies since + -- the things we want names for are obviously outside of our scope. + let ppeWithFallback = PPED.unsuffixifiedPPE $ PPED.addFallback globalPPED currentPPED + Cli.respondNumbered $ Output.ListNamespaceDependencies ppeWithFallback path externalDependencies --- | Check the dependencies of all types, terms, and metadata in the current namespace, +-- | Check the dependencies of all types and terms in the current namespace, -- returns a map of dependencies which do not have a name within the current namespace, -- alongside the names of all of that thing's dependents. -- diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDiffUtils.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDiffUtils.hs index 8f515dd5d0..0986f1d590 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDiffUtils.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/NamespaceDiffUtils.hs @@ -9,23 +9,21 @@ import Data.Map qualified as Map import Unison.Builtin qualified as Builtin import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli -import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.PrettyPrintUtils (prettyPrintEnvDecl) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Codebase (Codebase) import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch (Branch0 (..)) import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.BranchDiff qualified as BranchDiff import Unison.Codebase.Editor.Output.BranchDiff qualified as OBranchDiff -import Unison.Codebase.Path qualified as Path import Unison.DataDeclaration qualified as DD import Unison.Parser.Ann (Ann (..)) import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE -import Unison.PrettyPrintEnvDecl qualified as PPE hiding (biasTo) +import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Reference (Reference) import Unison.Reference qualified as Reference -import Unison.Server.Backend qualified as Backend import Unison.Sqlite qualified as Sqlite import Unison.Symbol (Symbol) @@ -36,20 +34,18 @@ diffHelper :: diffHelper before after = Cli.time "diffHelper" do Cli.Env {codebase} <- ask - rootBranch <- Cli.getRootBranch - currentPath <- Cli.getCurrentPath hqLength <- Cli.runTransaction Codebase.hashLength diff <- liftIO (BranchDiff.diff0 before after) - let (_parseNames, prettyNames0, _local) = Backend.namesForBranch rootBranch (Backend.AllNames $ Path.unabsolute currentPath) - ppe <- PPE.suffixifiedPPE <$> prettyPrintEnvDecl prettyNames0 - fmap (ppe,) do + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped + fmap (suffixifiedPPE,) do OBranchDiff.toOutput (Cli.runTransaction . Codebase.getTypeOfReferent codebase) (Cli.runTransaction . declOrBuiltin codebase) hqLength (Branch.toNames before) (Branch.toNames after) - ppe diff declOrBuiltin :: Codebase m Symbol Ann -> Reference -> Sqlite.Transaction (Maybe (DD.DeclOrBuiltin Symbol Ann)) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Run.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Run.hs index 89ba24fa76..4faadebba6 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Run.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Run.hs @@ -12,7 +12,8 @@ import Unison.Builtin.Decls qualified as DD import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils (basicParseNames, displayNames, getBasicPrettyPrintNames) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Codebase qualified as Codebase import Unison.Codebase.Editor.HandleInput.Load (EvalMode (Native, Permissive), evalUnisonFile) import Unison.Codebase.Editor.Output qualified as Output @@ -22,7 +23,7 @@ import Unison.Hash qualified as Hash import Unison.Parser.Ann (Ann (External)) import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE -import Unison.PrettyPrintEnv.Names qualified as PPE +import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Reference qualified as Reference import Unison.Result qualified as Result import Unison.Symbol (Symbol) @@ -36,6 +37,7 @@ import Unison.Typechecker.TypeLookup (TypeLookup) import Unison.Typechecker.TypeLookup qualified as TypeLookup import Unison.UnisonFile (TypecheckedUnisonFile) import Unison.UnisonFile qualified as UF +import Unison.UnisonFile.Names qualified as UF import Unison.Var qualified as Var handleRun :: Bool -> String -> [String] -> Cli () @@ -44,11 +46,12 @@ handleRun native main args = do (sym, term, typ, otyp) <- getTerm main uf <- createWatcherFile sym term typ pure (uf, otyp) - ppe <- do - names <- displayNames unisonFile - Cli.runTransaction Codebase.hashLength <&> (`PPE.fromSuffixNames` names) + names <- Cli.currentNames + let namesWithFileDefinitions = UF.addNamesFromTypeCheckedUnisonFile unisonFile names + pped <- Cli.prettyPrintEnvDeclFromNames namesWithFileDefinitions + let suffixifiedPPE = PPED.suffixifiedPPE pped let mode | native = Native | otherwise = Permissive - (_, xs) <- evalUnisonFile mode ppe unisonFile args + (_, xs) <- evalUnisonFile mode suffixifiedPPE unisonFile args mainRes :: Term Symbol () <- case lookup magicMainWatcherString (map bonk (Map.toList xs)) of Nothing -> @@ -59,7 +62,7 @@ handleRun native main args = do ) Just x -> pure (stripUnisonFileReferences unisonFile x) #lastRunResult .= Just (Term.amap (\() -> External) mainRes, mainResType, unisonFile) - Cli.respond (Output.RunResult ppe mainRes) + Cli.respond (Output.RunResult suffixifiedPPE mainRes) where bonk (_, (_ann, watchKind, _id, _term0, term1, _isCacheHit)) = (watchKind, term1) @@ -77,25 +80,24 @@ getTerm main = getTerm' main >>= \case NoTermWithThatName -> do mainType <- Runtime.mainType <$> view #runtime - basicPrettyPrintNames <- getBasicPrettyPrintNames - ppe <- Cli.runTransaction Codebase.hashLength <&> (`PPE.fromSuffixNames` basicPrettyPrintNames) - Cli.returnEarly $ Output.NoMainFunction main ppe [mainType] + pped <- Cli.currentPrettyPrintEnvDecl + let suffixifiedPPE = PPED.suffixifiedPPE pped + Cli.returnEarly $ Output.NoMainFunction main suffixifiedPPE [mainType] TermHasBadType ty -> do mainType <- Runtime.mainType <$> view #runtime - basicPrettyPrintNames <- getBasicPrettyPrintNames - ppe <- Cli.runTransaction Codebase.hashLength <&> (`PPE.fromSuffixNames` basicPrettyPrintNames) - Cli.returnEarly $ Output.BadMainFunction "run" main ty ppe [mainType] + pped <- Cli.currentPrettyPrintEnvDecl + let suffixifiedPPE = PPED.suffixifiedPPE pped + Cli.returnEarly $ Output.BadMainFunction "run" main ty suffixifiedPPE [mainType] GetTermSuccess x -> pure x getTerm' :: String -> Cli GetTermResult getTerm' mainName = let getFromCodebase = do Cli.Env {codebase, runtime} <- ask - - parseNames <- basicParseNames + names <- Cli.currentNames let loadTypeOfTerm ref = Cli.runTransaction (Codebase.getTypeOfTerm codebase ref) mainToFile - =<< MainTerm.getMainTerm loadTypeOfTerm parseNames mainName (Runtime.mainType runtime) + =<< MainTerm.getMainTerm loadTypeOfTerm names mainName (Runtime.mainType runtime) where mainToFile (MainTerm.NotAFunctionName _) = pure NoTermWithThatName mainToFile (MainTerm.NotFound _) = pure NoTermWithThatName diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs index 67318f0d25..921604a866 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/ShowDefinition.hs @@ -65,7 +65,8 @@ showDefinitions outputLoc pped terms types misses = do -- next update for that file (which will happen immediately) #latestFile ?= (fp, True) liftIO $ writeSource (Text.pack fp) renderedCodeText - Cli.respond $ LoadedDefinitionsToSourceFile fp renderedCodePretty + let numDefinitions = Map.size terms + Map.size types + Cli.respond $ LoadedDefinitionsToSourceFile fp numDefinitions when (not (null misses)) (Cli.respond (SearchTermsNotFound misses)) for_ outputPath \p -> do -- We set latestFile to be programmatically generated, if we diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/TermResolution.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/TermResolution.hs index d48dd2a481..8b237ad436 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/TermResolution.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/TermResolution.hs @@ -14,7 +14,8 @@ import Data.Maybe (catMaybes, fromJust) import Data.Set (fromList, toList) import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli -import Unison.Cli.NamesUtils (basicParseNames, basicPrettyPrintNamesA) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Codebase qualified as Codebase import Unison.Codebase.Editor.Output (Output (..)) import Unison.Codebase.Path (hqSplitFromName') @@ -26,7 +27,7 @@ import Unison.Names (Names) import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann) import Unison.PrettyPrintEnv (PrettyPrintEnv) -import Unison.PrettyPrintEnv.Names (fromSuffixNames) +import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Reference (Reference) import Unison.Referent (Referent, pattern Con, pattern Ref) import Unison.Symbol (Symbol) @@ -60,69 +61,66 @@ lookupTermRefWithType :: HQ.HashQualified Name -> Cli [(Reference, Type Symbol Ann)] lookupTermRefWithType codebase name = do - nms <- basicParseNames + names <- Cli.currentNames liftIO . Codebase.runTransaction codebase . fmap catMaybes . traverse annot . fst - $ lookupTermRefs name nms + $ lookupTermRefs name names where annot tm = fmap ((,) tm) <$> Codebase.getTypeOfTerm codebase tm resolveTerm :: HQ.HashQualified Name -> Cli Referent resolveTerm name = do - hashLength <- Cli.runTransaction Codebase.hashLength - basicParseNames >>= \nms -> - case lookupTerm name nms of - [] -> Cli.returnEarly (TermNotFound $ fromJust parsed) - where - parsed = hqSplitFromName' =<< HQ.toName name - [rf] -> pure rf - rfs -> - Cli.returnEarly (TermAmbiguous ppe name (fromList rfs)) - where - ppe = fromSuffixNames hashLength nms + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped + case lookupTerm name names of + [] -> Cli.returnEarly (TermNotFound $ fromJust parsed) + where + parsed = hqSplitFromName' =<< HQ.toName name + [rf] -> pure rf + rfs -> + Cli.returnEarly (TermAmbiguous suffixifiedPPE name (fromList rfs)) resolveCon :: HQ.HashQualified Name -> Cli ConstructorReference resolveCon name = do - hashLength <- Cli.runTransaction Codebase.hashLength - basicParseNames >>= \nms -> - case lookupCon name nms of - ([], _) -> Cli.returnEarly (TermNotFound $ fromJust parsed) - where - parsed = hqSplitFromName' =<< HQ.toName name - ([co], _) -> pure co - (_, rfts) -> - Cli.returnEarly (TermAmbiguous ppe name (fromList rfts)) - where - ppe = fromSuffixNames hashLength nms + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped + case lookupCon name names of + ([], _) -> Cli.returnEarly (TermNotFound $ fromJust parsed) + where + parsed = hqSplitFromName' =<< HQ.toName name + ([co], _) -> pure co + (_, rfts) -> + Cli.returnEarly (TermAmbiguous suffixifiedPPE name (fromList rfts)) resolveTermRef :: HQ.HashQualified Name -> Cli Reference resolveTermRef name = do - hashLength <- Cli.runTransaction Codebase.hashLength - basicParseNames >>= \nms -> - case lookupTermRefs name nms of - ([], _) -> Cli.returnEarly (TermNotFound $ fromJust parsed) - where - parsed = hqSplitFromName' =<< HQ.toName name - ([rf], _) -> pure rf - (_, rfts) -> - Cli.returnEarly (TermAmbiguous ppe name (fromList rfts)) - where - ppe = fromSuffixNames hashLength nms + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped + case lookupTermRefs name names of + ([], _) -> Cli.returnEarly (TermNotFound $ fromJust parsed) + where + parsed = hqSplitFromName' =<< HQ.toName name + ([rf], _) -> pure rf + (_, rfts) -> + Cli.returnEarly (TermAmbiguous suffixifiedPPE name (fromList rfts)) resolveMainRef :: HQ.HashQualified Name -> Cli (Reference, PrettyPrintEnv) resolveMainRef main = do Cli.Env {codebase, runtime} <- ask + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped let mainType = Runtime.mainType runtime smain = HQ.toString main - parseNames <- basicPrettyPrintNamesA - k <- Cli.runTransaction Codebase.hashLength - let ppe = fromSuffixNames k parseNames lookupTermRefWithType codebase main >>= \case [(rf, ty)] - | Typechecker.fitsScheme ty mainType -> pure (rf, ppe) - | otherwise -> Cli.returnEarly (BadMainFunction "main" smain ty ppe [mainType]) - _ -> Cli.returnEarly (NoMainFunction smain ppe [mainType]) + | Typechecker.fitsScheme ty mainType -> pure (rf, suffixifiedPPE) + | otherwise -> Cli.returnEarly (BadMainFunction "main" smain ty suffixifiedPPE [mainType]) + _ -> Cli.returnEarly (NoMainFunction smain suffixifiedPPE [mainType]) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Tests.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Tests.hs index 537064b272..74b3944feb 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Tests.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Tests.hs @@ -20,11 +20,12 @@ import Unison.Builtin.Decls qualified as DD import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils (basicParseNames, makePrintNamesFromLabeled') +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch qualified as Branch import Unison.Codebase.Editor.HandleInput.RuntimeUtils qualified as RuntimeUtils -import Unison.Codebase.Editor.Input +import Unison.Codebase.Editor.Input (TestInput (..)) import Unison.Codebase.Editor.Output import Unison.Codebase.Editor.Output qualified as Output import Unison.Codebase.Runtime qualified as Runtime @@ -36,7 +37,7 @@ import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann) import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE -import Unison.PrettyPrintEnv.Names qualified as PPE +import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.Reference qualified as Reference import Unison.Referent qualified as Referent import Unison.ShortHash qualified as SH @@ -53,10 +54,6 @@ import Unison.Util.Relation qualified as R import Unison.Util.Set qualified as Set import Unison.WatchKind qualified as WK -fqnPPE :: Names -> Cli PPE.PrettyPrintEnv -fqnPPE ns = - Cli.runTransaction Codebase.hashLength <&> (`PPE.fromNames` ns) - -- | Handle a @test@ command. -- Run pure tests in the current subnamespace. handleTest :: TestInput -> Cli () @@ -88,12 +85,13 @@ handleTest TestInput {includeLibNamespace, showFailures, showSuccesses} = do | otherwise -> Nothing _ -> Nothing let stats = Output.CachedTests (Set.size testRefs) (Map.size cachedTests) - names <- makePrintNamesFromLabeled' - ppe <- fqnPPE names + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let fqnPPE = PPED.unsuffixifiedPPE pped Cli.respond $ TestResults stats - ppe + fqnPPE showSuccesses showFailures oks @@ -108,9 +106,9 @@ handleTest TestInput {includeLibNamespace, showFailures, showSuccesses} = do Cli.respond (TermNotFound' . SH.shortenTo hqLength . Reference.toShortHash $ Reference.DerivedId r) pure [] Just tm -> do - Cli.respond $ TestIncrementalOutputStart ppe (n, total) r + Cli.respond $ TestIncrementalOutputStart fqnPPE (n, total) r -- v don't cache; test cache populated below - tm' <- RuntimeUtils.evalPureUnison ppe False tm + tm' <- RuntimeUtils.evalPureUnison fqnPPE False tm case tm' of Left e -> do Cli.respond (EvaluationFailure e) @@ -118,26 +116,27 @@ handleTest TestInput {includeLibNamespace, showFailures, showSuccesses} = do Right tm' -> do -- After evaluation, cache the result of the test Cli.runTransaction (Codebase.putWatch WK.TestWatch r tm') - Cli.respond $ TestIncrementalOutputEnd ppe (n, total) r (isTestOk tm') + Cli.respond $ TestIncrementalOutputEnd fqnPPE (n, total) r (isTestOk tm') pure [(r, tm')] let m = Map.fromList computedTests (mOks, mFails) = passFails m - Cli.respond $ TestResults Output.NewlyComputed ppe showSuccesses showFailures mOks mFails + Cli.respond $ TestResults Output.NewlyComputed fqnPPE showSuccesses showFailures mOks mFails handleIOTest :: HQ.HashQualified Name -> Cli () handleIOTest main = do Cli.Env {runtime} <- ask - parseNames <- basicParseNames - ppe <- (\hashLen -> PPE.fromSuffixNames hashLen parseNames) <$> Cli.runTransaction Codebase.hashLength + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped let isIOTest typ = Foldable.any (Typechecker.isSubtype typ) $ Runtime.ioTestTypes runtime - refs <- resolveHQNames parseNames (Set.singleton main) + refs <- resolveHQNames names (Set.singleton main) (fails, oks) <- refs & foldMapM \(ref, typ) -> do when (not $ isIOTest typ) do - Cli.returnEarly (BadMainFunction "io.test" (HQ.toString main) typ ppe (Foldable.toList $ Runtime.ioTestTypes runtime)) - runIOTest ppe ref - Cli.respond $ TestResults Output.NewlyComputed ppe True True oks fails + Cli.returnEarly (BadMainFunction "io.test" (HQ.toString main) typ suffixifiedPPE (Foldable.toList $ Runtime.ioTestTypes runtime)) + runIOTest suffixifiedPPE ref + Cli.respond $ TestResults Output.NewlyComputed suffixifiedPPE True True oks fails findTermsOfTypes :: Codebase.Codebase m Symbol Ann -> Bool -> NESet (Type.Type Symbol Ann) -> Cli (Set Reference.Id) findTermsOfTypes codebase includeLib filterTypes = do @@ -155,20 +154,21 @@ findTermsOfTypes codebase includeLib filterTypes = do handleAllIOTests :: Cli () handleAllIOTests = do Cli.Env {codebase, runtime} <- ask - parseNames <- basicParseNames - ppe <- (\hashLen -> PPE.fromSuffixNames hashLen parseNames) <$> Cli.runTransaction Codebase.hashLength + names <- Cli.currentNames + pped <- Cli.prettyPrintEnvDeclFromNames names + let suffixifiedPPE = PPED.suffixifiedPPE pped ioTestRefs <- findTermsOfTypes codebase False (Runtime.ioTestTypes runtime) case NESet.nonEmptySet ioTestRefs of - Nothing -> Cli.respond $ TestResults Output.NewlyComputed ppe True True [] [] + Nothing -> Cli.respond $ TestResults Output.NewlyComputed suffixifiedPPE True True [] [] Just neTestRefs -> do let total = NESet.size neTestRefs (fails, oks) <- toList neTestRefs & zip [1 :: Int ..] & foldMapM \(n, r) -> do - Cli.respond $ TestIncrementalOutputStart ppe (n, total) r - (fails, oks) <- runIOTest ppe r - Cli.respond $ TestIncrementalOutputEnd ppe (n, total) r (null fails) + Cli.respond $ TestIncrementalOutputStart suffixifiedPPE (n, total) r + (fails, oks) <- runIOTest suffixifiedPPE r + Cli.respond $ TestIncrementalOutputEnd suffixifiedPPE (n, total) r (null fails) pure (fails, oks) - Cli.respond $ TestResults Output.NewlyComputed ppe True True oks fails + Cli.respond $ TestResults Output.NewlyComputed suffixifiedPPE True True oks fails resolveHQNames :: Names -> Set (HQ.HashQualified Name) -> Cli (Set (Reference.Id, Type.Type Symbol Ann)) resolveHQNames parseNames hqNames = diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update.hs index 95d18c4689..96cf087458 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update.hs @@ -16,15 +16,13 @@ import Unison.ABT qualified as ABT import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils (displayNames) -import Unison.Cli.PrettyPrintUtils (prettyPrintEnvDecl) +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Cli.PrettyPrintUtils qualified as Cli import Unison.Cli.TypeCheck (computeTypecheckingEnvironment) import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch (Branch0 (..)) import Unison.Codebase.Branch qualified as Branch -import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.BranchUtil qualified as BranchUtil -import Unison.Codebase.Editor.HandleInput.MetadataUtils (addDefaultMetadata) import Unison.Codebase.Editor.Input import Unison.Codebase.Editor.Output import Unison.Codebase.Editor.Propagate qualified as Propagate @@ -33,7 +31,6 @@ import Unison.Codebase.Editor.SlurpComponent (SlurpComponent (..)) import Unison.Codebase.Editor.SlurpComponent qualified as SC import Unison.Codebase.Editor.SlurpResult (SlurpResult (..)) import Unison.Codebase.Editor.SlurpResult qualified as Slurp -import Unison.Codebase.Metadata qualified as Metadata import Unison.Codebase.Patch (Patch (..)) import Unison.Codebase.Patch qualified as Patch import Unison.Codebase.Path (Path) @@ -54,7 +51,6 @@ import Unison.Reference qualified as Reference import Unison.Referent (Referent) import Unison.Referent qualified as Referent import Unison.Result qualified as Result -import Unison.Runtime.IOSource qualified as IOSource import Unison.Sqlite qualified as Sqlite import Unison.Symbol (Symbol) import Unison.Syntax.Name qualified as Name (toVar, unsafeFromVar) @@ -73,7 +69,6 @@ import Unison.Util.Relation qualified as R import Unison.Util.Set qualified as Set import Unison.Var qualified as Var import Unison.WatchKind (WatchKind) -import Unison.WatchKind qualified as WK -- | Handle an @update@ command. handleUpdate :: Input -> OptionalPatch -> Set Name -> Cli () @@ -85,8 +80,8 @@ handleUpdate input optionalPatch requestedNames = do NoPatch -> Nothing DefaultPatch -> Just Cli.defaultPatchPath UsePatch p -> Just p - slurpCheckNames <- Branch.toNames <$> Cli.getCurrentBranch0 - sr <- getSlurpResultForUpdate requestedNames slurpCheckNames + currentCodebaseNames <- Cli.currentNames + sr <- getSlurpResultForUpdate requestedNames currentCodebaseNames let addsAndUpdates :: SlurpComponent addsAndUpdates = Slurp.updates sr <> Slurp.adds sr fileNames :: Names @@ -96,7 +91,7 @@ handleUpdate input optionalPatch requestedNames = do typeEdits = do v <- Set.toList (SC.types (updates sr)) let n = Name.unsafeFromVar v - let oldRefs0 = Names.typesNamed slurpCheckNames n + let oldRefs0 = Names.typesNamed currentCodebaseNames n let newRefs = Names.typesNamed fileNames n case (,) <$> NESet.nonEmptySet oldRefs0 <*> Set.asSingleton newRefs of Nothing -> error (reportBug "E722145" ("bad (old,new) names: " ++ show (oldRefs0, newRefs))) @@ -111,7 +106,7 @@ handleUpdate input optionalPatch requestedNames = do termEdits = do v <- Set.toList (SC.terms (updates sr)) let n = Name.unsafeFromVar v - let oldRefs0 = Names.refTermsNamed slurpCheckNames n + let oldRefs0 = Names.refTermsNamed currentCodebaseNames n let newRefs = Names.refTermsNamed fileNames n case (,) <$> NESet.nonEmptySet oldRefs0 <*> Set.asSingleton newRefs of Nothing -> error (reportBug "E936103" ("bad (old,new) names: " ++ show (oldRefs0, newRefs))) @@ -122,7 +117,7 @@ handleUpdate input optionalPatch requestedNames = do termDeprecations = [ (n, r) | (_, oldTypeRef, _) <- typeEdits, - (n, r) <- Names.constructorsForType oldTypeRef slurpCheckNames + (n, r) <- Names.constructorsForType oldTypeRef currentCodebaseNames ] patchOps <- for patchPath \patchPath -> do ye'ol'Patch <- Cli.getPatchAt patchPath @@ -195,11 +190,12 @@ handleUpdate input optionalPatch requestedNames = do . Codebase.addDefsToCodebase codebase . Slurp.filterUnisonFile sr $ Slurp.originalFile sr - ppe <- prettyPrintEnvDecl =<< displayNames (Slurp.originalFile sr) - Cli.respond $ SlurpOutput input (PPE.suffixifiedPPE ppe) sr + let codebaseAndFileNames = UF.addNamesFromTypeCheckedUnisonFile (Slurp.originalFile sr) currentCodebaseNames + pped <- Cli.prettyPrintEnvDeclFromNames codebaseAndFileNames + let suffixifiedPPE = PPE.suffixifiedPPE pped + Cli.respond $ SlurpOutput input suffixifiedPPE sr whenJust patchOps \(updatedPatch, _, _) -> void $ propagatePatchNoSync updatedPatch currentPath' - addDefaultMetadata addsAndUpdates Cli.syncRoot case patchPath of Nothing -> "update.nopatch" Just p -> @@ -596,18 +592,12 @@ doSlurpAdds slurp uf = Branch.batchUpdates (typeActions <> termActions) map doTerm . toList $ SC.terms slurp <> UF.constructorsForDecls (SC.types slurp) uf names = UF.typecheckedToNames uf - tests = Set.fromList $ view _1 <$> UF.watchesOfKind WK.TestWatch (UF.discardTypes uf) - (isTestType, isTestValue) = IOSource.isTest - md v = - if Set.member v tests - then Metadata.singleton isTestType isTestValue - else Metadata.empty doTerm :: Symbol -> (Path, Branch0 m -> Branch0 m) doTerm v = case toList (Names.termsNamed names (Name.unsafeFromVar v)) of [] -> errorMissingVar v [r] -> let split = Path.splitFromName (Name.unsafeFromVar v) - in BranchUtil.makeAddTermName split r (md v) + in BranchUtil.makeAddTermName split r wha -> error $ "Unison bug, typechecked file w/ multiple terms named " @@ -619,7 +609,7 @@ doSlurpAdds slurp uf = Branch.batchUpdates (typeActions <> termActions) [] -> errorMissingVar v [r] -> let split = Path.splitFromName (Name.unsafeFromVar v) - in BranchUtil.makeAddTypeName split r Metadata.empty + in BranchUtil.makeAddTypeName split r wha -> error $ "Unison bug, typechecked file w/ multiple types named " @@ -643,26 +633,19 @@ doSlurpUpdates typeEdits termEdits deprecated b0 = where doDeprecate (n, r) = [BranchUtil.makeDeleteTermName (Path.splitFromName n) r] - -- we copy over the metadata on the old thing - -- todo: if the thing being updated, m, is metadata for something x in b0 - -- update x's md to reference `m` doType :: (Name, TypeReference, TypeReference) -> [(Path, Branch0 m -> Branch0 m)] doType (n, old, new) = let split = Path.splitFromName n - oldMd = BranchUtil.getTypeMetadataAt split old b0 in [ BranchUtil.makeDeleteTypeName split old, - BranchUtil.makeAddTypeName split new oldMd + BranchUtil.makeAddTypeName split new ] doTerm :: (Name, TermReference, TermReference) -> [(Path, Branch0 m -> Branch0 m)] doTerm (n, old, new) = [ BranchUtil.makeDeleteTermName split (Referent.Ref old), - BranchUtil.makeAddTermName split (Referent.Ref new) oldMd + BranchUtil.makeAddTermName split (Referent.Ref new) ] where split = Path.splitFromName n - -- oldMd is the metadata linked to the old definition - -- we relink it to the new definition - oldMd = BranchUtil.getTermMetadataAt split (Referent.Ref old) b0 -- Returns True if the operation changed the namespace, False otherwise. propagatePatchNoSync :: Patch -> Path.Absolute -> Cli Bool diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs index e0d804b8d3..69502efc10 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs @@ -10,6 +10,8 @@ module Unison.Codebase.Editor.HandleInput.Update2 makeParsingEnv, prettyParseTypecheck, typecheckedUnisonFileToBranchUpdates, + getNamespaceDependentsOf, + makeComplicatedPPE, ) where @@ -25,7 +27,7 @@ import Data.Set qualified as Set import Data.Text qualified as Text import Data.Text.Lazy qualified as Lazy.Text import Text.Pretty.Simple (pShow) -import U.Codebase.Reference (Reference, ReferenceType) +import U.Codebase.Reference (Reference, TermReferenceId) import U.Codebase.Reference qualified as Reference import U.Codebase.Sqlite.Operations qualified as Ops import Unison.Builtin.Decls qualified as Decls @@ -52,23 +54,21 @@ import Unison.DataDeclaration.ConstructorId (ConstructorId) import Unison.Debug qualified as Debug import Unison.FileParsers qualified as FileParsers import Unison.Hash (Hash) -import Unison.HashQualified' qualified as HQ' import Unison.Name (Name) import Unison.Name qualified as Name import Unison.Name.Forward (ForwardName (..)) import Unison.Name.Forward qualified as ForwardName import Unison.NameSegment (NameSegment (NameSegment)) -import Unison.Names (Names) +import Unison.Names (Names (Names)) import Unison.Names qualified as Names import Unison.Parser.Ann (Ann) import Unison.Parser.Ann qualified as Ann import Unison.Parsers qualified as Parsers import Unison.Prelude -import Unison.PrettyPrintEnv (PrettyPrintEnv) -import Unison.PrettyPrintEnv qualified as PPE +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl (PrettyPrintEnvDecl) import Unison.PrettyPrintEnvDecl qualified as PPED -import Unison.PrettyPrintEnvDecl.Names qualified as PPE +import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Reference (TypeReferenceId) import Unison.Reference qualified as Reference (fromId) import Unison.Referent (Referent) @@ -88,13 +88,14 @@ import Unison.Util.Monoid qualified as Monoid import Unison.Util.Nametree (Defns (..)) import Unison.Util.Pretty (Pretty) import Unison.Util.Pretty qualified as Pretty +import Unison.Util.Relation (Relation) import Unison.Util.Relation qualified as Relation import Unison.Var (Var) import Unison.WatchKind qualified as WK handleUpdate2 :: Cli () handleUpdate2 = do - Cli.Env {codebase} <- ask + Cli.Env {codebase, writeSource} <- ask tuf <- Cli.expectLatestTypecheckedFile let termAndDeclNames = getTermAndDeclNames tuf currentPath <- Cli.getCurrentPath @@ -106,21 +107,16 @@ handleUpdate2 = do Cli.respond Output.UpdateLookingForDependents (pped, bigUf) <- Cli.runTransactionWithRollback \abort -> do dependents <- - Ops.dependentsWithinScope - (Names.referenceIds namesExcludingLibdeps) - (getExistingReferencesNamed termAndDeclNames namesExcludingLibdeps) - -- - construct PPE for printing UF* for typechecking (whatever data structure we decide to print) - bigUf <- buildBigUnisonFile abort codebase tuf dependents namesExcludingLibdeps ctorNames - pped <- - ( \hlen -> - shadowNames - hlen - (UF.typecheckedToNames tuf) - namesIncludingLibdeps - ) - <$> Codebase.hashLength - - pure (pped, bigUf) + getNamespaceDependentsOf namesExcludingLibdeps (getExistingReferencesNamed termAndDeclNames namesExcludingLibdeps) + hashLen <- Codebase.hashLength + bigUf <- + addDefinitionsToUnisonFile + abort + codebase + (findCtorNames Output.UOUUpdate namesExcludingLibdeps ctorNames) + dependents + (UF.discardTypes tuf) + pure (makeComplicatedPPE hashLen namesIncludingLibdeps (UF.typecheckedToNames tuf) dependents, bigUf) -- If the new-unison-file-to-typecheck is the same as old-unison-file-that-we-already-typechecked, then don't bother -- typechecking again. @@ -140,9 +136,8 @@ handleUpdate2 = do parsingEnv <- makeParsingEnv currentPath namesIncludingLibdeps secondTuf <- prettyParseTypecheck bigUf pped parsingEnv & onLeftM \prettyUf -> do - Cli.Env {isTranscript} <- ask - maybePath <- if isTranscript then pure Nothing else Just . fst <$> Cli.expectLatestFile - Cli.respond (Output.DisplayDefinitionsString maybePath prettyUf) + scratchFilePath <- fst <$> Cli.expectLatestFile + liftIO $ writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 prettyUf) Cli.returnEarly Output.UpdateTypecheckingFailure Cli.respond Output.UpdateTypecheckingSuccess pure secondTuf @@ -234,13 +229,13 @@ typecheckedUnisonFileToBranchUpdates abort getConstructors tuf = do Right actions -> pure actions let deleteTypeAction = BranchUtil.makeAnnihilateTypeName split split = splitVar symbol - insertTypeAction = BranchUtil.makeAddTypeName split (Reference.fromId typeRefId) Map.empty + insertTypeAction = BranchUtil.makeAddTypeName split (Reference.fromId typeRefId) insertTypeConstructorActions = let referentIdsWithNames = zip (Decl.constructorVars (Decl.asDataDecl decl)) (Decl.declConstructorReferents typeRefId decl) in map ( \(sym, rid) -> let splitConName = splitVar sym - in BranchUtil.makeAddTermName splitConName (Reference.fromId <$> rid) Map.empty + in BranchUtil.makeAddTermName splitConName (Reference.fromId <$> rid) ) referentIdsWithNames deleteStuff = deleteTypeAction : deleteConstructorActions @@ -257,7 +252,7 @@ typecheckedUnisonFileToBranchUpdates abort getConstructors tuf = do then let split = splitVar var in [ BranchUtil.makeAnnihilateTermName split, - BranchUtil.makeAddTermName split (Referent.fromTermReferenceId ref) Map.empty + BranchUtil.makeAddTermName split (Referent.fromTermReferenceId ref) ] else [] @@ -272,49 +267,30 @@ getExistingReferencesNamed defns names = fromTerms <> fromTypes fromTerms = foldMap (\n -> Set.map Referent.toReference $ Relation.lookupDom n $ Names.terms names) (defns ^. #terms) fromTypes = foldMap (\n -> Relation.lookupDom n $ Names.types names) (defns ^. #types) -buildBigUnisonFile :: - (forall a. Output -> Transaction a) -> - Codebase IO Symbol Ann -> - TypecheckedUnisonFile Symbol Ann -> - Map Reference.Id ReferenceType -> - Names -> - Map ForwardName (Referent, Name) -> - Transaction (UnisonFile Symbol Ann) -buildBigUnisonFile abort c tuf dependents names ctorNames = - addDefinitionsToUnisonFile Output.UOUUpdate abort c names ctorNames dependents (UF.discardTypes tuf) - --- | @addDefinitionsToUnisonFile abort codebase names ctorNames definitions file@ adds all @definitions@ to @file@, avoiding --- overwriting anything already in @file@. Every definition is put into the file with every naming it has in @names@ "on --- the left-hand-side of the equals" (but yes type decls don't really have a LHS). +-- | @addDefinitionsToUnisonFile abort codebase doFindCtorNames definitions file@ adds all @definitions@ to @file@, +-- avoiding overwriting anything already in @file@. Every definition is put into the file with every naming it has in +-- @names@ "on the left-hand-side of the equals" (but yes type decls don't really have a LHS). -- -- TODO: find a better module for this function, as it's used in a couple places addDefinitionsToUnisonFile :: - Output.UpdateOrUpgrade -> (forall void. Output -> Transaction void) -> Codebase IO Symbol Ann -> - Names -> - Map ForwardName (Referent, Name) -> - Map Reference.Id ReferenceType -> + (Maybe Int -> Name -> Either Output.Output [Name]) -> + (Relation Name TermReferenceId, Relation Name TypeReferenceId) -> UnisonFile Symbol Ann -> Transaction (UnisonFile Symbol Ann) -addDefinitionsToUnisonFile operation abort c names ctorNames dependents initialUnisonFile = - -- for each dependent, add its definition with all its names to the UnisonFile - foldM addComponent initialUnisonFile (Map.toList dependents') +addDefinitionsToUnisonFile abort codebase doFindCtorNames (terms, types) = + (\file -> foldM addTermComponent file (Set.map Reference.idToHash (Relation.ran terms))) + >=> (\file -> foldM addDeclComponent file (Set.map Reference.idToHash (Relation.ran types))) where - dependents' :: Map Hash ReferenceType = Map.mapKeys (\(Reference.Id h _pos) -> h) dependents - addComponent :: UnisonFile Symbol Ann -> (Hash, ReferenceType) -> Transaction (UnisonFile Symbol Ann) - addComponent uf (h, rt) = case rt of - Reference.RtTerm -> addTermComponent h uf - Reference.RtType -> addDeclComponent abort h uf - addTermComponent :: Hash -> UnisonFile Symbol Ann -> Transaction (UnisonFile Symbol Ann) - addTermComponent h uf = do - termComponent <- Codebase.unsafeGetTermComponent c h + addTermComponent :: UnisonFile Symbol Ann -> Hash -> Transaction (UnisonFile Symbol Ann) + addTermComponent uf h = do + termComponent <- Codebase.unsafeGetTermComponent codebase h pure $ foldl' addTermElement uf (zip termComponent [0 ..]) where addTermElement :: UnisonFile Symbol Ann -> ((Term Symbol Ann, Type Symbol Ann), Reference.Pos) -> UnisonFile Symbol Ann addTermElement uf ((tm, tp), i) = do - let r :: Referent = Referent.Ref $ Reference.Derived h i - termNames = Relation.lookupRan r names.terms + let termNames = Relation.lookupRan (Reference.Id h i) terms foldl' (addDefinition tm tp) uf termNames addDefinition :: Term Symbol Ann -> Type Symbol Ann -> UnisonFile Symbol Ann -> Name -> UnisonFile Symbol Ann addDefinition tm tp uf (Name.toVar -> v) = @@ -328,19 +304,20 @@ addDefinitionsToUnisonFile operation abort c names ctorNames dependents initialU termNames = Set.fromList [v | (v, _, _) <- uf.terms] <> foldMap (\x -> Set.fromList [v | (v, _, _) <- x]) uf.watches + isTest = Typechecker.isEqual (Decls.testResultType mempty) -- given a dependent hash, include that component in the scratch file -- todo: wundefined: cut off constructor name prefixes - addDeclComponent :: (forall a. Output -> Transaction a) -> Hash -> UnisonFile Symbol Ann -> Transaction (UnisonFile Symbol Ann) - addDeclComponent abort h uf = do + addDeclComponent :: UnisonFile Symbol Ann -> Hash -> Transaction (UnisonFile Symbol Ann) + addDeclComponent uf h = do declComponent <- fromJust <$> Codebase.getDeclComponent h foldM addDeclElement uf (zip declComponent [0 ..]) where -- for each name a decl has, update its constructor names according to what exists in the namespace addDeclElement :: UnisonFile Symbol Ann -> (Decl Symbol Ann, Reference.Pos) -> Transaction (UnisonFile Symbol Ann) addDeclElement uf (decl, i) = do - let declNames = Relation.lookupRan (Reference.Derived h i) names.types + let declNames = Relation.lookupRan (Reference.Id h i) types -- look up names for this decl's constructor based on the decl's name, and embed them in the decl definition. foldM (addRebuiltDefinition decl) uf declNames where @@ -353,20 +330,22 @@ addDefinitionsToUnisonFile operation abort c names ctorNames dependents initialU Right dd -> overwriteConstructorNames name dd >>= \case dd' -> pure uf {UF.dataDeclarationsId = Map.insertWith (\_new old -> old) (Name.toVar name) (Reference.Id h i, dd') uf.dataDeclarationsId} + overwriteConstructorNames :: Name -> DataDeclaration Symbol Ann -> Transaction (DataDeclaration Symbol Ann) overwriteConstructorNames name dd = let constructorNames :: Transaction [Symbol] - constructorNames = case findCtorNames operation names ctorNames (Just $ Decl.constructorCount dd) name of - Left err -> abort err - Right array | all (isJust . Name.stripNamePrefix name) array -> pure (map Name.toVar array) - Right array -> do - traceM "I ran into a situation where a type's constructors didn't match its name," - traceM "in a spot where I didn't expect to be discovering that.\n\n" - traceM "Type Name:" - traceM . Lazy.Text.unpack $ pShow name - traceM "Constructor Names:" - traceM . Lazy.Text.unpack $ pShow array - error "Sorry for crashing." + constructorNames = + case doFindCtorNames (Just $ Decl.constructorCount dd) name of + Left err -> abort err + Right array | all (isJust . Name.stripNamePrefix name) array -> pure (map Name.toVar array) + Right array -> do + traceM "I ran into a situation where a type's constructors didn't match its name," + traceM "in a spot where I didn't expect to be discovering that.\n\n" + traceM "Type Name:" + traceM . Lazy.Text.unpack $ pShow name + traceM "Constructor Names:" + traceM . Lazy.Text.unpack $ pShow array + error "Sorry for crashing." swapConstructorNames oldCtors = let (annotations, _vars, types) = unzip3 oldCtors @@ -440,41 +419,64 @@ getTermAndDeclNames tuf = keysToNames = Set.map Name.unsafeFromVar . Map.keysSet ctorsToNames = Set.fromList . map Name.unsafeFromVar . Decl.constructorVars --- | Combines 'n' and 'otherNames' then creates a ppe, but all references to --- any name in 'n' are printed unqualified. +-- | Given a namespace and a set of dependencies, return the subset of the namespace that consists of only the +-- (transitive) dependents of the dependencies. +getNamespaceDependentsOf :: Names -> Set Reference -> Transaction (Relation Name TermReferenceId, Relation Name TypeReferenceId) +getNamespaceDependentsOf names dependencies = do + dependents <- Ops.dependentsWithinScope (Names.referenceIds names) dependencies + let dependentTerms :: Set TermReferenceId + dependentTypes :: Set TypeReferenceId + (dependentTerms, dependentTypes) = + Map.foldlWithKey' + ( \(terms, types) refId -> \case + Reference.RtTerm -> let !terms1 = Set.insert refId terms in (terms1, types) + Reference.RtType -> let !types1 = Set.insert refId types in (terms, types1) + ) + (Set.empty, Set.empty) + dependents + pure (foldMap nameTerm dependentTerms, foldMap nameType dependentTypes) + where + nameTerm :: TermReferenceId -> Relation Name TermReferenceId + nameTerm ref = + Relation.fromManyDom (Relation.lookupRan (Referent.fromTermReferenceId ref) (Names.terms names)) ref + + nameType :: TypeReferenceId -> Relation Name TypeReferenceId + nameType ref = + Relation.fromManyDom (Relation.lookupRan (Reference.fromId ref) (Names.types names)) ref + +-- The big picture behind PPE building, though there are many details: +-- +-- * We are updating old references to new references by rendering old references as names that are then parsed +-- back to resolve to new references (the world's weirdest implementation of AST substitution). +-- +-- * We have to render names that refer to definitions in the file with a different suffixification strategy +-- (namely, "suffixify by name") than names that refer to things in the codebase. +-- +-- This is because you *may* refer to aliases that share a suffix by that suffix for definitions in the +-- codebase, but not in the file. -- --- This is useful with the current update strategy where, for all --- updates @#old -> #new@ we want to print dependents of #old and --- #new, and have all occurrences of #old and #new be printed with the --- unqualified name. +-- For example, the following file will fail to parse: -- --- For this usecase the names from the scratch file are passed as 'n' --- and the names from the codebase are passed in 'otherNames'. -shadowNames :: Int -> Names -> Names -> PrettyPrintEnvDecl -shadowNames hashLen n otherNames = - let PPED.PrettyPrintEnvDecl unsuffixified0 suffixified0 = PPE.fromNamesDecl hashLen (n <> otherNames) - unsuffixified = patchPrettyPrintEnv unsuffixified0 - suffixified = patchPrettyPrintEnv suffixified0 - patchPrettyPrintEnv :: PrettyPrintEnv -> PrettyPrintEnv - patchPrettyPrintEnv PPE.PrettyPrintEnv {termNames, typeNames} = - PPE.PrettyPrintEnv - { termNames = patch shadowedTermRefs termNames, - typeNames = patch shadowedTypeRefs typeNames - } - patch shadowed f ref = - let res = f ref - in case Set.member ref shadowed of - True -> map (second stripHashQualified) res - False -> res - stripHashQualified = \case - HQ'.HashQualified b _ -> HQ'.NameOnly b - HQ'.NameOnly b -> HQ'.NameOnly b - shadowedTermRefs = - let names = Relation.dom (Names.terms n) - otherTermNames = Names.terms otherNames - in Relation.ran (Names.terms n) <> foldMap (\a -> Relation.lookupDom a otherTermNames) names - shadowedTypeRefs = - let names = Relation.dom (Names.types n) - otherTypeNames = Names.types otherNames - in Relation.ran (Names.types n) <> foldMap (\a -> Relation.lookupDom a otherTypeNames) names - in PPED.PrettyPrintEnvDecl unsuffixified suffixified +-- one.foo = 10 +-- two.foo = 10 +-- hey = foo + foo -- "Which foo do you mean? There are two." +-- +-- However, the following file will not fail to parse, if `one.foo` and `two.foo` are aliases in the codebase: +-- +-- hey = foo + foo +makeComplicatedPPE :: + Int -> + Names -> + Names -> + (Relation Name TermReferenceId, Relation Name TypeReferenceId) -> + PrettyPrintEnvDecl +makeComplicatedPPE hashLen names initialFileNames (dependentTerms, dependentTypes) = + PPED.makePPED (PPE.namer namesInTheFile) (PPE.suffixifyByName namesInTheFile) + `PPED.addFallback` PPED.makePPED (PPE.hqNamer hashLen namesInTheNamespace) (PPE.suffixifyByHash namesInTheNamespace) + where + namesInTheFile = + initialFileNames + <> Names + (Relation.mapRan Referent.fromTermReferenceId dependentTerms) + (Relation.mapRan Reference.fromId dependentTypes) + namesInTheNamespace = Names.unionLeftName names initialFileNames diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs index 3d40d9c972..add8c66ca2 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Upgrade.hs @@ -12,7 +12,6 @@ import Data.Maybe (fromJust) import Data.Set qualified as Set import Data.Text qualified as Text import U.Codebase.Sqlite.DbId (ProjectId) -import U.Codebase.Sqlite.Operations qualified as Operations import U.Codebase.Sqlite.Queries qualified as Queries import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli @@ -27,13 +26,14 @@ import Unison.Codebase.Editor.HandleInput.Update2 ( addDefinitionsToUnisonFile, findCtorNames, forwardCtorNames, + getNamespaceDependentsOf, + makeComplicatedPPE, makeParsingEnv, prettyParseTypecheck, typecheckedUnisonFileToBranchUpdates, ) import Unison.Codebase.Editor.Output qualified as Output import Unison.Codebase.Path qualified as Path -import Unison.HashQualified' qualified as HQ' import Unison.Name (Name) import Unison.Name qualified as Name import Unison.NameSegment (NameSegment) @@ -41,17 +41,17 @@ import Unison.NameSegment qualified as NameSegment import Unison.Names (Names (..)) import Unison.Names qualified as Names import Unison.Prelude -import Unison.PrettyPrintEnv (PrettyPrintEnv (..)) -import Unison.PrettyPrintEnv.Names qualified as PPE.Names +import Unison.PrettyPrintEnv qualified as PPE +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl (PrettyPrintEnvDecl (..)) import Unison.PrettyPrintEnvDecl qualified as PPED (addFallback) -import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Project (ProjectAndBranch (..), ProjectBranchName) import Unison.Reference (TermReference, TypeReference) import Unison.Referent (Referent) import Unison.Referent qualified as Referent import Unison.Sqlite (Transaction) import Unison.UnisonFile qualified as UnisonFile +import Unison.Util.Pretty qualified as Pretty import Unison.Util.Relation (Relation) import Unison.Util.Relation qualified as Relation import Unison.Util.Set qualified as Set @@ -62,7 +62,7 @@ handleUpgrade oldDepName newDepName = do when (oldDepName == newDepName) do Cli.returnEarlyWithoutOutput - Cli.Env {codebase} <- ask + Cli.Env {codebase, writeSource} <- ask (projectAndBranch, _path) <- Cli.expectCurrentProjectBranch let projectId = projectAndBranch ^. #project . #projectId @@ -151,28 +151,27 @@ handleUpgrade oldDepName newDepName = do (unisonFile, printPPE) <- Cli.runTransactionWithRollback \abort -> do - -- Create a Unison file that contains all of our dependents of modified defns of `lib.old`. todo: twiddle + dependents <- + getNamespaceDependentsOf + namesExcludingLibdeps + ( filterUnchangedTerms (Branch.deepTerms oldDepWithoutDeps) + <> filterUnchangedTypes (Branch.deepTypes oldDepWithoutDeps) + <> filterTransitiveTerms (Branch.deepTerms oldTransitiveDeps) + <> filterTransitiveTypes (Branch.deepTypes oldTransitiveDeps) + ) unisonFile <- do - dependents <- - Operations.dependentsWithinScope - (Names.referenceIds namesExcludingLibdeps) - ( filterUnchangedTerms (Branch.deepTerms oldDepWithoutDeps) - <> filterUnchangedTypes (Branch.deepTypes oldDepWithoutDeps) - <> filterTransitiveTerms (Branch.deepTerms oldTransitiveDeps) - <> filterTransitiveTypes (Branch.deepTypes oldTransitiveDeps) - ) addDefinitionsToUnisonFile - Output.UOUUpgrade abort codebase - namesExcludingLibdeps - constructorNamesExcludingLibdeps + (findCtorNames Output.UOUUpgrade namesExcludingLibdeps constructorNamesExcludingLibdeps) dependents UnisonFile.emptyUnisonFile hashLength <- Codebase.hashLength - let primaryPPE = makeOldDepPPE oldDepName newDepName namesExcludingOldDep oldDep oldDepWithoutDeps newDepWithoutDeps - let secondaryPPE = PPED.fromNamesDecl hashLength namesExcludingOldDep - pure (unisonFile, primaryPPE `PPED.addFallback` secondaryPPE) + pure + ( unisonFile, + makeOldDepPPE oldDepName newDepName namesExcludingOldDep oldDep oldDepWithoutDeps newDepWithoutDeps + `PPED.addFallback` makeComplicatedPPE hashLength namesExcludingOldDep mempty dependents + ) parsingEnv <- makeParsingEnv projectPath namesExcludingOldDep typecheckedUnisonFile <- @@ -188,17 +187,12 @@ handleUpgrade oldDepName newDepName = do textualDescriptionOfUpgrade let temporaryBranchPath = Path.unabsolute (Cli.projectBranchPath (ProjectAndBranch projectId temporaryBranchId)) Cli.stepAt textualDescriptionOfUpgrade (temporaryBranchPath, \_ -> currentV1BranchWithoutOldDep) - Cli.Env {isTranscript} <- ask - maybePath <- - if isTranscript - then pure Nothing - else do - maybeLatestFile <- Cli.getLatestFile - case maybeLatestFile of - Nothing -> pure (Just "scratch.u") - Just (file, _) -> pure (Just file) - Cli.respond (Output.DisplayDefinitionsString maybePath prettyUnisonFile) - Cli.respond (Output.UpgradeFailure oldDepName newDepName) + scratchFilePath <- + Cli.getLatestFile <&> \case + Nothing -> "scratch.u" + Just (file, _) -> file + liftIO $ writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 prettyUnisonFile) + Cli.respond (Output.UpgradeFailure scratchFilePath oldDepName newDepName) Cli.returnEarlyWithoutOutput branchUpdates <- @@ -228,9 +222,9 @@ makeOldDepPPE :: Branch0 m -> PrettyPrintEnvDecl makeOldDepPPE oldDepName newDepName namesExcludingOldDep oldDep oldDepWithoutDeps newDepWithoutDeps = - let makePPE suffixifyTerms suffixifyTypes = - PrettyPrintEnv - { termNames = \ref -> + let makePPE suffixifier = + PPE.PrettyPrintEnv + ( \ref -> let oldDirectNames = Relation.lookupDom ref (Branch.deepTerms oldDepWithoutDeps) newDirectRefsForOldDirectNames = Relation.range (Branch.deepTerms newDepWithoutDeps) `Map.restrictKeys` oldDirectNames @@ -239,19 +233,11 @@ makeOldDepPPE oldDepName newDepName namesExcludingOldDep oldDep oldDepWithoutDep Set.member ref (Branch.deepReferents oldDep), Relation.memberRan ref (Names.terms namesExcludingOldDep) ) of - (False, False, _, _) -> - Names.namesForReferent fakeNames ref - & Set.toList - & map (\name -> (HQ'.fromName name, HQ'.fromName name)) - & suffixifyTerms - & PPE.Names.prioritize - (_, _, True, False) -> - Names.namesForReferent prefixedOldNames ref - & Set.toList - & map (\name -> (HQ'.fromName name, HQ'.fromName name)) - & PPE.Names.prioritize - _ -> [], - typeNames = \ref -> + (False, False, _, _) -> PPE.makeTermNames fakeNames suffixifier ref + (_, _, True, False) -> PPE.makeTermNames prefixedOldNames PPE.dontSuffixify ref + _ -> [] + ) + ( \ref -> let oldDirectNames = Relation.lookupDom ref (Branch.deepTypes oldDepWithoutDeps) newDirectRefsForOldDirectNames = Relation.range (Branch.deepTypes newDepWithoutDeps) `Map.restrictKeys` oldDirectNames @@ -260,30 +246,18 @@ makeOldDepPPE oldDepName newDepName namesExcludingOldDep oldDep oldDepWithoutDep Set.member ref (Branch.deepTypeReferences oldDep), Relation.memberRan ref (Names.types namesExcludingOldDep) ) of - (False, False, _, _) -> - Names.namesForReference fakeNames ref - & Set.toList - & map (\name -> (HQ'.fromName name, HQ'.fromName name)) - & suffixifyTypes - & PPE.Names.prioritize - (_, _, True, False) -> - Names.namesForReference prefixedOldNames ref - & Set.toList - & map (\name -> (HQ'.fromName name, HQ'.fromName name)) - & PPE.Names.prioritize + (False, False, _, _) -> PPE.makeTypeNames fakeNames suffixifier ref + (_, _, True, False) -> PPE.makeTypeNames prefixedOldNames PPE.dontSuffixify ref _ -> [] - } + ) in PrettyPrintEnvDecl - { unsuffixifiedPPE = makePPE id id, - suffixifiedPPE = - makePPE - (PPE.Names.shortestUniqueSuffixes (Names.terms namesExcludingOldDep)) - (PPE.Names.shortestUniqueSuffixes (Names.types namesExcludingOldDep)) + { unsuffixifiedPPE = makePPE PPE.dontSuffixify, + suffixifiedPPE = makePPE (PPE.suffixifyByHash namesExcludingOldDep) } where oldNames = Branch.toNames oldDep - prefixedOldNames = Names.prefix0 (Name.fromReverseSegments (oldDepName :| [Name.libSegment])) oldNames - fakeNames = Names.prefix0 (Name.fromReverseSegments (newDepName :| [Name.libSegment])) oldNames + prefixedOldNames = PPE.namer (Names.prefix0 (Name.fromReverseSegments (oldDepName :| [Name.libSegment])) oldNames) + fakeNames = PPE.namer (Names.prefix0 (Name.fromReverseSegments (newDepName :| [Name.libSegment])) oldNames) -- @findTemporaryBranchName projectId oldDepName newDepName@ finds some unused branch name in @projectId@ with a name -- like "upgrade--to-". diff --git a/unison-cli/src/Unison/Codebase/Editor/Input.hs b/unison-cli/src/Unison/Codebase/Editor/Input.hs index dc6e023007..1deebecd28 100644 --- a/unison-cli/src/Unison/Codebase/Editor/Input.hs +++ b/unison-cli/src/Unison/Codebase/Editor/Input.hs @@ -15,6 +15,7 @@ module Unison.Codebase.Editor.Input AbsBranchId, LooseCodeOrProject, parseBranchId, + parseBranchId2, parseShortCausalHash, HashOrHQSplit', Insistence (..), @@ -42,6 +43,7 @@ import Unison.Codebase.ShortCausalHash (ShortCausalHash) import Unison.Codebase.ShortCausalHash qualified as SCH import Unison.Codebase.SyncMode (SyncMode) import Unison.Codebase.Verbosity +import Unison.CommandLine.BranchRelativePath import Unison.HashQualified qualified as HQ import Unison.Name (Name) import Unison.NameSegment (NameSegment) @@ -86,6 +88,12 @@ parseBranchId ('#' : s) = case SCH.fromText (Text.pack s) of Just h -> pure $ Left h parseBranchId s = Right <$> Path.parsePath' s +parseBranchId2 :: String -> Either (P.Pretty P.ColorText) (Either ShortCausalHash BranchRelativePath) +parseBranchId2 ('#' : s) = case SCH.fromText (Text.pack s) of + Nothing -> Left "Invalid hash, expected a base32hex string." + Just h -> Right (Left h) +parseBranchId2 s = Right <$> parseBranchRelativePath s + parseShortCausalHash :: String -> Either String ShortCausalHash parseShortCausalHash ('#' : s) | Just sch <- SCH.fromText (Text.pack s) = Right sch parseShortCausalHash _ = Left "Invalid hash, expected a base32hex string." @@ -102,7 +110,7 @@ data Input -- directory ops -- `Link` must describe a repo and a source path within that repo. -- clone w/o merge, error if would clobber - ForkLocalBranchI (Either ShortCausalHash Path') Path' + ForkLocalBranchI (Either ShortCausalHash BranchRelativePath) BranchRelativePath | -- merge first causal into destination MergeLocalBranchI LooseCodeOrProject LooseCodeOrProject Branch.MergeMode | PreviewMergeLocalBranchI LooseCodeOrProject LooseCodeOrProject @@ -182,13 +190,6 @@ data Input | -- fetch scheme compiler from a given username and branch FetchSchemeCompilerI String String | TestI TestInput - | -- metadata - -- `link metadata definitions` (adds metadata to all of `definitions`) - LinkI (HQ.HashQualified Name) [Path.HQSplit'] - | -- `unlink metadata definitions` (removes metadata from all of `definitions`) - UnlinkI (HQ.HashQualified Name) [Path.HQSplit'] - | -- links from - LinksI Path.HQSplit' (Maybe String) | CreateAuthorI NameSegment {- identifier -} Text {- name -} | -- Display provided definitions. DisplayI OutputLocation (NonEmpty (HQ.HashQualified Name)) @@ -214,6 +215,7 @@ data Input NamespaceDependenciesI (Maybe Path') | DebugTabCompletionI [String] -- The raw arguments provided | DebugFuzzyOptionsI String [String] -- cmd and arguments + | DebugFormatI | DebugNumberedArgsI | DebugTypecheckedUnisonFileI | DebugDumpNamespacesI diff --git a/unison-cli/src/Unison/Codebase/Editor/Output.hs b/unison-cli/src/Unison/Codebase/Editor/Output.hs index 8e0dea2f8d..1b08b1ea1b 100644 --- a/unison-cli/src/Unison/Codebase/Editor/Output.hs +++ b/unison-cli/src/Unison/Codebase/Editor/Output.hs @@ -228,7 +228,6 @@ data Output [(Referent, [HQ'.HashQualified Name])] -- term match, term names -- list of all the definitions within this branch | ListOfDefinitions FindScope PPE.PrettyPrintEnv ListDetailed [SearchResult' Symbol Ann] - | ListOfLinks PPE.PrettyPrintEnv [(HQ.HashQualified Name, Reference, Maybe (Type Symbol Ann))] | ListShallow (IO PPE.PrettyPrintEnv) [ShallowListEntry Symbol Ann] | ListOfPatches (Set Name) | ListStructuredFind [HQ.HashQualified Name] @@ -252,9 +251,7 @@ data Output | DisplayRendered (Maybe FilePath) (P.Pretty P.ColorText) | -- "display" the provided code to the console. DisplayDefinitions (P.Pretty P.ColorText) - | -- Like `DisplayDefinitions`, but the definitions are already rendered. `Nothing` means they were output to the terminal. - DisplayDefinitionsString !(Maybe FilePath) !(P.Pretty P.ColorText {- rendered definitions -}) - | LoadedDefinitionsToSourceFile FilePath (P.Pretty P.ColorText) + | LoadedDefinitionsToSourceFile FilePath Int | TestIncrementalOutputStart PPE.PrettyPrintEnv (Int, Int) TermReferenceId | TestIncrementalOutputEnd PPE.PrettyPrintEnv (Int, Int) TermReferenceId Bool {- True if success, False for Failure -} | TestResults @@ -272,12 +269,9 @@ data Output | GitError GitError | ShareError ShareError | ViewOnShare (Either WriteShareRemoteNamespace (URI, ProjectName, ProjectBranchName)) - | ConfiguredMetadataParseError Path' String (P.Pretty P.ColorText) | NoConfiguredRemoteMapping PushPull Path.Absolute | ConfiguredRemoteMappingParseError PushPull Path.Absolute Text String - | MetadataMissingType PPE.PrettyPrintEnv Referent | TermMissingType Reference - | MetadataAmbiguous (HQ.HashQualified Name) PPE.PrettyPrintEnv [Referent] | AboutToPropagatePatch | -- todo: tell the user to run `todo` on the same patch they just used NothingToPatch PatchPath Path' @@ -312,7 +306,6 @@ data Output | DumpBitBooster CausalHash (Map CausalHash [CausalHash]) | DumpUnisonFileHashes Int [(Name, Reference.Id)] [(Name, Reference.Id)] [(Name, Reference.Id)] | BadName String - | DefaultMetadataNotification | CouldntLoadBranch CausalHash | HelpMessage Input.InputPattern | NamespaceEmpty (NonEmpty AbsBranchId) @@ -394,7 +387,7 @@ data Output | UpdateTypecheckingFailure | UpdateTypecheckingSuccess | UpdateIncompleteConstructorSet UpdateOrUpgrade Name (Map ConstructorId Name) (Maybe Int) - | UpgradeFailure !NameSegment !NameSegment + | UpgradeFailure !FilePath !NameSegment !NameSegment | UpgradeSuccess !NameSegment !NameSegment data UpdateOrUpgrade = UOUUpdate | UOUUpgrade @@ -509,7 +502,6 @@ isFailure o = case o of MovedOverExistingBranch {} -> False DeletedEverything -> False ListNames _ _ tys tms -> null tms && null tys - ListOfLinks _ ds -> null ds ListOfDefinitions _ _ _ ds -> null ds ListOfPatches s -> Set.null s ListStructuredFind tms -> null tms @@ -524,7 +516,6 @@ isFailure o = case o of Typechecked {} -> False LoadedDefinitionsToSourceFile {} -> False DisplayDefinitions {} -> False - DisplayDefinitionsString {} -> False -- somewhat arbitrary :shrug: DisplayRendered {} -> False TestIncrementalOutputStart {} -> False TestIncrementalOutputEnd {} -> False @@ -532,11 +523,8 @@ isFailure o = case o of CantUndo {} -> True GitError {} -> True BustedBuiltins {} -> True - ConfiguredMetadataParseError {} -> True NoConfiguredRemoteMapping {} -> True ConfiguredRemoteMappingParseError {} -> True - MetadataMissingType {} -> True - MetadataAmbiguous {} -> True PatchNeedsToBeConflictFree {} -> True PatchInvolvesExternalDependents {} -> True AboutToPropagatePatch {} -> False @@ -558,7 +546,6 @@ isFailure o = case o of HashAmbiguous {} -> True ShowReflog {} -> False LoadPullRequest {} -> False - DefaultMetadataNotification -> False HelpMessage {} -> True NoOp -> False ListDependencies {} -> False diff --git a/unison-cli/src/Unison/Codebase/Editor/Output/BranchDiff.hs b/unison-cli/src/Unison/Codebase/Editor/Output/BranchDiff.hs index 318f8b6643..27fff49aea 100644 --- a/unison-cli/src/Unison/Codebase/Editor/Output/BranchDiff.hs +++ b/unison-cli/src/Unison/Codebase/Editor/Output/BranchDiff.hs @@ -6,43 +6,21 @@ import Control.Lens import Data.List qualified as List import Data.Map qualified as Map import Data.Set qualified as Set -import Unison.Codebase.BranchDiff (BranchDiff (BranchDiff), DiffSlice) +import Unison.Codebase.BranchDiff (BranchDiff (BranchDiff)) import Unison.Codebase.BranchDiff qualified as BranchDiff -import Unison.Codebase.Metadata qualified as Metadata import Unison.Codebase.Patch qualified as P import Unison.DataDeclaration (DeclOrBuiltin) -import Unison.HashQualified qualified as HQ import Unison.HashQualified' (HashQualified) import Unison.Name (Name) import Unison.Name qualified as Name import Unison.Names (Names) import Unison.Names qualified as Names import Unison.Prelude -import Unison.PrettyPrintEnv qualified as PPE import Unison.Reference (Reference) import Unison.Referent (Referent) -import Unison.Referent qualified as Referent -import Unison.Runtime.IOSource (isPropagatedValue) import Unison.Syntax.Name () import Unison.Type (Type) import Unison.Util.Relation qualified as R -import Unison.Util.Relation3 qualified as R3 -import Unison.Util.Set (symmetricDifference) - -data MetadataDiff tm = MetadataDiff - { addedMetadata :: [tm], - removedMetadata :: [tm] - } - deriving (Ord, Eq, Functor, Foldable, Traversable, Show) - -instance Semigroup (MetadataDiff tm) where - a <> b = - MetadataDiff - (addedMetadata a <> addedMetadata b) - (removedMetadata a <> removedMetadata b) - -instance Monoid (MetadataDiff tm) where - mempty = MetadataDiff mempty mempty data BranchDiffOutput v a = BranchDiffOutput { updatedTypes :: [UpdateTypeDisplay v a], @@ -51,7 +29,6 @@ data BranchDiffOutput v a = BranchDiffOutput newTermConflicts :: [UpdateTermDisplay v a], resolvedTypeConflicts :: [UpdateTypeDisplay v a], resolvedTermConflicts :: [UpdateTermDisplay v a], - propagatedUpdates :: Int, updatedPatches :: [PatchDisplay], addedTypes :: [AddedTypeDisplay v a], addedTerms :: [AddedTermDisplay v a], @@ -81,7 +58,6 @@ isEmpty BranchDiffOutput {..} = && null renamedTypes && null renamedTerms && null updatedPatches - && propagatedUpdates == 0 -- Need to be able to turn a (Name,Reference) into a HashQualified relative to... what. -- the new namespace? @@ -89,8 +65,7 @@ isEmpty BranchDiffOutput {..} = data TermDisplay v a = TermDisplay { name :: HashQualified Name, ref :: Referent, - type_ :: Maybe (Type v a), - metadata :: MetadataDiff (MetadataDisplay v a) + type_ :: Maybe (Type v a) } deriving stock (Generic, Show) @@ -106,8 +81,7 @@ instance Ord (TermDisplay v a) where data TypeDisplay v a = TypeDisplay { name :: HashQualified Name, ref :: Reference, - decl :: Maybe (DeclOrBuiltin v a), - metadata :: MetadataDiff (MetadataDisplay v a) + decl :: Maybe (DeclOrBuiltin v a) } deriving stock (Generic, Show) @@ -120,9 +94,9 @@ instance Ord (TypeDisplay v a) where compare t0 t1 = Name.compareAlphabetical (t0 ^. #name) (t1 ^. #name) <> compare (t0 ^. #ref) (t1 ^. #ref) -type AddedTermDisplay v a = ([(HashQualified Name, [MetadataDisplay v a])], Referent, Maybe (Type v a)) +type AddedTermDisplay v a = ([HashQualified Name], Referent, Maybe (Type v a)) -type AddedTypeDisplay v a = ([(HashQualified Name, [MetadataDisplay v a])], Reference, Maybe (DeclOrBuiltin v a)) +type AddedTypeDisplay v a = ([HashQualified Name], Reference, Maybe (DeclOrBuiltin v a)) type RemovedTermDisplay v a = ([HashQualified Name], Referent, Maybe (Type v a)) @@ -162,8 +136,6 @@ instance Ord (UpdateTypeDisplay v a) where (t0 : _, t1 : _) -> compare t0 t1 (ts0, ts1) -> compare (null ts0) (null ts1) -type MetadataDisplay v a = (HQ.HashQualified Name, Referent, Maybe (Type v a)) - type RenameTermDisplay v a = (Referent, Maybe (Type v a), Set (HashQualified Name), Set (HashQualified Name)) type RenameTypeDisplay v a = (Reference, Maybe (DeclOrBuiltin v a), Set (HashQualified Name), Set (HashQualified Name)) @@ -178,7 +150,6 @@ toOutput :: Int -> Names -> Names -> - PPE.PrettyPrintEnv -> BranchDiff.BranchDiff -> m (BranchDiffOutput v a) toOutput @@ -187,56 +158,7 @@ toOutput hqLen names1 names2 - ppe (BranchDiff termsDiff typesDiff patchesDiff) = do - let -- This calculates the new reference's metadata as: - -- adds: now-attached metadata that was missing from - -- any of the old references associated with the name - -- removes: not-attached metadata that had been attached to any of - -- the old references associated with the name - getNewMetadataDiff :: (Ord r) => Bool -> DiffSlice r -> Name -> Set r -> r -> MetadataDiff Metadata.Value - getNewMetadataDiff hidePropagatedMd s n rs_old r_new = - let old_metadatas :: [Set Metadata.Value] = - toList . R.toMultimap . R.restrictDom rs_old . R3.lookupD2 n $ - BranchDiff.tremovedMetadata s - old_intersection :: Set Metadata.Value = - foldl' Set.intersection mempty old_metadatas - old_union :: Set Metadata.Value = - foldl' Set.union mempty old_metadatas - new_metadata :: Set Metadata.Value = - R.lookupDom n . R3.lookupD1 r_new $ BranchDiff.taddedMetadata s - toDelete = if hidePropagatedMd then Set.singleton isPropagatedValue else mempty - in MetadataDiff - { addedMetadata = toList $ new_metadata `Set.difference` old_intersection `Set.difference` toDelete, - removedMetadata = toList $ old_union `Set.difference` new_metadata `Set.difference` toDelete - } - -- For the metadata on a definition to have changed, the name - -- and the reference must have existed before and the reference - -- must not have been removed and the name must not have been removed or added - -- or updated 😅 - -- "getMetadataUpdates" = a defn has been updated via change of metadata - getMetadataUpdates :: (Ord r) => DiffSlice r -> Map Name (Set r, Set r) - getMetadataUpdates s = - Map.fromList - [ (n, (Set.singleton r, Set.singleton r)) -- the reference is unchanged - | (r, n, v) <- - R3.toList $ - BranchDiff.taddedMetadata s - <> BranchDiff.tremovedMetadata s, - R.notMember r n (BranchDiff.talladds s), - R.notMember r n (BranchDiff.tallremoves s), - -- don't count it as a metadata update if it already's already a regular update - let (oldRefs, newRefs) = - Map.findWithDefault mempty n (BranchDiff.tallnamespaceUpdates s) - in Set.notMember r oldRefs && Set.notMember r newRefs, - -- trenames :: Map r (Set Name, Set Name), -- ref (old, new) - case Map.lookup r (BranchDiff.trenames s) of - Nothing -> True - Just (olds, news) -> - Set.notMember n (symmetricDifference olds news), - v /= isPropagatedValue - ] - let isSimpleUpdate, isNewConflict, isResolvedConflict :: (Eq r) => (Set r, Set r) -> Bool isSimpleUpdate (old, new) = Set.size old == 1 && Set.size new == 1 isNewConflict (_old, new) = Set.size new > 1 -- should already be the case that old /= new @@ -249,9 +171,6 @@ toOutput let -- things where what the name pointed to changed nsUpdates :: Map Name (Set Reference, Set Reference) = BranchDiff.namespaceUpdates typesDiff - -- things where the metadata changed (`uniqueBy` below removes these - -- if they were already included in `nsUpdates) - metadataUpdates = getMetadataUpdates typesDiff loadOld :: Bool -> Name -> Reference -> m (SimpleTypeDisplay v a) loadOld forceHQ n r_old = (,,) @@ -262,10 +181,9 @@ toOutput ) <*> pure r_old <*> declOrBuiltin r_old - loadNew :: Bool -> Bool -> Name -> Set Reference -> Reference -> m (TypeDisplay v a) - loadNew hidePropagatedMd forceHQ n rs_old r_new = do + loadNew :: Bool -> Name -> Reference -> m (TypeDisplay v a) + loadNew forceHQ n r_new = do decl <- declOrBuiltin r_new - metadata <- fillMetadata ppe (getNewMetadataDiff hidePropagatedMd typesDiff n rs_old r_new) pure TypeDisplay { name = @@ -273,33 +191,27 @@ toOutput then Names.hqTypeName' hqLen n r_new else Names.hqTypeName hqLen names2 n r_new, ref = r_new, - decl, - metadata + decl } - loadEntry :: Bool -> (Name, (Set Reference, Set Reference)) -> m (UpdateTypeDisplay v a) - loadEntry hidePropagatedMd (n, (Set.toList -> [rold], Set.toList -> [rnew])) + loadEntry :: (Name, (Set Reference, Set Reference)) -> m (UpdateTypeDisplay v a) + loadEntry (n, (Set.toList -> [rold], Set.toList -> [rnew])) | rold == rnew = do - new <- for [rnew] (loadNew hidePropagatedMd False n (Set.singleton rold)) + new <- for [rnew] (loadNew False n) pure UpdateTypeDisplay { old = Nothing, new } - loadEntry hidePropagatedMd (n, (rs_old, rs_new)) = do + loadEntry (n, (rs_old, rs_new)) = do let forceHQ = Set.size rs_old > 1 || Set.size rs_new > 1 old <- Just <$> for (toList rs_old) (loadOld forceHQ n) - new <- for (toList rs_new) (loadNew hidePropagatedMd forceHQ n rs_old) + new <- for (toList rs_new) (loadNew forceHQ n) pure UpdateTypeDisplay {old, new} in liftA3 (,,) - ( List.sort - <$> liftA2 - (<>) - (for (Map.toList $ Map.filter isSimpleUpdate nsUpdates) (loadEntry True)) - (for (Map.toList metadataUpdates) (loadEntry False)) - ) - (List.sort <$> for (Map.toList $ Map.filter isNewConflict nsUpdates) (loadEntry True)) - (List.sort <$> for (Map.toList $ Map.filter isResolvedConflict nsUpdates) (loadEntry True)) + (List.sort <$> for (Map.toList $ Map.filter isSimpleUpdate nsUpdates) loadEntry) + (List.sort <$> for (Map.toList $ Map.filter isNewConflict nsUpdates) loadEntry) + (List.sort <$> for (Map.toList $ Map.filter isResolvedConflict nsUpdates) loadEntry) ( updatedTerms :: [UpdateTermDisplay v a], newTermConflicts :: [UpdateTermDisplay v a], @@ -307,9 +219,6 @@ toOutput ) <- let -- things where what the name pointed to changed nsUpdates = BranchDiff.namespaceUpdates termsDiff - -- things where the metadata changed (`uniqueBy` below removes these - -- if they were already included in `nsUpdates) - metadataUpdates = getMetadataUpdates termsDiff loadOld forceHQ n r_old = (,,) <$> pure @@ -319,10 +228,9 @@ toOutput ) <*> pure r_old <*> typeOf r_old - loadNew :: Bool -> Bool -> Name -> Set Referent -> Referent -> m (TermDisplay v a) - loadNew hidePropagatedMd forceHQ n rs_old r_new = do + loadNew :: Bool -> Name -> Referent -> m (TermDisplay v a) + loadNew forceHQ n r_new = do type_ <- typeOf r_new - metadata <- fillMetadata ppe (getNewMetadataDiff hidePropagatedMd termsDiff n rs_old r_new) pure TermDisplay { name = @@ -330,15 +238,14 @@ toOutput then Names.hqTermName' hqLen n r_new else Names.hqTermName hqLen names2 n r_new, ref = r_new, - type_, - metadata + type_ } - loadEntry :: Bool -> (Name, (Set Referent, Set Referent)) -> m (UpdateTermDisplay v a) - loadEntry hidePropagatedMd (n, (rs_old, rs_new)) + loadEntry :: (Name, (Set Referent, Set Referent)) -> m (UpdateTermDisplay v a) + loadEntry (n, (rs_old, rs_new)) -- if the references haven't changed, it's code for: only the metadata has changed -- and we can ignore the old references in the output. | rs_old == rs_new = do - new <- for (toList rs_new) (loadNew hidePropagatedMd False n rs_old) + new <- for (toList rs_new) (loadNew False n) pure UpdateTermDisplay { old = Nothing, @@ -347,65 +254,36 @@ toOutput | otherwise = do let forceHQ = Set.size rs_old > 1 || Set.size rs_new > 1 old <- Just <$> for (toList rs_old) (loadOld forceHQ n) - new <- for (toList rs_new) (loadNew hidePropagatedMd forceHQ n rs_old) + new <- for (toList rs_new) (loadNew forceHQ n) pure UpdateTermDisplay {old, new} in liftA3 (,,) -- this is sorting the Update section back into alphabetical Name order -- after calling loadEntry on the two halves. - ( List.sort - <$> liftA2 - (<>) - (for (Map.toList $ Map.filter isSimpleUpdate nsUpdates) (loadEntry True)) - (for (Map.toList metadataUpdates) (loadEntry False)) - ) - (List.sort <$> for (Map.toList $ Map.filter isNewConflict nsUpdates) (loadEntry True)) - (List.sort <$> for (Map.toList $ Map.filter isResolvedConflict nsUpdates) (loadEntry True)) - - let propagatedUpdates :: Int = - -- counting the number of named auto-propagated definitions - (Set.size . Set.unions . toList . BranchDiff.propagatedUpdates) typesDiff - + (Set.size . Set.unions . toList . BranchDiff.propagatedUpdates) termsDiff + (List.sort <$> for (Map.toList $ Map.filter isSimpleUpdate nsUpdates) loadEntry) + (List.sort <$> for (Map.toList $ Map.filter isNewConflict nsUpdates) loadEntry) + (List.sort <$> for (Map.toList $ Map.filter isResolvedConflict nsUpdates) loadEntry) let updatedPatches :: [PatchDisplay] = [(name, diff) | (name, BranchDiff.Modify diff) <- Map.toList patchesDiff] addedTypes :: [AddedTypeDisplay v a] <- do - let typeAdds :: [(Reference, [(Name, [Metadata.Value])])] = + let typeAdds :: [(Reference, Set Name)] = sortOn snd - [ (r, nsmd) - | (r, ns) <- Map.toList . R.toMultimap . BranchDiff.talladds $ typesDiff, - let nsmd = - [ (n, toList $ getAddedMetadata r n typesDiff) - | n <- toList ns - ] - ] - for typeAdds $ \(r, nsmd) -> do - hqmds :: [(HashQualified Name, [MetadataDisplay v a])] <- - for nsmd $ \(n, mdRefs) -> - (,) - <$> pure (Names.hqTypeName hqLen names2 n r) - <*> fillMetadata ppe mdRefs - (hqmds,r,) <$> declOrBuiltin r + (Map.toList . R.toMultimap . BranchDiff.talladds $ typesDiff) + for typeAdds \(r, ns) -> do + let hqs = map (\n -> Names.hqTypeName hqLen names2 n r) (Set.toList ns) + (hqs,r,) <$> declOrBuiltin r addedTerms :: [AddedTermDisplay v a] <- do - let termAdds :: [(Referent, [(Name, [Metadata.Value])])] = + let termAdds :: [(Referent, Set Name)] = sortOn snd - [ (r, nsmd) - | (r, ns) <- Map.toList . R.toMultimap . BranchDiff.talladds $ termsDiff, - let nsmd = - [ (n, toList $ getAddedMetadata r n termsDiff) - | n <- toList ns - ] - ] - for termAdds $ \(r, nsmd) -> do - hqmds <- for nsmd $ \(n, mdRefs) -> - (,) - <$> pure (Names.hqTermName hqLen names2 n r) - <*> fillMetadata ppe mdRefs - (hqmds,r,) <$> typeOf r + (Map.toList . R.toMultimap . BranchDiff.talladds $ termsDiff) + for termAdds \(r, ns) -> do + let hqs = map (\n -> Names.hqTermName hqLen names2 n r) (Set.toList ns) + (hqs,r,) <$> typeOf r let addedPatches :: [PatchDisplay] = [ (name, diff) @@ -468,7 +346,6 @@ toOutput newTermConflicts, resolvedTypeConflicts, resolvedTermConflicts, - propagatedUpdates, updatedPatches, addedTypes, addedTerms, @@ -479,14 +356,3 @@ toOutput renamedTypes, renamedTerms } - where - fillMetadata :: (Traversable t) => PPE.PrettyPrintEnv -> t Metadata.Value -> m (t (MetadataDisplay v a)) - fillMetadata ppe = traverse $ -- metadata values are all terms - \(Referent.Ref -> mdRef) -> - let name = PPE.termName ppe mdRef - in (name,mdRef,) <$> typeOf mdRef - getMetadata :: (Ord r) => r -> Name -> R3.Relation3 r Name Metadata.Value -> Set Metadata.Value - getMetadata r n = R.lookupDom n . R3.lookupD1 r - - getAddedMetadata :: (Ord r) => r -> Name -> BranchDiff.DiffSlice r -> Set Metadata.Value - getAddedMetadata r n slice = getMetadata r n $ BranchDiff.taddedMetadata slice diff --git a/unison-cli/src/Unison/Codebase/Editor/Output/DumpNamespace.hs b/unison-cli/src/Unison/Codebase/Editor/Output/DumpNamespace.hs index de5f07c88b..c190e6ff8b 100644 --- a/unison-cli/src/Unison/Codebase/Editor/Output/DumpNamespace.hs +++ b/unison-cli/src/Unison/Codebase/Editor/Output/DumpNamespace.hs @@ -7,8 +7,8 @@ import Unison.Reference (Reference) import Unison.Referent (Referent) data DumpNamespace = DumpNamespace - { terms :: Map Referent (Set NameSegment, Set Reference), - types :: Map Reference (Set NameSegment, Set Reference), + { terms :: Map Referent (Set NameSegment), + types :: Map Reference (Set NameSegment), patches :: Map NameSegment PatchHash, children :: Map NameSegment CausalHash, causalParents :: Set CausalHash diff --git a/unison-cli/src/Unison/Codebase/TranscriptParser.hs b/unison-cli/src/Unison/Codebase/TranscriptParser.hs index 34ed9e9b81..f49bea960c 100644 --- a/unison-cli/src/Unison/Codebase/TranscriptParser.hs +++ b/unison-cli/src/Unison/Codebase/TranscriptParser.hs @@ -49,7 +49,6 @@ import Unison.Cli.MonadUtils qualified as Cli import Unison.Cli.ProjectUtils qualified as ProjectUtils import Unison.Codebase (Codebase) import Unison.Codebase qualified as Codebase -import Unison.Codebase.Branch.Type qualified as Branch import Unison.Codebase.Editor.HandleInput qualified as HandleInput import Unison.Codebase.Editor.Input (Event (UnisonFileChanged), Input (..)) import Unison.Codebase.Editor.Output qualified as Output @@ -267,15 +266,21 @@ run verbosity dir stanzas codebase runtime sbRuntime nRuntime config ucmVersion Just accessToken -> \_codeserverID -> pure $ Right accessToken seedRef <- newIORef (0 :: Int) - inputQueue <- Q.newIO - cmdQueue <- Q.newIO + -- Queue of Stanzas and Just index, or Nothing if the stanza was programmatically generated + -- e.g. a unison-file update by a command like 'edit' + inputQueue <- Q.newIO @(Stanza, Maybe Int) + -- Queue of UCM commands to run. + -- Nothing indicates the end of a ucm block. + cmdQueue <- Q.newIO @(Maybe UcmLine) + -- Queue of scratch file updates triggered by UCM itself, e.g. via `edit`, `update`, etc. + ucmScratchFileUpdatesQueue <- Q.newIO @(ScratchFileName, Text) unisonFiles <- newIORef Map.empty out <- newIORef mempty hidden <- newIORef Shown allowErrors <- newIORef False hasErrors <- newIORef False mStanza <- newIORef Nothing - traverse_ (atomically . Q.enqueue inputQueue) (stanzas `zip` [1 :: Int ..]) + traverse_ (atomically . Q.enqueue inputQueue) (stanzas `zip` (Just <$> [1 :: Int ..])) let patternMap = Map.fromList $ validInputs @@ -319,6 +324,13 @@ run verbosity dir stanzas codebase runtime sbRuntime nRuntime config ucmVersion Just Nothing -> do liftIO (output "\n```\n") liftIO dieUnexpectedSuccess + atomically $ void $ do + scratchFileUpdates <- Q.flush ucmScratchFileUpdatesQueue + -- Push them onto the front stanza queue in the correct order. + for (reverse scratchFileUpdates) \(fp, contents) -> do + let fenceDescription = "unison:added-by-ucm " <> fp + -- Output blocks for any scratch file updates the ucm block triggered. + Q.undequeue inputQueue (UnprocessedFence fenceDescription contents, Nothing) awaitInput -- ucm command to run Just (Just ucmLine) -> do @@ -353,10 +365,8 @@ run verbosity dir stanzas codebase runtime sbRuntime nRuntime config ucmVersion [] -> awaitInput args -> do liftIO (output ("\n" <> show p <> "\n")) - rootVar <- use #root numberedArgs <- use #numberedArgs - let getRoot = fmap Branch.head . atomically $ readTMVar rootVar - liftIO (parseInput codebase getRoot curPath numberedArgs patternMap args) >>= \case + liftIO (parseInput codebase curPath numberedArgs patternMap args) >>= \case -- invalid command is treated as a failure Left msg -> do liftIO $ writeIORef hasErrors True @@ -399,10 +409,13 @@ run verbosity dir stanzas codebase runtime sbRuntime nRuntime config ucmVersion liftIO (writeIORef hidden hide) liftIO (outputEcho $ show s) liftIO (writeIORef allowErrors errOk) + -- Open a ucm block which will contain the output from UCM + -- after processing the the UnisonFileChanged event. liftIO (output "```ucm\n") + -- Close the ucm block after processing the UnisonFileChanged event. atomically . Q.enqueue cmdQueue $ Nothing let sourceName = fromMaybe "scratch.u" filename - liftIO $ writeSourceFile sourceName txt + liftIO $ updateVirtualFile sourceName txt pure $ Left (UnisonFileChanged sourceName txt) API apiRequests -> do liftIO (output "```api\n") @@ -435,6 +448,13 @@ run verbosity dir stanzas codebase runtime sbRuntime nRuntime config ucmVersion writeSourceFile :: ScratchFileName -> Text -> IO () writeSourceFile fp contents = do + shouldShowSourceChanges <- (== Shown) <$> readIORef hidden + when shouldShowSourceChanges $ do + atomically (Q.enqueue ucmScratchFileUpdatesQueue (fp, contents)) + updateVirtualFile fp contents + + updateVirtualFile :: ScratchFileName -> Text -> IO () + updateVirtualFile fp contents = do liftIO (modifyIORef' unisonFiles (Map.insert fp contents)) print :: Output.Output -> IO () @@ -509,7 +529,6 @@ run verbosity dir stanzas codebase runtime sbRuntime nRuntime config ucmVersion generateUniqueName = do i <- atomicModifyIORef' seedRef \i -> let !i' = i + 1 in (i', i) pure (Parser.uniqueBase32Namegen (Random.drgNewSeed (Random.seedFromInteger (fromIntegral i)))), - isTranscript = True, -- we are running a transcript loadSource = loadPreviousUnisonBlock, writeSource = writeSourceFile, notify = print, diff --git a/unison-cli/src/Unison/CommandLine.hs b/unison-cli/src/Unison/CommandLine.hs index ecc37e9c36..f97a25e331 100644 --- a/unison-cli/src/Unison/CommandLine.hs +++ b/unison-cli/src/Unison/CommandLine.hs @@ -26,7 +26,6 @@ module Unison.CommandLine where import Control.Concurrent (forkIO, killThread) -import Control.Lens (ifor) import Control.Monad.Except import Control.Monad.Trans.Except import Data.Configurator (autoConfig, autoReload) @@ -43,6 +42,7 @@ import Data.Vector qualified as Vector import System.FilePath (takeFileName) import Text.Regex.TDFA ((=~)) import Unison.Codebase (Codebase) +import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch (Branch0) import Unison.Codebase.Branch qualified as Branch import Unison.Codebase.Editor.Input (Event (..), Input (..)) @@ -50,7 +50,6 @@ import Unison.Codebase.Path qualified as Path import Unison.Codebase.Watch qualified as Watch import Unison.CommandLine.FZFResolvers qualified as FZFResolvers import Unison.CommandLine.FuzzySelect qualified as Fuzzy -import Unison.CommandLine.Globbing qualified as Globbing import Unison.CommandLine.InputPattern (InputPattern (..)) import Unison.CommandLine.InputPattern qualified as InputPattern import Unison.Parser.Ann (Ann) @@ -121,8 +120,7 @@ nothingTodo = emojiNote "😶" parseInput :: Codebase IO Symbol Ann -> - IO (Branch0 IO) -> - -- | Current path from root, used to expand globs + -- | Current path from root Path.Absolute -> -- | Numbered arguments [String] -> @@ -133,11 +131,9 @@ parseInput :: -- Returns either an error message or the fully expanded arguments list and parsed input. -- If the output is `Nothing`, the user cancelled the input (e.g. ctrl-c) IO (Either (P.Pretty CT.ColorText) (Maybe ([String], Input))) -parseInput codebase getRoot currentPath numberedArgs patterns segments = runExceptT do +parseInput codebase currentPath numberedArgs patterns segments = runExceptT do let getCurrentBranch0 :: IO (Branch0 IO) - getCurrentBranch0 = do - rootBranch <- getRoot - pure $ Branch.getAt0 (Path.unabsolute currentPath) rootBranch + getCurrentBranch0 = Branch.head <$> Codebase.getBranchAtPath codebase currentPath let projCtx = projectContextFromPath currentPath case segments of @@ -147,20 +143,7 @@ parseInput codebase getRoot currentPath numberedArgs patterns segments = runExce let expandedNumbers :: [String] expandedNumbers = foldMap (expandNumber numberedArgs) args - expandedGlobs <- ifor expandedNumbers $ \i arg -> do - if Globbing.containsGlob arg - then do - rootBranch <- liftIO getRoot - let targets = case InputPattern.argType pat i of - Just argT -> InputPattern.globTargets argT - Nothing -> mempty - case Globbing.expandGlobs targets rootBranch currentPath arg of - -- No globs encountered - Nothing -> pure [arg] - Just [] -> throwE $ "No matches for: " <> fromString arg - Just matches -> pure matches - else pure [arg] - lift (fzfResolve codebase projCtx getCurrentBranch0 pat (concat expandedGlobs)) >>= \case + lift (fzfResolve codebase projCtx getCurrentBranch0 pat expandedNumbers) >>= \case Left (NoFZFResolverForArgumentType _argDesc) -> throwError help Left (NoFZFOptions argDesc) -> throwError (noCompletionsMessage argDesc) Left FZFCancelled -> pure Nothing diff --git a/unison-cli/src/Unison/CommandLine/BranchRelativePath.hs b/unison-cli/src/Unison/CommandLine/BranchRelativePath.hs new file mode 100644 index 0000000000..cbdfb3403f --- /dev/null +++ b/unison-cli/src/Unison/CommandLine/BranchRelativePath.hs @@ -0,0 +1,135 @@ +module Unison.CommandLine.BranchRelativePath + ( BranchRelativePath (..), + parseBranchRelativePath, + branchRelativePathParser, + ResolvedBranchRelativePath (..), + ) +where + +import Control.Lens (view) +import Data.Char (isSpace) +import Data.Set qualified as Set +import Data.Text qualified as Text +import Data.These (These (..)) +import Text.Builder qualified +import Text.Megaparsec qualified as Megaparsec +import Text.Megaparsec.Char qualified as Megaparsec +import U.Codebase.Sqlite.Project qualified as Sqlite +import U.Codebase.Sqlite.ProjectBranch qualified as Sqlite +import Unison.Codebase.Path qualified as Path +import Unison.Codebase.Path.Parse qualified as Path +import Unison.Prelude +import Unison.Project (ProjectBranchName, ProjectBranchSpecifier (..), ProjectName) +import Unison.Project qualified as Project +import Unison.Util.ColorText qualified as CT +import Unison.Util.Pretty qualified as P + +data BranchRelativePath + = BranchRelative (These (Either ProjectBranchName (ProjectName, ProjectBranchName)) Path.Relative) + | LoosePath Path.Path' + deriving stock (Eq, Show) + +-- | Strings without colons are parsed as loose code paths. A path with a colon may specify: +-- 1. A project and branch +-- 2. Only a branch, in which case the project is assumed to be the current project +-- 3. Only a path, in which case the path is rooted at the branch root +-- +-- Specifying only a project is not allowed. +-- +-- >>> parseBranchRelativePath "foo" +-- Right (LoosePath foo) +-- >>> parseBranchRelativePath "foo/bar:" +-- Right (BranchRelative (This (Right (UnsafeProjectName "foo",UnsafeProjectBranchName "bar")))) +-- >>> parseBranchRelativePath "foo/bar:some.path" +-- Right (BranchRelative (These (Right (UnsafeProjectName "foo",UnsafeProjectBranchName "bar")) some.path)) +-- >>> parseBranchRelativePath "/bar:some.path" +-- Right (BranchRelative (These (Left (UnsafeProjectBranchName "bar")) some.path)) +-- >>> parseBranchRelativePath ":some.path" +-- Right (BranchRelative (That some.path)) +parseBranchRelativePath :: String -> Either (P.Pretty CT.ColorText) BranchRelativePath +parseBranchRelativePath str = + case Megaparsec.parse branchRelativePathParser "" (Text.pack str) of + Left e -> Left (P.string (Megaparsec.errorBundlePretty e)) + Right x -> Right x + +instance From BranchRelativePath Text where + from = \case + BranchRelative brArg -> case brArg of + This eitherProj -> + Text.Builder.run + ( Text.Builder.text (eitherProjToText eitherProj) + <> Text.Builder.char ':' + ) + That path -> + Text.Builder.run + ( Text.Builder.char ':' + <> Text.Builder.text (Path.convert path) + ) + These eitherProj path -> + Text.Builder.run + ( Text.Builder.text (eitherProjToText eitherProj) + <> Text.Builder.char ':' + <> Text.Builder.text (Path.convert path) + ) + LoosePath path -> Path.toText' path + where + eitherProjToText = \case + Left branchName -> from @(These ProjectName ProjectBranchName) @Text (That branchName) + Right (projName, branchName) -> into @Text (These projName branchName) + +data ResolvedBranchRelativePath + = ResolvedBranchRelative (Project.ProjectAndBranch Sqlite.Project Sqlite.ProjectBranch) (Maybe Path.Relative) + | ResolvedLoosePath Path.Absolute + +instance From ResolvedBranchRelativePath BranchRelativePath where + from = \case + ResolvedBranchRelative (Project.ProjectAndBranch proj branch) mRel -> case mRel of + Nothing -> BranchRelative (This (Right (view #name proj, view #name branch))) + Just rel -> BranchRelative (These (Right (view #name proj, view #name branch)) rel) + ResolvedLoosePath p -> LoosePath (Path.absoluteToPath' p) + +instance From ResolvedBranchRelativePath Text where + from = from . into @BranchRelativePath + +branchRelativePathParser :: Megaparsec.Parsec Void Text BranchRelativePath +branchRelativePathParser = + asum + [ LoosePath <$> path', + BranchRelative <$> branchRelative + ] + where + branchRelative :: Megaparsec.Parsec Void Text (These (Either ProjectBranchName (ProjectName, ProjectBranchName)) Path.Relative) + branchRelative = asum [fullPath, currentBranchRootPath] + + path' = Megaparsec.try do + offset <- Megaparsec.getOffset + pathStr <- Megaparsec.takeWhile1P (Just "path char") (not . isSpace) + case Path.parsePath' (Text.unpack pathStr) of + Left err -> failureAt offset err + Right x -> pure x + + relPath = do + offset <- Megaparsec.getOffset + path' >>= \(Path.Path' inner) -> case inner of + Left _ -> failureAt offset "Expected a relative path but found an absolute path" + Right x -> pure x + + fullPath = do + projectAndBranchNames <- do + projectBranch <- Project.projectAndBranchNamesParser ProjectBranchSpecifier'Name + offset <- Megaparsec.getOffset + _ <- Megaparsec.char ':' + case projectBranch of + This _ -> failureAt offset "Expected a project and branch before the colon (e.g. project/branch:a.path)" + That pbn -> pure (Left pbn) + These pn pbn -> pure (Right (pn, pbn)) + optional relPath <&> \case + Nothing -> This projectAndBranchNames + Just rp -> These projectAndBranchNames rp + + currentBranchRootPath = do + _ <- Megaparsec.char ':' + That <$> relPath + + failureAt :: forall a. Int -> String -> Megaparsec.Parsec Void Text a + failureAt offset str = Megaparsec.parseError (Megaparsec.FancyError offset (Set.singleton (Megaparsec.ErrorFail str))) diff --git a/unison-cli/src/Unison/CommandLine/Completion.hs b/unison-cli/src/Unison/CommandLine/Completion.hs index 13e4920607..bdaf4a1ddc 100644 --- a/unison-cli/src/Unison/CommandLine/Completion.hs +++ b/unison-cli/src/Unison/CommandLine/Completion.hs @@ -203,12 +203,9 @@ completeWithinNamespace compTypes query currentPath = do where -- Qualify any conflicted definitions. If the query has a "#" in it, then qualify ALL -- completions. - qualifyRefs :: NameSegment -> (Map r metadata) -> [HQ'.HashQualified NameSegment] + qualifyRefs :: NameSegment -> Map r metadata -> [HQ'.HashQualified NameSegment] qualifyRefs n refs - | ((Text.isInfixOf "#" . NameSegment.toText) querySuffix) || length refs > 1 = - refs - & Map.keys - <&> qualify n + | ((Text.isInfixOf "#" . NameSegment.toText) querySuffix) || length refs > 1 = refs & Map.keys <&> qualify n | otherwise = [HQ'.NameOnly n] -- If we're not completing namespaces, then all namespace completions should automatically diff --git a/unison-cli/src/Unison/CommandLine/Globbing.hs b/unison-cli/src/Unison/CommandLine/Globbing.hs deleted file mode 100644 index f9bbdc97ab..0000000000 --- a/unison-cli/src/Unison/CommandLine/Globbing.hs +++ /dev/null @@ -1,148 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ViewPatterns #-} - --- | Provides Globbing for selecting types, terms and namespaces using wildcards. -module Unison.CommandLine.Globbing - ( expandGlobs, - containsGlob, - TargetType (..), - ) -where - -import Control.Lens as Lens hiding (noneOf) -import Data.Either qualified as Either -import Data.Set qualified as Set -import Data.Text qualified as Text -import Unison.Codebase.Branch (Branch0) -import Unison.Codebase.Branch qualified as Branch -import Unison.Codebase.Path qualified as Path -import Unison.NameSegment (NameSegment (NameSegment)) -import Unison.NameSegment qualified as NameSegment -import Unison.Prelude -import Unison.Util.Monoid qualified as Monoid -import Unison.Util.Relation qualified as Relation -import Unison.Util.Star3 qualified as Star3 - --- | Possible targets which a glob may select. -data TargetType - = Type - | Term - | Namespace - deriving (Eq, Ord, Show) - --- | Glob paths are always relative to some branch. -type GlobPath = [Either NameSegment GlobArg] - --- | Represents a name segment containing a glob pattern --- e.g. start?end -> GlobArg "start" "end" -data GlobArg = GlobArg - { namespacePrefix :: Text, - namespaceSuffix :: Text - } - deriving (Show) - --- | Constructs a namespace "matcher" from a 'GlobArg' -globPredicate :: Either NameSegment GlobArg -> (NameSegment -> Bool) -globPredicate globArg (NameSegment.toText -> ns') = - case globArg of - Left (NameSegment.toText -> ns) -> ns == ns' - Right (GlobArg prefix suffix) -> prefix `Text.isPrefixOf` ns' && suffix `Text.isSuffixOf` ns' - --- | Expands a glob into a list of paths which lead to valid targets. -expandGlobToPaths :: Set TargetType -> GlobPath -> Branch0 m -> [Path.Relative] -expandGlobToPaths targets globPath branch = - (Path.Relative . Path.fromList) <$> expandGlobToNameSegments targets branch globPath - --- | Helper for 'expandGlobToPaths' -expandGlobToNameSegments :: forall m. Set TargetType -> Branch0 m -> GlobPath -> [[NameSegment]] -expandGlobToNameSegments targets branch globPath = - case globPath of - -- The glob path was empty; it yields no matches. - [] -> [] - -- If we're at the end of the path, add any targets which match. - [segment] -> - Monoid.whenM (Set.member Term targets) matchingTerms - <> Monoid.whenM (Set.member Type targets) matchingTypes - <> Monoid.whenM (Set.member Namespace targets) matchingNamespaces - where - predicate :: NameSegment -> Bool - predicate = globPredicate segment - matchingNamespaces, matchingTerms, matchingTypes :: [[NameSegment]] - matchingNamespaces = branch ^.. matchingChildBranches predicate . asIndex . to (pure @[]) - matchingTerms = matchingNamesInStar predicate (Branch._terms branch) - matchingTypes = matchingNamesInStar predicate (Branch._types branch) - matchingNamesInStar :: (NameSegment -> Bool) -> Branch.Star a NameSegment -> [[NameSegment]] - matchingNamesInStar predicate star = - star - & Star3.d1 - & Relation.ran - & Set.toList - & filter predicate - & fmap (pure @[]) -- Embed each name segment into a path. - -- If we have multiple remaining segments, descend into any children matching the current - -- segment, then keep matching on the remainder of the path. - (segment : rest) -> recursiveMatches - where - nextBranches :: [(NameSegment, (Branch0 m))] - nextBranches = branch ^@.. matchingChildBranches (globPredicate segment) - recursiveMatches :: [[NameSegment]] - recursiveMatches = - foldMap (\(ns, b) -> (ns :) <$> expandGlobToNameSegments targets b rest) nextBranches - --- | Find all child branches whose name matches a predicate. -matchingChildBranches :: (NameSegment -> Bool) -> IndexedTraversal' NameSegment (Branch0 m) (Branch0 m) -matchingChildBranches keyPredicate = Branch.children0 . indices keyPredicate - --- | Expand a single glob pattern into all matching targets of the specified types. -expandGlobs :: - forall m. - Set TargetType -> - -- | Root branch - Branch0 m -> - -- | UCM's current path - Path.Absolute -> - -- | The glob string, e.g. .base.List.?.doc - String -> - -- | Nothing if arg was not a glob. - -- otherwise, fully expanded, absolute paths. E.g. [".base.List.map"] - Maybe [String] -expandGlobs targets rootBranch currentPath s = do - guard (not . null $ targets) - let (isAbsolute, globPath) = globbedPathParser (Text.pack s) - guard (any Either.isRight $ globPath) - let currentBranch :: Branch0 m - currentBranch - | isAbsolute = rootBranch - | otherwise = Branch.getAt0 (Path.unabsolute currentPath) rootBranch - let paths = expandGlobToPaths targets globPath currentBranch - let relocatedPaths - | isAbsolute = (Path.Absolute . Path.unrelative) <$> paths - | otherwise = Path.resolve currentPath <$> paths - pure (Path.convert <$> relocatedPaths) - -containsGlob :: String -> Bool -containsGlob s = - let (_, globPath) = globbedPathParser (Text.pack s) - in any Either.isRight $ globPath - --- | Parses a single name segment into a GlobArg or a bare segment according to whether --- there's a glob. --- E.g. --- "toList" -> Left (NameSegment "toList") --- "to?" -> Left (GlobArg "to" "") --- We unintuitively use '?' for glob patterns right now since they're not valid in names. -globbedPathParser :: Text -> (Bool, GlobPath) -globbedPathParser txt = - let (isAbsolute, segments) = - case Text.split (== '.') txt of - -- An initial '.' creates an empty split - ("" : segments) -> (True, segments) - (segments) -> (False, segments) - in (isAbsolute, fmap globArgParser segments) - -globArgParser :: Text -> Either NameSegment GlobArg -globArgParser txt = - case Text.split (== '?') txt of - [prefix, suffix] -> Right (GlobArg prefix suffix) - _ -> Left (NameSegment txt) diff --git a/unison-cli/src/Unison/CommandLine/InputPattern.hs b/unison-cli/src/Unison/CommandLine/InputPattern.hs index b6006f39b9..f72506bab5 100644 --- a/unison-cli/src/Unison/CommandLine/InputPattern.hs +++ b/unison-cli/src/Unison/CommandLine/InputPattern.hs @@ -27,7 +27,6 @@ import Unison.Codebase (Codebase) import Unison.Codebase.Editor.Input (Input (..)) import Unison.Codebase.Path as Path import Unison.CommandLine.FZFResolvers (FZFResolver (..)) -import Unison.CommandLine.Globbing qualified as Globbing import Unison.Prelude import Unison.Util.ColorText qualified as CT import Unison.Util.Monoid (foldMapM) @@ -70,9 +69,6 @@ data ArgumentType = ArgumentType AuthenticatedHttpClient -> Path.Absolute -> -- Current path m [Line.Completion], - -- | Select which targets glob patterns may expand into for this argument. - -- An empty set disables globbing. - globTargets :: Set Globbing.TargetType, -- | If an argument is marked as required, but not provided, the fuzzy finder will be triggered if -- available. fzfResolver :: Maybe FZFResolver diff --git a/unison-cli/src/Unison/CommandLine/InputPatterns.hs b/unison-cli/src/Unison/CommandLine/InputPatterns.hs index 0b5e41f23f..d92377e331 100644 --- a/unison-cli/src/Unison/CommandLine/InputPatterns.hs +++ b/unison-cli/src/Unison/CommandLine/InputPatterns.hs @@ -19,7 +19,7 @@ import Network.URI qualified as URI import System.Console.Haskeline.Completion (Completion (Completion)) import System.Console.Haskeline.Completion qualified as Haskeline import System.Console.Haskeline.Completion qualified as Line -import Text.Megaparsec qualified as P +import Text.Megaparsec qualified as Megaparsec import U.Codebase.Sqlite.DbId (ProjectBranchId, ProjectId) import U.Codebase.Sqlite.Project qualified as Sqlite import U.Codebase.Sqlite.Queries qualified as Queries @@ -45,9 +45,9 @@ import Unison.Codebase.SyncMode qualified as SyncMode import Unison.Codebase.Verbosity (Verbosity) import Unison.Codebase.Verbosity qualified as Verbosity import Unison.CommandLine +import Unison.CommandLine.BranchRelativePath (parseBranchRelativePath) import Unison.CommandLine.Completion import Unison.CommandLine.FZFResolvers qualified as Resolvers -import Unison.CommandLine.Globbing qualified as Globbing import Unison.CommandLine.InputPattern (ArgumentType (..), InputPattern (InputPattern), IsOptional (..), unionSuggestions) import Unison.CommandLine.InputPattern qualified as I import Unison.HashQualified qualified as HQ @@ -1174,11 +1174,22 @@ forkLocal = [ ("namespace", Required, namespaceArg), ("new location", Required, newNameArg) ] - (makeExample forkLocal ["src", "dest"] <> "creates the namespace `dest` as a copy of `src`.") + ( P.wrapColumn2 + [ ( makeExample forkLocal ["src", "dest"], + "creates the namespace `dest` as a copy of `src`." + ), + ( makeExample forkLocal ["project0/branch0:a.path", "project1/branch1:foo"], + "creates the namespace `foo` in `branch1` of `project1` as a copy of `a.path` in `project0/branch0`." + ), + ( makeExample forkLocal ["srcproject/srcbranch", "dest"], + "creates the namespace `dest` as a copy of the branch `srcbranch` of `srcproject`." + ) + ] + ) ( \case - [src, dest] -> first fromString $ do - src <- Input.parseBranchId src - dest <- Path.parsePath' dest + [src, dest] -> do + src <- Input.parseBranchId2 src + dest <- parseBranchRelativePath dest pure $ Input.ForkLocalBranchI src dest _ -> Left (I.help forkLocal) ) @@ -1419,6 +1430,23 @@ debugFuzzyOptions = _ -> Left (I.help debugFuzzyOptions) ) +debugFormat :: InputPattern +debugFormat = + InputPattern + "debug.format" + [] + I.Hidden + [("source-file", Optional, filePathArg)] + ( P.lines + [ P.wrap $ "This command can be used to test ucm's file formatter on the latest typechecked file.", + makeExample' debugFormat + ] + ) + ( \case + [] -> Right Input.DebugFormatI + _ -> Left (I.help debugFormat) + ) + push :: InputPattern push = InputPattern @@ -1872,7 +1900,6 @@ topicNameArg = in ArgumentType { typeName = "topic", suggestions = \q _ _ _ -> pure (exactComplete q $ topics), - globTargets = mempty, fzfResolver = Just $ Resolvers.fuzzySelectFromList (Text.pack <$> topics) } @@ -1881,7 +1908,6 @@ codebaseServerNameArg = ArgumentType { typeName = "codebase-server", suggestions = \_ _ _ _ -> pure [], - globTargets = mempty, fzfResolver = Nothing } @@ -2148,79 +2174,6 @@ viewPatch = _ -> Left $ warn "`view.patch` takes a patch and that's it." ) -link :: InputPattern -link = - InputPattern - "link" - [] - I.Visible - [("metadata", Required, definitionQueryArg), ("definition", OnePlus, definitionQueryArg)] - ( fromString $ - concat - [ "`link metadata defn` creates a link to `metadata` from `defn`. ", - "Use `links defn` or `links defn ` to view outgoing links, ", - "and `unlink metadata defn` to remove a link. The `defn` can be either the ", - "name of a term or type, multiple such names, or a range like `1-4` ", - "for a range of definitions listed by a prior `find` command." - ] - ) - ( \case - md : defs -> first fromString $ do - md <- case HQ.fromString md of - Nothing -> Left "Invalid hash qualified identifier for metadata." - Just hq -> pure hq - defs <- traverse Path.parseHQSplit' defs - Right $ Input.LinkI md defs - _ -> Left (I.help link) - ) - -links :: InputPattern -links = - InputPattern - "links" - [] - I.Visible - [("definition to link", Required, definitionQueryArg), ("metadata", Optional, definitionQueryArg)] - ( P.column2 - [ (makeExample links ["defn"], "shows all outgoing links from `defn`."), - (makeExample links ["defn", ""], "shows all links of the given type.") - ] - ) - ( \case - src : rest -> first fromString $ do - src <- Path.parseHQSplit' src - let ty = case rest of - [] -> Nothing - _ -> Just $ unwords rest - in Right $ Input.LinksI src ty - _ -> Left (I.help links) - ) - -unlink :: InputPattern -unlink = - InputPattern - "unlink" - ["delete.link"] - I.Visible - [("metadata", Required, definitionQueryArg), ("definition", OnePlus, definitionQueryArg)] - ( fromString $ - concat - [ "`unlink metadata defn` removes a link to `metadata` from `defn`.", - "The `defn` can be either the ", - "name of a term or type, multiple such names, or a range like `1-4` ", - "for a range of definitions listed by a prior `find` command." - ] - ) - ( \case - md : defs -> first fromString $ do - md <- case HQ.fromString md of - Nothing -> Left "Invalid hash qualified identifier for metadata." - Just hq -> pure hq - defs <- traverse Path.parseHQSplit' defs - Right $ Input.UnlinkI md defs - _ -> Left (I.help unlink) - ) - names :: Input.IsGlobal -> InputPattern names isGlobal = InputPattern @@ -2352,7 +2305,7 @@ debugNameDiff = aliases = [], visibility = I.Hidden, args = [("before namespace", Required, namespaceArg), ("after namespace", Required, namespaceArg)], - help = P.wrap "List all name changes between two causal hashes. Does not detect patch or metadata changes.", + help = P.wrap "List all name changes between two causal hashes. Does not detect patch changes.", parse = ( \case [from, to] -> first fromString $ do @@ -2902,7 +2855,6 @@ branchInputPattern = ArgumentType { typeName = "new-branch", suggestions = \_ _ _ _ -> pure [], - globTargets = mempty, fzfResolver = Nothing } suggestionsConfig = @@ -3053,6 +3005,7 @@ validInputs = debugNumberedArgs, debugTabCompletion, debugFuzzyOptions, + debugFormat, delete, deleteBranch, deleteProject, @@ -3095,8 +3048,6 @@ validInputs = history, ioTest, ioTestAll, - link, - links, load, makeStandalone, mergeBuiltins, @@ -3142,7 +3093,6 @@ validInputs = todo, ui, undo, - unlink, up, update, updateBuiltins, @@ -3174,7 +3124,6 @@ commandNameArg = in ArgumentType { typeName = "command", suggestions = \q _ _ _ -> pure (exactComplete q options), - globTargets = mempty, fzfResolver = Just $ Resolvers.fuzzySelectFromList (Text.pack <$> options) } @@ -3183,7 +3132,6 @@ exactDefinitionArg = ArgumentType { typeName = "definition", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteTermOrType q p), - globTargets = Set.fromList [Globbing.Term, Globbing.Type], fzfResolver = Just Resolvers.definitionResolver } @@ -3192,7 +3140,6 @@ fuzzyDefinitionQueryArg = ArgumentType { typeName = "fuzzy definition query", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteTermOrType q p), - globTargets = Set.fromList [Globbing.Term, Globbing.Type], fzfResolver = Just Resolvers.definitionResolver } @@ -3204,7 +3151,6 @@ exactDefinitionTypeQueryArg = ArgumentType { typeName = "type definition query", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteType q p), - globTargets = Set.fromList [Globbing.Type], fzfResolver = Just Resolvers.typeDefinitionResolver } @@ -3213,7 +3159,6 @@ exactDefinitionTypeOrTermQueryArg = ArgumentType { typeName = "type or term definition query", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteTermOrType q p), - globTargets = Set.fromList [Globbing.Term], fzfResolver = Just Resolvers.definitionResolver } @@ -3222,7 +3167,6 @@ exactDefinitionTermQueryArg = ArgumentType { typeName = "term definition query", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteTerm q p), - globTargets = Set.fromList [Globbing.Term], fzfResolver = Just Resolvers.termDefinitionResolver } @@ -3231,7 +3175,6 @@ patchArg = ArgumentType { typeName = "patch", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompletePatch q p), - globTargets = Set.fromList [], fzfResolver = Nothing } @@ -3240,7 +3183,6 @@ namespaceArg = ArgumentType { typeName = "namespace", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteNamespace q p), - globTargets = Set.fromList [Globbing.Namespace], fzfResolver = Just Resolvers.namespaceResolver } @@ -3256,7 +3198,6 @@ namespaceOrProjectBranchArg config = [ projectAndOrBranchSuggestions config, namespaceSuggestions ], - globTargets = mempty, fzfResolver = Just Resolvers.projectOrBranchResolver } @@ -3268,7 +3209,6 @@ namespaceOrDefinitionArg = namespaces <- prefixCompleteNamespace q p termsTypes <- prefixCompleteTermOrType q p pure (List.nubOrd $ namespaces <> termsTypes), - globTargets = Set.fromList [Globbing.Namespace, Globbing.Term, Globbing.Type], fzfResolver = Just Resolvers.namespaceOrDefinitionResolver } @@ -3282,7 +3222,6 @@ newNameArg = ArgumentType { typeName = "new-name", suggestions = \q cb _http p -> Codebase.runTransaction cb (prefixCompleteNamespace q p), - globTargets = mempty, fzfResolver = Nothing } @@ -3291,7 +3230,6 @@ noCompletionsArg = ArgumentType { typeName = "word", suggestions = noCompletions, - globTargets = mempty, fzfResolver = Nothing } @@ -3300,7 +3238,6 @@ filePathArg = ArgumentType { typeName = "file-path", suggestions = noCompletions, - globTargets = mempty, fzfResolver = Nothing } @@ -3319,7 +3256,6 @@ gitUrlArg = "gls" -> complete "git(git@gitlab.com:" "bbs" -> complete "git(git@bitbucket.com:" _ -> pure [], - globTargets = mempty, fzfResolver = Nothing } @@ -3339,7 +3275,6 @@ remoteNamespaceArg = "bbs" -> complete "git(git@bitbucket.com:" _ -> do sharePathCompletion http input, - globTargets = mempty, fzfResolver = Nothing } @@ -3579,7 +3514,6 @@ projectAndBranchNamesArg config = ArgumentType { typeName = "project-and-branch-names", suggestions = projectAndOrBranchSuggestions config, - globTargets = Set.empty, fzfResolver = Just Resolvers.projectAndOrBranchArg } @@ -3589,7 +3523,6 @@ projectBranchNameArg config = ArgumentType { typeName = "project-branch-name", suggestions = projectAndOrBranchSuggestions config, - globTargets = Set.empty, fzfResolver = Just Resolvers.projectBranchResolver } @@ -3599,7 +3532,6 @@ projectBranchNameWithOptionalProjectNameArg = ArgumentType { typeName = "project-branch-name-with-optional-project-name", suggestions = \_ _ _ _ -> pure [], - globTargets = Set.empty, fzfResolver = Just Resolvers.projectBranchResolver } @@ -3613,7 +3545,6 @@ projectNameArg = Codebase.runTransaction codebase do Queries.loadAllProjectsBeginningWith (Just input) pure $ map projectToCompletion projects, - globTargets = Set.empty, fzfResolver = Just $ Resolvers.multiResolver [Resolvers.projectNameOptions] } where @@ -3627,7 +3558,7 @@ projectNameArg = parsePullSource :: Text -> Maybe (ReadRemoteNamespace (These ProjectName ProjectBranchNameOrLatestRelease)) parsePullSource = - P.parseMaybe (readRemoteNamespaceParser ProjectBranchSpecifier'NameOrLatestRelease) + Megaparsec.parseMaybe (readRemoteNamespaceParser ProjectBranchSpecifier'NameOrLatestRelease) -- | Parse a 'Input.PushSource'. parsePushSource :: String -> Either (P.Pretty CT.ColorText) Input.PushSource @@ -3642,7 +3573,7 @@ parsePushSource sourceStr = -- | Parse a push target. parsePushTarget :: String -> Either (P.Pretty CT.ColorText) (WriteRemoteNamespace (These ProjectName ProjectBranchName)) parsePushTarget target = - case P.parseMaybe UriParser.writeRemoteNamespace (Text.pack target) of + case Megaparsec.parseMaybe UriParser.writeRemoteNamespace (Text.pack target) of Nothing -> Left (I.help push) Just path -> Right path @@ -3664,7 +3595,7 @@ parseWriteGitRepo :: String -> String -> Either (P.Pretty P.ColorText) WriteGitR parseWriteGitRepo label input = do first (fromString . show) -- turn any parsing errors into a Pretty. - (P.parse (UriParser.writeGitRepo <* P.eof) label (Text.pack input)) + (Megaparsec.parse (UriParser.writeGitRepo <* Megaparsec.eof) label (Text.pack input)) collectNothings :: (a -> Maybe b) -> [a] -> [a] collectNothings f as = [a | (Nothing, a) <- map f as `zip` as] @@ -3685,23 +3616,23 @@ explainRemote pushPull = where gitRepo = PushPull.fold @(P.Pretty P.ColorText) "git@github.com:" "https://github.com/" pushPull -showErrorFancy :: (P.ShowErrorComponent e) => P.ErrorFancy e -> String -showErrorFancy (P.ErrorFail msg) = msg -showErrorFancy (P.ErrorIndentation ord ref actual) = +showErrorFancy :: (Megaparsec.ShowErrorComponent e) => Megaparsec.ErrorFancy e -> String +showErrorFancy (Megaparsec.ErrorFail msg) = msg +showErrorFancy (Megaparsec.ErrorIndentation ord ref actual) = "incorrect indentation (got " - <> show (P.unPos actual) + <> show (Megaparsec.unPos actual) <> ", should be " <> p - <> show (P.unPos ref) + <> show (Megaparsec.unPos ref) <> ")" where p = case ord of LT -> "less than " EQ -> "equal to " GT -> "greater than " -showErrorFancy (P.ErrorCustom a) = P.showErrorComponent a +showErrorFancy (Megaparsec.ErrorCustom a) = Megaparsec.showErrorComponent a -showErrorItem :: P.ErrorItem (P.Token Text) -> String -showErrorItem (P.Tokens ts) = P.showTokens (Proxy @Text) ts -showErrorItem (P.Label label) = NE.toList label -showErrorItem P.EndOfInput = "end of input" +showErrorItem :: Megaparsec.ErrorItem (Megaparsec.Token Text) -> String +showErrorItem (Megaparsec.Tokens ts) = Megaparsec.showTokens (Proxy @Text) ts +showErrorItem (Megaparsec.Label label) = NE.toList label +showErrorItem Megaparsec.EndOfInput = "end of input" diff --git a/unison-cli/src/Unison/CommandLine/Main.hs b/unison-cli/src/Unison/CommandLine/Main.hs index 7ad2f61406..38b4de6949 100644 --- a/unison-cli/src/Unison/CommandLine/Main.hs +++ b/unison-cli/src/Unison/CommandLine/Main.hs @@ -28,7 +28,6 @@ import Unison.Cli.ProjectUtils (projectBranchPathPrism) import Unison.Codebase (Codebase) import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch (Branch) -import Unison.Codebase.Branch qualified as Branch import Unison.Codebase.Editor.HandleInput qualified as HandleInput import Unison.Codebase.Editor.Input (Event, Input (..)) import Unison.Codebase.Editor.Output (Output) @@ -58,11 +57,10 @@ import UnliftIO.STM getUserInput :: Codebase IO Symbol Ann -> AuthenticatedHttpClient -> - IO (Branch IO) -> Path.Absolute -> [String] -> IO Input -getUserInput codebase authHTTPClient getRoot currentPath numberedArgs = +getUserInput codebase authHTTPClient currentPath numberedArgs = Line.runInputT settings (haskelineCtrlCHandling go) @@ -101,7 +99,7 @@ getUserInput codebase authHTTPClient getRoot currentPath numberedArgs = Just l -> case words l of [] -> go ws -> do - liftIO (parseInput codebase (Branch.head <$> getRoot) currentPath numberedArgs IP.patternMap ws) >>= \case + liftIO (parseInput codebase currentPath numberedArgs IP.patternMap ws) >>= \case Left msg -> do liftIO $ putPrettyLn msg go @@ -178,7 +176,6 @@ main dir welcome initialPath config initialInputs runtime sbRuntime nRuntime cod getUserInput codebase authHTTPClient - (atomically . readTMVar $ loopState ^. #root) (loopState ^. #currentPath) (loopState ^. #numberedArgs) let loadSourceFile :: Text -> IO Cli.LoadSourceResult @@ -225,19 +222,10 @@ main dir welcome initialPath config initialInputs runtime sbRuntime nRuntime cod let foldLine :: Text foldLine = "\n\n---- Anything below this line is ignored by Unison.\n\n" - let prependToFile :: Text -> FilePath -> IO () - prependToFile contents fp = do - exists <- Directory.doesFileExist fp - existingSource <- - if exists - then readUtf8 fp - else pure "" - writeUtf8 fp (Text.concat [contents, foldLine, existingSource]) - let writeSourceFile :: Text -> Text -> IO () writeSourceFile fp contents = do path <- Directory.canonicalizePath (Text.unpack fp) - prependToFile contents path + prependUtf8 path (contents <> foldLine) let env = Cli.Env @@ -245,7 +233,6 @@ main dir welcome initialPath config initialInputs runtime sbRuntime nRuntime cod codebase, config, credentialManager, - isTranscript = False, -- we are not running a transcript loadSource = loadSourceFile, writeSource = writeSourceFile, generateUniqueName = Parser.uniqueBase32Namegen <$> Random.getSystemDRG, diff --git a/unison-cli/src/Unison/CommandLine/OutputMessages.hs b/unison-cli/src/Unison/CommandLine/OutputMessages.hs index b4edd9d3dc..69adaba9ec 100644 --- a/unison-cli/src/Unison/CommandLine/OutputMessages.hs +++ b/unison-cli/src/Unison/CommandLine/OutputMessages.hs @@ -5,7 +5,6 @@ module Unison.CommandLine.OutputMessages where -import Control.Exception (catch, finally, mask, throwIO) import Control.Lens hiding (at) import Control.Monad.State import Control.Monad.State.Strict qualified as State @@ -22,7 +21,6 @@ import Data.Set qualified as Set import Data.Set.NonEmpty (NESet) import Data.Text qualified as Text import Data.Text.Encoding qualified as Text -import Data.Text.IO qualified as Text import Data.Time (UTCTime, getCurrentTime) import Data.Tuple (swap) import Data.Tuple.Extra (dupe) @@ -31,10 +29,7 @@ import Network.HTTP.Types qualified as Http import Servant.Client qualified as Servant import System.Console.ANSI qualified as ANSI import System.Console.Haskeline.Completion qualified as Completion -import System.Directory (canonicalizePath, getHomeDirectory, removeFile, renameFile) -import System.FilePath qualified as FilePath -import System.IO qualified as IO -import System.IO.Error (isDoesNotExistError) +import System.Directory (canonicalizePath, getHomeDirectory) import U.Codebase.Branch (NamespaceStats (..)) import U.Codebase.Branch.Diff (NameChanges (..)) import U.Codebase.HashTags (CausalHash (..)) @@ -761,21 +756,18 @@ notifyUser dir = \case [prettyReadRemoteNamespaceWith absurd baseNS, prettyPath' squashedPath] <> "to push the changes." ] - LoadedDefinitionsToSourceFile fp code -> + LoadedDefinitionsToSourceFile fp numDefinitions -> pure $ P.callout "☝️" $ P.lines - [ P.wrap $ "I added these definitions to the top of " <> fromString fp, - "", - P.indentN 2 code, + [ P.wrap $ "I added " <> P.shown @Int numDefinitions <> " definitions to the top of " <> fromString fp, "", P.wrap $ - "You can edit them there, then do" + "You can edit them there, then run" <> makeExample' IP.update <> "to replace the definitions currently in this namespace." ] DisplayDefinitions code -> pure code - DisplayDefinitionsString isTranscript definitions -> displayDefinitionsString isTranscript definitions OutputRewrittenFile dest vs -> displayOutputRewrittenFile dest vs DisplayRendered outputLoc pp -> displayRendered outputLoc pp @@ -823,34 +815,6 @@ notifyUser dir = \case <> " with the codebase, or the term was deleted just now " <> " by someone else. Trying your command again might fix it." ] - MetadataMissingType ppe ref -> - pure . P.fatalCallout . P.lines $ - [ P.wrap $ - "The metadata value " - <> P.red (prettyTermName ppe ref) - <> "is missing a type signature in the codebase.", - "", - P.wrap $ - "This might be due to pulling an incomplete" - <> "or invalid codebase, or because files inside the codebase" - <> "are being deleted external to UCM." - ] - MetadataAmbiguous hq _ppe [] -> - pure - . P.warnCallout - . P.wrap - $ "I couldn't find any metadata matching " - <> P.syntaxToColor (prettyHashQualified hq) - MetadataAmbiguous _ ppe refs -> - pure . P.warnCallout . P.lines $ - [ P.wrap $ - "I'm not sure which metadata value you're referring to" - <> "since there are multiple matches:", - "", - P.indentN 2 $ P.spaced (P.blue . prettyTermName ppe <$> refs), - "", - tip "Try again and supply one of the above definitions explicitly." - ] EvaluationFailure err -> pure err TypeTermMismatch typeName termName -> pure $ @@ -1029,8 +993,6 @@ notifyUser dir = \case ] ListOfDefinitions fscope ppe detailed results -> listOfDefinitions fscope ppe detailed results - ListOfLinks ppe results -> - listOfLinks ppe [(name, tm) | (name, _ref, tm) <- results] ListNames global len types terms -> if null types && null terms then @@ -1458,19 +1420,6 @@ notifyUser dir = \case (P.column2 . fmap format) ([(1 :: Integer) ..] `zip` (toList patches)) where format (i, p) = (P.hiBlack . fromString $ show i <> ".", prettyName p) - ConfiguredMetadataParseError p md err -> - pure . P.fatalCallout . P.lines $ - [ P.wrap $ - "I couldn't understand the default metadata that's set for " - <> prettyPath' p - <> " in .unisonConfig.", - P.wrap $ - "The value I found was" - <> (P.backticked . P.blue . P.string) md - <> "but I encountered the following error when trying to parse it:", - "", - err - ] NoConfiguredRemoteMapping pp p -> do let (localPathExample, sharePathExample) = if Path.isRoot p @@ -1700,7 +1649,6 @@ notifyUser dir = \case pure (P.okCallout "No conflicts or edits in progress.") HelpMessage pat -> pure $ IP.showPatternHelp pat NoOp -> pure $ P.string "I didn't make any changes." - DefaultMetadataNotification -> pure $ P.wrap "I added some default metadata." DumpBitBooster head map -> let go output [] = output go output (head : queue) = case Map.lookup head map of @@ -2227,12 +2175,14 @@ notifyUser dir = \case <> operationName <> "again." ] - UpgradeFailure old new -> + UpgradeFailure path old new -> pure . P.wrap $ "I couldn't automatically upgrade" <> P.text (NameSegment.toText old) <> "to" <> P.group (P.text (NameSegment.toText new) <> ".") + <> "However, I've added the definitions that need attention to the top of" + <> P.group (prettyFilePath path <> ".") UpgradeSuccess old new -> pure . P.wrap $ "I upgraded" @@ -2336,6 +2286,7 @@ prettyUpdatePathError repoInfo = \case prettyUploadEntitiesError :: Share.UploadEntitiesError -> Pretty prettyUploadEntitiesError = \case + Share.UploadEntitiesError'EntityValidationFailure validationFailureErr -> prettyValidationFailure validationFailureErr Share.UploadEntitiesError'HashMismatchForEntity _hashMismatch -> error "TODO: hash mismatch error message" Share.UploadEntitiesError'InvalidRepoInfo err repoInfo -> invalidRepoInfo err repoInfo Share.UploadEntitiesError'NeedDependencies dependencies -> needDependencies dependencies @@ -2343,6 +2294,42 @@ prettyUploadEntitiesError = \case Share.UploadEntitiesError'ProjectNotFound project -> shareProjectNotFound project Share.UploadEntitiesError'UserNotFound userHandle -> shareUserNotFound (Share.RepoInfo userHandle) +prettyValidationFailure :: Share.EntityValidationError -> Pretty +prettyValidationFailure = \case + Share.EntityHashMismatch entityType (Share.HashMismatchForEntity{supplied, computed}) -> + P.lines + [ P.wrap $ "The hash associated with the given " <> prettyEntityType entityType <> " entity is incorrect.", + "", + P.wrap $ "The associated hash is: " <> prettyHash32 supplied, + P.wrap $ "The computed hash is: " <> prettyHash32 computed + ] + Share.UnsupportedEntityType hash32 entityType -> + P.lines + [ P.wrap $ "The entity with hash " <> prettyHash32 hash32 <> " of type " <> prettyEntityType entityType <> " is not supported by your version of ucm.", + P.wrap $ "Try upgrading to the latest version of ucm." + ] + Share.InvalidByteEncoding hash32 entityType msg -> + P.lines + [ P.wrap $ "Failed to decode a " <> prettyEntityType entityType <> " entity with the hash " <> prettyHash32 hash32 <> ".", + "Please create an issue and report this to the Unison team", + "", + P.wrap $ "The error was: " <> P.text msg + ] + Share.HashResolutionFailure hash32 -> + P.lines + [ P.wrap $ "Failed to resolve a referenced hash when validating the hash for " <> prettyHash32 hash32 <> ".", + "Please create an issue and report this to the Unison team" + ] + where + prettyEntityType = \case + Share.TermComponentType -> "term component" + Share.DeclComponentType -> "type component" + Share.PatchType -> "patch" + Share.PatchDiffType -> "patch diff" + Share.NamespaceType -> "namespace" + Share.NamespaceDiffType -> "namespace diff" + Share.CausalType -> "causal" + prettyTransportError :: CodeserverTransportError -> Pretty prettyTransportError = \case DecodeFailure msg resp -> @@ -2402,6 +2389,12 @@ prettyEntityValidationError = \case "", P.wrap $ "The error was: " <> P.text err ] + Share.HashResolutionFailure hash -> + -- See https://github.com/unisonweb/unison/pull/4381#discussion_r1452652087 for discussion. + P.lines + [ P.wrap $ "Failed to resolve data when hashing " <> prettyHash32 hash <> ".", + "Please create an issue and report this to the Unison team" + ] prettyEntityType :: Share.EntityType -> Pretty prettyEntityType = \case @@ -2540,9 +2533,6 @@ displayOutputRewrittenFile fp vs = do "The rewritten file has been added to the top of " <> fromString fp ] -foldLine :: (IsString s) => P.Pretty s -foldLine = "\n\n---- Anything below this line is ignored by Unison.\n\n" - displayDefinitions' :: (Var v) => (Ord a1) => @@ -2600,34 +2590,6 @@ displayRendered outputLoc pp = P.indentN 2 pp ] -displayDefinitionsString :: Maybe FilePath -> Pretty -> IO Pretty -displayDefinitionsString maybePath definitions = - case maybePath of - Nothing -> pure definitions - Just path -> do - let withTempFile tmpFilePath tmpHandle = do - Text.hPutStrLn tmpHandle (Text.pack (P.toPlain 80 definitions)) - Text.hPutStrLn tmpHandle "\n---\n" - IO.withFile path IO.ReadMode \currentScratchFile -> do - let copyLoop = do - chunk <- Text.hGetChunk currentScratchFile - case Text.length chunk == 0 of - True -> pure () - False -> do - Text.hPutStr tmpHandle chunk - copyLoop - copyLoop - IO.hClose tmpHandle - renameFile tmpFilePath path - mask \unmask -> do - (tmpFilePath, tmpHandle) <- IO.openTempFile (FilePath.takeDirectory path) "unison-scratch" - unmask (withTempFile tmpFilePath tmpHandle) `finally` do - IO.hClose tmpHandle - removeFile tmpFilePath `catch` \case - e | isDoesNotExistError e -> pure () - e -> throwIO e - pure mempty - displayTestResults :: Bool -> -- whether to show the tip PPE.PrettyPrintEnv -> @@ -2904,33 +2866,6 @@ listOfDefinitions :: listOfDefinitions fscope ppe detailed results = pure $ listOfDefinitions' fscope ppe detailed results -listOfLinks :: - (Var v) => PPE.PrettyPrintEnv -> [(HQ.HashQualified Name, Maybe (Type v a))] -> IO Pretty -listOfLinks _ [] = - pure . P.callout "😶" . P.wrap $ - "No results. Try using the " - <> IP.makeExample IP.link [] - <> "command to add metadata to a definition." -listOfLinks ppe results = - pure $ - P.lines - [ P.numberedColumn2 - num - [ (P.syntaxToColor $ prettyHashQualified hq, ": " <> prettyType typ) | (hq, typ) <- results - ], - "", - tip $ - "Try using" - <> IP.makeExample IP.display ["1"] - <> "to display the first result or" - <> IP.makeExample IP.view ["1"] - <> "to view its source." - ] - where - num i = P.hiBlack $ P.shown i <> "." - prettyType Nothing = "❓ (missing a type for this definition)" - prettyType (Just t) = TypePrinter.pretty ppe t - data ShowNumbers = ShowNumbers | HideNumbers -- | `ppe` is just for rendering type signatures @@ -2980,7 +2915,6 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = else pure mempty, if (not . null) updatedTypes || (not . null) updatedTerms - || propagatedUpdates > 0 || (not . null) updatedPatches then do prettyUpdatedTypes :: [Pretty] <- traverse prettyUpdateType updatedTypes @@ -2991,16 +2925,6 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = "\n\n" [ P.bold "Updates:", P.indentNonEmptyN 2 . P.sepNonEmpty "\n\n" $ prettyUpdatedTypes <> prettyUpdatedTerms, - if propagatedUpdates > 0 - then - P.indentN 2 $ - P.wrap - ( P.hiBlack $ - "There were " - <> P.shown propagatedUpdates - <> "auto-propagated updates." - ) - else mempty, P.indentNonEmptyN 2 . P.linesNonEmpty $ prettyUpdatedPatches ] else pure mempty, @@ -3146,7 +3070,7 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = -} prettyUpdateType (OBD.UpdateTypeDisplay (Just olds) news) = do - olds <- traverse (mdTypeLine oldPath) [OBD.TypeDisplay name r decl mempty | (name, r, decl) <- olds] + olds <- traverse (mdTypeLine oldPath) [OBD.TypeDisplay name r decl | (name, r, decl) <- olds] news <- traverse (mdTypeLine newPath) news let (oldnums, olddatas) = unzip olds let (newnums, newdatas) = unzip news @@ -3156,47 +3080,46 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = (P.boxLeft olddatas <> [downArrow] <> P.boxLeft newdatas) {- - 13. ┌ability Yyz (+1 metadata) - 14. └ability copies.Yyz (+2 metadata) + 13. ┌ability Yyz + 14. └ability copies.Yyz -} prettyAddTypes :: forall a. [OBD.AddedTypeDisplay v a] -> Numbered Pretty prettyAddTypes = fmap P.lines . traverse prettyGroup where prettyGroup :: OBD.AddedTypeDisplay v a -> Numbered Pretty - prettyGroup (hqmds, r, odecl) = do - pairs <- traverse (prettyLine r odecl) hqmds + prettyGroup (hqs, r, odecl) = do + pairs <- traverse (prettyLine r odecl) hqs let (nums, decls) = unzip pairs - let boxLeft = case hqmds of _ : _ : _ -> P.boxLeft; _ -> id + let boxLeft = case hqs of + _ : _ : _ -> P.boxLeft + _ -> id pure . P.column2 $ zip nums (boxLeft decls) - prettyLine :: Reference -> Maybe (DD.DeclOrBuiltin v a) -> (HQ'.HashQualified Name, [OBD.MetadataDisplay v a]) -> Numbered (Pretty, Pretty) - prettyLine r odecl (hq, mds) = do + prettyLine :: Reference -> Maybe (DD.DeclOrBuiltin v a) -> HQ'.HashQualified Name -> Numbered (Pretty, Pretty) + prettyLine r odecl hq = do n <- numHQ' newPath hq (Referent.Ref r) - pure . (n,) $ - prettyDecl hq odecl <> case length mds of - 0 -> mempty - c -> " (+" <> P.shown c <> " metadata)" + pure . (n,) $ prettyDecl hq odecl prettyAddTerms :: forall a. [OBD.AddedTermDisplay v a] -> Numbered Pretty prettyAddTerms = fmap (P.column3 . mconcat) . traverse prettyGroup . reorderTerms where reorderTerms = sortOn (not . Referent.isConstructor . view _2) prettyGroup :: OBD.AddedTermDisplay v a -> Numbered [(Pretty, Pretty, Pretty)] - prettyGroup (hqmds, r, otype) = do - pairs <- traverse (prettyLine r otype) hqmds + prettyGroup (hqs, r, otype) = do + pairs <- traverse (prettyLine r otype) hqs let (nums, names, decls) = unzip3 pairs - boxLeft = case hqmds of _ : _ : _ -> P.boxLeft; _ -> id + boxLeft = + case hqs of + _ : _ : _ -> P.boxLeft + _ -> id pure $ zip3 nums (boxLeft names) decls prettyLine :: Referent -> Maybe (Type v a) -> - (HQ'.HashQualified Name, [OBD.MetadataDisplay v a]) -> + HQ'.HashQualified Name -> Numbered (Pretty, Pretty, Pretty) - prettyLine r otype (hq, mds) = do + prettyLine r otype hq = do n <- numHQ' newPath hq r - pure . (n,phq' hq,) $ - ": " <> prettyType otype <> case length mds of - 0 -> mempty - c -> " (+" <> P.shown c <> " metadata)" + pure . (n,phq' hq,) $ ": " <> prettyType otype prettySummarizePatch, prettyNamePatch :: Input.AbsBranchId -> OBD.PatchDisplay -> Numbered Pretty -- 12. patch p (added 3 updates, deleted 1) @@ -3264,11 +3187,10 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = downArrow = P.bold "↓" mdTypeLine :: Input.AbsBranchId -> OBD.TypeDisplay v a -> Numbered (Pretty, Pretty) - mdTypeLine p (OBD.TypeDisplay hq r odecl mddiff) = do + mdTypeLine p (OBD.TypeDisplay hq r odecl) = do n <- numHQ' p hq (Referent.Ref r) fmap ((n,) . P.linesNonEmpty) . sequence $ - [ pure $ prettyDecl hq odecl, - P.indentN leftNumsWidth <$> prettyMetadataDiff mddiff + [ pure $ prettyDecl hq odecl ] -- + 2. MIT : License @@ -3278,12 +3200,11 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = P.Width -> OBD.TermDisplay v a -> Numbered (Pretty, Pretty) - mdTermLine p namesWidth (OBD.TermDisplay hq r otype mddiff) = do + mdTermLine p namesWidth (OBD.TermDisplay hq r otype) = do n <- numHQ' p hq r fmap ((n,) . P.linesNonEmpty) . sequence - $ [ pure $ P.rightPad namesWidth (phq' hq) <> " : " <> prettyType otype, - prettyMetadataDiff mddiff + $ [ pure $ P.rightPad namesWidth (phq' hq) <> " : " <> prettyType otype ] prettyUpdateTerm :: OBD.UpdateTermDisplay v a -> Numbered Pretty @@ -3297,7 +3218,7 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = olds <- traverse (mdTermLine oldPath namesWidth) - [OBD.TermDisplay name r typ mempty | (name, r, typ) <- olds] + [OBD.TermDisplay name r typ | (name, r, typ) <- olds] news <- traverse (mdTermLine newPath namesWidth) news let (oldnums, olddatas) = unzip olds let (newnums, newdatas) = unzip news @@ -3311,16 +3232,6 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = fmap (P.Width . HQ'.nameLength Name.toText . view #name) news <> fmap (P.Width . HQ'.nameLength Name.toText . view _1) olds - prettyMetadataDiff :: OBD.MetadataDiff (OBD.MetadataDisplay v a) -> Numbered Pretty - prettyMetadataDiff OBD.MetadataDiff {..} = - P.column2M $ - map (elem oldPath "- ") removedMetadata - <> map (elem newPath "+ ") addedMetadata - where - elem p x (hq, r, otype) = do - num <- numHQ p hq r - pure (x <> num <> " " <> phq hq, ": " <> prettyType otype) - prettyType :: Maybe (Type v a) -> Pretty prettyType = maybe (P.red "type not found") (TypePrinter.pretty ppe) prettyDecl hq = @@ -3328,17 +3239,12 @@ showDiffNamespace sn ppe oldPath newPath OBD.BranchDiffOutput {..} = (P.red "type not found") (P.syntaxToColor . DeclPrinter.prettyDeclOrBuiltinHeader (HQ'.toHQ hq)) phq' :: _ -> Pretty = P.syntaxToColor . prettyHashQualified' - phq :: _ -> Pretty = P.syntaxToColor . prettyHashQualified -- DeclPrinter.prettyDeclHeader : HQ -> Either numPatch :: Input.AbsBranchId -> Name -> Numbered Pretty numPatch prefix name = addNumberedArg' $ prefixBranchId prefix name - numHQ :: Input.AbsBranchId -> HQ.HashQualified Name -> Referent -> Numbered Pretty - numHQ prefix hq r = - addNumberedArg' . HQ.toStringWith (prefixBranchId prefix) . HQ.requalify hq $ r - numHQ' :: Input.AbsBranchId -> HQ'.HashQualified Name -> Referent -> Numbered Pretty numHQ' prefix hq r = addNumberedArg' . HQ'.toStringWith (prefixBranchId prefix) . HQ'.requalify hq $ r diff --git a/unison-cli/src/Unison/LSP.hs b/unison-cli/src/Unison/LSP.hs index 850236ab38..e0d70adbde 100644 --- a/unison-cli/src/Unison/LSP.hs +++ b/unison-cli/src/Unison/LSP.hs @@ -36,6 +36,7 @@ import Unison.LSP.Completion (completionHandler, completionItemResolveHandler) import Unison.LSP.Configuration qualified as Config import Unison.LSP.FileAnalysis qualified as Analysis import Unison.LSP.FoldingRange (foldingRangeRequest) +import Unison.LSP.Formatting (formatDocRequest, formatRangeRequest) import Unison.LSP.HandlerUtils qualified as Handlers import Unison.LSP.Hover (hoverHandler) import Unison.LSP.NotificationHandlers qualified as Notifications @@ -168,6 +169,8 @@ lspRequestHandlers = & SMM.insert Msg.SMethod_TextDocumentFoldingRange (mkHandler foldingRangeRequest) & SMM.insert Msg.SMethod_TextDocumentCompletion (mkHandler completionHandler) & SMM.insert Msg.SMethod_CompletionItemResolve (mkHandler completionItemResolveHandler) + & SMM.insert Msg.SMethod_TextDocumentFormatting (mkHandler formatDocRequest) + & SMM.insert Msg.SMethod_TextDocumentRangeFormatting (mkHandler formatRangeRequest) where defaultTimeout = 10_000 -- 10s mkHandler :: diff --git a/unison-cli/src/Unison/LSP/Conversions.hs b/unison-cli/src/Unison/LSP/Conversions.hs index 4d5f5c36a6..307fd5c99d 100644 --- a/unison-cli/src/Unison/LSP/Conversions.hs +++ b/unison-cli/src/Unison/LSP/Conversions.hs @@ -16,24 +16,36 @@ rangeToInterval (Range start end) = annToInterval :: Ann -> Maybe (Interval.Interval Position) annToInterval ann = annToRange ann <&> rangeToInterval +-- | Convert a Unison file-position where the first char is 1 and line is 1, to an LSP `Position` +-- where the first char is 0 and line is 0. uToLspPos :: Lex.Pos -> Position uToLspPos uPos = Position - { _line = fromIntegral $ Lex.line uPos - 1, -- 1 indexed vs 0 indexed - _character = fromIntegral $ Lex.column uPos - 1 + { _line = fromIntegral $ max 0 (Lex.line uPos - 1), + _character = fromIntegral $ max 0 (Lex.column uPos - 1) } +-- | Convert an LSP `Position` where the first char is 0 and line is 0, to a Unison file-position +-- where the first char is 1 and line is 1. lspToUPos :: Position -> Lex.Pos lspToUPos Position {_line = line, _character = char} = Lex.Pos - (fromIntegral $ line + 1) -- 1 indexed vs 0 indexed + (fromIntegral $ line + 1) (fromIntegral $ char + 1) +-- | Convert a Unison `Range` where the first char is 1 and line is 1, to an LSP `Range` +-- where the first char is 0 and line is 0. uToLspRange :: Range.Range -> Range uToLspRange (Range.Range start end) = Range (uToLspPos start) (uToLspPos end) +-- | Convert an LSP `Range` where the first char is 0 and line is 0, to a Unison `Range` +-- where the first char is 1 and line is 1. +lspToURange :: Range -> Range.Range +lspToURange (Range start end) = Range.Range (lspToUPos start) (lspToUPos end) + annToRange :: Ann -> Maybe Range annToRange = \case Ann.Intrinsic -> Nothing Ann.External -> Nothing + Ann.GeneratedFrom a -> annToRange a Ann.Ann start end -> Just $ Range (uToLspPos start) (uToLspPos end) diff --git a/unison-cli/src/Unison/LSP/Diagnostics.hs b/unison-cli/src/Unison/LSP/Diagnostics.hs index 31a4de9f65..bf9d154980 100644 --- a/unison-cli/src/Unison/LSP/Diagnostics.hs +++ b/unison-cli/src/Unison/LSP/Diagnostics.hs @@ -1,8 +1,5 @@ module Unison.LSP.Diagnostics - ( annToRange, - uToLspPos, - uToLspRange, - reportDiagnostics, + ( reportDiagnostics, mkDiagnostic, DiagnosticSeverity (..), ) @@ -11,27 +8,7 @@ where import Language.LSP.Protocol.Message qualified as Msg import Language.LSP.Protocol.Types import Unison.LSP.Types -import Unison.Parser.Ann (Ann) -import Unison.Parser.Ann qualified as Ann import Unison.Prelude -import Unison.Syntax.Lexer qualified as Lex -import Unison.Util.Range qualified as Range - -annToRange :: Ann -> Maybe Range -annToRange = \case - Ann.Intrinsic -> Nothing - Ann.External -> Nothing - Ann.Ann start end -> Just $ Range (uToLspPos start) (uToLspPos end) - -uToLspPos :: Lex.Pos -> Position -uToLspPos uPos = - Position - { _line = fromIntegral $ Lex.line uPos - 1, -- 1 indexed vs 0 indexed - _character = fromIntegral $ Lex.column uPos - 1 -- 1 indexed vs 0 indexed - } - -uToLspRange :: Range.Range -> Range -uToLspRange (Range.Range start end) = Range (uToLspPos start) (uToLspPos end) reportDiagnostics :: (Foldable f) => diff --git a/unison-cli/src/Unison/LSP/FileAnalysis.hs b/unison-cli/src/Unison/LSP/FileAnalysis.hs index 4337d4ce1a..ab3295488b 100644 --- a/unison-cli/src/Unison/LSP/FileAnalysis.hs +++ b/unison-cli/src/Unison/LSP/FileAnalysis.hs @@ -41,6 +41,7 @@ import Unison.LSP.Types import Unison.LSP.Types qualified as LSP import Unison.LSP.VFS qualified as VFS import Unison.Name (Name) +import Unison.Names (Names) import Unison.Names qualified as Names import Unison.Parser.Ann (Ann) import Unison.Parsers qualified as Parsers @@ -48,6 +49,7 @@ import Unison.Pattern qualified as Pattern import Unison.Prelude import Unison.PrettyPrintEnv (PrettyPrintEnv) import Unison.PrettyPrintEnv qualified as PPE +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.PrintError qualified as PrintError @@ -55,23 +57,22 @@ import Unison.Referent qualified as Referent import Unison.Result (Note) import Unison.Result qualified as Result import Unison.Symbol (Symbol) -import Unison.Symbol qualified as Symbol import Unison.Syntax.HashQualified' qualified as HQ' (toText) import Unison.Syntax.Lexer qualified as L import Unison.Syntax.Name qualified as Name import Unison.Syntax.Parser qualified as Parser import Unison.Syntax.TypePrinter qualified as TypePrinter import Unison.Term qualified as Term -import Unison.Type (Type) import Unison.Typechecker.Context qualified as Context import Unison.Typechecker.TypeError qualified as TypeError import Unison.UnisonFile qualified as UF import Unison.UnisonFile.Names qualified as UF +import Unison.UnisonFile.Summary (FileSummary (..), fileDefLocations) +import Unison.UnisonFile.Summary qualified as FileSummary import Unison.Util.Monoid (foldMapM) import Unison.Util.Pretty qualified as Pretty import Unison.Util.Relation qualified as R1 import Unison.Var qualified as Var -import Unison.WatchKind (pattern TestWatch) import UnliftIO.STM import Witherable @@ -110,7 +111,7 @@ checkFile doc = runMaybeT do & foldMap (\(RangedCodeAction {_codeActionRanges, _codeAction}) -> (,_codeAction) <$> _codeActionRanges) & toRangeMap let typeSignatureHints = fromMaybe mempty (mkTypeSignatureHints <$> parsedFile <*> typecheckedFile) - let fileSummary = mkFileSummary parsedFile typecheckedFile + let fileSummary = FileSummary.mkFileSummary parsedFile typecheckedFile let tokenMap = getTokenMap tokens conflictWarningDiagnostics <- fold <$> for fileSummary \fs -> @@ -122,106 +123,11 @@ checkFile doc = runMaybeT do let fileAnalysis = FileAnalysis {diagnostics = diagnosticRanges, codeActions = codeActionRanges, fileSummary, typeSignatureHints, ..} pure fileAnalysis --- | If a symbol is a 'User' symbol, return (Just sym), otherwise return Nothing. -assertUserSym :: Symbol -> Maybe Symbol -assertUserSym sym = case sym of - Symbol.Symbol _ (Var.User {}) -> Just sym - _ -> Nothing - --- | Summarize the information available to us from the current state of the file. --- See 'FileSummary' for more information. -mkFileSummary :: Maybe (UF.UnisonFile Symbol Ann) -> Maybe (UF.TypecheckedUnisonFile Symbol Ann) -> Maybe FileSummary -mkFileSummary parsed typechecked = case (parsed, typechecked) of - (Nothing, Nothing) -> Nothing - (_, Just tf@(UF.TypecheckedUnisonFileId {dataDeclarationsId', effectDeclarationsId', hashTermsId})) -> - let (trms, testWatches, exprWatches) = - hashTermsId & ifoldMap \sym (ann, ref, wk, trm, typ) -> - case wk of - Nothing -> (Map.singleton sym (ann, Just ref, trm, getUserTypeAnnotation sym <|> Just typ), mempty, mempty) - Just TestWatch -> (mempty, [(ann, assertUserSym sym, Just ref, trm, getUserTypeAnnotation sym <|> Just typ)], mempty) - Just _ -> (mempty, mempty, [(ann, assertUserSym sym, Just ref, trm, getUserTypeAnnotation sym <|> Just typ)]) - in Just $ - FileSummary - { dataDeclsBySymbol = dataDeclarationsId', - dataDeclsByReference = declsRefMap dataDeclarationsId', - effectDeclsBySymbol = effectDeclarationsId', - effectDeclsByReference = declsRefMap effectDeclarationsId', - termsBySymbol = trms, - termsByReference = termsRefMap trms, - testWatchSummary = testWatches, - exprWatchSummary = exprWatches, - fileNames = UF.typecheckedToNames tf - } - (Just uf@(UF.UnisonFileId {dataDeclarationsId, effectDeclarationsId, terms, watches}), _) -> - let trms = - terms & foldMap \(sym, ann, trm) -> - (Map.singleton sym (ann, Nothing, trm, Nothing)) - (testWatches, exprWatches) = - watches & ifoldMap \wk tms -> - tms & foldMap \(v, ann, trm) -> - case wk of - TestWatch -> ([(ann, assertUserSym v, Nothing, trm, Nothing)], mempty) - _ -> (mempty, [(ann, assertUserSym v, Nothing, trm, Nothing)]) - in Just $ - FileSummary - { dataDeclsBySymbol = dataDeclarationsId, - dataDeclsByReference = declsRefMap dataDeclarationsId, - effectDeclsBySymbol = effectDeclarationsId, - effectDeclsByReference = declsRefMap effectDeclarationsId, - termsBySymbol = trms, - termsByReference = termsRefMap trms, - testWatchSummary = testWatches, - exprWatchSummary = exprWatches, - fileNames = UF.toNames uf - } - where - declsRefMap :: (Ord v, Ord r) => Map v (r, a) -> Map r (Map v a) - declsRefMap m = - m - & Map.toList - & fmap (\(v, (r, a)) -> (r, Map.singleton v a)) - & Map.fromListWith (<>) - termsRefMap :: (Ord v, Ord r) => Map v (ann, r, a, b) -> Map r (Map v (ann, a, b)) - termsRefMap m = - m - & Map.toList - & fmap (\(v, (ann, r, a, b)) -> (r, Map.singleton v (ann, a, b))) - & Map.fromListWith (<>) - -- Gets the user provided type annotation for a term if there is one. - -- This type sig will have Ann's within the file if it exists. - getUserTypeAnnotation :: Symbol -> Maybe (Type Symbol Ann) - getUserTypeAnnotation v = do - UF.UnisonFileId {terms, watches} <- parsed - trm <- (terms <> fold watches) ^? folded . filteredBy (_1 . only v) . _3 - typ <- Term.getTypeAnnotation trm - pure typ - -- | Get the location of user defined definitions within the file getFileDefLocations :: Uri -> MaybeT Lsp (Map Symbol (Set Ann)) getFileDefLocations uri = do fileDefLocations <$> getFileSummary uri --- | Compute the location of user defined definitions within the file -fileDefLocations :: FileSummary -> Map Symbol (Set Ann) -fileDefLocations FileSummary {dataDeclsBySymbol, effectDeclsBySymbol, testWatchSummary, exprWatchSummary, termsBySymbol} = - fold - [ dataDeclsBySymbol <&> \(_, decl) -> - decl - & DD.annotation - & Set.singleton, - effectDeclsBySymbol <&> \(_, decl) -> - decl - & DD.toDataDecl - & DD.annotation - & Set.singleton, - (testWatchSummary <> exprWatchSummary) - & foldMap \(ann, maySym, _id, _trm, _typ) -> - case maySym of - Nothing -> mempty - Just sym -> Map.singleton sym (Set.singleton ann), - termsBySymbol <&> \(ann, _id, _trm, _typ) -> Set.singleton ann - ] - fileAnalysisWorker :: Lsp () fileAnalysisWorker = forever do dirtyFilesV <- asks dirtyFilesVar @@ -491,6 +397,21 @@ getFileAnalysis uri = do Just mvar -> pure mvar atomically (readTMVar tmvar) +-- | Build a Names from a file if it's parseable. +-- +-- If the file typechecks, generate names from that, +-- otherwise, generate names from the 'parsed' file. Note that the +-- names for a parsed file contains only names for parts of decls, since +-- we don't know references within terms before typechecking due to TDNR. +-- This should be fine though, since those references will all be kept in the +-- ABT as symbols anyways. +-- +-- See UF.toNames and UF.typecheckedToNames for more info. +getFileNames :: Uri -> MaybeT Lsp Names +getFileNames fileUri = do + FileAnalysis {typecheckedFile = tf, parsedFile = pf} <- getFileAnalysis fileUri + hoistMaybe (fmap UF.typecheckedToNames tf <|> fmap UF.toNames pf) + getFileSummary :: Uri -> MaybeT Lsp FileSummary getFileSummary uri = do FileAnalysis {fileSummary} <- getFileAnalysis uri @@ -512,11 +433,11 @@ ppedForFileHelper uf tf = do (Nothing, Nothing) -> codebasePPED (_, Just tf) -> let fileNames = UF.typecheckedToNames tf - filePPED = PPED.fromNamesDecl hashLen fileNames + filePPED = PPED.makePPED (PPE.hqNamer hashLen fileNames) (PPE.suffixifyByHash fileNames) in filePPED `PPED.addFallback` codebasePPED (Just uf, _) -> let fileNames = UF.toNames uf - filePPED = PPED.fromNamesDecl hashLen fileNames + filePPED = PPED.makePPED (PPE.hqNamer hashLen fileNames) (PPE.suffixifyByHash fileNames) in filePPED `PPED.addFallback` codebasePPED mkTypeSignatureHints :: UF.UnisonFile Symbol Ann -> UF.TypecheckedUnisonFile Symbol Ann -> Map Symbol TypeSignatureHint diff --git a/unison-cli/src/Unison/LSP/Formatting.hs b/unison-cli/src/Unison/LSP/Formatting.hs new file mode 100644 index 0000000000..48e46d8028 --- /dev/null +++ b/unison-cli/src/Unison/LSP/Formatting.hs @@ -0,0 +1,40 @@ +{-# LANGUAGE DataKinds #-} + +module Unison.LSP.Formatting where + +import Control.Lens hiding (List) +import Data.Set qualified as Set +import Language.LSP.Protocol.Lens +import Language.LSP.Protocol.Message qualified as Msg +import Language.LSP.Protocol.Types +import Unison.Codebase.Editor.HandleInput.FormatFile qualified as Formatting +import Unison.LSP.Conversions (lspToURange, uToLspRange) +import Unison.LSP.FileAnalysis (getFileAnalysis) +import Unison.LSP.FileAnalysis qualified as FileAnalysis +import Unison.LSP.Types +import Unison.Prelude + +formatDocRequest :: Msg.TRequestMessage 'Msg.Method_TextDocumentFormatting -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentFormatting) -> Lsp ()) -> Lsp () +formatDocRequest m respond = do + edits <- formatDefs (m ^. params . textDocument . uri) Nothing + respond . Right . InL $ edits + +formatRangeRequest :: Msg.TRequestMessage 'Msg.Method_TextDocumentRangeFormatting -> (Either Msg.ResponseError (Msg.MessageResult 'Msg.Method_TextDocumentRangeFormatting) -> Lsp ()) -> Lsp () +formatRangeRequest m respond = do + let p = m ^. params + edits <- formatDefs (p ^. textDocument . uri) (Just . Set.singleton $ p ^. range) + respond . Right . InL $ edits + +-- | Format all definitions in a file. +formatDefs :: Uri -> Maybe (Set Range {- the ranges to format, if Nothing then format the whole file. -}) -> Lsp [TextEdit] +formatDefs fileUri mayRangesToFormat = + fromMaybe [] <$> runMaybeT do + FileAnalysis {parsedFile = mayParsedFile, typecheckedFile = mayTypecheckedFile} <- getFileAnalysis fileUri + currentPath <- lift getCurrentPath + Config {formattingWidth} <- lift getConfig + MaybeT $ + Formatting.formatFile (\uf tf -> FileAnalysis.ppedForFileHelper uf tf) formattingWidth currentPath mayParsedFile mayTypecheckedFile (Set.map lspToURange <$> mayRangesToFormat) + <&> (fmap . fmap) uTextReplacementToLSP + where + uTextReplacementToLSP :: Formatting.TextReplacement -> TextEdit + uTextReplacementToLSP (Formatting.TextReplacement newText range) = TextEdit (uToLspRange range) newText diff --git a/unison-cli/src/Unison/LSP/Queries.hs b/unison-cli/src/Unison/LSP/Queries.hs index 82b1a4a7e5..30a7e5f693 100644 --- a/unison-cli/src/Unison/LSP/Queries.hs +++ b/unison-cli/src/Unison/LSP/Queries.hs @@ -55,6 +55,7 @@ import Unison.Term (MatchCase (MatchCase), Term) import Unison.Term qualified as Term import Unison.Type (Type) import Unison.Type qualified as Type +import Unison.UnisonFile.Summary (FileSummary (..)) import Unison.Util.Pretty qualified as Pretty -- | Returns a reference to whatever the symbol at the given position refers to. @@ -360,6 +361,7 @@ annIsFilePosition = \case Ann.Intrinsic -> False Ann.External -> False Ann.Ann {} -> True + Ann.GeneratedFrom ann -> annIsFilePosition ann -- | Okay, so currently during synthesis in typechecking the typechecker adds `Ann` nodes -- to the term specifying types of subterms. This is a problem because we the types in these diff --git a/unison-cli/src/Unison/LSP/Types.hs b/unison-cli/src/Unison/LSP/Types.hs index d02d15a28d..91881b8f5d 100644 --- a/unison-cli/src/Unison/LSP/Types.hs +++ b/unison-cli/src/Unison/LSP/Types.hs @@ -26,7 +26,6 @@ import Language.LSP.VFS import Unison.Codebase import Unison.Codebase.Path qualified as Path import Unison.Codebase.Runtime (Runtime) -import Unison.DataDeclaration qualified as DD import Unison.Debug qualified as Debug import Unison.LSP.Orphans () import Unison.LabeledDependency (LabeledDependency) @@ -36,7 +35,6 @@ import Unison.Names (Names) import Unison.Parser.Ann import Unison.Prelude import Unison.PrettyPrintEnvDecl (PrettyPrintEnvDecl) -import Unison.Reference qualified as Reference import Unison.Referent (Referent) import Unison.Result (Note) import Unison.Server.Backend qualified as Backend @@ -44,9 +42,9 @@ import Unison.Server.NameSearch (NameSearch) import Unison.Sqlite qualified as Sqlite import Unison.Symbol import Unison.Syntax.Lexer qualified as Lexer -import Unison.Term (Term) import Unison.Type (Type) import Unison.UnisonFile qualified as UF +import Unison.UnisonFile.Summary (FileSummary (..)) import UnliftIO -- | A custom LSP monad wrapper so we can provide our own environment. @@ -131,25 +129,6 @@ data FileAnalysis = FileAnalysis } deriving stock (Show) --- | A file that parses might not always type-check, but often we just want to get as much --- information as we have available. This provides a type where we can summarize the --- information available in a Unison file. --- --- If the file typechecked then all the Ref Ids and types will be filled in, otherwise --- they will be Nothing. -data FileSummary = FileSummary - { dataDeclsBySymbol :: Map Symbol (Reference.Id, DD.DataDeclaration Symbol Ann), - dataDeclsByReference :: Map Reference.Id (Map Symbol (DD.DataDeclaration Symbol Ann)), - effectDeclsBySymbol :: Map Symbol (Reference.Id, DD.EffectDeclaration Symbol Ann), - effectDeclsByReference :: Map Reference.Id (Map Symbol (DD.EffectDeclaration Symbol Ann)), - termsBySymbol :: Map Symbol (Ann, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann)), - termsByReference :: Map (Maybe Reference.Id) (Map Symbol (Ann, Term Symbol Ann, Maybe (Type Symbol Ann))), - testWatchSummary :: [(Ann, Maybe Symbol, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann))], - exprWatchSummary :: [(Ann, Maybe Symbol, Maybe Reference.Id, Term Symbol Ann, Maybe (Type Symbol Ann))], - fileNames :: Names - } - deriving stock (Show) - getCurrentPath :: Lsp Path.Absolute getCurrentPath = asks currentPathCache >>= liftIO @@ -166,7 +145,8 @@ getParseNames :: Lsp Names getParseNames = asks parseNamesCache >>= liftIO data Config = Config - { -- 'Nothing' will load ALL available completions, which is slower, but may provide a better + { formattingWidth :: Int, + -- 'Nothing' will load ALL available completions, which is slower, but may provide a better -- solution for some users. -- -- 'Just n' will only fetch the first 'n' completions and will prompt the client to ask for @@ -179,17 +159,20 @@ instance Aeson.FromJSON Config where parseJSON = Aeson.withObject "Config" \obj -> do maxCompletions <- obj Aeson..:! "maxCompletions" Aeson..!= maxCompletions defaultLSPConfig Debug.debugM Debug.LSP "Config" $ "maxCompletions: " <> show maxCompletions + formattingWidth <- obj Aeson..:? "formattingWidth" Aeson..!= formattingWidth defaultLSPConfig pure Config {..} instance Aeson.ToJSON Config where - toJSON (Config maxCompletions) = + toJSON (Config formattingWidth maxCompletions) = Aeson.object - [ "maxCompletions" Aeson..= maxCompletions + [ "formattingWidth" Aeson..= formattingWidth, + "maxCompletions" Aeson..= maxCompletions ] defaultLSPConfig :: Config defaultLSPConfig = Config {..} where + formattingWidth = 80 maxCompletions = Just 100 -- | Lift a backend computation into the Lsp monad. diff --git a/unison-cli/src/Unison/LSP/UCMWorker.hs b/unison-cli/src/Unison/LSP/UCMWorker.hs index 7d0d1ed352..d358f67dd8 100644 --- a/unison-cli/src/Unison/LSP/UCMWorker.hs +++ b/unison-cli/src/Unison/LSP/UCMWorker.hs @@ -3,15 +3,17 @@ module Unison.LSP.UCMWorker where import Control.Monad.Reader import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch (Branch) +import Unison.Codebase.Branch qualified as Branch +import Unison.Codebase.Branch.Names qualified as Branch import Unison.Codebase.Path qualified as Path import Unison.Debug qualified as Debug import Unison.LSP.Completion import Unison.LSP.Types import Unison.LSP.VFS qualified as VFS import Unison.Names (Names) +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl -import Unison.PrettyPrintEnvDecl.Names qualified as PPE -import Unison.Server.Backend qualified as Backend +import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Server.NameSearch (NameSearch) import Unison.Server.NameSearch.FromNames qualified as NameSearch import Unison.Sqlite qualified as Sqlite @@ -25,17 +27,18 @@ ucmWorker :: STM (Branch IO) -> STM Path.Absolute -> Lsp () -ucmWorker ppeVar parseNamesVar nameSearchCacheVar getLatestRoot getLatestPath = do +ucmWorker ppedVar parseNamesVar nameSearchCacheVar getLatestRoot getLatestPath = do Env {codebase, completionsVar} <- ask let loop :: (Branch IO, Path.Absolute) -> Lsp a loop (currentRoot, currentPath) = do Debug.debugM Debug.LSP "LSP path: " currentPath - let parseNames = Backend.getCurrentParseNames (Backend.Within (Path.unabsolute currentPath)) currentRoot + let currentBranch0 = Branch.getAt0 (Path.unabsolute currentPath) (Branch.head currentRoot) + let parseNames = Branch.toNames currentBranch0 hl <- liftIO $ Codebase.runTransaction codebase Codebase.hashLength - let ppe = PPE.fromNamesDecl hl parseNames + let pped = PPED.makePPED (PPE.hqNamer hl parseNames) (PPE.suffixifyByHash parseNames) atomically $ do writeTVar parseNamesVar parseNames - writeTVar ppeVar ppe + writeTVar ppedVar pped writeTVar nameSearchCacheVar (NameSearch.makeNameSearch hl parseNames) -- Re-check everything with the new names and ppe VFS.markAllFilesDirty diff --git a/unison-cli/src/Unison/Share/Sync.hs b/unison-cli/src/Unison/Share/Sync.hs index 524083b217..bffb8b9cad 100644 --- a/unison-cli/src/Unison/Share/Sync.hs +++ b/unison-cli/src/Unison/Share/Sync.hs @@ -22,8 +22,6 @@ where import Control.Concurrent.STM import Control.Lens -import GHC.IO (unsafePerformIO) -import System.Environment (lookupEnv) import Control.Monad.Except import Control.Monad.Reader (ask) import Control.Monad.Trans.Reader (ReaderT, runReaderT) @@ -43,12 +41,14 @@ import Data.Set.NonEmpty (NESet) import Data.Set.NonEmpty qualified as NESet import Data.Text.Lazy qualified as Text.Lazy import Data.Text.Lazy.Encoding qualified as Text.Lazy +import GHC.IO (unsafePerformIO) import Ki qualified import Network.HTTP.Client qualified as Http.Client import Network.HTTP.Types qualified as HTTP import Servant.API qualified as Servant ((:<|>) (..), (:>)) import Servant.Client (BaseUrl) import Servant.Client qualified as Servant +import System.Environment (lookupEnv) import U.Codebase.HashTags (CausalHash) import U.Codebase.Sqlite.Queries qualified as Q import U.Codebase.Sqlite.V2.HashHandle (v2HashHandle) @@ -77,6 +77,8 @@ maxSimultaneousPullDownloaders :: Int maxSimultaneousPullDownloaders = 5 -- | The maximum number of push workers at a time. Each push worker reads from the database and uploads entities. +-- Share currently parallelizes on it's own in the backend, and any more than one push worker +-- just results in serialization conflicts which slow things down. maxSimultaneousPushWorkers :: Int maxSimultaneousPushWorkers = 5 @@ -481,7 +483,6 @@ shouldValidateEntities = unsafePerformIO $ do _ -> False {-# NOINLINE shouldValidateEntities #-} - type WorkerCount = TVar Int diff --git a/unison-cli/tests/Unison/Test/Cli/Monad.hs b/unison-cli/tests/Unison/Test/Cli/Monad.hs index eea5398f69..3b9407da11 100644 --- a/unison-cli/tests/Unison/Test/Cli/Monad.hs +++ b/unison-cli/tests/Unison/Test/Cli/Monad.hs @@ -16,7 +16,7 @@ test = Cli.runCli dummyEnv dummyLoopState do Cli.label \goto -> do Cli.label \_ -> do - #numberedArgs .= ["foo"] + Cli.setNumberedArgs ["foo"] goto (1 :: Int) pure 2 -- test that 'goto' short-circuits, as expected diff --git a/unison-cli/tests/Unison/Test/GitSync.hs b/unison-cli/tests/Unison/Test/GitSync.hs index f527dc75bb..a4a719a7b9 100644 --- a/unison-cli/tests/Unison/Test/GitSync.hs +++ b/unison-cli/tests/Unison/Test/GitSync.hs @@ -193,57 +193,6 @@ test = ``` |] ), - pushPullTest - "metadataForTerm" - fmt - ( \repo -> - [i| - ```unison:hide - doc = "y is the number 3" - y = 3 - ``` - ```ucm - .> debug.file - .> add - .> link doc y - .> links y - .> history - .> push.create git(${repo}) - ``` - |] - ) - ( \repo -> - [i| - ```ucm - .> pull git(${repo}) - .> links y - ``` - |] - ), - pushPullTest - "metadataForType" - fmt - ( \repo -> - [i| - ```unison:hide - doc = "Nat means natural number" - ``` - ```ucm - .> add - .> alias.type ##Nat Nat - .> link doc Nat - .> push.create git(${repo}) - ``` - |] - ) - ( \repo -> - [i| - ```ucm - .> pull git(${repo}) - .> links Nat - ``` - |] - ), pushPullTest "subNamespace" fmt diff --git a/unison-cli/unison-cli.cabal b/unison-cli/unison-cli.cabal index 11a9fae31b..48e43fe680 100644 --- a/unison-cli/unison-cli.cabal +++ b/unison-cli/unison-cli.cabal @@ -54,8 +54,8 @@ library Unison.Codebase.Editor.HandleInput.DeleteProject Unison.Codebase.Editor.HandleInput.EditNamespace Unison.Codebase.Editor.HandleInput.FindAndReplace + Unison.Codebase.Editor.HandleInput.FormatFile Unison.Codebase.Editor.HandleInput.Load - Unison.Codebase.Editor.HandleInput.MetadataUtils Unison.Codebase.Editor.HandleInput.MoveAll Unison.Codebase.Editor.HandleInput.MoveBranch Unison.Codebase.Editor.HandleInput.MoveTerm @@ -94,11 +94,11 @@ library Unison.Codebase.TranscriptParser Unison.Codebase.Watch Unison.CommandLine + Unison.CommandLine.BranchRelativePath Unison.CommandLine.Completion Unison.CommandLine.DisplayValues Unison.CommandLine.FuzzySelect Unison.CommandLine.FZFResolvers - Unison.CommandLine.Globbing Unison.CommandLine.InputPattern Unison.CommandLine.InputPatterns Unison.CommandLine.Main @@ -117,6 +117,7 @@ library Unison.LSP.Diagnostics Unison.LSP.FileAnalysis Unison.LSP.FoldingRange + Unison.LSP.Formatting Unison.LSP.HandlerUtils Unison.LSP.Hover Unison.LSP.NotificationHandlers diff --git a/unison-core/src/Unison/ABT.hs b/unison-core/src/Unison/ABT.hs index 2c20454586..fe9a8f930e 100644 --- a/unison-core/src/Unison/ABT.hs +++ b/unison-core/src/Unison/ABT.hs @@ -130,6 +130,7 @@ import U.Core.ABT visitPure, visit_, vmap, + vmapM, pattern AbsN', pattern Tm', pattern Var', @@ -202,13 +203,6 @@ isFreeIn v t = Set.member v (freeVars t) annotate :: a -> Term f v a -> Term f v a annotate a (Term fvs _ out) = Term fvs a out -vmapM :: (Applicative m, Traversable f, Foldable f, Ord v2) => (v -> m v2) -> Term f v a -> m (Term f v2 a) -vmapM f (Term _ a out) = case out of - Var v -> annotatedVar a <$> f v - Tm fa -> tm' a <$> traverse (vmapM f) fa - Cycle r -> cycle' a <$> vmapM f r - Abs v body -> abs' a <$> f v <*> vmapM f body - amap :: (Functor f, Foldable f, Ord v) => (a -> a2) -> Term f v a -> Term f v a2 amap = amap' . const diff --git a/unison-core/src/Unison/DataDeclaration.hs b/unison-core/src/Unison/DataDeclaration.hs index 6c820e6f1e..bfeb0b1d84 100644 --- a/unison-core/src/Unison/DataDeclaration.hs +++ b/unison-core/src/Unison/DataDeclaration.hs @@ -147,23 +147,25 @@ withEffectDeclM f = fmap EffectDeclaration . f . toDataDecl -- propose to move this code to some very feature-specific module —AI generateRecordAccessors :: (Semigroup a, Var v) => + (a -> a) -> [(v, a)] -> v -> Reference -> [(v, a, Term v a)] -generateRecordAccessors fields typename typ = +generateRecordAccessors generatedAnn fields typename typ = join [tm t i | (t, i) <- fields `zip` [(0 :: Int) ..]] where argname = Var.uncapitalize typename - tm (fname, ann) i = + tm (fname, fieldAnn) i = [ (Var.namespaced [typename, fname], ann, get), (Var.namespaced [typename, fname, Var.named "set"], ann, set), (Var.namespaced [typename, fname, Var.named "modify"], ann, modify) ] where + ann = generatedAnn fieldAnn -- example: `point -> case point of Point x _ -> x` get = - Term.lam ann argname $ + Term.lam (generatedAnn fieldAnn) argname $ Term.match ann (Term.var ann argname) @@ -177,7 +179,7 @@ generateRecordAccessors fields typename typ = rhs = ABT.abs' ann fname (Term.var ann fname) -- example: `x point -> case point of Point _ y -> Point x y` set = - Term.lam' ann [fname', argname] $ + Term.lam' (generatedAnn ann) [fname', argname] $ Term.match ann (Term.var ann argname) @@ -202,7 +204,7 @@ generateRecordAccessors fields typename typ = ] -- example: `f point -> case point of Point x y -> Point (f x) y` modify = - Term.lam' ann [fname', argname] $ + Term.lam' (generatedAnn ann) [fname', argname] $ Term.match ann (Term.var ann argname) diff --git a/unison-core/src/Unison/DataDeclaration/Names.hs b/unison-core/src/Unison/DataDeclaration/Names.hs index 7639c2d64c..e1e7549308 100644 --- a/unison-core/src/Unison/DataDeclaration/Names.hs +++ b/unison-core/src/Unison/DataDeclaration/Names.hs @@ -2,8 +2,8 @@ module Unison.DataDeclaration.Names (bindNames, dataDeclToNames', effectDeclToNames') where -import Data.Set qualified as Set import Data.Map qualified as Map +import Data.Set qualified as Set import Unison.ABT qualified as ABT import Unison.ConstructorReference (GConstructorReference (..)) import Unison.ConstructorType qualified as CT @@ -57,4 +57,4 @@ bindNames varToName localNames names (DataDeclaration m a bound constructors) = pure $ DataDeclaration m a bound constructors where keepFree = Set.fromList (Map.elems localNames) - subs = Map.toList $ Map.map (Type.var ()) localNames \ No newline at end of file + subs = Map.toList $ Map.map (Type.var ()) localNames diff --git a/unison-core/src/Unison/HashQualified'.hs b/unison-core/src/Unison/HashQualified'.hs index a8a68c6fa9..48bacfc6d1 100644 --- a/unison-core/src/Unison/HashQualified'.hs +++ b/unison-core/src/Unison/HashQualified'.hs @@ -79,6 +79,11 @@ fromNamedReference n r = HashQualified n (Reference.toShortHash r) fromName :: n -> HashQualified n fromName = NameOnly +fromNameHash :: n -> Maybe ShortHash -> HashQualified n +fromNameHash name = \case + Nothing -> NameOnly name + Just hash -> HashQualified name hash + matchesNamedReferent :: (Eq n) => n -> Referent -> HashQualified n -> Bool matchesNamedReferent n r = \case NameOnly n' -> n' == n diff --git a/unison-core/src/Unison/Name.hs b/unison-core/src/Unison/Name.hs index abc8d8d34d..58a096fc61 100644 --- a/unison-core/src/Unison/Name.hs +++ b/unison-core/src/Unison/Name.hs @@ -5,6 +5,7 @@ module Unison.Name -- * Basic construction cons, + snoc, joinDot, fromSegment, fromSegments, @@ -40,7 +41,8 @@ module Unison.Name preferShallowLibDepth, searchByRankedSuffix, searchBySuffix, - shortestUniqueSuffix, + suffixifyByName, + suffixifyByHash, sortByText, sortNamed, sortNames, @@ -61,6 +63,7 @@ import Data.List.Extra qualified as List import Data.List.NonEmpty (NonEmpty ((:|))) import Data.List.NonEmpty qualified as List.NonEmpty import Data.Map qualified as Map +import Data.Monoid (Sum (..)) import Data.RFC5051 qualified as RFC5051 import Data.Set qualified as Set import Unison.Name.Internal @@ -118,6 +121,13 @@ cons x name = ("cannot cons " ++ show x ++ " onto absolute name" ++ show name) Name Relative (y :| ys) -> Name Relative (y :| ys ++ [x]) +-- | Snoc a name segment onto the end of a name. +-- +-- /O(1)/. +snoc :: Name -> NameSegment -> Name +snoc (Name pos (s1 :| ss)) s0 = + Name pos (s0 :| s1 : ss) + -- | Return the number of name segments in a name. -- -- /O(n)/, where /n/ is the number of name segments. @@ -488,6 +498,23 @@ unqualified :: Name -> Name unqualified (Name _ (s :| _)) = Name Relative (s :| []) +-- Tries to shorten `fqn` to the smallest suffix that still +-- unambiguously refers to the same name. Uses an efficient +-- logarithmic lookup in the provided relation. +-- +-- NB: Only works if the `Ord` instance for `Name` orders based on +-- `Name.reverseSegments`. +suffixifyByName :: forall r. (Ord r) => Name -> R.Relation Name r -> Name +suffixifyByName fqn rel = + fromMaybe fqn (List.find isOk (suffixes' fqn)) + where + isOk :: Name -> Bool + isOk suffix = matchingNameCount == 1 + where + matchingNameCount :: Int + matchingNameCount = + getSum (R.searchDomG (\_ _ -> Sum 1) (compareSuffix suffix) rel) + -- Tries to shorten `fqn` to the smallest suffix that still refers the same references. -- Uses an efficient logarithmic lookup in the provided relation. -- The returned `Name` may refer to multiple hashes if the original FQN @@ -495,19 +522,20 @@ unqualified (Name _ (s :| _)) = -- -- NB: Only works if the `Ord` instance for `Name` orders based on -- `Name.reverseSegments`. -shortestUniqueSuffix :: forall r. (Ord r) => Name -> R.Relation Name r -> Name -shortestUniqueSuffix fqn rel = +suffixifyByHash :: forall r. (Ord r) => Name -> R.Relation Name r -> Name +suffixifyByHash fqn rel = fromMaybe fqn (List.find isOk (suffixes' fqn)) where allRefs :: Set r allRefs = R.lookupDom fqn rel + isOk :: Name -> Bool isOk suffix = - Set.size rs == 1 || rs == allRefs + Set.size refs == 1 || refs == allRefs where - rs :: Set r - rs = + refs :: Set r + refs = R.searchDom (compareSuffix suffix) rel -- | Returns the common prefix of two names as segments diff --git a/unison-core/src/Unison/Names/Scoped.hs b/unison-core/src/Unison/Names/Scoped.hs deleted file mode 100644 index f346ad60a2..0000000000 --- a/unison-core/src/Unison/Names/Scoped.hs +++ /dev/null @@ -1,22 +0,0 @@ -module Unison.Names.Scoped where - -import Unison.Names (Names) - --- | Contains all useful permutations of names scoped to a given branch. -data ScopedNames = ScopedNames - { relativeScopedNames :: Names, - absoluteRootNames :: Names - } - --- | Return all names contained in the path, relative to that path. -namesAtPath :: ScopedNames -> Names -namesAtPath (ScopedNames {relativeScopedNames}) = relativeScopedNames - --- | Includes ALL absolute names AND includes relative names for anything in the path. -parseNames :: ScopedNames -> Names -parseNames (ScopedNames {relativeScopedNames, absoluteRootNames}) = relativeScopedNames <> absoluteRootNames - --- | Includes includes relative names for anything in the path, and absolute names for --- everything else. -prettyNames :: ScopedNames -> Names -prettyNames (ScopedNames {relativeScopedNames}) = relativeScopedNames diff --git a/unison-core/src/Unison/NamesWithHistory.hs b/unison-core/src/Unison/NamesWithHistory.hs index f68fe579ce..5ba7ea72fa 100644 --- a/unison-core/src/Unison/NamesWithHistory.hs +++ b/unison-core/src/Unison/NamesWithHistory.hs @@ -104,9 +104,11 @@ push n0 ns = unionLeft0 n1 ns uniqueTerms = [(n, ref) | (n, nubOrd -> [ref]) <- Map.toList terms'] uniqueTypes = [(n, ref) | (n, nubOrd -> [ref]) <- Map.toList types'] +-- | Prefer names in the first argument, falling back to names in the second. +-- This can be used to shadow names in the codebase with names in a unison file for instance: +-- e.g. @shadowing scratchFileNames codebaseNames@ shadowing :: Names -> Names -> Names -shadowing = - Names.unionLeft +shadowing = Names.unionLeft -- Find all types whose name has a suffix matching the provided `HashQualified`, -- returning types with relative names if they exist, and otherwise diff --git a/unison-core/unison-core1.cabal b/unison-core/unison-core1.cabal index 57d19f42ea..e814b15c35 100644 --- a/unison-core/unison-core1.cabal +++ b/unison-core/unison-core1.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.1. +-- This file has been generated from package.yaml by hpack version 0.35.2. -- -- see: https://github.com/sol/hpack @@ -41,7 +41,6 @@ library Unison.Name.Internal Unison.Names Unison.Names.ResolutionResult - Unison.Names.Scoped Unison.NamesWithHistory Unison.Pattern Unison.Position diff --git a/unison-share-api/src/Unison/Server/Backend.hs b/unison-share-api/src/Unison/Server/Backend.hs index cf92a6b97f..791548d878 100644 --- a/unison-share-api/src/Unison/Server/Backend.hs +++ b/unison-share-api/src/Unison/Server/Backend.hs @@ -7,10 +7,11 @@ module Unison.Server.Backend BackendError (..), Backend (..), ShallowListEntry (..), + listEntryName, BackendEnv (..), + TermEntry (..), TypeEntry (..), FoundRef (..), - NameScoping (..), IncludeCycles (..), DefinitionResults (..), @@ -18,7 +19,6 @@ module Unison.Server.Backend fuzzyFind, -- * Utilities - basicSuffixifiedNames, bestNameForTerm, bestNameForType, definitionsByName, @@ -27,8 +27,6 @@ module Unison.Server.Backend expandShortCausalHash, findDocInBranch, formatSuffixedType, - getCurrentParseNames, - getCurrentPrettyNames, getShallowCausalAtPathFromRootHash, getTermTag, getTypeTag, @@ -39,16 +37,12 @@ module Unison.Server.Backend lsAtPath, lsBranch, mungeSyntaxText, - namesForBranch, - parseNamesForBranch, - prettyNamesForBranch, resolveCausalHashV2, resolveRootBranchHashV2, - scopedNamesForBranchHash, + namesAtPathFromRootBranchHash, termEntryDisplayName, termEntryHQName, termEntryToNamedTerm, - termEntryType, termEntryLabeledDependencies, termListEntry, termReferentsByShortHash, @@ -67,20 +61,18 @@ module Unison.Server.Backend -- * Unused, could remove? resolveRootBranchHash, - shallowPPE, isTestResultList, - toAllNames, fixupNamesRelative, -- * Re-exported for Share Server termsToSyntax, typesToSyntax, definitionResultsDependencies, - termEntryTag, evalDocRef, mkTermDefinition, mkTypeDefinition, displayTerm, + formatTypeName, ) where @@ -143,13 +135,13 @@ import Unison.Name (Name) import Unison.Name qualified as Name import Unison.NameSegment (NameSegment (..)) import Unison.NameSegment qualified as NameSegment -import Unison.Names (Names (Names)) +import Unison.Names (Names) import Unison.Names qualified as Names -import Unison.Names.Scoped qualified as ScopedNames import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann) import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE +import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnv.Util qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.PrettyPrintEnvDecl.Names qualified as PPED @@ -193,7 +185,6 @@ import Unison.Util.Monoid qualified as Monoid import Unison.Util.Pretty (Width) import Unison.Util.Pretty qualified as Pretty import Unison.Util.Relation qualified as R -import Unison.Util.Set qualified as Set import Unison.Util.SyntaxText qualified as UST import Unison.Var (Var) import Unison.WatchKind qualified as WK @@ -255,85 +246,6 @@ hoistBackend :: (forall x. m x -> n x) -> Backend m a -> Backend n a hoistBackend f (Backend m) = Backend (mapReaderT (mapExceptT f) m) -suffixifyNames :: Int -> Names -> PPE.PrettyPrintEnv -suffixifyNames hashLength = - PPED.suffixifiedPPE . PPED.fromNamesDecl hashLength - --- implementation detail of parseNamesForBranch and prettyNamesForBranch --- Returns (parseNames, prettyNames, localNames) -namesForBranch :: Branch m -> NameScoping -> (Names, Names, Names) -namesForBranch root scope = - (parseNames0, prettyPrintNames0, currentPathNames) - where - path :: Path - includeAllNames :: Bool - (path, includeAllNames) = case scope of - AllNames path -> (path, True) - Within path -> (path, False) - WithinStrict path -> (path, False) - root0 = Branch.head root - currentBranch = fromMaybe Branch.empty $ Branch.getAt path root - absoluteRootNames = Names.makeAbsolute (Branch.toNames root0) - currentBranch0 = Branch.head currentBranch - currentPathNames = Branch.toNames currentBranch0 - -- all names, but with local names in their relative form only, rather - -- than absolute; external names appear as absolute - currentAndExternalNames = - currentPathNames - `Names.unionLeft` Names.mapNames Name.makeAbsolute externalNames - where - externalNames = rootNames `Names.difference` pathPrefixed currentPathNames - rootNames = Branch.toNames root0 - pathPrefixed = case Path.toName path of - Nothing -> const mempty - Just pathName -> Names.prefix0 pathName - -- parsing should respond to local and absolute names - parseNames0 = currentPathNames <> Monoid.whenM includeAllNames absoluteRootNames - -- pretty-printing should use local names where available - prettyPrintNames0 = - if includeAllNames - then currentAndExternalNames - else currentPathNames - -basicSuffixifiedNames :: Int -> Branch m -> NameScoping -> PPE.PrettyPrintEnv -basicSuffixifiedNames hashLength root nameScope = - let names0 = prettyNamesForBranch root nameScope - in suffixifyNames hashLength names0 - -parseNamesForBranch :: Branch m -> NameScoping -> Names -parseNamesForBranch root = namesForBranch root <&> \(n, _, _) -> n - -prettyNamesForBranch :: Branch m -> NameScoping -> Names -prettyNamesForBranch root = namesForBranch root <&> \(_, n, _) -> n - -shallowPPE :: (MonadIO m) => Codebase m v a -> V2Branch.Branch m -> m PPE.PrettyPrintEnv -shallowPPE codebase b = do - (hashLength, names) <- Codebase.runTransaction codebase do - hl <- Codebase.hashLength - names <- shallowNames codebase b - pure (hl, names) - pure $ PPED.suffixifiedPPE . PPED.fromNamesDecl hashLength $ names - --- | A 'Names' which only includes mappings for things _directly_ accessible from the branch. --- --- I.e. names in nested children are omitted. --- This should probably live elsewhere, but the package dependency graph makes it hard to find --- a good place. -shallowNames :: forall m v a. (Monad m) => Codebase m v a -> V2Branch.Branch m -> Sqlite.Transaction Names -shallowNames codebase b = do - newTerms <- - V2Branch.terms b - & Map.mapKeys Name.fromSegment - & fmap Map.keysSet - & traverse . Set.traverse %%~ Cv.referent2to1 (Codebase.getDeclType codebase) - - let newTypes = - V2Branch.types b - & Map.mapKeys Name.fromSegment - & fmap Map.keysSet - & traverse . Set.traverse %~ Cv.reference2to1 - pure (Names (R.fromMultimap newTerms) (R.fromMultimap newTypes)) - loadReferentType :: Codebase m Symbol Ann -> Referent -> @@ -485,11 +397,11 @@ isDoc codebase ref = do isDoc' :: (Var v, Monoid loc) => Maybe (Type v loc) -> Bool isDoc' typeOfTerm = do - -- A term is a dococ if its type conforms to the `Doc` type. + -- A term is a doc if its type conforms to the `Doc` type. case typeOfTerm of Just t -> - Typechecker.isSubtype t doc1Type - || Typechecker.isSubtype t doc2Type + Typechecker.isEqual t doc1Type + || Typechecker.isEqual t doc2Type Nothing -> False doc1Type :: (Ord v, Monoid a) => Type v a @@ -501,7 +413,7 @@ doc2Type = Type.ref mempty DD.doc2Ref isTestResultList :: forall v a. (Var v, Monoid a) => Maybe (Type v a) -> Bool isTestResultList typ = case typ of Nothing -> False - Just t -> Typechecker.isSubtype t resultListType + Just t -> Typechecker.isEqual t resultListType resultListType :: (Ord v, Monoid a) => Type v a resultListType = Type.app mempty (Type.list mempty) (Type.ref mempty Decls.testResultRef) @@ -547,15 +459,11 @@ getTermTag :: m TermTag getTermTag codebase r sig = do -- A term is a doc if its type conforms to the `Doc` type. - let isDoc = case sig of - Just t -> - Typechecker.isSubtype t (Type.ref mempty Decls.docRef) - || Typechecker.isSubtype t (Type.ref mempty DD.doc2Ref) - Nothing -> False + let isDoc = isDoc' sig -- A term is a test if it has the type [test.Result] let isTest = case sig of Just t -> - Typechecker.isSubtype t (Decls.testResultType mempty) + Typechecker.isEqual t (Decls.testResultType mempty) Nothing -> False constructorType <- case r of V2Referent.Ref {} -> pure Nothing @@ -692,43 +600,6 @@ lsBranch codebase b0 = do ++ branchEntries ++ patchEntries --- currentPathNames :: Path -> Names --- currentPathNames = Branch.toNames . Branch.head . Branch.getAt - --- | Configure how names will be constructed and filtered. --- this is typically used when fetching names for printing source code or when finding --- definitions by name. -data NameScoping - = -- | Find all names, making any names which are children of this path, - -- otherwise leave them absolute. - AllNames Path - | -- | Filter returned names to only include names within this path. - Within Path - | -- | Like `Within`, but does not include a fallback - WithinStrict Path - -toAllNames :: NameScoping -> NameScoping -toAllNames (AllNames p) = AllNames p -toAllNames (Within p) = AllNames p -toAllNames (WithinStrict p) = AllNames p - -getCurrentPrettyNames :: Int -> NameScoping -> Branch m -> PPED.PrettyPrintEnvDecl -getCurrentPrettyNames hashLen scope root = - case scope of - WithinStrict _ -> primary - _ -> - PPED.PrettyPrintEnvDecl - (PPED.unsuffixifiedPPE primary `PPE.addFallback` PPED.unsuffixifiedPPE backup) - (PPED.suffixifiedPPE primary `PPE.addFallback` PPED.suffixifiedPPE backup) - where - backup = PPED.fromNamesDecl hashLen $ parseNamesForBranch root (AllNames mempty) - where - primary = PPED.fromNamesDecl hashLen $ parseNamesForBranch root scope - -getCurrentParseNames :: NameScoping -> Branch m -> Names -getCurrentParseNames scope root = - parseNamesForBranch root scope - -- Any absolute names in the input which have `root` as a prefix -- are converted to names relative to current path. All other names are -- converted to absolute names. For example: @@ -1017,7 +888,7 @@ docsForDefinitionName codebase (NameSearch {termSearch}) searchType name = do Referent.Ref r -> maybe [] (pure . (r,)) <$> Codebase.getTypeOfTerm codebase r _ -> pure [] - pure [r | (r, t) <- rts, Typechecker.isSubtype t (Type.ref mempty DD.doc2Ref)] + pure [r | (r, t) <- rts, isDoc' (Just t)] -- | Evaluate and render the given docs renderDocRefs :: @@ -1056,9 +927,8 @@ docsInBranchToHtmlFiles runtime codebase root currentPath directory = do hqLength <- Codebase.hashLength pure (docTermsWithNames, hqLength) let docNamesByRef = Map.fromList docTermsWithNames - let printNames = prettyNamesForBranch root (AllNames currentPath) - let ppe = PPED.fromNamesDecl hqLength printNames - docs <- for docTermsWithNames (renderDoc' ppe runtime codebase) + let pped = Branch.toPrettyPrintEnvDecl hqLength (Branch.head currentBranch) + docs <- for docTermsWithNames (renderDoc' pped runtime codebase) liftIO $ docs & foldMapM \(name, text, doc, errs) -> do renderDocToHtmlFile docNamesByRef directory (name, text, doc) @@ -1144,21 +1014,16 @@ bestNameForType ppe width = . TypePrinter.prettySyntax @v ppe . Type.ref () --- | Returns (parse, pretty, local, ppe) where: --- --- - 'parse' includes ALL fully qualified names from the root, and ALSO all names from within the provided path, relative to that path. --- - 'pretty' includes names within the provided path, relative to that path, and also all globally scoped names _outside_ of the path --- - 'local' includes ONLY the names within the provided path --- - 'ppe' is a ppe which searches for a name within the path first, but falls back to a global name search. --- The 'suffixified' component of this ppe will search for the shortest unambiguous suffix within the scope in which the name is found (local, falling back to global) -scopedNamesForBranchHash :: +-- | Gets the names and PPED for the branch at the provided path from the root branch for the +-- provided branch hash. +namesAtPathFromRootBranchHash :: forall m n v a. (MonadIO m) => Codebase m v a -> Maybe (V2Branch.CausalBranch n) -> Path -> Backend m (Names, PPED.PrettyPrintEnvDecl) -scopedNamesForBranchHash codebase mbh path = do +namesAtPathFromRootBranchHash codebase mbh path = do shouldUseNamesIndex <- asks useNamesIndex (rootBranchHash, rootCausalHash) <- case mbh of Just cb -> pure (V2Causal.valueHash cb, V2Causal.causalHash cb) @@ -1167,28 +1032,15 @@ scopedNamesForBranchHash codebase mbh path = do pure (V2Causal.valueHash cb, V2Causal.causalHash cb) haveNameLookupForRoot <- lift $ Codebase.runTransaction codebase (Ops.checkBranchHashNameLookupExists rootBranchHash) hashLen <- lift $ Codebase.runTransaction codebase Codebase.hashLength - (parseNames, localNames) <- + names <- if shouldUseNamesIndex then do when (not haveNameLookupForRoot) . throwError $ ExpectedNameLookup rootBranchHash - lift . Codebase.runTransaction codebase $ indexNames rootBranchHash + lift . Codebase.runTransaction codebase $ Codebase.namesAtPath rootBranchHash path else do - (parseNames, _pretty, localNames) <- flip namesForBranch (AllNames path) <$> resolveCausalHash (Just rootCausalHash) codebase - pure (parseNames, localNames) - - let localPPE = PPED.fromNamesDecl hashLen localNames - let globalPPE = PPED.fromNamesDecl hashLen parseNames - pure (localNames, mkPPE localPPE globalPPE) - where - mkPPE :: PPED.PrettyPrintEnvDecl -> PPED.PrettyPrintEnvDecl -> PPED.PrettyPrintEnvDecl - mkPPE primary addFallback = - PPED.PrettyPrintEnvDecl - (PPED.unsuffixifiedPPE primary `PPE.addFallback` PPED.unsuffixifiedPPE addFallback) - (PPED.suffixifiedPPE primary `PPE.addFallback` PPED.suffixifiedPPE addFallback) - indexNames :: BranchHash -> Sqlite.Transaction (Names, Names) - indexNames bh = do - scopedNames <- Codebase.namesAtPath bh path - pure (ScopedNames.parseNames scopedNames, ScopedNames.namesAtPath scopedNames) + Branch.toNames . Branch.getAt0 path . Branch.head <$> resolveCausalHash (Just rootCausalHash) codebase + let pped = PPED.makePPED (PPE.hqNamer hashLen names) (PPE.suffixifyByHash names) + pure (names, pped) resolveCausalHash :: (Monad m) => Maybe CausalHash -> Codebase m v a -> Backend m (Branch m) diff --git a/unison-share-api/src/Unison/Server/Local/Definitions.hs b/unison-share-api/src/Unison/Server/Local/Definitions.hs index f65973f6ff..3fb8ec86ba 100644 --- a/unison-share-api/src/Unison/Server/Local/Definitions.hs +++ b/unison-share-api/src/Unison/Server/Local/Definitions.hs @@ -62,7 +62,7 @@ prettyDefinitionsForHQName perspective shallowRoot renderWidth suffixifyBindings -- ppe which returns names fully qualified to the current perspective, not to the codebase root. let biases = maybeToList $ HQ.toName query hqLength <- liftIO $ Codebase.runTransaction codebase $ Codebase.hashLength - (localNamesOnly, unbiasedPPED) <- scopedNamesForBranchHash codebase (Just shallowRoot) namesRoot + (localNamesOnly, unbiasedPPED) <- namesAtPathFromRootBranchHash codebase (Just shallowRoot) namesRoot let pped = PPED.biasTo biases unbiasedPPED let nameSearch = makeNameSearch hqLength localNamesOnly (DefinitionResults terms types misses) <- liftIO $ Codebase.runTransaction codebase do diff --git a/unison-share-api/src/Unison/Server/Local/Endpoints/DefinitionSummary.hs b/unison-share-api/src/Unison/Server/Local/Endpoints/DefinitionSummary.hs index fedff587de..1ba846f120 100644 --- a/unison-share-api/src/Unison/Server/Local/Endpoints/DefinitionSummary.hs +++ b/unison-share-api/src/Unison/Server/Local/Endpoints/DefinitionSummary.hs @@ -126,7 +126,7 @@ serveTermSummary codebase referent mayName mayRoot relativeTo mayWidth = do namesPerspective <- Ops.namesPerspectiveForRootAndPath (V2Causal.valueHash root) (coerce . Path.toList $ fromMaybe Path.Empty relativeTo) PPESqlite.ppedForReferences namesPerspective deps False -> do - (_localNames, ppe) <- Backend.scopedNamesForBranchHash codebase (Just root) relativeToPath + (_localNames, ppe) <- Backend.namesAtPathFromRootBranchHash codebase (Just root) relativeToPath pure ppe let formattedTermSig = Backend.formatSuffixedType ppe width typeSig let summary = mkSummary termReference formattedTermSig diff --git a/unison-share-api/src/Unison/Server/Local/Endpoints/FuzzyFind.hs b/unison-share-api/src/Unison/Server/Local/Endpoints/FuzzyFind.hs index b604e80171..530eaa91c3 100644 --- a/unison-share-api/src/Unison/Server/Local/Endpoints/FuzzyFind.hs +++ b/unison-share-api/src/Unison/Server/Local/Endpoints/FuzzyFind.hs @@ -160,7 +160,7 @@ serveFuzzyFind codebase mayRoot relativeTo limit typeWidth query = do rootCausal <- Backend.hoistBackend (Codebase.runTransaction codebase) do Backend.normaliseRootCausalHash mayRoot - (localNamesOnly, ppe) <- Backend.scopedNamesForBranchHash codebase (Just rootCausal) path + (localNamesOnly, ppe) <- Backend.namesAtPathFromRootBranchHash codebase (Just rootCausal) path relativeToBranch <- do (lift . Codebase.runTransaction codebase) do relativeToCausal <- Codebase.getShallowCausalAtPath path (Just rootCausal) diff --git a/unison-share-api/src/Unison/Server/Local/Endpoints/NamespaceDetails.hs b/unison-share-api/src/Unison/Server/Local/Endpoints/NamespaceDetails.hs index e9f8f1c287..5edb2ef232 100644 --- a/unison-share-api/src/Unison/Server/Local/Endpoints/NamespaceDetails.hs +++ b/unison-share-api/src/Unison/Server/Local/Endpoints/NamespaceDetails.hs @@ -68,7 +68,7 @@ namespaceDetails runtime codebase namespacePath mayRoot _mayWidth = do shallowBranch <- lift $ V2Causal.value namespaceCausal pure (rootCausalHash, namespaceCausal, shallowBranch) namespaceDetails <- do - (_localNamesOnly, ppe) <- Backend.scopedNamesForBranchHash codebase (Just rootCausal) namespacePath + (_localNamesOnly, ppe) <- Backend.namesAtPathFromRootBranchHash codebase (Just rootCausal) namespacePath let mayReadmeRef = Backend.findDocInBranch readmeNames shallowBranch renderedReadme <- for mayReadmeRef \readmeRef -> do -- Local server currently ignores eval errors. diff --git a/unison-share-api/src/Unison/Server/NameSearch.hs b/unison-share-api/src/Unison/Server/NameSearch.hs index 0d8b17987c..cac70c4f76 100644 --- a/unison-share-api/src/Unison/Server/NameSearch.hs +++ b/unison-share-api/src/Unison/Server/NameSearch.hs @@ -1,4 +1,11 @@ -module Unison.Server.NameSearch where +module Unison.Server.NameSearch + ( Search(..) + , NameSearch(..) + , hoistSearch + , hoistNameSearch + , applySearch + , SearchType(..) + ) where import Control.Lens import Data.List qualified as List @@ -6,7 +13,7 @@ import Data.Set qualified as Set import Unison.HashQualified qualified as HQ import Unison.HashQualified' qualified as HQ' import Unison.Name (Name) -import Unison.NamesWithHistory (SearchType) +import Unison.NamesWithHistory (SearchType(..)) import Unison.Prelude import Unison.Reference (Reference) import Unison.Referent (Referent) @@ -27,11 +34,27 @@ data Search m r = Search matchesNamedRef :: Name -> r -> HQ'.HashQualified Name -> Bool } +hoistSearch :: (forall x. m x -> n x) -> Search m r -> Search n r +hoistSearch f Search {lookupNames, lookupRelativeHQRefs', makeResult, matchesNamedRef} = + Search + { lookupNames = f . lookupNames, + lookupRelativeHQRefs' = \st hqname -> f $ lookupRelativeHQRefs' st hqname, + makeResult = \n r -> f . makeResult n r, + matchesNamedRef = \n r -> matchesNamedRef n r + } + data NameSearch m = NameSearch { typeSearch :: Search m Reference, termSearch :: Search m Referent } +hoistNameSearch :: (forall x. m x -> n x) -> NameSearch m -> NameSearch n +hoistNameSearch f NameSearch {typeSearch, termSearch} = + NameSearch + { typeSearch = hoistSearch f typeSearch, + termSearch = hoistSearch f termSearch + } + -- | Interpret a 'Search' as a function from name to search results. applySearch :: (Show r, Monad m) => Search m r -> SearchType -> HQ'.HashQualified Name -> m [SR.SearchResult] applySearch Search {lookupNames, lookupRelativeHQRefs', makeResult, matchesNamedRef} searchType query = do diff --git a/unison-share-api/src/Unison/Sync/EntityValidation.hs b/unison-share-api/src/Unison/Sync/EntityValidation.hs index 0477bcc9bb..fdd986f0d8 100644 --- a/unison-share-api/src/Unison/Sync/EntityValidation.hs +++ b/unison-share-api/src/Unison/Sync/EntityValidation.hs @@ -14,10 +14,12 @@ import Data.Text qualified as Text import U.Codebase.HashTags import U.Codebase.Sqlite.Branch.Format qualified as BranchFormat import U.Codebase.Sqlite.Causal qualified as CausalFormat +import U.Codebase.Sqlite.Decl.Format qualified as DeclFormat import U.Codebase.Sqlite.Decode qualified as Decode import U.Codebase.Sqlite.Entity qualified as Entity import U.Codebase.Sqlite.HashHandle qualified as HH import U.Codebase.Sqlite.Orphans () +import U.Codebase.Sqlite.Patch.Format qualified as PatchFormat import U.Codebase.Sqlite.Serialization qualified as Serialization import U.Codebase.Sqlite.Term.Format qualified as TermFormat import U.Codebase.Sqlite.V2.HashHandle (v2HashHandle) @@ -33,20 +35,43 @@ import Unison.Sync.Types qualified as Share -- We should add more validation as more entities are shared. validateEntity :: Hash32 -> Share.Entity Text Hash32 Hash32 -> Maybe Share.EntityValidationError validateEntity expectedHash32 entity = do - case Share.entityToTempEntity id entity of - Entity.TC (TermFormat.SyncTerm localComp) -> do - validateTerm expectedHash localComp - Entity.N (BranchFormat.SyncDiff {}) -> do - (Just $ Share.UnsupportedEntityType expectedHash32 Share.NamespaceDiffType) - Entity.N (BranchFormat.SyncFull localIds (BranchFormat.LocalBranchBytes bytes)) -> do - validateBranchFull expectedHash localIds bytes - Entity.C CausalFormat.SyncCausalFormat {valueHash, parents} -> do - validateCausal expectedHash32 valueHash (toList parents) - _ -> Nothing + case Share.entityToTempEntity id entity of + Entity.TC (TermFormat.SyncTerm localComp) -> do + validateTerm expectedHash localComp + Entity.DC (DeclFormat.SyncDecl localComp) -> do + validateDecl expectedHash localComp + Entity.N (BranchFormat.SyncDiff {}) -> do + Just $ Share.UnsupportedEntityType expectedHash32 Share.NamespaceDiffType + Entity.N (BranchFormat.SyncFull localIds (BranchFormat.LocalBranchBytes bytes)) -> do + validateBranchFull expectedHash localIds bytes + Entity.C CausalFormat.SyncCausalFormat {valueHash, parents} -> do + validateCausal expectedHash32 valueHash (toList parents) + Entity.P (PatchFormat.SyncDiff {}) -> do + Just $ Share.UnsupportedEntityType expectedHash32 Share.PatchDiffType + Entity.P (PatchFormat.SyncFull localIds bytes) -> do + validatePatchFull expectedHash32 localIds bytes where expectedHash :: Hash expectedHash = Hash32.toHash expectedHash32 +validatePatchFull :: Hash32 -> PatchFormat.PatchLocalIds' Text Hash32 Hash32 -> BS.ByteString -> Maybe Share.EntityValidationError +validatePatchFull expectedHash32 localIds bytes = do + let expectedHash = Hash32.toHash expectedHash32 + case runGetS Serialization.getLocalPatch bytes of + Left e -> Just $ Share.InvalidByteEncoding expectedHash32 Share.PatchType (Text.pack e) + Right localPatch -> do + let localIds' = + localIds + { PatchFormat.patchTextLookup = PatchFormat.patchTextLookup localIds, + PatchFormat.patchHashLookup = ComponentHash . Hash32.toHash <$> PatchFormat.patchHashLookup localIds, + PatchFormat.patchDefnLookup = ComponentHash . Hash32.toHash <$> PatchFormat.patchDefnLookup localIds + } + let actualHash = + HH.hashPatchFormatFull v2HashHandle localIds' localPatch + if actualHash == PatchHash expectedHash + then Nothing + else Just $ Share.EntityHashMismatch Share.NamespaceType (mismatch expectedHash (unPatchHash actualHash)) + validateBranchFull :: Hash -> BranchFormat.BranchLocalIds' Text Hash32 Hash32 (Hash32, Hash32) -> @@ -79,6 +104,16 @@ validateTerm expectedHash syncLocalComp = do Nothing -> Nothing Just (HH.HashMismatch {expectedHash, actualHash}) -> Just . Share.EntityHashMismatch Share.TermComponentType $ mismatch expectedHash actualHash +validateDecl :: Hash -> (DeclFormat.SyncLocallyIndexedComponent' Text Hash32) -> (Maybe Share.EntityValidationError) +validateDecl expectedHash syncLocalComp = do + case Decode.unsyncDeclComponent syncLocalComp of + Left decodeErr -> Just (Share.InvalidByteEncoding (Hash32.fromHash expectedHash) Share.DeclComponentType (tShow decodeErr)) + Right localComp -> do + case HH.verifyDeclFormatHash v2HashHandle (ComponentHash expectedHash) (DeclFormat.Decl localComp) of + Nothing -> Nothing + Just (HH.DeclHashMismatch (HH.HashMismatch {expectedHash, actualHash})) -> Just . Share.EntityHashMismatch Share.TermComponentType $ mismatch expectedHash actualHash + Just HH.DeclHashResolutionFailure -> Just $ Share.HashResolutionFailure (Hash32.fromHash expectedHash) + validateCausal :: Hash32 -> Hash32 -> [Hash32] -> Maybe Share.EntityValidationError validateCausal expectedHash32 valueHash32 parentHashes32 = do let expectedHash = Hash32.toHash expectedHash32 diff --git a/unison-share-api/src/Unison/Sync/Types.hs b/unison-share-api/src/Unison/Sync/Types.hs index a44194d0a0..e2e91f6899 100644 --- a/unison-share-api/src/Unison/Sync/Types.hs +++ b/unison-share-api/src/Unison/Sync/Types.hs @@ -26,7 +26,8 @@ module Unison.Sync.Types -- *** Entity Traversals entityHashes_, - patchHashes_, + patchOldHashes_, + patchNewHashes_, patchDiffHashes_, namespaceDiffHashes_, causalHashes_, @@ -171,7 +172,7 @@ entityHashes_ :: (Applicative m, Ord hash') => (hash -> m hash') -> Entity text entityHashes_ f = \case TC tc -> TC <$> bitraverse pure f tc DC dc -> DC <$> bitraverse pure f dc - P patch -> P <$> patchHashes_ f patch + P patch -> P <$> patchNewHashes_ f patch PD patch -> PD <$> patchDiffHashes_ f patch N ns -> N <$> bitraverse pure f ns ND ns -> ND <$> namespaceDiffHashes_ f ns @@ -329,8 +330,13 @@ instance (FromJSON text, FromJSON oldHash, FromJSON newHash) => FromJSON (Patch Base64Bytes bytes <- obj .: "bytes" pure Patch {..} -patchHashes_ :: (Applicative m) => (hash -> m hash') -> Patch text noSyncHash hash -> m (Patch text noSyncHash hash') -patchHashes_ f (Patch {..}) = do +patchOldHashes_ :: (Applicative m) => (oldHash -> m oldHash') -> Patch text oldHash newHash -> m (Patch text oldHash' newHash) +patchOldHashes_ f (Patch {..}) = do + oldHashLookup <- traverse f oldHashLookup + pure (Patch {..}) + +patchNewHashes_ :: (Applicative m) => (newHash -> m newHash') -> Patch text oldHash newHash -> m (Patch text oldHash newHash') +patchNewHashes_ f (Patch {..}) = do newHashLookup <- traverse f newHashLookup pure (Patch {..}) @@ -619,6 +625,7 @@ data EntityValidationError = EntityHashMismatch EntityType HashMismatchForEntity | UnsupportedEntityType Hash32 EntityType | InvalidByteEncoding Hash32 EntityType Text {- decoding err msg -} + | HashResolutionFailure Hash32 deriving stock (Show, Eq, Ord) deriving anyclass (Exception) @@ -627,6 +634,7 @@ instance ToJSON EntityValidationError where EntityHashMismatch typ mismatch -> jsonUnion "mismatched_hash" (object ["type" .= typ, "mismatch" .= mismatch]) UnsupportedEntityType hash typ -> jsonUnion "unsupported_entity_type" (object ["hash" .= hash, "type" .= typ]) InvalidByteEncoding hash typ errMsg -> jsonUnion "invalid_byte_encoding" (object ["hash" .= hash, "type" .= typ, "error" .= errMsg]) + HashResolutionFailure hash -> jsonUnion "hash_resolution_failure" hash instance FromJSON EntityValidationError where parseJSON = Aeson.withObject "EntityValidationError" \obj -> @@ -678,7 +686,8 @@ data UploadEntitiesResponse deriving stock (Show, Eq, Ord) data UploadEntitiesError - = UploadEntitiesError'HashMismatchForEntity HashMismatchForEntity + = UploadEntitiesError'EntityValidationFailure EntityValidationError + | UploadEntitiesError'HashMismatchForEntity HashMismatchForEntity | -- | msg, repoInfo UploadEntitiesError'InvalidRepoInfo Text RepoInfo | UploadEntitiesError'NeedDependencies (NeedDependencies Hash32) @@ -698,6 +707,8 @@ data HashMismatchForEntity = HashMismatchForEntity instance ToJSON UploadEntitiesResponse where toJSON = \case UploadEntitiesSuccess -> jsonUnion "success" (Object mempty) + UploadEntitiesFailure (UploadEntitiesError'EntityValidationFailure err) -> + jsonUnion "entity_validation_failure" err UploadEntitiesFailure (UploadEntitiesError'HashMismatchForEntity mismatch) -> jsonUnion "hash_mismatch_for_entity" mismatch UploadEntitiesFailure (UploadEntitiesError'InvalidRepoInfo msg repoInfo) -> @@ -712,6 +723,7 @@ instance FromJSON UploadEntitiesResponse where parseJSON = Aeson.withObject "UploadEntitiesResponse" \obj -> obj .: "type" >>= Aeson.withText "type" \case "success" -> pure UploadEntitiesSuccess + "entity_validation_failure" -> UploadEntitiesFailure . UploadEntitiesError'EntityValidationFailure <$> obj .: "payload" "need_dependencies" -> UploadEntitiesFailure . UploadEntitiesError'NeedDependencies <$> obj .: "payload" "no_write_permission" -> UploadEntitiesFailure . UploadEntitiesError'NoWritePermission <$> obj .: "payload" "hash_mismatch_for_entity" -> @@ -735,9 +747,9 @@ instance FromJSON HashMismatchForEntity where Aeson.withObject "HashMismatchForEntity" \obj -> HashMismatchForEntity <$> obj - .: "supplied" + .: "supplied" <*> obj - .: "computed" + .: "computed" ------------------------------------------------------------------------------------------------------------------------ -- Fast-forward path diff --git a/unison-src/transcripts-manual/rewrites.md b/unison-src/transcripts-manual/rewrites.md index 78dea1536c..15a5a06387 100644 --- a/unison-src/transcripts-manual/rewrites.md +++ b/unison-src/transcripts-manual/rewrites.md @@ -7,10 +7,10 @@ ## Structural find and replace -Here's a scratch file with some rewrite rules: +Here's a scratch file with some rewrite rules: -```unison:hide /private/tmp/rewrites-tmp.u -ex1 = List.map (x -> x + 1) [1,2,3,4,5,6,7] +```unison:hide +ex1 = List.map (x -> x + 1) [1,2,3,4,5,6,7] eitherToOptional e a = @rewrite @@ -25,17 +25,13 @@ Either.mapRight f = cases Left e -> Left e Right a -> Right (f a) -rule1 f x = @rewrite +rule1 f x = @rewrite term x + 1 ==> Nat.increment x term (a -> f a) ==> f -- eta reduction unique type Optional2 a = Some2 a | None2 rule2 x = @rewrite signature Optional ==> Optional2 - -cleanup = do - _ = IO.removeFile.impl "/private/tmp/rewrites-tmp.u" - () ``` Let's rewrite these: @@ -46,7 +42,7 @@ Let's rewrite these: ``` ```ucm:hide -.> load /private/tmp/rewrites-tmp.u +.> load .> add ``` @@ -58,17 +54,17 @@ After adding to the codebase, here's the rewritten source: Another example, showing that we can rewrite to definitions that only exist in the file: -```unison:hide /private/tmp/rewrites-tmp.u +```unison:hide unique ability Woot1 where woot1 : () -> Nat unique ability Woot2 where woot2 : () -> Nat -woot1to2 x = @rewrite +woot1to2 x = @rewrite term Woot1.woot1 ==> Woot2.woot2 term blah ==> blah2 - signature _ . Woot1 ==> Woot2 + signature _ . Woot1 ==> Woot2 -wootEx : Nat ->{Woot1} Nat -wootEx a = +wootEx : Nat ->{Woot1} Nat +wootEx a = _ = !woot1 blah @@ -83,24 +79,24 @@ Let's apply the rewrite `woot1to2`: ``` ```ucm:hide -.> load /private/tmp/rewrites-tmp.u +.> load .> add ``` After adding the rewritten form to the codebase, here's the rewritten `Woot1` to `Woot2`: ```ucm -.> view wootEx +.> view wootEx ``` This example shows that rewrite rules can to refer to term definitions that only exist in the file: -```unison:hide /private/tmp/rewrites-tmp.u -foo1 = +```unison:hide +foo1 = b = "b" 123 -foo2 = +foo2 = a = "a" 233 @@ -109,39 +105,39 @@ rule = @rewrite term foo1 ==> foo2 case None ==> Left "89899" -sameFileEx = +sameFileEx = _ = "ex" foo1 ``` ```ucm:hide .> rewrite rule -.> load /private/tmp/rewrites-tmp.u +.> load .> add ``` After adding the rewritten form to the codebase, here's the rewritten definitions: ```ucm -.> view foo1 foo2 sameFileEx +.> view foo1 foo2 sameFileEx ``` ## Capture avoidance -```unison:hide /private/tmp/rewrites-tmp.u -bar1 = +```unison:hide +bar1 = b = "bar" 123 -bar2 = - a = 39494 +bar2 = + a = 39494 233 rule bar2 = @rewrite case None ==> Left "oh no" term bar1 ==> bar2 -sameFileEx = +sameFileEx = _ = "ex" bar1 ``` @@ -155,19 +151,19 @@ In the above example, `bar2` is locally bound by the rule, so when applied, it s Instead, it should be an unbound free variable, which doesn't typecheck: ```ucm:error -.> load /private/tmp/rewrites-tmp.u +.> load ``` In this example, the `a` is locally bound by the rule, so it shouldn't capture the `a = 39494` binding which is in scope at the point of the replacement: -```unison:hide /private/tmp/rewrites-tmp.u -bar2 = - a = 39494 +```unison:hide +bar2 = + a = 39494 233 rule a = @rewrite case None ==> Left "oh no" - term 233 ==> a + term 233 ==> a ``` ```ucm @@ -177,11 +173,7 @@ rule a = @rewrite The `a` introduced will be freshened to not capture the `a` in scope, so it remains as an unbound variable and is a type error: ```ucm:error -.> load /private/tmp/rewrites-tmp.u -``` - -```ucm:hide -.> run cleanup +.> load ``` ## Structural find @@ -195,12 +187,12 @@ eitherEx = Left ("hello", "there") ``` ```unison:hide -findEitherEx x = @rewrite term Left ("hello", x) ==> Left ("hello" Text.++ x) -findEitherFailure = @rewrite signature a . Either Failure a ==> () +findEitherEx x = @rewrite term Left ("hello", x) ==> Left ("hello" Text.++ x) +findEitherFailure = @rewrite signature a . Either Failure a ==> () ``` ```ucm .> sfind findEitherEx .> sfind findEitherFailure .> find 1-5 -``` \ No newline at end of file +``` diff --git a/unison-src/transcripts-manual/rewrites.output.md b/unison-src/transcripts-manual/rewrites.output.md index 1828a361e1..e082410087 100644 --- a/unison-src/transcripts-manual/rewrites.output.md +++ b/unison-src/transcripts-manual/rewrites.output.md @@ -1,13 +1,10 @@ ## Structural find and replace -Here's a scratch file with some rewrite rules: +Here's a scratch file with some rewrite rules: ```unison ---- -title: /private/tmp/rewrites-tmp.u ---- -ex1 = List.map (x -> x + 1) [1,2,3,4,5,6,7] +ex1 = List.map (x -> x + 1) [1,2,3,4,5,6,7] eitherToOptional e a = @rewrite @@ -22,21 +19,15 @@ Either.mapRight f = cases Left e -> Left e Right a -> Right (f a) -rule1 f x = @rewrite +rule1 f x = @rewrite term x + 1 ==> Nat.increment x term (a -> f a) ==> f -- eta reduction unique type Optional2 a = Some2 a | None2 rule2 x = @rewrite signature Optional ==> Optional2 - -cleanup = do - _ = IO.removeFile.impl "/private/tmp/rewrites-tmp.u" - () - ``` - Let's rewrite these: ```ucm @@ -46,7 +37,7 @@ Let's rewrite these: I found and replaced matches in these definitions: ex1 - The rewritten file has been added to the top of /private/tmp/rewrites-tmp.u + The rewritten file has been added to the top of scratch.u .> rewrite eitherToOptional @@ -55,9 +46,69 @@ Let's rewrite these: I found and replaced matches in these definitions: Either.mapRight - The rewritten file has been added to the top of /private/tmp/rewrites-tmp.u + The rewritten file has been added to the top of scratch.u + +``` +```unison:added-by-ucm scratch.u +-- | Rewrote using: +-- | Modified definition(s): ex1 + +ex1 = List.map Nat.increment [1, 2, 3, 4, 5, 6, 7] + +eitherToOptional e a = + @rewrite + term Left e ==> None + term Right a ==> Some a + case Left e ==> None + case Right a ==> Some a + signature e a . Either e a ==> Optional a + +Either.mapRight : (a ->{g} b) -> Either e a ->{g} Either e b +Either.mapRight f = cases + Left e -> Left e + Right a -> Right (f a) + +rule1 f x = + use Nat + + @rewrite + term x + 1 ==> Nat.increment x + term a -> f a ==> f + +type Optional2 a = Some2 a | None2 + +rule2 x = @rewrite signature Optional ==> Optional2 +``` + +```unison:added-by-ucm scratch.u +-- | Rewrote using: +-- | Modified definition(s): Either.mapRight + +ex1 = List.map Nat.increment [1, 2, 3, 4, 5, 6, 7] + +eitherToOptional e a = + @rewrite + term Left e ==> None + term Right a ==> Some a + case Left e ==> None + case Right a ==> Some a + signature e a . Either e a ==> Optional a + +Either.mapRight : (a ->{g} b) -> Optional a ->{g} Optional b +Either.mapRight f = cases + None -> None + Some a -> Some (f a) + +rule1 f x = + use Nat + + @rewrite + term x + 1 ==> Nat.increment x + term a -> f a ==> f +type Optional2 a = Some2 a | None2 + +rule2 x = @rewrite signature Optional ==> Optional2 ``` + After adding to the codebase, here's the rewritten source: ```ucm @@ -88,28 +139,23 @@ After adding to the codebase, here's the rewritten source: Another example, showing that we can rewrite to definitions that only exist in the file: ```unison ---- -title: /private/tmp/rewrites-tmp.u ---- unique ability Woot1 where woot1 : () -> Nat unique ability Woot2 where woot2 : () -> Nat -woot1to2 x = @rewrite +woot1to2 x = @rewrite term Woot1.woot1 ==> Woot2.woot2 term blah ==> blah2 - signature _ . Woot1 ==> Woot2 + signature _ . Woot1 ==> Woot2 -wootEx : Nat ->{Woot1} Nat -wootEx a = +wootEx : Nat ->{Woot1} Nat +wootEx a = _ = !woot1 blah blah = 123 blah2 = 456 - ``` - Let's apply the rewrite `woot1to2`: ```ucm @@ -119,13 +165,37 @@ Let's apply the rewrite `woot1to2`: I found and replaced matches in these definitions: wootEx - The rewritten file has been added to the top of /private/tmp/rewrites-tmp.u + The rewritten file has been added to the top of scratch.u ``` +```unison:added-by-ucm scratch.u +-- | Rewrote using: +-- | Modified definition(s): wootEx + +ability Woot1 where woot1 : '{Woot1} Nat + +ability Woot2 where woot2 : '{Woot2} Nat + +woot1to2 x = + @rewrite + term Woot1.woot1 ==> Woot2.woot2 + term blah ==> blah2 + signature _ . Woot1 ==> Woot2 + +wootEx : Nat ->{Woot2} Nat +wootEx a = + _ = !Woot2.woot2 + blah2 + +blah = 123 + +blah2 = 456 +``` + After adding the rewritten form to the codebase, here's the rewritten `Woot1` to `Woot2`: ```ucm -.> view wootEx +.> view wootEx wootEx : Nat ->{Woot2} Nat wootEx a = @@ -136,14 +206,11 @@ After adding the rewritten form to the codebase, here's the rewritten `Woot1` to This example shows that rewrite rules can to refer to term definitions that only exist in the file: ```unison ---- -title: /private/tmp/rewrites-tmp.u ---- -foo1 = +foo1 = b = "b" 123 -foo2 = +foo2 = a = "a" 233 @@ -152,17 +219,15 @@ rule = @rewrite term foo1 ==> foo2 case None ==> Left "89899" -sameFileEx = +sameFileEx = _ = "ex" foo1 - ``` - After adding the rewritten form to the codebase, here's the rewritten definitions: ```ucm -.> view foo1 foo2 sameFileEx +.> view foo1 foo2 sameFileEx foo1 : Nat foo1 = @@ -183,28 +248,23 @@ After adding the rewritten form to the codebase, here's the rewritten definition ## Capture avoidance ```unison ---- -title: /private/tmp/rewrites-tmp.u ---- -bar1 = +bar1 = b = "bar" 123 -bar2 = - a = 39494 +bar2 = + a = 39494 233 rule bar2 = @rewrite case None ==> Left "oh no" term bar1 ==> bar2 -sameFileEx = +sameFileEx = _ = "ex" bar1 - ``` - In the above example, `bar2` is locally bound by the rule, so when applied, it should not refer to the `bar2` top level binding. ```ucm @@ -214,15 +274,37 @@ In the above example, `bar2` is locally bound by the rule, so when applied, it s I found and replaced matches in these definitions: sameFileEx - The rewritten file has been added to the top of /private/tmp/rewrites-tmp.u + The rewritten file has been added to the top of scratch.u ``` +```unison:added-by-ucm scratch.u +-- | Rewrote using: +-- | Modified definition(s): sameFileEx + +bar1 = + b = "bar" + 123 + +bar2 = + a = 39494 + 233 + +rule bar2 = + @rewrite + case None ==> Left "oh no" + term bar1 ==> bar2 + +sameFileEx = + _ = "ex" + bar21 +``` + Instead, it should be an unbound free variable, which doesn't typecheck: ```ucm -.> load /private/tmp/rewrites-tmp.u +.> load - Loading changes detected in /private/tmp/rewrites-tmp.u. + Loading changes detected in scratch.u. I couldn't find any definitions matching the name bar21 inside the namespace . @@ -244,20 +326,15 @@ Instead, it should be an unbound free variable, which doesn't typecheck: In this example, the `a` is locally bound by the rule, so it shouldn't capture the `a = 39494` binding which is in scope at the point of the replacement: ```unison ---- -title: /private/tmp/rewrites-tmp.u ---- -bar2 = - a = 39494 +bar2 = + a = 39494 233 rule a = @rewrite case None ==> Left "oh no" - term 233 ==> a - + term 233 ==> a ``` - ```ucm .> rewrite rule @@ -265,15 +342,29 @@ rule a = @rewrite I found and replaced matches in these definitions: bar2 - The rewritten file has been added to the top of /private/tmp/rewrites-tmp.u + The rewritten file has been added to the top of scratch.u ``` +```unison:added-by-ucm scratch.u +-- | Rewrote using: +-- | Modified definition(s): bar2 + +bar2 = + a = 39494 + a1 + +rule a = + @rewrite + case None ==> Left "oh no" + term 233 ==> a +``` + The `a` introduced will be freshened to not capture the `a` in scope, so it remains as an unbound variable and is a type error: ```ucm -.> load /private/tmp/rewrites-tmp.u +.> load - Loading changes detected in /private/tmp/rewrites-tmp.u. + Loading changes detected in scratch.u. I couldn't find any definitions matching the name a1 inside the namespace . @@ -299,8 +390,8 @@ eitherEx = Left ("hello", "there") ``` ```unison -findEitherEx x = @rewrite term Left ("hello", x) ==> Left ("hello" Text.++ x) -findEitherFailure = @rewrite signature a . Either Failure a ==> () +findEitherEx x = @rewrite term Left ("hello", x) ==> Left ("hello" Text.++ x) +findEitherFailure = @rewrite signature a . Either Failure a ==> () ``` ```ucm diff --git a/unison-src/transcripts-round-trip/main.md b/unison-src/transcripts-round-trip/main.md index 99a3add2ae..7287a7ddba 100644 --- a/unison-src/transcripts-round-trip/main.md +++ b/unison-src/transcripts-round-trip/main.md @@ -11,7 +11,7 @@ This transcript verifies that the pretty-printer produces code that can be succe .a1> add ``` -```unison /private/tmp/roundtrip.u +```unison x = () ``` @@ -30,7 +30,7 @@ So we can see the pretty-printed output: ``` ```ucm:hide -.a2> load /private/tmp/roundtrip.u +.a2> load ``` ```ucm:hide @@ -59,7 +59,7 @@ Now check that definitions in 'reparses.u' at least parse on round trip: This just makes 'roundtrip.u' the latest scratch file. -```unison:hide /private/tmp/roundtrip.u +```unison:hide x = () ``` @@ -74,7 +74,7 @@ x = () ```ucm:hide .> move.namespace a3 a3_old .a3> copy.namespace .builtin lib.builtin -.a3> load /private/tmp/roundtrip.u +.a3> load .a3> add .a3> delete.namespace.force lib.builtin .a3_old> delete.namespace.force lib.builtin @@ -95,6 +95,6 @@ Regression test for https://github.com/unisonweb/unison/pull/3548 ```ucm:hide .> alias.term ##Nat.+ plus .> edit plus -.> load /private/tmp/roundtrip.u +.> load .> undo ``` diff --git a/unison-src/transcripts-round-trip/main.output.md b/unison-src/transcripts-round-trip/main.output.md index 5d425488fc..d7774d8712 100644 --- a/unison-src/transcripts-round-trip/main.output.md +++ b/unison-src/transcripts-round-trip/main.output.md @@ -1,21 +1,16 @@ This transcript verifies that the pretty-printer produces code that can be successfully parsed, for a variety of examples. Terms or types that fail to round-trip can be added to either `reparses-with-same-hash.u` or `reparses.u` as regression tests. ```unison ---- -title: /private/tmp/roundtrip.u ---- x = () - ``` - ```ucm - Loading changes detected in /private/tmp/roundtrip.u. + Loading changes detected in scratch.u. - I found and typechecked these definitions in - /private/tmp/roundtrip.u. If you do an `add` or `update`, - here's how your codebase would change: + 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`: @@ -29,720 +24,673 @@ So we can see the pretty-printed output: ☝️ - I added these definitions to the top of - /private/tmp/roundtrip.u + I added 105 definitions to the top of scratch.u - structural ability Abort where abort : {Abort} a - - structural ability Ask a where ask : {Ask a} a - - structural type Fix_2337 - = Fix_2337 Boolean Boolean - - structural ability Fix_2392 where zonk : {Fix_2392} Nat - - structural type Fix_2392a x y - = Oog Nat Nat (Nat, Nat) - - structural type foo.Join - = Join Boolean - | Table - | Values [Nat] - - structural type Fully.qualifiedName - = Dontcare () Nat - - structural type HandlerWebSocket x y z p q - = HandlerWebSocket x - - structural type Id a - = Id a - - structural type SomethingUnusuallyLong - = SomethingUnusuallyLong Text Text Text - - structural type UUID - = UUID Nat (Nat, Nat) - - structural ability Zoink where - nay : Text -> (Nat, Nat) ->{Zoink} Nat - yay.there : Text ->{Zoink} Nat - - (>>>>) : Nat -> Nat -> () - (>>>>) n = cases _ -> bug "" - - Abort.toDefault! : a -> '{g, Abort} a ->{g} a - Abort.toDefault! default thunk = - h x = Abort.toDefault! (handler_1778 default x) thunk - handle !thunk with h - - Abort.toOptional : '{g, Abort} a -> '{g} Optional a - Abort.toOptional thunk = do toOptional! thunk - - Abort.toOptional! : '{g, Abort} a ->{g} Optional a - Abort.toOptional! thunk = toDefault! None '(Some !thunk) - - catchAll : x -> Nat - catchAll x = 99 - - Decode.remainder : '{Ask (Optional Bytes)} Bytes - Decode.remainder = do - use Bytes ++ - match ask with - None -> Bytes.empty - Some b -> b ++ !Decode.remainder - - ex1 : Nat - ex1 = - use Foo.bar qux1 qux3 - use Nat + - a = qux3 + qux3 - qux1 + qux1 + Foo.bar.qux2 - - ex2 : Nat - ex2 = - use Foo.bar qux1 - use Nat + - a = - use Foo.bar qux3 - z = 203993 - qux3 + qux3 - qux1 + qux1 + Foo.bar.qux2 - - ex3 : () - ex3 = - a = do - use Foo.bar qux3 - use Nat + - x = qux3 + qux3 - x + x - () - - ex3a : () - ex3a = - use Foo.bar qux3 - use Nat + - a = do qux3 + qux3 - () - - fix_1035 : Text - fix_1035 = - use Text ++ - "aaaaaaaaaaaaaaaaaaaaaa" - ++ "bbbbbbbbbbbbbbbbbbbbbb" - ++ "cccccccccccccccccccccc" - ++ "dddddddddddddddddddddd" - - fix_1536 : 'Nat - fix_1536 = do - y = 0 - y - - fix_1778 : 'Optional Nat - fix_1778 = - (do - abort - 0) |> toOptional - - fix_2048 : Doc2 - fix_2048 = - {{ - **my text** __my text__ **MY_TEXT** ___MY__TEXT___ - ~~MY~TEXT~~ **MY*TEXT** - }} - - fix_2224 : [()] -> () - fix_2224 = cases - x +: (x' +: rest) -> x - _ -> () - - fix_2224a : [()] -> () - fix_2224a = cases - rest :+ x' :+ x -> () - _ -> () - - fix_2224b : [[()]] -> () - fix_2224b = cases - rest :+ (rest' :+ x) -> x - _ -> () - - fix_2271 : Doc2 - fix_2271 = - {{ # Full doc body indented - - ``` raw - myVal1 = 42 - myVal2 = 43 - myVal4 = 44 - ``` - - ``` raw - indented1= "hi" - indented2="this is two indents" - ``` - - I am two spaces over }} - - Fix_2337.f : Fix_2337 -> Boolean - Fix_2337.f = cases Fix_2337 a b -> a - - Fix_2392.f : - Nat -> Fix_2392a ('{Fix_2392} a) ('{Fix_2392} b) -> Nat - Fix_2392.f n _ = n - - fix_2650 : Nat - fix_2650 = - addNumbers : 'Nat - addNumbers = do - use Nat + - y = 12 - 13 + y - !addNumbers - - fix_2650a : tvar -> fun -> () - fix_2650a tvar fun = () - - fix_2650b : tvar -> '() - fix_2650b tvar = - do - fix_2650a tvar cases - Some _ -> - "oh boy isn't this a very very very very very very very long string?" - None -> "" - - fix_2650c : Optional Nat -> () - fix_2650c = cases - Some - loooooooooooooooooooooooooooooooooooooooooooooooooooooooong| loooooooooooooooooooooooooooooooooooooooooooooooooooooooong - == 1 -> - () - _ -> () - - fix_3110a : x -> f -> () - fix_3110a x f = - _ = 99 - () - - fix_3110b : () - fix_3110b = - fix_3110a - [1, 2, 3] (x -> let - y = Nat.increment x - ()) - - fix_3110c : () - fix_3110c = - fix_3110a [1, 2, 3] (x -> ignore (Nat.increment x)) - - fix_3110d : () - fix_3110d = fix_3110a [1, 2, 3] '(x -> do - y = Nat.increment x + You can edit them there, then run `update` to replace the + definitions currently in this namespace. + +``` +```unison:added-by-ucm scratch.u +structural ability Abort where abort : {Abort} a + +structural ability Ask a where ask : {Ask a} a + +structural type Fix_2337 + = Fix_2337 Boolean Boolean + +structural ability Fix_2392 where zonk : {Fix_2392} Nat + +structural type Fix_2392a x y + = Oog Nat Nat (Nat, Nat) + +structural type foo.Join + = Join Boolean + | Table + | Values [Nat] + +structural type Fully.qualifiedName + = Dontcare () Nat + +structural type HandlerWebSocket x y z p q + = HandlerWebSocket x + +structural type Id a + = Id a + +structural type SomethingUnusuallyLong + = SomethingUnusuallyLong Text Text Text + +structural type UUID + = UUID Nat (Nat, Nat) + +structural ability Zoink where + nay : Text -> (Nat, Nat) ->{Zoink} Nat + yay.there : Text ->{Zoink} Nat + +(>>>>) : Nat -> Nat -> () +(>>>>) n = cases _ -> bug "" + +Abort.toDefault! : a -> '{g, Abort} a ->{g} a +Abort.toDefault! default thunk = + h x = Abort.toDefault! (handler_1778 default x) thunk + handle !thunk with h + +Abort.toOptional : '{g, Abort} a -> '{g} Optional a +Abort.toOptional thunk = do toOptional! thunk + +Abort.toOptional! : '{g, Abort} a ->{g} Optional a +Abort.toOptional! thunk = toDefault! None '(Some !thunk) + +catchAll : x -> Nat +catchAll x = 99 + +Decode.remainder : '{Ask (Optional Bytes)} Bytes +Decode.remainder = do + use Bytes ++ + match ask with + None -> Bytes.empty + Some b -> b ++ !Decode.remainder + +ex1 : Nat +ex1 = + use Foo.bar qux1 qux3 + use Nat + + a = qux3 + qux3 + qux1 + qux1 + Foo.bar.qux2 + +ex2 : Nat +ex2 = + use Foo.bar qux1 + use Nat + + a = + use Foo.bar qux3 + z = 203993 + qux3 + qux3 + qux1 + qux1 + Foo.bar.qux2 + +ex3 : () +ex3 = + a = do + use Foo.bar qux3 + use Nat + + x = qux3 + qux3 + x + x + () + +ex3a : () +ex3a = + use Foo.bar qux3 + use Nat + + a = do qux3 + qux3 + () + +fix_1035 : Text +fix_1035 = + use Text ++ + "aaaaaaaaaaaaaaaaaaaaaa" + ++ "bbbbbbbbbbbbbbbbbbbbbb" + ++ "cccccccccccccccccccccc" + ++ "dddddddddddddddddddddd" + +fix_1536 : 'Nat +fix_1536 = do + y = 0 + y + +fix_1778 : 'Optional Nat +fix_1778 = + (do + abort + 0) |> toOptional + +fix_2048 : Doc2 +fix_2048 = + {{ + **my text** __my text__ **MY_TEXT** ___MY__TEXT___ ~~MY~TEXT~~ **MY*TEXT** + }} + +fix_2224 : [()] -> () +fix_2224 = cases + x +: (x' +: rest) -> x + _ -> () + +fix_2224a : [()] -> () +fix_2224a = cases + rest :+ x' :+ x -> () + _ -> () + +fix_2224b : [[()]] -> () +fix_2224b = cases + rest :+ (rest' :+ x) -> x + _ -> () + +fix_2271 : Doc2 +fix_2271 = + {{ # Full doc body indented + + ``` raw + myVal1 = 42 + myVal2 = 43 + myVal4 = 44 + ``` + + ``` raw + indented1= "hi" + indented2="this is two indents" + ``` + + I am two spaces over }} + +Fix_2337.f : Fix_2337 -> Boolean +Fix_2337.f = cases Fix_2337 a b -> a + +Fix_2392.f : Nat -> Fix_2392a ('{Fix_2392} a) ('{Fix_2392} b) -> Nat +Fix_2392.f n _ = n + +fix_2650 : Nat +fix_2650 = + addNumbers : 'Nat + addNumbers = do + use Nat + + y = 12 + 13 + y + !addNumbers + +fix_2650a : tvar -> fun -> () +fix_2650a tvar fun = () + +fix_2650b : tvar -> '() +fix_2650b tvar = + do + fix_2650a tvar cases + Some _ -> + "oh boy isn't this a very very very very very very very long string?" + None -> "" + +fix_2650c : Optional Nat -> () +fix_2650c = cases + Some loooooooooooooooooooooooooooooooooooooooooooooooooooooooong| loooooooooooooooooooooooooooooooooooooooooooooooooooooooong + == 1 -> + () + _ -> () + +fix_3110a : x -> f -> () +fix_3110a x f = + _ = 99 + () + +fix_3110b : () +fix_3110b = + fix_3110a + [1, 2, 3] (x -> let + y = Nat.increment x + ()) + +fix_3110c : () +fix_3110c = fix_3110a [1, 2, 3] (x -> ignore (Nat.increment x)) + +fix_3110d : () +fix_3110d = fix_3110a [1, 2, 3] '(x -> do + y = Nat.increment x + ()) + +fix_3627 : Nat -> Nat -> Nat +fix_3627 = cases + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -> + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + Nat.+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +fix_3710 : '(Nat, Nat, Nat, Nat, Nat, Nat) +fix_3710 = do + (a, b) = (1, 2) + (c, d) = (3, 4) + (e, f) = (5, 6) + (a, b, c, d, e, f) + +fix_3710a : (Nat, Nat, Nat, Nat, Nat, Nat) +fix_3710a = + (a, b) = (1, 2) + (c, d) = (3, 4) + (e, f) = (5, 6) + (a, b, c, d, e, f) + +fix_3710b : x -> (Nat, x, Nat, Nat, Nat, Nat) +fix_3710b x = + (a, b) = (1, x) + (c, d) = (3, 4) + (e, f) = (5, 6) + (a, b, c, d, e, f) + +fix_3710c : x -> '(Nat, x, Nat, Nat, Nat, Nat) +fix_3710c x = do + (a, b) = (1, x) + (c, d) = (3, 4) + (e, f) = (5, 6) + (a, b, c, d, e, f) + +fix_3710d : Optional a -> a +fix_3710d = cases + Some x -> x + None -> bug "oops" + +fix_4258 : x -> y -> z -> () +fix_4258 x y z = + _ = "fix_4258" + () + +fix_4258_example : () +fix_4258_example = fix_4258 1 () 2 + +fix_4340 : HandlerWebSocket (Nat ->{g, Abort} Text) y z p q +fix_4340 = HandlerWebSocket cases + 1 -> "hi sdflkj sdlfkjsdflkj sldfkj sldkfj sdf asdlkfjs dlfkj sldfkj sdf" + _ -> abort + +fix_4352 : Doc2 +fix_4352 = {{ `` +1 `` }} + +fix_4384 : Doc2 +fix_4384 = {{ {{ docExampleBlock 0 '2 }} }} + +fix_4384a : Doc2 +fix_4384a = + use Nat + + {{ {{ docExampleBlock 0 '(1 + 1) }} }} + +fix_4384b : Doc2 +fix_4384b = {{ {{ docExampleBlock 0 '99 }} }} + +fix_4384c : Doc2 +fix_4384c = + use Nat + + {{ {{ docExampleBlock 0 do + x = 1 + y = 2 + x + y }} }} + +fix_4384d : Doc2 +fix_4384d = + {{ + {{ + docExampleBlock 0 '[ 1 + , 2 + , 3 + , 4 + , 5 + , 6 + , 7 + , 8 + , 9 + , 10 + , 11 + , 12 + , 13 + , 14 + , 15 + , 16 + , 17 + , 18 + ] }} + }} + +fix_4384e : Doc2 +fix_4384e = + id : x -> x + id x = x + {{ + {{ + docExampleBlock + 0 (id id id id id id id id id id id id id id id id id id id id id (x -> 0)) + }} + }} + +Fix_525.bar.quaffle : Nat +Fix_525.bar.quaffle = 32 + +fix_525_exampleTerm : Text -> Nat +fix_525_exampleTerm quaffle = + use Nat + + bar.quaffle + 1 + +fix_525_exampleType : Id qualifiedName -> Id Fully.qualifiedName +fix_525_exampleType z = Id (Dontcare () 19) + +Foo.bar.qux1 : Nat +Foo.bar.qux1 = 42 + +Foo.bar.qux2 : Nat +Foo.bar.qux2 = 44 + +Foo.bar.qux3 : Nat +Foo.bar.qux3 = 46 + +Foo'.bar.qux1 : Text +Foo'.bar.qux1 = "43" + +Foo'.bar.qux2 : Text +Foo'.bar.qux2 = "45" + +Foo'.bar.qux3 : Text +Foo'.bar.qux3 = "47" + +forkAt : loc -> c -> Nat +forkAt loc c = + x = 99 + 390439034 + +handler_1778 : a -> Request {Abort} a -> a +handler_1778 default = cases + { a } -> a + { abort -> _ } -> default + +ignore : x -> () +ignore x = () + +longlines : x -> x +longlines x = + u = 92393 + x + +longlines1 : 'Text +longlines1 = + do + longlines + (longlines_helper + "This has to laksdjf alsdkfj alskdjf asdf be a long enough string to force a line break" ()) - - fix_3627 : Nat -> Nat -> Nat - fix_3627 = cases - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -> - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - Nat.+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb - - fix_3710 : '(Nat, Nat, Nat, Nat, Nat, Nat) - fix_3710 = do - (a, b) = (1, 2) - (c, d) = (3, 4) - (e, f) = (5, 6) - (a, b, c, d, e, f) - - fix_3710a : (Nat, Nat, Nat, Nat, Nat, Nat) - fix_3710a = - (a, b) = (1, 2) - (c, d) = (3, 4) - (e, f) = (5, 6) - (a, b, c, d, e, f) - - fix_3710b : x -> (Nat, x, Nat, Nat, Nat, Nat) - fix_3710b x = - (a, b) = (1, x) - (c, d) = (3, 4) - (e, f) = (5, 6) - (a, b, c, d, e, f) - - fix_3710c : x -> '(Nat, x, Nat, Nat, Nat, Nat) - fix_3710c x = do - (a, b) = (1, x) - (c, d) = (3, 4) - (e, f) = (5, 6) - (a, b, c, d, e, f) - - fix_3710d : Optional a -> a - fix_3710d = cases - Some x -> x - None -> bug "oops" - - fix_4258 : x -> y -> z -> () - fix_4258 x y z = - _ = "fix_4258" - () - - fix_4258_example : () - fix_4258_example = fix_4258 1 () 2 - - fix_4340 : HandlerWebSocket (Nat ->{g, Abort} Text) y z p q - fix_4340 = - HandlerWebSocket cases - 1 -> - "hi sdflkj sdlfkjsdflkj sldfkj sldkfj sdf asdlkfjs dlfkj sldfkj sdf" - _ -> abort - - fix_4352 : Doc2 - fix_4352 = {{ `` +1 `` }} - - fix_4384 : Doc2 - fix_4384 = {{ {{ docExampleBlock 0 '2 }} }} - - fix_4384a : Doc2 - fix_4384a = - use Nat + - {{ {{ docExampleBlock 0 '(1 + 1) }} }} - - fix_4384b : Doc2 - fix_4384b = {{ {{ docExampleBlock 0 '99 }} }} - - fix_4384c : Doc2 - fix_4384c = - use Nat + - {{ {{ docExampleBlock 0 do - x = 1 - y = 2 - x + y }} }} - - fix_4384d : Doc2 - fix_4384d = - {{ - {{ - docExampleBlock 0 '[ 1 - , 2 - , 3 - , 4 - , 5 - , 6 - , 7 - , 8 - , 9 - , 10 - , 11 - , 12 - , 13 - , 14 - , 15 - , 16 - , 17 - , 18 - ] }} - }} - - fix_4384e : Doc2 - fix_4384e = - id : x -> x - id x = x - {{ - {{ - docExampleBlock + +longlines2 : (Text, '{g} Bytes) +longlines2 = + ( "adsf" + , '(toUtf8 + "adsfsfdgsfdgsdfgsdfgsfdgsfdgsdgsgsgfsfgsgsfdgsgfsfdgsgfsfdgsdgsdfgsgf") + ) + +longlines_helper : x -> 'x +longlines_helper x = do x + +multiline_fn : a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> Nat +multiline_fn a b c d e f g h i j = 42 + +multiline_list : [Nat] +multiline_list = + use Nat + + [ 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + , multiline_fn + 12939233 + 2102020 + 329292 + 429292 + 522020 + 62929292 + 72020202 + 820202 + 920202 + 1020202 + ] + +nested_fences : Doc2 +nested_fences = + {{ ```` raw + ```unison + r = "boopydoo" + ``` + ```` }} + +raw_a : Text +raw_a = + """ + a + b + """ + +raw_b : Text +raw_b = + """ + a + b + c -- note blank line + + """ + +raw_c : Text +raw_c = + """ + ignored (wonky case) + Use an extra blank line if you'd like a trailing newline. Like so: + + """ + +raw_d : Text +raw_d = + """ + ignored (works great) + Use an extra blank line if you'd like a trailing newline. Like so: + + """ + +simplestPossibleExample : Nat +simplestPossibleExample = + use Nat + + 1 + 1 + +softhang : a -> b -> Nat +softhang a b = 42 + +softhang2 : x -> f -> Nat +softhang2 x f = 0 + +softhang21 : Nat +softhang21 = + use Nat + + handle + x = 1 + y = abort + x + y + with cases + { a } -> a + { abort -> _ } -> 0 + +softhang21a : Text +softhang21a = + use Nat + + handle + x = 1 + y = abort + x + y + with cases + { a } -> "lskdfjlaksjdf al;ksdjf;lkj sa;sldkfja;sldfkj a;lsdkfj asd;lfkj " + { abort -> _ } -> + "lskdfjlaksjdf al;ksdjf;lkj sa;sldkfja;sldfkj a;lsdkfj asd;lfkj " + +softhang22 : Nat +softhang22 = softhang2 [0, 1, 2, 3, 4, 5] cases + 0 -> 0 + 1 -> 1 + n -> n Nat.+ 100 + +softhang23 : 'Nat +softhang23 = do + use Nat + + catchAll do + x = 1 + y = 2 + x + y + +softhang24 : 'Nat +softhang24 = do match 0 with + 0 -> 0 + 1 -> 1 + n -> n + +softhang25 : Text +softhang25 = match Nat.increment 1 with + 2 -> "yay" + n -> "oh no" + +softhang26 : Nat +softhang26 = softhang2 [1, 2, 3, 4] cases + 0 -> 1 + n -> n Nat.+ 1 + +softhang27 : somewhere -> Nat +softhang27 somewhere = forkAt somewhere do + use Nat + + x = 1 + y = 2 + x + y + +softhang28 : Nat +softhang28 = + softhang2 [0, 1, 2, 3, 4, 5] cases + 0 -> 0 + 1 -> 1 + n -> + forkAt 0 - (id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - id - (x -> 0)) }} - }} - - Fix_525.bar.quaffle : Nat - Fix_525.bar.quaffle = 32 - - fix_525_exampleTerm : Text -> Nat - fix_525_exampleTerm quaffle = - use Nat + - bar.quaffle + 1 - - fix_525_exampleType : - Id qualifiedName -> Id Fully.qualifiedName - fix_525_exampleType z = Id (Dontcare () 19) - - Foo.bar.qux1 : Nat - Foo.bar.qux1 = 42 - - Foo.bar.qux2 : Nat - Foo.bar.qux2 = 44 - - Foo.bar.qux3 : Nat - Foo.bar.qux3 = 46 - - Foo'.bar.qux1 : Text - Foo'.bar.qux1 = "43" - - Foo'.bar.qux2 : Text - Foo'.bar.qux2 = "45" - - Foo'.bar.qux3 : Text - Foo'.bar.qux3 = "47" - - forkAt : loc -> c -> Nat - forkAt loc c = - x = 99 - 390439034 - - handler_1778 : a -> Request {Abort} a -> a - handler_1778 default = cases - { a } -> a - { abort -> _ } -> default - - ignore : x -> () - ignore x = () - - longlines : x -> x - longlines x = - u = 92393 - x - - longlines1 : 'Text - longlines1 = - do - longlines - (longlines_helper - "This has to laksdjf alsdkfj alskdjf asdf be a long enough string to force a line break" - ()) - - longlines2 : (Text, '{g} Bytes) - longlines2 = - ( "adsf" - , '(toUtf8 - "adsfsfdgsfdgsdfgsdfgsfdgsfdgsdgsgsgfsfgsgsfdgsgfsfdgsgfsfdgsdgsdfgsgf") - ) - - longlines_helper : x -> 'x - longlines_helper x = do x - - multiline_fn : - a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> Nat - multiline_fn a b c d e f g h i j = 42 - - multiline_list : [Nat] - multiline_list = - use Nat + - [ 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - + 1 - , multiline_fn - 12939233 - 2102020 - 329292 - 429292 - 522020 - 62929292 - 72020202 - 820202 - 920202 - 1020202 - ] - - nested_fences : Doc2 - nested_fences = - {{ ```` raw - ```unison - r = "boopydoo" - ``` - ```` }} - - raw_a : Text - raw_a = - """ - a - b - """ - - raw_b : Text - raw_b = - """ - a - b - c -- note blank line - - """ - - raw_c : Text - raw_c = - """ - ignored (wonky case) - Use an extra blank line if you'd like a trailing newline. Like so: - - """ - - raw_d : Text - raw_d = - """ - ignored (works great) - Use an extra blank line if you'd like a trailing newline. Like so: - - """ - - simplestPossibleExample : Nat - simplestPossibleExample = - use Nat + - 1 + 1 - - softhang : a -> b -> Nat - softhang a b = 42 - - softhang2 : x -> f -> Nat - softhang2 x f = 0 - - softhang21 : Nat - softhang21 = - use Nat + - handle - x = 1 - y = abort - x + y - with cases - { a } -> a - { abort -> _ } -> 0 - - softhang21a : Text - softhang21a = - use Nat + - handle - x = 1 - y = abort - x + y - with cases - { a } -> - "lskdfjlaksjdf al;ksdjf;lkj sa;sldkfja;sldfkj a;lsdkfj asd;lfkj " - { abort -> _ } -> - "lskdfjlaksjdf al;ksdjf;lkj sa;sldkfja;sldfkj a;lsdkfj asd;lfkj " - - softhang22 : Nat - softhang22 = softhang2 [0, 1, 2, 3, 4, 5] cases - 0 -> 0 - 1 -> 1 - n -> n Nat.+ 100 - - softhang23 : 'Nat - softhang23 = do - use Nat + - catchAll do - x = 1 - y = 2 - x + y - - softhang24 : 'Nat - softhang24 = do match 0 with - 0 -> 0 - 1 -> 1 - n -> n - - softhang25 : Text - softhang25 = match Nat.increment 1 with - 2 -> "yay" - n -> "oh no" - - softhang26 : Nat - softhang26 = softhang2 [1, 2, 3, 4] cases - 0 -> 1 - n -> n Nat.+ 1 - - softhang27 : somewhere -> Nat - softhang27 somewhere = forkAt somewhere do - use Nat + - x = 1 - y = 2 - x + y - - softhang28 : Nat - softhang28 = - softhang2 [0, 1, 2, 3, 4, 5] cases - 0 -> 0 - 1 -> 1 - n -> - forkAt - 0 - (n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n - Nat.+ n) - - softhang_a : x -> 'Nat - softhang_a x = do - use Nat + - a = 1 - b = 2 - softhang a do - c = 3 - a + b - - softhang_b : x -> 'Nat - softhang_b x = + (n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n + Nat.+ n) + +softhang_a : x -> 'Nat +softhang_a x = do + use Nat + + a = 1 + b = 2 + softhang a do + c = 3 + a + b + +softhang_b : x -> 'Nat +softhang_b x = + do + use Nat + + a = 1 + b = 2 + softhang + (100 + + 200 + + 300 + + 400 + + 500 + + 600 + + 700 + + 800 + + 900 + + 1000 + + 1100 + + 1200 + + 1300 + + 1400 + + 1500) do - use Nat + - a = 1 - b = 2 - softhang - (100 - + 200 - + 300 - + 400 - + 500 - + 600 - + 700 - + 800 - + 900 - + 1000 - + 1100 - + 1200 - + 1300 - + 1400 - + 1500) - do - c = 3 - a + b - - softhang_c : x -> 'Nat - softhang_c x = do - use Nat + - a = 1 - b = 2 - 1 + (softhang a do - c = 3 - a + b) - - softhang_d : x -> '(b -> Nat) - softhang_d x = do - use Nat + - a = 1 - b = 2 - c = softhang do - c = 3 - a + b - c - - somethingVeryLong : 'Nat - somethingVeryLong = - go x = - do - match (a -> a) x with - SomethingUnusuallyLong - lijaefliejalfijelfj aefilaeifhlei liaehjffeafijij - | lijaefliejalfijelfj == aefilaeifhlei -> 0 - | lijaefliejalfijelfj == liaehjffeafijij -> 1 - _ -> 2 - go (SomethingUnusuallyLong "one" "two" "three") - - stew_issue : () - stew_issue = - error x = () - a ++ b = 0 - toText a = a - Debug : a -> b -> () - Debug a b = () - error (Debug None '(Debug "Failed " 42)) - - stew_issue2 : () - stew_issue2 = - error x = () - a ++ b = 0 - toText a = a - Debug : a -> b -> () - Debug a b = () - error (Debug None '("Failed " ++ toText 42)) - - stew_issue3 : () - stew_issue3 = - id x = x - error x = () - a ++ b = 0 - blah x y = 99 - toText a = a - configPath = 0 - Debug a b = () - error - (Debug None '("Failed to get timestamp of config file " - ++ toText configPath)) - - test3 : '('('r)) - test3 = do - run : Nat -> a - run x = bug x - runrun = 42 - a = "asldkfj" - b = "asdflkjasdf" - ''(run runrun ''runrun) - - use_clauses_example : Int -> Text -> Nat - use_clauses_example oo quaffle = - use Nat + - bar.quaffle + bar.quaffle + 1 - - use_clauses_example2 : Int -> Nat - use_clauses_example2 oo = - use Nat + - quaffle = "hi" - bar.quaffle + bar.quaffle + bar.quaffle + 1 - - UUID.random : 'UUID - UUID.random = do UUID 0 (0, 0) - - UUID.randomUUIDBytes : 'Bytes - UUID.randomUUIDBytes = do - use Bytes ++ - (UUID a (b, _)) = !random - encodeNat64be a ++ encodeNat64be b - - (|>) : a -> (a ->{e} b) ->{e} b - a |> f = f a - - You can edit them there, then do `update` to replace the - definitions currently in this namespace. + c = 3 + a + b + +softhang_c : x -> 'Nat +softhang_c x = do + use Nat + + a = 1 + b = 2 + 1 + (softhang a do + c = 3 + a + b) + +softhang_d : x -> '(b -> Nat) +softhang_d x = do + use Nat + + a = 1 + b = 2 + c = softhang do + c = 3 + a + b + c + +somethingVeryLong : 'Nat +somethingVeryLong = + go x = + do + match (a -> a) x with + SomethingUnusuallyLong + lijaefliejalfijelfj aefilaeifhlei liaehjffeafijij + | lijaefliejalfijelfj == aefilaeifhlei -> 0 + | lijaefliejalfijelfj == liaehjffeafijij -> 1 + _ -> 2 + go (SomethingUnusuallyLong "one" "two" "three") + +stew_issue : () +stew_issue = + error x = () + a ++ b = 0 + toText a = a + Debug : a -> b -> () + Debug a b = () + error (Debug None '(Debug "Failed " 42)) + +stew_issue2 : () +stew_issue2 = + error x = () + a ++ b = 0 + toText a = a + Debug : a -> b -> () + Debug a b = () + error (Debug None '("Failed " ++ toText 42)) + +stew_issue3 : () +stew_issue3 = + id x = x + error x = () + a ++ b = 0 + blah x y = 99 + toText a = a + configPath = 0 + Debug a b = () + error + (Debug None '("Failed to get timestamp of config file " + ++ toText configPath)) +test3 : '('('r)) +test3 = do + run : Nat -> a + run x = bug x + runrun = 42 + a = "asldkfj" + b = "asdflkjasdf" + ''(run runrun ''runrun) + +use_clauses_example : Int -> Text -> Nat +use_clauses_example oo quaffle = + use Nat + + bar.quaffle + bar.quaffle + 1 + +use_clauses_example2 : Int -> Nat +use_clauses_example2 oo = + use Nat + + quaffle = "hi" + bar.quaffle + bar.quaffle + bar.quaffle + 1 + +UUID.random : 'UUID +UUID.random = do UUID 0 (0, 0) + +UUID.randomUUIDBytes : 'Bytes +UUID.randomUUIDBytes = do + use Bytes ++ + (UUID a (b, _)) = !random + encodeNat64be a ++ encodeNat64be b + +(|>) : a -> (a ->{e} b) ->{e} b +a |> f = f a ``` + This diff should be empty if the two namespaces are equivalent. If it's nonempty, the diff will show us the hashes that differ. ```ucm @@ -756,46 +704,42 @@ Now check that definitions in 'reparses.u' at least parse on round trip: This just makes 'roundtrip.u' the latest scratch file. ```unison ---- -title: /private/tmp/roundtrip.u ---- x = () - ``` - ```ucm .a3> edit 1-5000 ☝️ - I added these definitions to the top of - /private/tmp/roundtrip.u - - explanationOfThisFile : Text - explanationOfThisFile = - """ - Put definitions in here that are expected to - parse with a different hash after pretty-printing. - """ - - sloppyDocEval : Doc2 - sloppyDocEval = - use Nat + - {{ - Here's an example of an eval block that's technically a - lambda but should print as a backticked block (since old - docs in the wild still use this format). - - ``` - 1 + 1 - ``` - }} + I added 2 definitions to the top of scratch.u - You can edit them there, then do `update` to replace the + You can edit them there, then run `update` to replace the definitions currently in this namespace. ``` +```unison:added-by-ucm scratch.u +explanationOfThisFile : Text +explanationOfThisFile = + """ + Put definitions in here that are expected to + parse with a different hash after pretty-printing. + """ + +sloppyDocEval : Doc2 +sloppyDocEval = + use Nat + + {{ + Here's an example of an eval block that's technically a lambda but should + print as a backticked block (since old docs in the wild still use this + format). + + ``` + 1 + 1 + ``` + }} +``` + These are currently all expected to have different hashes on round trip. ```ucm diff --git a/unison-src/transcripts-using-base/all-base-hashes.output.md b/unison-src/transcripts-using-base/all-base-hashes.output.md index e46f81d1c9..3c027adfa9 100644 --- a/unison-src/transcripts-using-base/all-base-hashes.output.md +++ b/unison-src/transcripts-using-base/all-base-hashes.output.md @@ -29,7 +29,7 @@ This transcript is intended to make visible accidental changes to the hashing al bSplit : [(a, b)] -> a -> ([(a, b)], [(a, b)]) 9. -- #1j3e8vsn97qrprjr69ls6llab601sdh577uuvtu8pafmngf59suakbjr7asheadidcj3red140fnmdagsv9ihhdar1mc05ig28jtfr0 - unique type builtin.ANSI.Color + type builtin.ANSI.Color 10. -- #1j3e8vsn97qrprjr69ls6llab601sdh577uuvtu8pafmngf59suakbjr7asheadidcj3red140fnmdagsv9ihhdar1mc05ig28jtfr0#0 builtin.ANSI.Color.Black : Color @@ -89,7 +89,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Any.unsafeExtract : Any -> a 29. -- #345f3nptqq1c1ped6gq8578kb2bhp1jejnqborsn6fq59rpe1rren3ogia9o9u8oc339vll953inma8pocc686ooknaitud8i5m27vg - unique type builtin.Author + type builtin.Author 30. -- #345f3nptqq1c1ped6gq8578kb2bhp1jejnqborsn6fq59rpe1rren3ogia9o9u8oc339vll953inma8pocc686ooknaitud8i5m27vg#0 builtin.Author.Author : GUID -> Text -> Author @@ -345,7 +345,7 @@ This transcript is intended to make visible accidental changes to the hashing al ->{Exception} Either [Link.Term] [Link.Term] 109. -- #ldqsht5qvddaabskcad3idka4nqkv6lfncrp0s0o4rqbbnk1qvq269bueu7qobhvaf7gpluqtpn9bgp9u69jsntv0u6o4qtbktnfrs0 - unique type builtin.ConsoleText + type builtin.ConsoleText 110. -- #ldqsht5qvddaabskcad3idka4nqkv6lfncrp0s0o4rqbbnk1qvq269bueu7qobhvaf7gpluqtpn9bgp9u69jsntv0u6o4qtbktnfrs0#5 builtin.ConsoleText.Background : Color @@ -371,7 +371,7 @@ This transcript is intended to make visible accidental changes to the hashing al -> ConsoleText 116. -- #pgornst1pqaea8qmf8ckbtvrm7f6hn49djhffgebajmo12faf4jku63ftc9fp0r4k58e0qcdi77g08f34b2ihvsu97s48du6mfn7vko - unique type builtin.CopyrightHolder + type builtin.CopyrightHolder 117. -- #pgornst1pqaea8qmf8ckbtvrm7f6hn49djhffgebajmo12faf4jku63ftc9fp0r4k58e0qcdi77g08f34b2ihvsu97s48du6mfn7vko#0 builtin.CopyrightHolder.CopyrightHolder : GUID @@ -464,7 +464,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Debug.watch : Text -> a -> a 141. -- #p65rcethk26an850aaaceojremfu054hqllhoip1mt9s22584j9r62o08qo9t0pri7ssgu9m7f0rfp4nujhulgbmo41tkgl182quhd8 - unique type builtin.Doc + type builtin.Doc 142. -- #baiqeiovdrs4ju0grn5q5akq64k4kuhgifqno52smkkttqg31jkgm3qa9o3ohe54fgpiigd1tj0an7rfveopfg622sjj9v9g44n27go builtin.Doc.++ : Doc2 -> Doc2 -> Doc2 @@ -488,7 +488,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc.Source : Link -> Doc 149. -- #ej86si0ur1lsjade71dojr25phk9bbom9rdks6dltolos5tjivakujcriqe02npba53n9gd7tkh8bmv08ttjb9t35lq2ch5heshqcs0 - unique type builtin.Doc2 + type builtin.Doc2 150. -- #ej86si0ur1lsjade71dojr25phk9bbom9rdks6dltolos5tjivakujcriqe02npba53n9gd7tkh8bmv08ttjb9t35lq2ch5heshqcs0#27 builtin.Doc2.Anchor : Text -> Doc2 -> Doc2 @@ -524,7 +524,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.Folded : Boolean -> Doc2 -> Doc2 -> Doc2 161. -- #h3gajooii4tsdseghcbcsq4qq7c33mtb71u5npg35b06mgv7v654g0n55gpq212umfmq7nvi11o28m1v13r5fto5g8ium3ee4qk1i68 - unique type builtin.Doc2.FrontMatter + type builtin.Doc2.FrontMatter 162. -- #h3gajooii4tsdseghcbcsq4qq7c33mtb71u5npg35b06mgv7v654g0n55gpq212umfmq7nvi11o28m1v13r5fto5g8ium3ee4qk1i68#0 builtin.Doc2.FrontMatter.FrontMatter : [(Text, Text)] @@ -546,7 +546,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.Join : [Doc2] -> Doc2 167. -- #lpf7g5c2ct61mci2okedmug8o0i2j0rhpealc05r2musapmn15cina6dsqdvis234evvb2bo09l2p8v5qhh0me7gi1j37nqqp47qvto - unique type builtin.Doc2.LaTeXInline + type builtin.Doc2.LaTeXInline 168. -- #lpf7g5c2ct61mci2okedmug8o0i2j0rhpealc05r2musapmn15cina6dsqdvis234evvb2bo09l2p8v5qhh0me7gi1j37nqqp47qvto#0 builtin.Doc2.LaTeXInline.LaTeXInline : Text @@ -556,7 +556,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.Linebreak : Doc2 170. -- #ut0tds116gr0soc9p6nroaalqlq423u1mao3p4jjultjmok3vbck69la7rs26duptji5v5hscijpek4hotu4krbfah8np3sntr87gb0 - unique type builtin.Doc2.MediaSource + type builtin.Doc2.MediaSource 171. -- #ut0tds116gr0soc9p6nroaalqlq423u1mao3p4jjultjmok3vbck69la7rs26duptji5v5hscijpek4hotu4krbfah8np3sntr87gb0#0 builtin.Doc2.MediaSource.MediaSource : Text @@ -611,7 +611,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.Special : SpecialForm -> Doc2 184. -- #e46kdnv67raqhc4m3jnitkh3o9seq3q5mtlqnvobjlqnnd2tk7nui54b6grui7eql62fne4fo3ndetmeb23oj5es85habha5f6saoi0 - unique type builtin.Doc2.SpecialForm + type builtin.Doc2.SpecialForm 185. -- #e46kdnv67raqhc4m3jnitkh3o9seq3q5mtlqnvobjlqnnd2tk7nui54b6grui7eql62fne4fo3ndetmeb23oj5es85habha5f6saoi0#4 builtin.Doc2.SpecialForm.Embed : Any -> SpecialForm @@ -667,7 +667,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.Style : Text -> Doc2 -> Doc2 198. -- #sv2cta4p4th10h7tpurvr0t6s3cbahlevvmpadk01v32e39kse8aicdvfsm2dbk6ltc68ht788jvkfhk6ol2mch7eubngtug019e8fg - unique type builtin.Doc2.Svg + type builtin.Doc2.Svg 199. -- #sv2cta4p4th10h7tpurvr0t6s3cbahlevvmpadk01v32e39kse8aicdvfsm2dbk6ltc68ht788jvkfhk6ol2mch7eubngtug019e8fg#0 builtin.Doc2.Svg.Svg : Text -> Svg @@ -676,7 +676,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.Table : [[Doc2]] -> Doc2 201. -- #s0an21vospbdlsbddiskuvt3ngbf00n78sip2o1mnp4jgp16i7sursbm14bf8ap7osphqbis2lduep3i29b7diu8sf03f8tlqd7rgcg - unique type builtin.Doc2.Term + type builtin.Doc2.Term 202. -- #42hub6f3fn0p5fk8t5bb2njhbgg5dj75vtqijvins6h45pkorakbu3g8h312ghu98ee4h75tb61fti192ckpk9cpdle9hsr8pdthkjo builtin.Doc2.term : '{g} a -> Doc2.Term @@ -691,7 +691,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Doc2.UntitledSection : [Doc2] -> Doc2 206. -- #794fndq1941e2khqv5uh7fmk9es2g4fkp8pr48objgs6blc1pqsdt2ab4o79noril2l7s70iu2eimn1smpd8t40j4g18btian8a2pt0 - unique type builtin.Doc2.Video + type builtin.Doc2.Video 207. -- #46er7fsgre91rer0mpk6vhaa2vie19i0piubvtnfmt3vq7odcjfr6tlf0mc57q4jnij9rkolpekjd6dpqdotn41guk9lp9qioa88m58 builtin.Doc2.Video.config : Video -> [(Text, Text)] @@ -870,7 +870,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Float.truncate : Float -> Int 260. -- #hqectlr3gt02r6r984b3627eg5bq3d82lab5q18e3ql09u1ka8dblf5k50ae0q0d8gk87udqd7b6767q86gogdt8ghpdiq77gk6blr8 - unique type builtin.GUID + type builtin.GUID 261. -- #hqectlr3gt02r6r984b3627eg5bq3d82lab5q18e3ql09u1ka8dblf5k50ae0q0d8gk87udqd7b6767q86gogdt8ghpdiq77gk6blr8#0 builtin.GUID.GUID : Bytes -> GUID @@ -1039,13 +1039,13 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Int.xor : Int -> Int -> Int 308. -- #s6ijmhqkkaus51chjgahogc7sdrqj9t66i599le2k7ts6fkl216f997hbses3mqk6a21vaj3cm1mertbldn0g503jt522vfo4rfv720 - unique type builtin.io2.ArithmeticFailure + type builtin.io2.ArithmeticFailure 309. -- #6dtvam7msqc64dimm8p0d8ehdf0330o4qbd2fdafb11jj1c2rg4ke3jdcmbgo6s4pf2jgm0vb76jeavv4ba6ht71t74p963a1miekag - unique type builtin.io2.ArrayFailure + type builtin.io2.ArrayFailure 310. -- #dc6n5ebu839ik3b6ohmnqm6p0cifn7o94em1g41mjp4ae0gmv3b4rupba499lbasfrp4bqce9u4hd6518unlbg8vk993c0q6rigos98 - unique type builtin.io2.BufferMode + type builtin.io2.BufferMode 311. -- #dc6n5ebu839ik3b6ohmnqm6p0cifn7o94em1g41mjp4ae0gmv3b4rupba499lbasfrp4bqce9u4hd6518unlbg8vk993c0q6rigos98#2 builtin.io2.BufferMode.BlockBuffering : BufferMode @@ -1090,7 +1090,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin type builtin.io2.Clock.internals.TimeSpec 323. -- #r29dja8j9dmjjp45trccchaata8eo1h6d6haar1eai74pq1jt4m7u3ldhlq79f7phfo57eq4bau39vqotl2h63k7ff1m5sj5o9ajuf8 - unique type builtin.io2.Failure + type builtin.io2.Failure 324. -- #r29dja8j9dmjjp45trccchaata8eo1h6d6haar1eai74pq1jt4m7u3ldhlq79f7phfo57eq4bau39vqotl2h63k7ff1m5sj5o9ajuf8#0 builtin.io2.Failure.Failure : Type @@ -1099,7 +1099,7 @@ This transcript is intended to make visible accidental changes to the hashing al -> Failure 325. -- #jhnlob35huv3rr7jg6aa4gtd8okhprla7gvlq8io429qita8vj7k696n9jvp4b8ct9i2pc1jodb8ap2bipqtgp138epdgfcth7vqvt8 - unique type builtin.io2.FileMode + type builtin.io2.FileMode 326. -- #jhnlob35huv3rr7jg6aa4gtd8okhprla7gvlq8io429qita8vj7k696n9jvp4b8ct9i2pc1jodb8ap2bipqtgp138epdgfcth7vqvt8#2 builtin.io2.FileMode.Append : FileMode @@ -1360,7 +1360,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.io2.IO.tryEval : '{IO} a ->{IO, Exception} a 391. -- #h4smnou0l3fg4dn92g2r88j0imfvufjerkgbuscvvmaprv12l22nk6sff3c12edlikb2vfg3vfdj4b23a09q4lvtk75ckbe4lsmtuc0 - unique type builtin.io2.IOError + type builtin.io2.IOError 392. -- #h4smnou0l3fg4dn92g2r88j0imfvufjerkgbuscvvmaprv12l22nk6sff3c12edlikb2vfg3vfdj4b23a09q4lvtk75ckbe4lsmtuc0#0 builtin.io2.IOError.AlreadyExists : IOError @@ -1387,10 +1387,10 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.io2.IOError.UserError : IOError 400. -- #6ivk1e38hh0l9gcl8fn4mhf8bmak3qaji36vevg5e1n16ju5i4cl9u5gmqi7u16b907rd98gd60pouma892efbqt2ri58tmu99hp77g - unique type builtin.io2.IOFailure + type builtin.io2.IOFailure 401. -- #574pvphqahl981k517dtrqtq812m05h3hj6t2bt9sn3pknenfik1krscfdb6r66nf1sm7g3r1r56k0c6ob7vg4opfq4gihi8njbnhsg - unique type builtin.io2.MiscFailure + type builtin.io2.MiscFailure 402. -- ##MVar builtin type builtin.io2.MVar @@ -1468,13 +1468,13 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.io2.Ref.Ticket.read : Ticket a -> a 423. -- #vph2eas3lf2gi259f3khlrspml3id2l8u0ru07kb5fd833h238jk4iauju0b6decth9i3nao5jkf5eej1e1kovgmu5tghhh8jq3i7p8 - unique type builtin.io2.RuntimeFailure + type builtin.io2.RuntimeFailure 424. -- ##sandboxLinks builtin.io2.sandboxLinks : Link.Term ->{IO} [Link.Term] 425. -- #1bca3hq98sfgr6a4onuon1tsda69cdjggq8pkmlsfola6492dbrih5up6dv18ptfbqeocm9q6parf64pj773p7p19qe76238o4trc40 - unique type builtin.io2.SeekMode + type builtin.io2.SeekMode 426. -- #1bca3hq98sfgr6a4onuon1tsda69cdjggq8pkmlsfola6492dbrih5up6dv18ptfbqeocm9q6parf64pj773p7p19qe76238o4trc40#0 builtin.io2.SeekMode.AbsoluteSeek : SeekMode @@ -1489,7 +1489,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin type builtin.io2.Socket 430. -- #121tku5rfh21t247v1cakhd6ir44fakkqsm799rrfp5qcjdls4nvdu4r3nco80stdd86tdo2hhh0ulcpoaofnrnkjun04kqnfmjqio8 - unique type builtin.io2.StdHandle + type builtin.io2.StdHandle 431. -- #121tku5rfh21t247v1cakhd6ir44fakkqsm799rrfp5qcjdls4nvdu4r3nco80stdd86tdo2hhh0ulcpoaofnrnkjun04kqnfmjqio8#2 builtin.io2.StdHandle.StdErr : StdHandle @@ -1510,13 +1510,13 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.io2.STM.retry : '{STM} a 437. -- #cggbdfff21ac5uedf4qvn4to83clinvhsovrila35u7f7e73g4l6hoj8pjmjnk713a8luhnn4bi1j9ai1nl0can1un66hvg230eog9g - unique type builtin.io2.STMFailure + type builtin.io2.STMFailure 438. -- ##ThreadId builtin type builtin.io2.ThreadId 439. -- #ggh649864d9bfnk90n7kgtj7dflddc4kn8osu7u7mub8p7l8biid8dgtungj4u005h7karbgupfpum9jp94spks3ma1sgh39bhirv38 - unique type builtin.io2.ThreadKilledFailure + type builtin.io2.ThreadKilledFailure 440. -- ##Tls builtin type builtin.io2.Tls @@ -1620,7 +1620,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin type builtin.io2.Tls.Version 465. -- #r3gag1btclr8iclbdt68irgt8n1d1vf7agv5umke3dgdbl11acj6easav6gtihanrjnct18om07638rne9ej06u2bkv2v4l36knm2l0 - unique type builtin.io2.TlsFailure + type builtin.io2.TlsFailure 466. -- ##TVar builtin type builtin.io2.TVar @@ -1654,19 +1654,19 @@ This transcript is intended to make visible accidental changes to the hashing al ->{IO} Either [Link.Term] [Link.Term] 475. -- #c23jofurcegj93796o0karmkcm6baifupiuu1rtkniu74avn6a4r1n66ga5rml5di7easkgn4iak800u3tnb6kfisbrv6tcfgkb13a8 - unique type builtin.IsPropagated + type builtin.IsPropagated 476. -- #c23jofurcegj93796o0karmkcm6baifupiuu1rtkniu74avn6a4r1n66ga5rml5di7easkgn4iak800u3tnb6kfisbrv6tcfgkb13a8#0 builtin.IsPropagated.IsPropagated : IsPropagated 477. -- #q6snodsh7i7u6k7gtqj73tt7nv6htjofs5f37vg2v3dsfk6hau71fs5mcv0hq3lqg111fsvoi92mngm08850aftfgh65uka9mhqvft0 - unique type builtin.IsTest + type builtin.IsTest 478. -- #q6snodsh7i7u6k7gtqj73tt7nv6htjofs5f37vg2v3dsfk6hau71fs5mcv0hq3lqg111fsvoi92mngm08850aftfgh65uka9mhqvft0#0 builtin.IsTest.IsTest : IsTest 479. -- #68haromionghg6cvojngjrgc7t0ob658nkk8b20fpho6k6ltjtf6rfmr4ia1omige97hk34lu21qsj933vl1dkpbna7evbjfkh71r9g - unique type builtin.License + type builtin.License 480. -- #knhl4mlkqf0mt877flahlbas2ufb7bub8f11vi9ihh9uf7r6jqaglk7rm6912q1vml50866ddl0qfa4o6d7o0gomchaoae24m0u2nk8 builtin.License.copyrightHolders : License @@ -1715,13 +1715,13 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.License.years.set : [Year] -> License -> License 490. -- #uj652rrb45urfnojgt1ssqoji7iiibu27uhrc1sfl68lm54hbr7r1dpgppsv0pvf0oile2uk2h2gn1h4vgng30fga66idihhen14qc0 - unique type builtin.LicenseType + type builtin.LicenseType 491. -- #uj652rrb45urfnojgt1ssqoji7iiibu27uhrc1sfl68lm54hbr7r1dpgppsv0pvf0oile2uk2h2gn1h4vgng30fga66idihhen14qc0#0 builtin.LicenseType.LicenseType : Doc -> LicenseType 492. -- #f4b37niu61dc517c32h3os36ig34fgnt7inaaoqdbecmscchthi14gdo0vj3eee1ru746ibvl9vnmm1pglrv3125qnhsbc0i1tqtic0 - unique type builtin.Link + type builtin.Link 493. -- ##Link.Term builtin type builtin.Link.Term @@ -2023,7 +2023,7 @@ This transcript is intended to make visible accidental changes to the hashing al structural type builtin.Pretty txt 576. -- #fqfaur9v9v4fks5d0c74ouitpjp121c3fbu2l9t05km8otjcj43gk453vu668pg54rte6qmh4v3uao6vbfpntrtaq057jgni1jk8fj8 - unique type builtin.Pretty.Annotated w txt + type builtin.Pretty.Annotated w txt 577. -- #fqfaur9v9v4fks5d0c74ouitpjp121c3fbu2l9t05km8otjcj43gk453vu668pg54rte6qmh4v3uao6vbfpntrtaq057jgni1jk8fj8#1 builtin.Pretty.Annotated.Append : w @@ -2134,7 +2134,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin type builtin.Request 603. -- #bga77hj5p43epjosu36iero5ulpm7hqrct1slj5ivdcajsr52ksjam8d5smq2965netv9t43o3g0amgva26qoatt4qth29khkuds2t0 - unique type builtin.RewriteCase a b + type builtin.RewriteCase a b 604. -- #bga77hj5p43epjosu36iero5ulpm7hqrct1slj5ivdcajsr52ksjam8d5smq2965netv9t43o3g0amgva26qoatt4qth29khkuds2t0#0 builtin.RewriteCase.RewriteCase : a @@ -2142,13 +2142,13 @@ This transcript is intended to make visible accidental changes to the hashing al -> RewriteCase a b 605. -- #qcot4bpj2skgnui8hoignn6fl2gnn2nfrur451ft2egd5n1ndu6ti4uu7r1mvtc8r4p7iielfijk2mb7md9tt2m2rdvaikah4oluf7o - unique type builtin.Rewrites a + type builtin.Rewrites a 606. -- #qcot4bpj2skgnui8hoignn6fl2gnn2nfrur451ft2egd5n1ndu6ti4uu7r1mvtc8r4p7iielfijk2mb7md9tt2m2rdvaikah4oluf7o#0 builtin.Rewrites.Rewrites : a -> Rewrites a 607. -- #nu6eab37fl81lb5hfcainu83hph0ksqjsjgjbqvc3t8o13djtt5511qfa6tuggc5c3re06c5p6eto5o2cqme0jdlo31nnd13npqigjo - unique type builtin.RewriteSignature a b + type builtin.RewriteSignature a b 608. -- #nu6eab37fl81lb5hfcainu83hph0ksqjsjgjbqvc3t8o13djtt5511qfa6tuggc5c3re06c5p6eto5o2cqme0jdlo31nnd13npqigjo#0 builtin.RewriteSignature.RewriteSignature : (a @@ -2157,7 +2157,7 @@ This transcript is intended to make visible accidental changes to the hashing al -> RewriteSignature a b 609. -- #bvffhraos4oatd3qmedt676dqul9c1oj8r4cqns36lsrue84kl0ote15iqbbmgu8joek3gce1h2raqas5b9nnvs2d79l9mrpmmi2sf0 - unique type builtin.RewriteTerm a b + type builtin.RewriteTerm a b 610. -- #bvffhraos4oatd3qmedt676dqul9c1oj8r4cqns36lsrue84kl0ote15iqbbmgu8joek3gce1h2raqas5b9nnvs2d79l9mrpmmi2sf0#0 builtin.RewriteTerm.RewriteTerm : a @@ -2327,7 +2327,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.syntax.docWord : Text -> Doc2 660. -- #aql7qk3iud6vs4cvu43aimopoosgk0fnipibdkc3so13adencmibgfn0u5c01r0adei55nkl3ttsjhl8gbj7tr4gnpj63g64ftbq6s0 - unique type builtin.Test.Result + type builtin.Test.Result 661. -- #aql7qk3iud6vs4cvu43aimopoosgk0fnipibdkc3so13adencmibgfn0u5c01r0adei55nkl3ttsjhl8gbj7tr4gnpj63g64ftbq6s0#0 builtin.Test.Result.Fail : Text -> Result @@ -2511,7 +2511,7 @@ This transcript is intended to make visible accidental changes to the hashing al builtin.Value.value : a -> Value 720. -- #dem6aglnj8cppfrnq9qipl7geo5pim3auo9cmv1rhh5la9edalj19sspbpm1pd4vh0plokdh6qfo48gs034dqlg0s7j9fhr9p9ndtpo - unique type builtin.Year + type builtin.Year 721. -- #dem6aglnj8cppfrnq9qipl7geo5pim3auo9cmv1rhh5la9edalj19sspbpm1pd4vh0plokdh6qfo48gs034dqlg0s7j9fhr9p9ndtpo#0 builtin.Year.Year : Nat -> Year diff --git a/unison-src/transcripts-using-base/binary-encoding-nats.output.md b/unison-src/transcripts-using-base/binary-encoding-nats.output.md index 0648296e03..773d53a245 100644 --- a/unison-src/transcripts-using-base/binary-encoding-nats.output.md +++ b/unison-src/transcripts-using-base/binary-encoding-nats.output.md @@ -64,7 +64,7 @@ testABunchOfNats _ = ⍟ These new definitions are ok to `add`: - unique type EncDec + type EncDec BE16 : EncDec BE32 : EncDec BE64 : EncDec @@ -81,7 +81,7 @@ testABunchOfNats _ = ⍟ I've added these definitions: - unique type EncDec + type EncDec BE16 : EncDec BE32 : EncDec BE64 : EncDec diff --git a/unison-src/transcripts-using-base/doc.output.md b/unison-src/transcripts-using-base/doc.output.md index ac966b95af..892687f38b 100644 --- a/unison-src/transcripts-using-base/doc.output.md +++ b/unison-src/transcripts-using-base/doc.output.md @@ -38,7 +38,7 @@ unique type time.DayOfWeek = Sun | Mon | Tue | Wed | Thu | Fri | Sat ⍟ These new definitions are ok to `add`: - unique type time.DayOfWeek + type time.DayOfWeek ImportantConstant : Nat ImportantConstant.doc : Doc2 d1 : Doc2 @@ -63,14 +63,7 @@ You can preview what docs will look like when rendered to the console using the The 7 days of the week, defined as: - unique type DayOfWeek - = Sun - | Mon - | Tue - | Wed - | Thu - | Fri - | Sat + type DayOfWeek = Sun | Mon | Tue | Wed | Thu | Fri | Sat ``` The `docs ImportantConstant` command will look for `ImportantConstant.doc` in the file or codebase. You can do this instead of explicitly linking docs to definitions. diff --git a/unison-src/transcripts-using-base/fix2297.md b/unison-src/transcripts-using-base/fix2297.md index 2ecd676850..26c2108d2a 100644 --- a/unison-src/transcripts-using-base/fix2297.md +++ b/unison-src/transcripts-using-base/fix2297.md @@ -2,12 +2,12 @@ This tests a case where a function was somehow discarding abilities. ```unison:error -ability Trivial where +structural ability Trivial where trivial : () -- This handler SHOULD leave any additional effects alone and unhandled handleTrivial : '{e, Trivial} a -> {e} a -handleTrivial action = +handleTrivial action = h : Request {Trivial} a -> a h = cases {trivial -> resume} -> handle !resume with h @@ -15,8 +15,8 @@ handleTrivial action = handle !action with h testAction : '{Exception, IO, Trivial} () -testAction _ = - printText "hi!" +testAction = do + printLine "hi!" trivial wat : () diff --git a/unison-src/transcripts-using-base/fix2297.output.md b/unison-src/transcripts-using-base/fix2297.output.md index a381f4afb0..70f0fa13df 100644 --- a/unison-src/transcripts-using-base/fix2297.output.md +++ b/unison-src/transcripts-using-base/fix2297.output.md @@ -2,12 +2,12 @@ This tests a case where a function was somehow discarding abilities. ```unison -ability Trivial where +structural ability Trivial where trivial : () -- This handler SHOULD leave any additional effects alone and unhandled handleTrivial : '{e, Trivial} a -> {e} a -handleTrivial action = +handleTrivial action = h : Request {Trivial} a -> a h = cases {trivial -> resume} -> handle !resume with h @@ -15,8 +15,8 @@ handleTrivial action = handle !action with h testAction : '{Exception, IO, Trivial} () -testAction _ = - printText "hi!" +testAction = do + printLine "hi!" trivial wat : () @@ -29,13 +29,9 @@ wat = handleTrivial testAction -- Somehow this completely forgets about Excepti Loading changes detected in scratch.u. - I expected to see `structural` or `unique` at the start of - this line: + The expression in red needs the {Exception} ability, but this location does not have access to any abilities. - 1 | ability Trivial where + 19 | wat = handleTrivial testAction -- Somehow this completely forgets about Exception and IO - Learn more about when to use `structural` vs `unique` in the - Unison Docs: - https://www.unison-lang.org/learn/language-reference/unique-types/ ``` diff --git a/unison-src/transcripts-using-base/hashing.md b/unison-src/transcripts-using-base/hashing.md index 56240777d5..3016771a73 100644 --- a/unison-src/transcripts-using-base/hashing.md +++ b/unison-src/transcripts-using-base/hashing.md @@ -55,7 +55,7 @@ And here's the full API: Note that the universal versions of `hash` and `hmac` are currently unimplemented and will bomb at runtime: ```unison -> crypto.hash Sha3_256 (fromHex "3849238492") +> hash Sha3_256 (fromHex "3849238492") ``` ## Hashing tests diff --git a/unison-src/transcripts-using-base/hashing.output.md b/unison-src/transcripts-using-base/hashing.output.md index 0be98abc05..85fd626ee2 100644 --- a/unison-src/transcripts-using-base/hashing.output.md +++ b/unison-src/transcripts-using-base/hashing.output.md @@ -122,7 +122,7 @@ And here's the full API: ```ucm .builtin.crypto> find - 1. hash : HashAlgorithm -> a -> Bytes + 1. hash : HashAlgorithm -> a -> ##Bytes 2. builtin type HashAlgorithm 3. HashAlgorithm.Blake2b_256 : HashAlgorithm 4. HashAlgorithm.Blake2b_512 : HashAlgorithm @@ -133,9 +133,9 @@ And here's the full API: 9. HashAlgorithm.Sha2_512 : HashAlgorithm 10. HashAlgorithm.Sha3_256 : HashAlgorithm 11. HashAlgorithm.Sha3_512 : HashAlgorithm - 12. hashBytes : HashAlgorithm -> Bytes -> Bytes - 13. hmac : HashAlgorithm -> Bytes -> a -> Bytes - 14. hmacBytes : HashAlgorithm -> Bytes -> Bytes -> Bytes + 12. hashBytes : HashAlgorithm -> ##Bytes -> ##Bytes + 13. hmac : HashAlgorithm -> ##Bytes -> a -> ##Bytes + 14. hmacBytes : HashAlgorithm -> ##Bytes -> ##Bytes -> ##Bytes .> cd . @@ -144,7 +144,7 @@ And here's the full API: Note that the universal versions of `hash` and `hmac` are currently unimplemented and will bomb at runtime: ```unison -> crypto.hash Sha3_256 (fromHex "3849238492") +> hash Sha3_256 (fromHex "3849238492") ``` ```ucm @@ -158,7 +158,7 @@ Note that the universal versions of `hash` and `hmac` are currently unimplemente Now evaluating any watch expressions (lines starting with `>`)... Ctrl+C cancels. - 1 | > crypto.hash Sha3_256 (fromHex "3849238492") + 1 | > hash Sha3_256 (fromHex "3849238492") ⧩ 0xs1259de8ec2c8b925dce24f591ed5cc1d1a5dc01cf88cf8f2343fc9728e124af4 diff --git a/unison-src/transcripts-using-base/namespace-dependencies.md b/unison-src/transcripts-using-base/namespace-dependencies.md index 57f7e4e28c..9a625e42a8 100644 --- a/unison-src/transcripts-using-base/namespace-dependencies.md +++ b/unison-src/transcripts-using-base/namespace-dependencies.md @@ -1,27 +1,15 @@ # namespace.dependencies command ```ucm:hide -.> builtins.merge +.external> builtins.merge ``` ```unison:hide -myMetadata = "just some text" -``` - -```ucm:hide -.metadata> add -.> cd . -``` - -```unison:hide -dependsOnNat = 1 -dependsOnInt = -1 -dependsOnIntAndNat = Nat.drop 1 10 -hasMetadata = 3 +external.mynat = 1 +mynamespace.dependsOnText = external.mynat Nat.+ 10 ``` ```ucm -.dependencies> add -.dependencies> link .metadata.myMetadata hasMetadata -.dependencies> namespace.dependencies +.> add +.mynamespace> namespace.dependencies ``` diff --git a/unison-src/transcripts-using-base/namespace-dependencies.output.md b/unison-src/transcripts-using-base/namespace-dependencies.output.md index 53cfb44a55..caf4dc52c7 100644 --- a/unison-src/transcripts-using-base/namespace-dependencies.output.md +++ b/unison-src/transcripts-using-base/namespace-dependencies.output.md @@ -1,44 +1,25 @@ # namespace.dependencies command ```unison -myMetadata = "just some text" -``` - -```unison -dependsOnNat = 1 -dependsOnInt = -1 -dependsOnIntAndNat = Nat.drop 1 10 -hasMetadata = 3 +external.mynat = 1 +mynamespace.dependsOnText = external.mynat Nat.+ 10 ``` ```ucm - ☝️ The namespace .dependencies is empty. - -.dependencies> add +.> add ⍟ I've added these definitions: - dependsOnInt : Int - dependsOnIntAndNat : Nat - dependsOnNat : Nat - hasMetadata : Nat - -.dependencies> link .metadata.myMetadata hasMetadata - - Updates: - - 1. dependencies.hasMetadata : Nat - + 2. myMetadata : Text + external.mynat : Nat + mynamespace.dependsOnText : Nat -.dependencies> namespace.dependencies +.mynamespace> namespace.dependencies - External dependency Dependents in .dependencies - builtin.Int 1. dependsOnInt + External dependency Dependents in .mynamespace + .builtin.Nat 1. dependsOnText - builtin.Nat 2. dependsOnIntAndNat - 3. dependsOnNat - 4. hasMetadata + .builtin.Nat.+ 1. dependsOnText - builtin.Nat.drop 2. dependsOnIntAndNat + .external.mynat 1. dependsOnText ``` diff --git a/unison-src/transcripts-using-base/update-test-to-non-test.md b/unison-src/transcripts-using-base/update-test-to-non-test.md deleted file mode 100644 index 4a20ff5f7e..0000000000 --- a/unison-src/transcripts-using-base/update-test-to-non-test.md +++ /dev/null @@ -1,18 +0,0 @@ -When updating a term from a test to a non-test, we don't delete its metadata that indicates it's a test. This is a bug. - -```unison -test> foo = [] -``` - -```ucm -.> add -``` - -```unison -foo = 1 -``` - -```ucm -.> update.old -.> links foo -``` diff --git a/unison-src/transcripts/abilities.output.md b/unison-src/transcripts/abilities.output.md index f9e873b6a1..c90d76a45d 100644 --- a/unison-src/transcripts/abilities.output.md +++ b/unison-src/transcripts/abilities.output.md @@ -27,7 +27,7 @@ ha = cases ⍟ These new definitions are ok to `add`: - unique ability A + ability A ha : Request {A} r -> r ``` @@ -36,7 +36,7 @@ ha = cases ⍟ I've added these definitions: - unique ability A + ability A ha : Request {A} r -> r ``` diff --git a/unison-src/transcripts/ability-order-doesnt-affect-hash.output.md b/unison-src/transcripts/ability-order-doesnt-affect-hash.output.md index e686d0402d..879dc0c624 100644 --- a/unison-src/transcripts/ability-order-doesnt-affect-hash.output.md +++ b/unison-src/transcripts/ability-order-doesnt-affect-hash.output.md @@ -24,8 +24,8 @@ term2 _ = () ⍟ These new definitions are ok to `add`: - unique ability Bar - unique ability Foo + ability Bar + ability Foo term1 : '{Bar, Foo} () term2 : '{Bar, Foo} () @@ -35,8 +35,8 @@ term2 _ = () ⍟ I've added these definitions: - unique ability Bar - unique ability Foo + ability Bar + ability Foo term1 : '{Bar, Foo} () term2 : '{Bar, Foo} () diff --git a/unison-src/transcripts/ability-term-conflicts-on-update.md b/unison-src/transcripts/ability-term-conflicts-on-update.md index bc83bc0eb1..04810a4939 100644 --- a/unison-src/transcripts/ability-term-conflicts-on-update.md +++ b/unison-src/transcripts/ability-term-conflicts-on-update.md @@ -3,7 +3,7 @@ https://github.com/unisonweb/unison/issues/2786 ```ucm:hide -.builtins> builtins.mergeio +.ns> builtins.merge ``` First we add an ability to the codebase. @@ -68,6 +68,11 @@ We should also be able to successfully update the whole thing. # Constructor-term conflict +```ucm:hide +.ns2> builtins.merge +``` + + ```unison X.x = 1 ``` diff --git a/unison-src/transcripts/ability-term-conflicts-on-update.output.md b/unison-src/transcripts/ability-term-conflicts-on-update.output.md index 1f7a7d7c7e..901446e8d4 100644 --- a/unison-src/transcripts/ability-term-conflicts-on-update.output.md +++ b/unison-src/transcripts/ability-term-conflicts-on-update.output.md @@ -20,17 +20,15 @@ unique ability Channels where ⍟ These new definitions are ok to `add`: - unique ability Channels + ability Channels ``` ```ucm - ☝️ The namespace .ns is empty. - .ns> add ⍟ I've added these definitions: - unique ability Channels + ability Channels ``` Now we update the ability, changing the name of the constructor, _but_, we simultaneously @@ -64,7 +62,7 @@ thing _ = send 1 ⍟ These names already exist. You can `update` them to your new definition: - unique ability Channels + ability Channels ``` These should fail with a term/ctor conflict since we exclude the ability from the update. @@ -88,7 +86,7 @@ These should fail with a term/ctor conflict since we exclude the ability from th ⍟ I've updated these names to your new definition: - unique ability Channels + ability Channels ``` If however, `Channels.send` and `thing` _depend_ on `Channels`, updating them should succeed since it pulls in the ability as a dependency. @@ -185,8 +183,6 @@ X.x = 1 ``` ```ucm - ☝️ The namespace .ns2 is empty. - .ns2> add ⍟ I've added these definitions: diff --git a/unison-src/transcripts/add-run.output.md b/unison-src/transcripts/add-run.output.md index 18684e406c..3d97788e78 100644 --- a/unison-src/transcripts/add-run.output.md +++ b/unison-src/transcripts/add-run.output.md @@ -302,7 +302,7 @@ main = '5 .> view .an.absolute.name - an.absolute.name : Nat - an.absolute.name = 5 + .an.absolute.name : Nat + .an.absolute.name = 5 ``` diff --git a/unison-src/transcripts/alias-many.md b/unison-src/transcripts/alias-many.md index bd92d3bf31..4acc3feef5 100644 --- a/unison-src/transcripts/alias-many.md +++ b/unison-src/transcripts/alias-many.md @@ -95,7 +95,7 @@ List.takeWhile p xs = go xs [] ``` ```ucm:hide -.runar> add +.stuff> add ``` The `alias.many` command can be used to copy definitions from the current namespace into your curated one. @@ -113,17 +113,8 @@ The names that will be used in the target namespace are the names you specify, r Let's try it! ```ucm -.> cd .builtin -.builtin> find -.builtin> alias.many 94-104 .mylib -``` - -I want to incorporate a few more from another namespace: -```ucm -.builtin> cd .runar -.runar> find -.runar> alias.many 1-15 .mylib -.runar> cd .mylib +.> alias.many stuff.List.adjacentPairs stuff.List.all stuff.List.any stuff.List.chunk stuff.List.chunksOf stuff.List.dropWhile stuff.List.first stuff.List.init stuff.List.intersperse stuff.List.isEmpty stuff.List.last stuff.List.replicate stuff.List.splitAt stuff.List.tail stuff.List.takeWhile .mylib +.> cd .mylib .mylib> find ``` diff --git a/unison-src/transcripts/alias-many.output.md b/unison-src/transcripts/alias-many.output.md index 60ce7ba186..5647e14eee 100644 --- a/unison-src/transcripts/alias-many.output.md +++ b/unison-src/transcripts/alias-many.output.md @@ -14,809 +14,65 @@ The names that will be used in the target namespace are the names you specify, r Let's try it! ```ucm -.> cd .builtin - -.builtin> find - - 1. builtin type Any - 2. Any.Any : a -> Any - 3. Any.unsafeExtract : Any -> a - 4. builtin type Boolean - 5. Boolean.not : Boolean -> Boolean - 6. bug : a -> b - 7. builtin type Bytes - 8. Bytes.++ : Bytes -> Bytes -> Bytes - 9. Bytes.at : Nat -> Bytes -> Optional Nat - 10. Bytes.decodeNat16be : Bytes -> Optional (Nat, Bytes) - 11. Bytes.decodeNat16le : Bytes -> Optional (Nat, Bytes) - 12. Bytes.decodeNat32be : Bytes -> Optional (Nat, Bytes) - 13. Bytes.decodeNat32le : Bytes -> Optional (Nat, Bytes) - 14. Bytes.decodeNat64be : Bytes -> Optional (Nat, Bytes) - 15. Bytes.decodeNat64le : Bytes -> Optional (Nat, Bytes) - 16. Bytes.drop : Nat -> Bytes -> Bytes - 17. Bytes.empty : Bytes - 18. Bytes.encodeNat16be : Nat -> Bytes - 19. Bytes.encodeNat16le : Nat -> Bytes - 20. Bytes.encodeNat32be : Nat -> Bytes - 21. Bytes.encodeNat32le : Nat -> Bytes - 22. Bytes.encodeNat64be : Nat -> Bytes - 23. Bytes.encodeNat64le : Nat -> Bytes - 24. Bytes.flatten : Bytes -> Bytes - 25. Bytes.fromBase16 : Bytes -> Either Text Bytes - 26. Bytes.fromBase32 : Bytes -> Either Text Bytes - 27. Bytes.fromBase64 : Bytes -> Either Text Bytes - 28. Bytes.fromBase64UrlUnpadded : Bytes -> Either Text Bytes - 29. Bytes.fromList : [Nat] -> Bytes - 30. Bytes.gzip.compress : Bytes -> Bytes - 31. Bytes.gzip.decompress : Bytes -> Either Text Bytes - 32. Bytes.indexOf : Bytes -> Bytes -> Optional Nat - 33. Bytes.size : Bytes -> Nat - 34. Bytes.take : Nat -> Bytes -> Bytes - 35. Bytes.toBase16 : Bytes -> Bytes - 36. Bytes.toBase32 : Bytes -> Bytes - 37. Bytes.toBase64 : Bytes -> Bytes - 38. Bytes.toBase64UrlUnpadded : Bytes -> Bytes - 39. Bytes.toList : Bytes -> [Nat] - 40. Bytes.zlib.compress : Bytes -> Bytes - 41. Bytes.zlib.decompress : Bytes -> Either Text Bytes - 42. builtin type Char - 43. builtin type Char.Class - 44. Char.Class.alphanumeric : Class - 45. Char.Class.and : Class -> Class -> Class - 46. Char.Class.any : Class - 47. Char.Class.anyOf : [Char] -> Class - 48. Char.Class.control : Class - 49. Char.Class.is : Class -> Char -> Boolean - 50. Char.Class.letter : Class - 51. Char.Class.lower : Class - 52. Char.Class.mark : Class - 53. Char.Class.not : Class -> Class - 54. Char.Class.number : Class - 55. Char.Class.or : Class -> Class -> Class - 56. Char.Class.printable : Class - 57. Char.Class.punctuation : Class - 58. Char.Class.range : Char -> Char -> Class - 59. Char.Class.separator : Class - 60. Char.Class.symbol : Class - 61. Char.Class.upper : Class - 62. Char.Class.whitespace : Class - 63. Char.fromNat : Nat -> Char - 64. Char.toNat : Char -> Nat - 65. Char.toText : Char -> Text - 66. builtin type Code - 67. Code.cache_ : [(Term, Code)] ->{IO} [Term] - 68. Code.dependencies : Code -> [Term] - 69. Code.deserialize : Bytes -> Either Text Code - 70. Code.display : Text -> Code -> Text - 71. Code.isMissing : Term ->{IO} Boolean - 72. Code.lookup : Term ->{IO} Optional Code - 73. Code.serialize : Code -> Bytes - 74. Code.validate : [(Term, Code)] ->{IO} Optional Failure - 75. Code.validateLinks : [(Term, Code)] - ->{Exception} Either [Term] [Term] - 76. crypto.hash : HashAlgorithm -> a -> Bytes - 77. builtin type crypto.HashAlgorithm - 78. crypto.HashAlgorithm.Blake2b_256 : HashAlgorithm - 79. crypto.HashAlgorithm.Blake2b_512 : HashAlgorithm - 80. crypto.HashAlgorithm.Blake2s_256 : HashAlgorithm - 81. crypto.HashAlgorithm.Md5 : HashAlgorithm - 82. crypto.HashAlgorithm.Sha1 : HashAlgorithm - 83. crypto.HashAlgorithm.Sha2_256 : HashAlgorithm - 84. crypto.HashAlgorithm.Sha2_512 : HashAlgorithm - 85. crypto.HashAlgorithm.Sha3_256 : HashAlgorithm - 86. crypto.HashAlgorithm.Sha3_512 : HashAlgorithm - 87. crypto.hashBytes : HashAlgorithm -> Bytes -> Bytes - 88. crypto.hmac : HashAlgorithm -> Bytes -> a -> Bytes - 89. crypto.hmacBytes : HashAlgorithm - -> Bytes - -> Bytes - -> Bytes - 90. Debug.toText : a -> Optional (Either Text Text) - 91. Debug.trace : Text -> a -> () - 92. Debug.watch : Text -> a -> a - 93. unique type Doc - 94. Doc.Blob : Text -> Doc - 95. Doc.Evaluate : Term -> Doc - 96. Doc.Join : [Doc] -> Doc - 97. Doc.Link : Link -> Doc - 98. Doc.Signature : Term -> Doc - 99. Doc.Source : Link -> Doc - 100. structural type Either a b - 101. Either.Left : a -> Either a b - 102. Either.Right : b -> Either a b - 103. structural ability Exception - 104. Exception.raise : Failure ->{Exception} x - 105. builtin type Float - 106. Float.* : Float -> Float -> Float - 107. Float.+ : Float -> Float -> Float - 108. Float.- : Float -> Float -> Float - 109. Float./ : Float -> Float -> Float - 110. Float.abs : Float -> Float - 111. Float.acos : Float -> Float - 112. Float.acosh : Float -> Float - 113. Float.asin : Float -> Float - 114. Float.asinh : Float -> Float - 115. Float.atan : Float -> Float - 116. Float.atan2 : Float -> Float -> Float - 117. Float.atanh : Float -> Float - 118. Float.ceiling : Float -> Int - 119. Float.cos : Float -> Float - 120. Float.cosh : Float -> Float - 121. Float.eq : Float -> Float -> Boolean - 122. Float.exp : Float -> Float - 123. Float.floor : Float -> Int - 124. Float.fromRepresentation : Nat -> Float - 125. Float.fromText : Text -> Optional Float - 126. Float.gt : Float -> Float -> Boolean - 127. Float.gteq : Float -> Float -> Boolean - 128. Float.log : Float -> Float - 129. Float.logBase : Float -> Float -> Float - 130. Float.lt : Float -> Float -> Boolean - 131. Float.lteq : Float -> Float -> Boolean - 132. Float.max : Float -> Float -> Float - 133. Float.min : Float -> Float -> Float - 134. Float.pow : Float -> Float -> Float - 135. Float.round : Float -> Int - 136. Float.sin : Float -> Float - 137. Float.sinh : Float -> Float - 138. Float.sqrt : Float -> Float - 139. Float.tan : Float -> Float - 140. Float.tanh : Float -> Float - 141. Float.toRepresentation : Float -> Nat - 142. Float.toText : Float -> Text - 143. Float.truncate : Float -> Int - 144. Handle.toText : Handle -> Text - 145. builtin type ImmutableArray - 146. ImmutableArray.copyTo! : MutableArray g a - -> Nat - -> ImmutableArray a - -> Nat - -> Nat - ->{g, Exception} () - 147. ImmutableArray.read : ImmutableArray a - -> Nat - ->{Exception} a - 148. ImmutableArray.size : ImmutableArray a -> Nat - 149. builtin type ImmutableByteArray - 150. ImmutableByteArray.copyTo! : MutableByteArray g - -> Nat - -> ImmutableByteArray - -> Nat - -> Nat - ->{g, Exception} () - 151. ImmutableByteArray.read16be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 152. ImmutableByteArray.read24be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 153. ImmutableByteArray.read32be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 154. ImmutableByteArray.read40be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 155. ImmutableByteArray.read64be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 156. ImmutableByteArray.read8 : ImmutableByteArray - -> Nat - ->{Exception} Nat - 157. ImmutableByteArray.size : ImmutableByteArray -> Nat - 158. builtin type Int - 159. Int.* : Int -> Int -> Int - 160. Int.+ : Int -> Int -> Int - 161. Int.- : Int -> Int -> Int - 162. Int./ : Int -> Int -> Int - 163. Int.and : Int -> Int -> Int - 164. Int.complement : Int -> Int - 165. Int.eq : Int -> Int -> Boolean - 166. Int.fromRepresentation : Nat -> Int - 167. Int.fromText : Text -> Optional Int - 168. Int.gt : Int -> Int -> Boolean - 169. Int.gteq : Int -> Int -> Boolean - 170. Int.increment : Int -> Int - 171. Int.isEven : Int -> Boolean - 172. Int.isOdd : Int -> Boolean - 173. Int.leadingZeros : Int -> Nat - 174. Int.lt : Int -> Int -> Boolean - 175. Int.lteq : Int -> Int -> Boolean - 176. Int.mod : Int -> Int -> Int - 177. Int.negate : Int -> Int - 178. Int.or : Int -> Int -> Int - 179. Int.popCount : Int -> Nat - 180. Int.pow : Int -> Nat -> Int - 181. Int.shiftLeft : Int -> Nat -> Int - 182. Int.shiftRight : Int -> Nat -> Int - 183. Int.signum : Int -> Int - 184. Int.toFloat : Int -> Float - 185. Int.toRepresentation : Int -> Nat - 186. Int.toText : Int -> Text - 187. Int.trailingZeros : Int -> Nat - 188. Int.truncate0 : Int -> Nat - 189. Int.xor : Int -> Int -> Int - 190. unique type io2.ArithmeticFailure - 191. unique type io2.ArrayFailure - 192. unique type io2.BufferMode - 193. io2.BufferMode.BlockBuffering : BufferMode - 194. io2.BufferMode.LineBuffering : BufferMode - 195. io2.BufferMode.NoBuffering : BufferMode - 196. io2.BufferMode.SizedBlockBuffering : Nat -> BufferMode - 197. io2.Clock.internals.monotonic : '{IO} Either - Failure TimeSpec - 198. io2.Clock.internals.nsec : TimeSpec -> Nat - 199. io2.Clock.internals.processCPUTime : '{IO} Either - Failure TimeSpec - 200. io2.Clock.internals.realtime : '{IO} Either - Failure TimeSpec - 201. io2.Clock.internals.sec : TimeSpec -> Int - 202. io2.Clock.internals.systemTimeZone : Int - ->{IO} ( Int, - Nat, - Text) - 203. io2.Clock.internals.threadCPUTime : '{IO} Either - Failure TimeSpec - 204. builtin type io2.Clock.internals.TimeSpec - 205. unique type io2.Failure - 206. io2.Failure.Failure : Type -> Text -> Any -> Failure - 207. unique type io2.FileMode - 208. io2.FileMode.Append : FileMode - 209. io2.FileMode.Read : FileMode - 210. io2.FileMode.ReadWrite : FileMode - 211. io2.FileMode.Write : FileMode - 212. builtin type io2.Handle - 213. builtin type io2.IO - 214. io2.IO.array : Nat ->{IO} MutableArray {IO} a - 215. io2.IO.arrayOf : a -> Nat ->{IO} MutableArray {IO} a - 216. io2.IO.bytearray : Nat ->{IO} MutableByteArray {IO} - 217. io2.IO.bytearrayOf : Nat - -> Nat - ->{IO} MutableByteArray {IO} - 218. io2.IO.clientSocket.impl : Text - -> Text - ->{IO} Either Failure Socket - 219. io2.IO.closeFile.impl : Handle ->{IO} Either Failure () - 220. io2.IO.closeSocket.impl : Socket ->{IO} Either Failure () - 221. io2.IO.createDirectory.impl : Text - ->{IO} Either Failure () - 222. io2.IO.createTempDirectory.impl : Text - ->{IO} Either - Failure Text - 223. io2.IO.delay.impl : Nat ->{IO} Either Failure () - 224. io2.IO.directoryContents.impl : Text - ->{IO} Either - Failure [Text] - 225. io2.IO.fileExists.impl : Text - ->{IO} Either Failure Boolean - 226. io2.IO.forkComp : '{IO} a ->{IO} ThreadId - 227. io2.IO.getArgs.impl : '{IO} Either Failure [Text] - 228. io2.IO.getBuffering.impl : Handle - ->{IO} Either - Failure BufferMode - 229. io2.IO.getBytes.impl : Handle - -> Nat - ->{IO} Either Failure Bytes - 230. io2.IO.getChar.impl : Handle ->{IO} Either Failure Char - 231. io2.IO.getCurrentDirectory.impl : '{IO} Either - Failure Text - 232. io2.IO.getEcho.impl : Handle - ->{IO} Either Failure Boolean - 233. io2.IO.getEnv.impl : Text ->{IO} Either Failure Text - 234. io2.IO.getFileSize.impl : Text ->{IO} Either Failure Nat - 235. io2.IO.getFileTimestamp.impl : Text - ->{IO} Either Failure Nat - 236. io2.IO.getLine.impl : Handle ->{IO} Either Failure Text - 237. io2.IO.getSomeBytes.impl : Handle - -> Nat - ->{IO} Either Failure Bytes - 238. io2.IO.getTempDirectory.impl : '{IO} Either Failure Text - 239. io2.IO.handlePosition.impl : Handle - ->{IO} Either Failure Nat - 240. io2.IO.isDirectory.impl : Text - ->{IO} Either Failure Boolean - 241. io2.IO.isFileEOF.impl : Handle - ->{IO} Either Failure Boolean - 242. io2.IO.isFileOpen.impl : Handle - ->{IO} Either Failure Boolean - 243. io2.IO.isSeekable.impl : Handle - ->{IO} Either Failure Boolean - 244. io2.IO.kill.impl : ThreadId ->{IO} Either Failure () - 245. io2.IO.listen.impl : Socket ->{IO} Either Failure () - 246. io2.IO.openFile.impl : Text - -> FileMode - ->{IO} Either Failure Handle - 247. io2.IO.process.call : Text -> [Text] ->{IO} Nat - 248. io2.IO.process.exitCode : ProcessHandle - ->{IO} Optional Nat - 249. io2.IO.process.kill : ProcessHandle ->{IO} () - 250. io2.IO.process.start : Text - -> [Text] - ->{IO} ( Handle, - Handle, - Handle, - ProcessHandle) - 251. io2.IO.process.wait : ProcessHandle ->{IO} Nat - 252. io2.IO.putBytes.impl : Handle - -> Bytes - ->{IO} Either Failure () - 253. io2.IO.randomBytes : Nat ->{IO} Bytes - 254. io2.IO.ready.impl : Handle ->{IO} Either Failure Boolean - 255. io2.IO.ref : a ->{IO} Ref {IO} a - 256. io2.IO.removeDirectory.impl : Text - ->{IO} Either Failure () - 257. io2.IO.removeFile.impl : Text ->{IO} Either Failure () - 258. io2.IO.renameDirectory.impl : Text - -> Text - ->{IO} Either Failure () - 259. io2.IO.renameFile.impl : Text - -> Text - ->{IO} Either Failure () - 260. io2.IO.seekHandle.impl : Handle - -> SeekMode - -> Int - ->{IO} Either Failure () - 261. io2.IO.serverSocket.impl : Optional Text - -> Text - ->{IO} Either Failure Socket - 262. io2.IO.setBuffering.impl : Handle - -> BufferMode - ->{IO} Either Failure () - 263. io2.IO.setCurrentDirectory.impl : Text - ->{IO} Either - Failure () - 264. io2.IO.setEcho.impl : Handle - -> Boolean - ->{IO} Either Failure () - 265. io2.IO.socketAccept.impl : Socket - ->{IO} Either Failure Socket - 266. io2.IO.socketPort.impl : Socket ->{IO} Either Failure Nat - 267. io2.IO.socketReceive.impl : Socket - -> Nat - ->{IO} Either Failure Bytes - 268. io2.IO.socketSend.impl : Socket - -> Bytes - ->{IO} Either Failure () - 269. io2.IO.stdHandle : StdHandle -> Handle - 270. io2.IO.systemTime.impl : '{IO} Either Failure Nat - 271. io2.IO.systemTimeMicroseconds : '{IO} Int - 272. io2.IO.tryEval : '{IO} a ->{IO, Exception} a - 273. unique type io2.IOError - 274. io2.IOError.AlreadyExists : IOError - 275. io2.IOError.EOF : IOError - 276. io2.IOError.IllegalOperation : IOError - 277. io2.IOError.NoSuchThing : IOError - 278. io2.IOError.PermissionDenied : IOError - 279. io2.IOError.ResourceBusy : IOError - 280. io2.IOError.ResourceExhausted : IOError - 281. io2.IOError.UserError : IOError - 282. unique type io2.IOFailure - 283. unique type io2.MiscFailure - 284. builtin type io2.MVar - 285. io2.MVar.isEmpty : MVar a ->{IO} Boolean - 286. io2.MVar.new : a ->{IO} MVar a - 287. io2.MVar.newEmpty : '{IO} MVar a - 288. io2.MVar.put.impl : MVar a -> a ->{IO} Either Failure () - 289. io2.MVar.read.impl : MVar a ->{IO} Either Failure a - 290. io2.MVar.swap.impl : MVar a -> a ->{IO} Either Failure a - 291. io2.MVar.take.impl : MVar a ->{IO} Either Failure a - 292. io2.MVar.tryPut.impl : MVar a - -> a - ->{IO} Either Failure Boolean - 293. io2.MVar.tryRead.impl : MVar a - ->{IO} Either - Failure (Optional a) - 294. io2.MVar.tryTake : MVar a ->{IO} Optional a - 295. builtin type io2.ProcessHandle - 296. builtin type io2.Promise - 297. io2.Promise.new : '{IO} Promise a - 298. io2.Promise.read : Promise a ->{IO} a - 299. io2.Promise.tryRead : Promise a ->{IO} Optional a - 300. io2.Promise.write : Promise a -> a ->{IO} Boolean - 301. io2.Ref.cas : Ref {IO} a -> Ticket a -> a ->{IO} Boolean - 302. io2.Ref.readForCas : Ref {IO} a ->{IO} Ticket a - 303. builtin type io2.Ref.Ticket - 304. io2.Ref.Ticket.read : Ticket a -> a - 305. unique type io2.RuntimeFailure - 306. io2.sandboxLinks : Term ->{IO} [Term] - 307. unique type io2.SeekMode - 308. io2.SeekMode.AbsoluteSeek : SeekMode - 309. io2.SeekMode.RelativeSeek : SeekMode - 310. io2.SeekMode.SeekFromEnd : SeekMode - 311. builtin type io2.Socket - 312. unique type io2.StdHandle - 313. io2.StdHandle.StdErr : StdHandle - 314. io2.StdHandle.StdIn : StdHandle - 315. io2.StdHandle.StdOut : StdHandle - 316. builtin type io2.STM - 317. io2.STM.atomically : '{STM} a ->{IO} a - 318. io2.STM.retry : '{STM} a - 319. unique type io2.STMFailure - 320. builtin type io2.ThreadId - 321. unique type io2.ThreadKilledFailure - 322. builtin type io2.Tls - 323. builtin type io2.Tls.Cipher - 324. builtin type io2.Tls.ClientConfig - 325. io2.Tls.ClientConfig.certificates.set : [SignedCert] - -> ClientConfig - -> ClientConfig - 326. io2.TLS.ClientConfig.ciphers.set : [Cipher] - -> ClientConfig - -> ClientConfig - 327. io2.Tls.ClientConfig.default : Text - -> Bytes - -> ClientConfig - 328. io2.Tls.ClientConfig.versions.set : [Version] - -> ClientConfig - -> ClientConfig - 329. io2.Tls.decodeCert.impl : Bytes - -> Either Failure SignedCert - 330. io2.Tls.decodePrivateKey : Bytes -> [PrivateKey] - 331. io2.Tls.encodeCert : SignedCert -> Bytes - 332. io2.Tls.encodePrivateKey : PrivateKey -> Bytes - 333. io2.Tls.handshake.impl : Tls ->{IO} Either Failure () - 334. io2.Tls.newClient.impl : ClientConfig - -> Socket - ->{IO} Either Failure Tls - 335. io2.Tls.newServer.impl : ServerConfig - -> Socket - ->{IO} Either Failure Tls - 336. builtin type io2.Tls.PrivateKey - 337. io2.Tls.receive.impl : Tls ->{IO} Either Failure Bytes - 338. io2.Tls.send.impl : Tls -> Bytes ->{IO} Either Failure () - 339. builtin type io2.Tls.ServerConfig - 340. io2.Tls.ServerConfig.certificates.set : [SignedCert] - -> ServerConfig - -> ServerConfig - 341. io2.Tls.ServerConfig.ciphers.set : [Cipher] - -> ServerConfig - -> ServerConfig - 342. io2.Tls.ServerConfig.default : [SignedCert] - -> PrivateKey - -> ServerConfig - 343. io2.Tls.ServerConfig.versions.set : [Version] - -> ServerConfig - -> ServerConfig - 344. builtin type io2.Tls.SignedCert - 345. io2.Tls.terminate.impl : Tls ->{IO} Either Failure () - 346. builtin type io2.Tls.Version - 347. unique type io2.TlsFailure - 348. builtin type io2.TVar - 349. io2.TVar.new : a ->{STM} TVar a - 350. io2.TVar.newIO : a ->{IO} TVar a - 351. io2.TVar.read : TVar a ->{STM} a - 352. io2.TVar.readIO : TVar a ->{IO} a - 353. io2.TVar.swap : TVar a -> a ->{STM} a - 354. io2.TVar.write : TVar a -> a ->{STM} () - 355. io2.validateSandboxed : [Term] -> a -> Boolean - 356. io2.Value.validateSandboxed : [Term] - -> Value - ->{IO} Either [Term] [Term] - 357. unique type IsPropagated - 358. IsPropagated.IsPropagated : IsPropagated - 359. unique type IsTest - 360. IsTest.IsTest : IsTest - 361. unique type Link - 362. builtin type Link.Term - 363. Link.Term : Term -> Link - 364. Link.Term.toText : Term -> Text - 365. builtin type Link.Type - 366. Link.Type : Type -> Link - 367. builtin type List - 368. List.++ : [a] -> [a] -> [a] - 369. List.+: : a -> [a] -> [a] - 370. List.:+ : [a] -> a -> [a] - 371. List.at : Nat -> [a] -> Optional a - 372. List.cons : a -> [a] -> [a] - 373. List.drop : Nat -> [a] -> [a] - 374. List.empty : [a] - 375. List.size : [a] -> Nat - 376. List.snoc : [a] -> a -> [a] - 377. List.take : Nat -> [a] -> [a] - 378. metadata.isPropagated : IsPropagated - 379. metadata.isTest : IsTest - 380. builtin type MutableArray - 381. MutableArray.copyTo! : MutableArray g a - -> Nat - -> MutableArray g a - -> Nat - -> Nat - ->{g, Exception} () - 382. MutableArray.freeze : MutableArray g a - -> Nat - -> Nat - ->{g} ImmutableArray a - 383. MutableArray.freeze! : MutableArray g a - ->{g} ImmutableArray a - 384. MutableArray.read : MutableArray g a - -> Nat - ->{g, Exception} a - 385. MutableArray.size : MutableArray g a -> Nat - 386. MutableArray.write : MutableArray g a - -> Nat - -> a - ->{g, Exception} () - 387. builtin type MutableByteArray - 388. MutableByteArray.copyTo! : MutableByteArray g - -> Nat - -> MutableByteArray g - -> Nat - -> Nat - ->{g, Exception} () - 389. MutableByteArray.freeze : MutableByteArray g - -> Nat - -> Nat - ->{g} ImmutableByteArray - 390. MutableByteArray.freeze! : MutableByteArray g - ->{g} ImmutableByteArray - 391. MutableByteArray.read16be : MutableByteArray g - -> Nat - ->{g, Exception} Nat - 392. MutableByteArray.read24be : MutableByteArray g - -> Nat - ->{g, Exception} Nat - 393. MutableByteArray.read32be : MutableByteArray g - -> Nat - ->{g, Exception} Nat - 394. MutableByteArray.read40be : MutableByteArray g - -> Nat - ->{g, Exception} Nat - 395. MutableByteArray.read64be : MutableByteArray g - -> Nat - ->{g, Exception} Nat - 396. MutableByteArray.read8 : MutableByteArray g - -> Nat - ->{g, Exception} Nat - 397. MutableByteArray.size : MutableByteArray g -> Nat - 398. MutableByteArray.write16be : MutableByteArray g - -> Nat - -> Nat - ->{g, Exception} () - 399. MutableByteArray.write32be : MutableByteArray g - -> Nat - -> Nat - ->{g, Exception} () - 400. MutableByteArray.write64be : MutableByteArray g - -> Nat - -> Nat - ->{g, Exception} () - 401. MutableByteArray.write8 : MutableByteArray g - -> Nat - -> Nat - ->{g, Exception} () - 402. builtin type Nat - 403. Nat.* : Nat -> Nat -> Nat - 404. Nat.+ : Nat -> Nat -> Nat - 405. Nat./ : Nat -> Nat -> Nat - 406. Nat.and : Nat -> Nat -> Nat - 407. Nat.complement : Nat -> Nat - 408. Nat.drop : Nat -> Nat -> Nat - 409. Nat.eq : Nat -> Nat -> Boolean - 410. Nat.fromText : Text -> Optional Nat - 411. Nat.gt : Nat -> Nat -> Boolean - 412. Nat.gteq : Nat -> Nat -> Boolean - 413. Nat.increment : Nat -> Nat - 414. Nat.isEven : Nat -> Boolean - 415. Nat.isOdd : Nat -> Boolean - 416. Nat.leadingZeros : Nat -> Nat - 417. Nat.lt : Nat -> Nat -> Boolean - 418. Nat.lteq : Nat -> Nat -> Boolean - 419. Nat.mod : Nat -> Nat -> Nat - 420. Nat.or : Nat -> Nat -> Nat - 421. Nat.popCount : Nat -> Nat - 422. Nat.pow : Nat -> Nat -> Nat - 423. Nat.shiftLeft : Nat -> Nat -> Nat - 424. Nat.shiftRight : Nat -> Nat -> Nat - 425. Nat.sub : Nat -> Nat -> Int - 426. Nat.toFloat : Nat -> Float - 427. Nat.toInt : Nat -> Int - 428. Nat.toText : Nat -> Text - 429. Nat.trailingZeros : Nat -> Nat - 430. Nat.xor : Nat -> Nat -> Nat - 431. structural type Optional a - 432. Optional.None : Optional a - 433. Optional.Some : a -> Optional a - 434. builtin type Pattern - 435. Pattern.capture : Pattern a -> Pattern a - 436. Pattern.captureAs : a -> Pattern a -> Pattern a - 437. Pattern.isMatch : Pattern a -> a -> Boolean - 438. Pattern.join : [Pattern a] -> Pattern a - 439. Pattern.many : Pattern a -> Pattern a - 440. Pattern.or : Pattern a -> Pattern a -> Pattern a - 441. Pattern.replicate : Nat -> Nat -> Pattern a -> Pattern a - 442. Pattern.run : Pattern a -> a -> Optional ([a], a) - 443. builtin type Ref - 444. Ref.read : Ref g a ->{g} a - 445. Ref.write : Ref g a -> a ->{g} () - 446. builtin type Request - 447. unique type RewriteCase a b - 448. RewriteCase.RewriteCase : a -> b -> RewriteCase a b - 449. unique type Rewrites a - 450. Rewrites.Rewrites : a -> Rewrites a - 451. unique type RewriteSignature a b - 452. RewriteSignature.RewriteSignature : (a -> b -> ()) - -> RewriteSignature - a b - 453. unique type RewriteTerm a b - 454. RewriteTerm.RewriteTerm : a -> b -> RewriteTerm a b - 455. builtin type Scope - 456. Scope.array : Nat ->{Scope s} MutableArray (Scope s) a - 457. Scope.arrayOf : a - -> Nat - ->{Scope s} MutableArray (Scope s) a - 458. Scope.bytearray : Nat - ->{Scope s} MutableByteArray (Scope s) - 459. Scope.bytearrayOf : Nat - -> Nat - ->{Scope s} MutableByteArray - (Scope s) - 460. Scope.ref : a ->{Scope s} Ref {Scope s} a - 461. Scope.run : (∀ s. '{g, Scope s} r) ->{g} r - 462. structural type SeqView a b - 463. SeqView.VElem : a -> b -> SeqView a b - 464. SeqView.VEmpty : SeqView a b - 465. Socket.toText : Socket -> Text - 466. unique type Test.Result - 467. Test.Result.Fail : Text -> Result - 468. Test.Result.Ok : Text -> Result - 469. builtin type Text - 470. Text.!= : Text -> Text -> Boolean - 471. Text.++ : Text -> Text -> Text - 472. Text.drop : Nat -> Text -> Text - 473. Text.empty : Text - 474. Text.eq : Text -> Text -> Boolean - 475. Text.fromCharList : [Char] -> Text - 476. Text.fromUtf8.impl : Bytes -> Either Failure Text - 477. Text.gt : Text -> Text -> Boolean - 478. Text.gteq : Text -> Text -> Boolean - 479. Text.indexOf : Text -> Text -> Optional Nat - 480. Text.lt : Text -> Text -> Boolean - 481. Text.lteq : Text -> Text -> Boolean - 482. Text.patterns.anyChar : Pattern Text - 483. Text.patterns.char : Class -> Pattern Text - 484. Text.patterns.charIn : [Char] -> Pattern Text - 485. Text.patterns.charRange : Char -> Char -> Pattern Text - 486. Text.patterns.digit : Pattern Text - 487. Text.patterns.eof : Pattern Text - 488. Text.patterns.letter : Pattern Text - 489. Text.patterns.literal : Text -> Pattern Text - 490. Text.patterns.notCharIn : [Char] -> Pattern Text - 491. Text.patterns.notCharRange : Char -> Char -> Pattern Text - 492. Text.patterns.punctuation : Pattern Text - 493. Text.patterns.space : Pattern Text - 494. Text.repeat : Nat -> Text -> Text - 495. Text.reverse : Text -> Text - 496. Text.size : Text -> Nat - 497. Text.take : Nat -> Text -> Text - 498. Text.toCharList : Text -> [Char] - 499. Text.toLowercase : Text -> Text - 500. Text.toUppercase : Text -> Text - 501. Text.toUtf8 : Text -> Bytes - 502. Text.uncons : Text -> Optional (Char, Text) - 503. Text.unsnoc : Text -> Optional (Text, Char) - 504. ThreadId.toText : ThreadId -> Text - 505. todo : a -> b - 506. structural type Tuple a b - 507. Tuple.Cons : a -> b -> Tuple a b - 508. structural type Unit - 509. Unit.Unit : () - 510. Universal.< : a -> a -> Boolean - 511. Universal.<= : a -> a -> Boolean - 512. Universal.== : a -> a -> Boolean - 513. Universal.> : a -> a -> Boolean - 514. Universal.>= : a -> a -> Boolean - 515. Universal.compare : a -> a -> Int - 516. Universal.murmurHash : a -> Nat - 517. unsafe.coerceAbilities : (a ->{e1} b) -> a -> b - 518. builtin type Value - 519. Value.dependencies : Value -> [Term] - 520. Value.deserialize : Bytes -> Either Text Value - 521. Value.load : Value ->{IO} Either [Term] a - 522. Value.serialize : Value -> Bytes - 523. Value.value : a -> Value - - -.builtin> alias.many 94-104 .mylib - - Here's what changed in .mylib : - - Added definitions: - - 1. structural type Either a b - 2. structural ability Exception - 3. Doc.Blob : Text -> Doc - 4. Doc.Evaluate : Term -> Doc - 5. Doc.Join : [Doc] -> Doc - 6. Either.Left : a -> Either a b - 7. Doc.Link : Link -> Doc - 8. Either.Right : b -> Either a b - 9. Doc.Signature : Term -> Doc - 10. Doc.Source : Link -> Doc - 11. Exception.raise : Failure ->{Exception} x - - Tip: You can use `undo` or `reflog` to undo this change. - -``` -I want to incorporate a few more from another namespace: -```ucm -.builtin> cd .runar - -.runar> find - - 1. List.adjacentPairs : [a] -> [(a, a)] - 2. List.all : (a ->{g} Boolean) -> [a] ->{g} Boolean - 3. List.any : (a ->{g} Boolean) -> [a] ->{g} Boolean - 4. List.chunk : Nat -> [a] -> [[a]] - 5. List.chunksOf : Nat -> [a] -> [[a]] - 6. List.dropWhile : (a ->{g} Boolean) -> [a] ->{g} [a] - 7. List.first : [a] -> Optional a - 8. List.init : [a] -> Optional [a] - 9. List.intersperse : a -> [a] -> [a] - 10. List.isEmpty : [a] -> Boolean - 11. List.last : [a] -> Optional a - 12. List.replicate : Nat -> a -> [a] - 13. List.splitAt : Nat -> [a] -> ([a], [a]) - 14. List.tail : [a] -> Optional [a] - 15. List.takeWhile : (a ->{𝕖} Boolean) -> [a] ->{𝕖} [a] - - -.runar> alias.many 1-15 .mylib +.> alias.many stuff.List.adjacentPairs stuff.List.all stuff.List.any stuff.List.chunk stuff.List.chunksOf stuff.List.dropWhile stuff.List.first stuff.List.init stuff.List.intersperse stuff.List.isEmpty stuff.List.last stuff.List.replicate stuff.List.splitAt stuff.List.tail stuff.List.takeWhile .mylib Here's what changed in .mylib : Added definitions: - 1. List.adjacentPairs : [a] -> [(a, a)] - 2. List.all : (a ->{g} Boolean) - -> [a] - ->{g} Boolean - 3. List.any : (a ->{g} Boolean) - -> [a] - ->{g} Boolean - 4. List.chunk : Nat -> [a] -> [[a]] - 5. List.chunksOf : Nat -> [a] -> [[a]] - 6. List.dropWhile : (a ->{g} Boolean) -> [a] ->{g} [a] - 7. List.first : [a] -> Optional a - 8. List.init : [a] -> Optional [a] - 9. List.intersperse : a -> [a] -> [a] - 10. List.isEmpty : [a] -> Boolean - 11. List.last : [a] -> Optional a - 12. List.replicate : Nat -> a -> [a] - 13. List.splitAt : Nat -> [a] -> ([a], [a]) - 14. List.tail : [a] -> Optional [a] - 15. List.takeWhile : (a ->{𝕖} Boolean) -> [a] ->{𝕖} [a] + 1. stuff.List.adjacentPairs : [a] -> [(a, a)] + 2. stuff.List.all : (a ->{g} Boolean) + -> [a] + ->{g} Boolean + 3. stuff.List.any : (a ->{g} Boolean) + -> [a] + ->{g} Boolean + 4. stuff.List.chunk : Nat -> [a] -> [[a]] + 5. stuff.List.chunksOf : Nat -> [a] -> [[a]] + 6. stuff.List.dropWhile : (a ->{g} Boolean) + -> [a] + ->{g} [a] + 7. stuff.List.first : [a] -> Optional a + 8. stuff.List.init : [a] -> Optional [a] + 9. stuff.List.intersperse : a -> [a] -> [a] + 10. stuff.List.isEmpty : [a] -> Boolean + 11. stuff.List.last : [a] -> Optional a + 12. stuff.List.replicate : Nat -> a -> [a] + 13. stuff.List.splitAt : Nat -> [a] -> ([a], [a]) + 14. stuff.List.tail : [a] -> Optional [a] + 15. stuff.List.takeWhile : (a ->{𝕖} Boolean) + -> [a] + ->{𝕖} [a] Tip: You can use `undo` or `reflog` to undo this change. -.runar> cd .mylib +.> cd .mylib .mylib> find - 1. Doc.Blob : Text -> Doc - 2. Doc.Evaluate : Term -> Doc - 3. Doc.Join : [Doc] -> Doc - 4. Doc.Link : Link -> Doc - 5. Doc.Signature : Term -> Doc - 6. Doc.Source : Link -> Doc - 7. structural type Either a b - 8. Either.Left : a -> Either a b - 9. Either.Right : b -> Either a b - 10. structural ability Exception - 11. Exception.raise : Failure ->{Exception} x - 12. List.adjacentPairs : [a] -> [(a, a)] - 13. List.all : (a ->{g} Boolean) -> [a] ->{g} Boolean - 14. List.any : (a ->{g} Boolean) -> [a] ->{g} Boolean - 15. List.chunk : Nat -> [a] -> [[a]] - 16. List.chunksOf : Nat -> [a] -> [[a]] - 17. List.dropWhile : (a ->{g} Boolean) -> [a] ->{g} [a] - 18. List.first : [a] -> Optional a - 19. List.init : [a] -> Optional [a] - 20. List.intersperse : a -> [a] -> [a] - 21. List.isEmpty : [a] -> Boolean - 22. List.last : [a] -> Optional a - 23. List.replicate : Nat -> a -> [a] - 24. List.splitAt : Nat -> [a] -> ([a], [a]) - 25. List.tail : [a] -> Optional [a] - 26. List.takeWhile : (a ->{𝕖} Boolean) -> [a] ->{𝕖} [a] + 1. stuff.List.adjacentPairs : [a] -> [(a, a)] + 2. stuff.List.all : (a ->{g} ##Boolean) + -> [a] + ->{g} ##Boolean + 3. stuff.List.any : (a ->{g} ##Boolean) + -> [a] + ->{g} ##Boolean + 4. stuff.List.chunk : ##Nat -> [a] -> [[a]] + 5. stuff.List.chunksOf : ##Nat -> [a] -> [[a]] + 6. stuff.List.dropWhile : (a ->{g} ##Boolean) + -> [a] + ->{g} [a] + 7. stuff.List.first : [a] -> #nirp5os0q6 a + 8. stuff.List.init : [a] -> #nirp5os0q6 [a] + 9. stuff.List.intersperse : a -> [a] -> [a] + 10. stuff.List.isEmpty : [a] -> ##Boolean + 11. stuff.List.last : [a] -> #nirp5os0q6 a + 12. stuff.List.replicate : ##Nat -> a -> [a] + 13. stuff.List.splitAt : ##Nat -> [a] -> ([a], [a]) + 14. stuff.List.tail : [a] -> #nirp5os0q6 [a] + 15. stuff.List.takeWhile : (a ->{𝕖} ##Boolean) + -> [a] + ->{𝕖} [a] ``` diff --git a/unison-src/transcripts/ambiguous-metadata.md b/unison-src/transcripts/ambiguous-metadata.md deleted file mode 100644 index 09d5dfa8b3..0000000000 --- a/unison-src/transcripts/ambiguous-metadata.md +++ /dev/null @@ -1,17 +0,0 @@ - -## An example scenario that surfaces an 'ambiguous metadata' error. - -```unison:hide -foo.doc = [: a :] -boo.doc = [: b :] -x = 1 -``` - -```ucm:hide:all -.> add -``` - -```ucm:error -.> merge foo boo -.> link boo.doc x -``` \ No newline at end of file diff --git a/unison-src/transcripts/ambiguous-metadata.output.md b/unison-src/transcripts/ambiguous-metadata.output.md deleted file mode 100644 index ed87844426..0000000000 --- a/unison-src/transcripts/ambiguous-metadata.output.md +++ /dev/null @@ -1,44 +0,0 @@ - -## An example scenario that surfaces an 'ambiguous metadata' error. - -```unison -foo.doc = [: a :] -boo.doc = [: b :] -x = 1 -``` - -```ucm -.> merge foo boo - - Here's what's changed in boo after the merge: - - New name conflicts: - - 1. doc#7ivmrc4c8v : #p65rcethk2 - ↓ - 2. ┌ doc#7ivmrc4c8v : #p65rcethk2 - 3. └ doc#9f3kmo37cv : #p65rcethk2 - - Tip: You can use `todo` to see if this generated any work to - do in this namespace and `test` to run the tests. Or you - can use `undo` or `reflog` to undo the results of this - merge. - - Applying changes from patch... - -.> link boo.doc x - - ⚠️ - - I'm not sure which metadata value you're referring to since - there are multiple matches: - - doc#7ivmrc4c8v - foo.doc - - Tip: Try again and supply one of the above definitions - explicitly. - - I didn't make any changes. - -``` diff --git a/unison-src/transcripts/api-getDefinition.md b/unison-src/transcripts/api-getDefinition.md index 20fe6c867a..4a56b2bc9e 100644 --- a/unison-src/transcripts/api-getDefinition.md +++ b/unison-src/transcripts/api-getDefinition.md @@ -1,16 +1,16 @@ # Get Definitions Test ```ucm:hide -.> builtins.mergeio +.nested> builtins.mergeio ``` ```unison:hide {{ Documentation }} -nested.names.x = 42 +names.x = 42 ``` ```ucm:hide -.> add +.nested> add ``` ```api @@ -18,26 +18,27 @@ nested.names.x = 42 GET /api/non-project-code/getDefinition?names=x -- Term names should strip relativeTo prefix. -GET /api/non-project-code/getDefinition?names=x&relativeTo=nested +GET /api/non-project-code/getDefinition?names=names.x&relativeTo=nested -- Should find definitions by hash, names should be relative GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=nested +``` --- Should filter out any definitions which aren't in the provided namespace even if the hash matches. -GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=emptypath +```ucm:hide +.doctest> builtins.mergeio ``` ```unison:hide -doctest.thing.doc = {{ The correct docs for the thing }} -doctest.thing = "A thing" -doctest.thingalias.doc = {{ Docs for the alias, should not be displayed }} -doctest.thingalias = "A thing" -doctest.otherstuff.thing.doc = {{ A doc for a different term with the same name, should not be displayed }} -doctest.otherstuff.thing = "A different thing" +thing.doc = {{ The correct docs for the thing }} +thing = "A thing" +thingalias.doc = {{ Docs for the alias, should not be displayed }} +thingalias = "A thing" +otherstuff.thing.doc = {{ A doc for a different term with the same name, should not be displayed }} +otherstuff.thing = "A different thing" ``` ```ucm:hide -.> add +.doctest> add ``` Only docs for the term we request should be returned, even if there are other term docs with the same suffix. diff --git a/unison-src/transcripts/api-getDefinition.output.md b/unison-src/transcripts/api-getDefinition.output.md index 6a9514ad4e..24debb744d 100644 --- a/unison-src/transcripts/api-getDefinition.output.md +++ b/unison-src/transcripts/api-getDefinition.output.md @@ -2,7 +2,7 @@ ```unison {{ Documentation }} -nested.names.x = 42 +names.x = 42 ``` ```api @@ -16,16 +16,7 @@ GET /api/non-project-code/getDefinition?names=x "typeDefinitions": {} } -- Term names should strip relativeTo prefix. -GET /api/non-project-code/getDefinition?names=x&relativeTo=nested -{ - "missingDefinitions": [ - "x" - ], - "termDefinitions": {}, - "typeDefinitions": {} -} --- Should find definitions by hash, names should be relative -GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=nested +GET /api/non-project-code/getDefinition?names=names.x&relativeTo=nested { "missingDefinitions": [], "termDefinitions": { @@ -119,8 +110,8 @@ GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=nested }, "typeDefinitions": {} } --- Should filter out any definitions which aren't in the provided namespace even if the hash matches. -GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=emptypath +-- Should find definitions by hash, names should be relative +GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=nested { "missingDefinitions": [], "termDefinitions": { @@ -192,21 +183,35 @@ GET /api/non-project-code/getDefinition?names=%23qkhkl0n238&relativeTo=emptypath ], "tag": "UserObject" }, - "termDocs": [], + "termDocs": [ + [ + "doc", + "#ulr9f75rpcrv79d7sfo2ep2tvbntu3e360lfomird2bdpj4bnea230e8o5j0b9our8vggocpa7eck3pus14fcfajlttat1bg71t6rbg", + { + "contents": [ + { + "contents": "Documentation", + "tag": "Word" + } + ], + "tag": "Paragraph" + } + ] + ], "termNames": [ - ".nested.names.x" + "names.x" ] } }, "typeDefinitions": {} } ``````unison -doctest.thing.doc = {{ The correct docs for the thing }} -doctest.thing = "A thing" -doctest.thingalias.doc = {{ Docs for the alias, should not be displayed }} -doctest.thingalias = "A thing" -doctest.otherstuff.thing.doc = {{ A doc for a different term with the same name, should not be displayed }} -doctest.otherstuff.thing = "A different thing" +thing.doc = {{ The correct docs for the thing }} +thing = "A thing" +thingalias.doc = {{ Docs for the alias, should not be displayed }} +thingalias = "A thing" +otherstuff.thing.doc = {{ A doc for a different term with the same name, should not be displayed }} +otherstuff.thing = "A different thing" ``` Only docs for the term we request should be returned, even if there are other term docs with the same suffix. diff --git a/unison-src/transcripts/branch-command.md b/unison-src/transcripts/branch-command.md index 0cc2bd26bb..4b1636be41 100644 --- a/unison-src/transcripts/branch-command.md +++ b/unison-src/transcripts/branch-command.md @@ -1,7 +1,6 @@ The `branch` command creates a new branch. ```ucm:hide -.> builtins.merge .> project.create-empty foo .> project.create-empty bar ``` @@ -13,6 +12,7 @@ someterm = 18 ``` ```ucm +.some.loose.code.lib> builtins.merge .some.loose.code> add ``` diff --git a/unison-src/transcripts/branch-command.output.md b/unison-src/transcripts/branch-command.output.md index f3a18017f8..69049acbd9 100644 --- a/unison-src/transcripts/branch-command.output.md +++ b/unison-src/transcripts/branch-command.output.md @@ -7,7 +7,11 @@ someterm = 18 ``` ```ucm - ☝️ The namespace .some.loose.code is empty. + ☝️ The namespace .some.loose.code.lib is empty. + +.some.loose.code.lib> builtins.merge + + Done. .some.loose.code> add diff --git a/unison-src/transcripts/branch-relative-path.md b/unison-src/transcripts/branch-relative-path.md new file mode 100644 index 0000000000..8414db2f16 --- /dev/null +++ b/unison-src/transcripts/branch-relative-path.md @@ -0,0 +1,31 @@ +```ucm:hide +.> builtins.merge +.> project.create-empty p0 +.> project.create-empty p1 +``` + +```unison +foo = 5 +foo.bar = 1 +``` + +```ucm +p0/main> add +``` + +```unison +bonk = 5 +donk.bonk = 1 +``` + +```ucm +p1/main> add +p1/main> fork p0/main: zzz +p1/main> find zzz +p1/main> fork p0/main:foo yyy +p1/main> find yyy +p0/main> fork p1/main: p0/main:p1 +p0/main> ls p1 +p0/main> ls p1.zzz +p0/main> ls p1.yyy +``` diff --git a/unison-src/transcripts/branch-relative-path.output.md b/unison-src/transcripts/branch-relative-path.output.md new file mode 100644 index 0000000000..4f2be5861a --- /dev/null +++ b/unison-src/transcripts/branch-relative-path.output.md @@ -0,0 +1,97 @@ +```unison +foo = 5 +foo.bar = 1 +``` + +```ucm + + Loading changes detected in scratch.u. + + I found and typechecked these definitions in scratch.u. If you + do an `add` or `update`, here's how your codebase would + change: + + ⍟ These new definitions are ok to `add`: + + foo : ##Nat + foo.bar : ##Nat + +``` +```ucm +p0/main> add + + ⍟ I've added these definitions: + + foo : ##Nat + foo.bar : ##Nat + +``` +```unison +bonk = 5 +donk.bonk = 1 +``` + +```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`: + + bonk : ##Nat + (also named foo) + donk.bonk : ##Nat + (also named foo.bar) + +``` +```ucm +p1/main> add + + ⍟ I've added these definitions: + + bonk : ##Nat + donk.bonk : ##Nat + +p1/main> fork p0/main: zzz + + Done. + +p1/main> find zzz + + 1. zzz.foo : ##Nat + 2. zzz.foo.bar : ##Nat + + +p1/main> fork p0/main:foo yyy + + Done. + +p1/main> find yyy + + 1. yyy.bar : ##Nat + + +p0/main> fork p1/main: p0/main:p1 + + Done. + +p0/main> ls p1 + + 1. bonk (##Nat) + 2. donk/ (1 term) + 3. yyy/ (1 term) + 4. zzz/ (2 terms) + +p0/main> ls p1.zzz + + 1. foo (##Nat) + 2. foo/ (1 term) + +p0/main> ls p1.yyy + + 1. bar (##Nat) + +``` diff --git a/unison-src/transcripts/command-replace.md b/unison-src/transcripts/command-replace.md index 1e584529cd..c1d07740a9 100644 --- a/unison-src/transcripts/command-replace.md +++ b/unison-src/transcripts/command-replace.md @@ -3,7 +3,7 @@ Let's set up some definitions to start: ```ucm:hide -.> builtins.merge +.lib> builtins.merge ``` ```unison @@ -15,44 +15,44 @@ structural type Y = Two Nat Nat ``` ```ucm -.scratch> add +.> add ``` Test that replace works with terms ```ucm -.scratch> replace x y -.scratch> view x +.> replace x y +.> view x ``` Test that replace works with types ```ucm -.scratch> replace X Y -.scratch> find -.scratch> view.patch patch -.scratch> view X +.> replace X Y +.> find +.> view.patch patch +.> view X ``` Try with a type/term mismatch ```ucm:error -.scratch> replace X x +.> replace X x ``` ```ucm:error -.scratch> replace y Y +.> replace y Y ``` Try with missing references ```ucm:error -.scratch> replace X NOPE +.> replace X NOPE ``` ```ucm:error -.scratch> replace y nope +.> replace y nope ``` ```ucm:error -.scratch> replace nope X +.> replace nope X ``` ```ucm:error -.scratch> replace nope y +.> replace nope y ``` ```ucm:error -.scratch> replace nope nope +.> replace nope nope ``` diff --git a/unison-src/transcripts/command-replace.output.md b/unison-src/transcripts/command-replace.output.md index 5e3440a2cd..1fb85d5020 100644 --- a/unison-src/transcripts/command-replace.output.md +++ b/unison-src/transcripts/command-replace.output.md @@ -27,9 +27,7 @@ structural type Y = Two Nat Nat ``` ```ucm - ☝️ The namespace .scratch is empty. - -.scratch> add +.> add ⍟ I've added these definitions: @@ -41,11 +39,11 @@ structural type Y = Two Nat Nat ``` Test that replace works with terms ```ucm -.scratch> replace x y +.> replace x y Done. -.scratch> view x +.> view x x : Nat x = 2 @@ -53,11 +51,11 @@ Test that replace works with terms ``` Test that replace works with types ```ucm -.scratch> replace X Y +.> replace X Y Done. -.scratch> find +.> find 1. structural type X 2. x : Nat @@ -67,7 +65,7 @@ Test that replace works with types 6. Y.Two : Nat -> Nat -> X -.scratch> view.patch patch +.> view.patch patch Edited Types: 1. #68k40ra7l7 -> 3. X @@ -77,14 +75,14 @@ Test that replace works with types delete.term-replacement or delete.type-replacement, as appropriate. -.scratch> view X +.> view X structural type X = One Nat Nat ``` Try with a type/term mismatch ```ucm -.scratch> replace X x +.> replace X x ⚠️ @@ -92,7 +90,7 @@ Try with a type/term mismatch ``` ```ucm -.scratch> replace y Y +.> replace y Y ⚠️ @@ -101,7 +99,7 @@ Try with a type/term mismatch ``` Try with missing references ```ucm -.scratch> replace X NOPE +.> replace X NOPE ⚠️ @@ -110,7 +108,7 @@ Try with missing references ``` ```ucm -.scratch> replace y nope +.> replace y nope ⚠️ @@ -119,7 +117,7 @@ Try with missing references ``` ```ucm -.scratch> replace nope X +.> replace nope X ⚠️ @@ -128,7 +126,7 @@ Try with missing references ``` ```ucm -.scratch> replace nope y +.> replace nope y ⚠️ @@ -137,7 +135,7 @@ Try with missing references ``` ```ucm -.scratch> replace nope nope +.> replace nope nope ⚠️ diff --git a/unison-src/transcripts/create-author.md b/unison-src/transcripts/create-author.md index 9a8a7dfb8b..d9a39c735f 100644 --- a/unison-src/transcripts/create-author.md +++ b/unison-src/transcripts/create-author.md @@ -4,14 +4,7 @@ Demonstrating `create.author`: -```unison:hide -def1 = 1 -def2 = 2 -``` - ```ucm -.foo> add .foo> create.author alicecoder "Alice McGee" .foo> view 2 -.foo> link metadata.authors.alicecoder def1 def2 ``` diff --git a/unison-src/transcripts/create-author.output.md b/unison-src/transcripts/create-author.output.md index d1bb3be4b8..3a5635947b 100644 --- a/unison-src/transcripts/create-author.output.md +++ b/unison-src/transcripts/create-author.output.md @@ -1,44 +1,22 @@ Demonstrating `create.author`: -```unison -def1 = 1 -def2 = 2 -``` - ```ucm ☝️ The namespace .foo is empty. -.foo> add - - ⍟ I've added these definitions: - - def1 : Nat - def2 : Nat - .foo> create.author alicecoder "Alice McGee" Added definitions: - 1. metadata.authors.alicecoder : Author - 2. metadata.copyrightHolders.alicecoder : CopyrightHolder - 3. metadata.authors.alicecoder.guid : GUID + 1. metadata.authors.alicecoder : #345f3nptqq + 2. metadata.copyrightHolders.alicecoder : #pgornst1pq + 3. metadata.authors.alicecoder.guid : #hqectlr3gt Tip: Add License values for alicecoder under metadata. .foo> view 2 - metadata.copyrightHolders.alicecoder : CopyrightHolder - metadata.copyrightHolders.alicecoder = - CopyrightHolder guid "Alice McGee" - -.foo> link metadata.authors.alicecoder def1 def2 - - Updates: - - 1. foo.def1 : Nat - + 2. authors.alicecoder : Author - - 3. foo.def2 : Nat - + 4. authors.alicecoder : Author + .foo.metadata.copyrightHolders.alicecoder : CopyrightHolder + .foo.metadata.copyrightHolders.alicecoder = + CopyrightHolder alicecoder.guid "Alice McGee" ``` diff --git a/unison-src/transcripts/cycle-update-5.output.md b/unison-src/transcripts/cycle-update-5.output.md index 7ef754b3ef..3e3361f70c 100644 --- a/unison-src/transcripts/cycle-update-5.output.md +++ b/unison-src/transcripts/cycle-update-5.output.md @@ -58,7 +58,7 @@ inner.ping _ = !pong + 3 ⍟ I've added these definitions: - inner.ping : 'Nat + inner.ping : '##Nat .> view inner.ping diff --git a/unison-src/transcripts/cycle-update-6.md b/unison-src/transcripts/cycle-update-6.md deleted file mode 100644 index 4f3b8f93ff..0000000000 --- a/unison-src/transcripts/cycle-update-6.md +++ /dev/null @@ -1,36 +0,0 @@ -Not yet working: properly updating implicit terms with conflicted names. - -```ucm -.> builtins.merge -``` - -```unison -ping : 'Nat -ping _ = !pong + 1 - -pong : 'Nat -pong _ = !ping + 2 - -inner.pong : 'Nat -inner.pong _ = !ping + 3 -``` - -N.B. The `find.verbose pong` is just to print the hash, for easy copying. - -```ucm -.> add -.> find.verbose pong -.> merge inner -``` - -```unison -ping : 'Nat -ping _ = ! #4t465jk908dsue9fgdfi06fihppsme16cvaua29hjm1585de1mvt11dftqrab5chhla3reilsj4c0e7vlkkcct56khgaa5saeu4du48 + 4 -``` - -```ucm -.> update -.> view ping pong -``` - -Here we see that we didn't properly update `pong` to point to the new `ping` because it was conflicted. diff --git a/unison-src/transcripts/cycle-update-6.output.md b/unison-src/transcripts/cycle-update-6.output.md deleted file mode 100644 index 0833a50cf5..0000000000 --- a/unison-src/transcripts/cycle-update-6.output.md +++ /dev/null @@ -1,125 +0,0 @@ -Not yet working: properly updating implicit terms with conflicted names. - -```ucm -.> builtins.merge - - Done. - -``` -```unison -ping : 'Nat -ping _ = !pong + 1 - -pong : 'Nat -pong _ = !ping + 2 - -inner.pong : 'Nat -inner.pong _ = !ping + 3 -``` - -```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`: - - inner.pong : 'Nat - ping : 'Nat - pong : 'Nat - -``` -N.B. The `find.verbose pong` is just to print the hash, for easy copying. - -```ucm -.> add - - ⍟ I've added these definitions: - - inner.pong : 'Nat - ping : 'Nat - pong : 'Nat - -.> find.verbose pong - - 1. -- #lu6v9j6kvdigbcicuea5fd2e51o05rhgjp62gcgu13h7h59p7nockft2s20fflr4n6l59q7sf6l0fs8f8cnf0a4876dnvperel1vpa0 - inner.pong : 'Nat - - 2. -- #4t465jk908dsue9fgdfi06fihppsme16cvaua29hjm1585de1mvt11dftqrab5chhla3reilsj4c0e7vlkkcct56khgaa5saeu4du48 - pong : 'Nat - - - -.> merge inner - - Here's what's changed in the current namespace after the - merge: - - New name conflicts: - - 1. pong#4t465jk908 : 'Nat - ↓ - 2. ┌ pong#4t465jk908 : 'Nat - 3. └ pong#lu6v9j6kvd : 'Nat - - Name changes: - - Original Changes - 4. inner.pong 5. pong#lu6v9j6kvd (added) - - Tip: You can use `todo` to see if this generated any work to - do in this namespace and `test` to run the tests. Or you - can use `undo` or `reflog` to undo the results of this - merge. - - Applying changes from patch... - -``` -```unison -ping : 'Nat -ping _ = ! #4t465jk908dsue9fgdfi06fihppsme16cvaua29hjm1585de1mvt11dftqrab5chhla3reilsj4c0e7vlkkcct56khgaa5saeu4du48 + 4 -``` - -```ucm - - Loading changes detected in scratch.u. - - I found and typechecked these definitions in scratch.u. If you - do an `add` or `update`, here's how your codebase would - change: - - ⍟ These names already exist. You can `update` them to your - new definition: - - ping : 'Nat - -``` -```ucm -.> update - - Okay, I'm searching the branch for code that needs to be - updated... - - That's done. Now I'm making sure everything typechecks... - - Everything typechecks, so I'm saving the results... - - Done. - -.> view ping pong - - ping : 'Nat - ping _ = - use Nat + - !#4t465jk908 + 4 - - pong : 'Nat - pong _ = - use Nat + - !ping + 2 - -``` -Here we see that we didn't properly update `pong` to point to the new `ping because it was conflicted. diff --git a/unison-src/transcripts/delete.md b/unison-src/transcripts/delete.md index fdacbf6e19..e58ae89189 100644 --- a/unison-src/transcripts/delete.md +++ b/unison-src/transcripts/delete.md @@ -50,7 +50,7 @@ foo = 2 A delete should remove both versions of the term. ```ucm -.a> delete.verbose foo +.> delete.verbose a.foo ``` ```ucm:error @@ -77,11 +77,11 @@ structural type Foo = Foo ``` ```ucm -.a> delete.verbose Foo +.> delete.verbose a.Foo ``` ```ucm -.a> delete.verbose Foo.Foo +.> delete.verbose a.Foo.Foo ``` Finally, let's try to delete a term and a type with the same name. diff --git a/unison-src/transcripts/delete.output.md b/unison-src/transcripts/delete.output.md index df2f657313..f40d197e7a 100644 --- a/unison-src/transcripts/delete.output.md +++ b/unison-src/transcripts/delete.output.md @@ -68,7 +68,7 @@ foo = 1 ⍟ I've added these definitions: - foo : Nat + foo : ##Nat ``` ```unison @@ -82,7 +82,7 @@ foo = 2 ⍟ I've added these definitions: - foo : Nat + foo : ##Nat .a> merge .b @@ -91,10 +91,10 @@ foo = 2 New name conflicts: - 1. foo#gjmq673r1v : Nat + 1. foo#gjmq673r1v : ##Nat ↓ - 2. ┌ foo#dcgdua2lj6 : Nat - 3. └ foo#gjmq673r1v : Nat + 2. ┌ foo#dcgdua2lj6 : ##Nat + 3. └ foo#gjmq673r1v : ##Nat Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you @@ -107,7 +107,7 @@ foo = 2 A delete should remove both versions of the term. ```ucm -.a> delete.verbose foo +.> delete.verbose a.foo Removed definitions: @@ -123,6 +123,8 @@ A delete should remove both versions of the term. ``` ```ucm + ☝️ The namespace .a is empty. + .a> ls nothing to show @@ -161,12 +163,9 @@ structural type Foo = Foo New name conflicts: 1. structural type Foo#089vmor9c5 - ↓ 2. ┌ structural type Foo#00nv2kob8f - 3. └ structural type Foo#089vmor9c5 - 4. Foo.Foo#089vmor9c5#0 : 'Foo#089vmor9c5 ↓ @@ -182,7 +181,7 @@ structural type Foo = Foo ``` ```ucm -.a> delete.verbose Foo +.> delete.verbose a.Foo Removed definitions: @@ -199,7 +198,7 @@ structural type Foo = Foo ``` ```ucm -.a> delete.verbose Foo.Foo +.> delete.verbose a.Foo.Foo Removed definitions: diff --git a/unison-src/transcripts/deleteReplacements.output.md b/unison-src/transcripts/deleteReplacements.output.md index 9d00e1d996..61383546b5 100644 --- a/unison-src/transcripts/deleteReplacements.output.md +++ b/unison-src/transcripts/deleteReplacements.output.md @@ -83,7 +83,7 @@ unique[a] type Foo = Foo ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -91,7 +91,7 @@ unique[a] type Foo = Foo ⍟ I've added these definitions: - unique type Foo + type Foo ``` ```unison @@ -109,7 +109,7 @@ unique[b] type Foo = Foo | Bar ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -117,7 +117,7 @@ unique[b] type Foo = Foo | Bar ⍟ I've updated these names to your new definition: - unique type Foo + type Foo .> view.patch @@ -153,7 +153,7 @@ unique[aa] type bar = Foo ⍟ These new definitions are ok to `add`: - unique type bar + type bar bar : ##Nat ``` @@ -162,7 +162,7 @@ unique[aa] type bar = Foo ⍟ I've added these definitions: - unique type bar + type bar bar : ##Nat ``` @@ -181,7 +181,7 @@ unique[bb] type bar = Foo | Bar ⍟ These names already exist. You can `update` them to your new definition: - unique type bar + type bar ``` ```ucm @@ -189,7 +189,7 @@ unique[bb] type bar = Foo | Bar ⍟ I've updated these names to your new definition: - unique type bar + type bar .> view.patch @@ -257,7 +257,7 @@ baz = 0 ⚠️ I was expecting the following names to be types, though I found terms instead. - .baz + baz .> view.patch @@ -278,7 +278,7 @@ unique type qux = Qux ⍟ These new definitions are ok to `add`: - unique type qux + type qux ``` ```ucm @@ -286,14 +286,14 @@ unique type qux = Qux ⍟ I've added these definitions: - unique type qux + type qux .> delete.term-replacement qux ⚠️ I was expecting the following names to be terms, though I found types instead. - .qux + qux .> view.patch diff --git a/unison-src/transcripts/diff-namespace.md b/unison-src/transcripts/diff-namespace.md index d5f2290293..8ee7794039 100644 --- a/unison-src/transcripts/diff-namespace.md +++ b/unison-src/transcripts/diff-namespace.md @@ -1,5 +1,5 @@ ```ucm:hide -.> builtins.mergeio +.> builtins.merge ``` ```unison:hide @@ -24,9 +24,8 @@ fslkdjflskdjflksjdf = 663 Things we want to test: * Diffing identical namespaces -* Adds, removes, updates (with and without metadata updates) +* Adds, removes, updates * Adds with multiple names - * Adds with multiple names and different metadata on each * Moved and copied definitions * Moves that have more that 1 initial or final name * ... terms and types @@ -48,7 +47,6 @@ structural ability X a1 a2 where x : () .ns1> add .ns1> alias.term fromJust fromJust' .ns1> alias.term helloWorld helloWorld2 -.ns1> link b fromJust .ns1> fork .ns1 .ns2 .ns1> cd . ``` @@ -83,17 +81,11 @@ unique type Y a b = Y a b ```ucm .ns2> update.old -.ns2> links fromJust .> diff.namespace ns1 ns2 .> alias.term ns2.d ns2.d' .> alias.type ns2.A ns2.A' .> alias.type ns2.X ns2.X' .> diff.namespace ns1 ns2 -.> link ns1.c ns2.f -.> link ns2.c ns2.c -.> diff.namespace ns1 ns2 -.> unlink ns2.b ns2.fromJust -.> diff.namespace ns1 ns2 .> alias.type ns1.X ns1.X2 .> alias.type ns2.A' ns2.A'' .> view.patch ns2.patch @@ -198,17 +190,10 @@ Resolved name conflicts: -- updates where LHS had multiple hashes and RHS has on - [x] similarly, if a conflicted name is resolved by deleting the last name to a reference, I (arya) suspect it will show up as a Remove - [d] Maybe group and/or add headings to the types, constructors, terms -- [x] check whether creating a name conflict + adding metadata puts the update - in both categories; if it does, then filter out metadataUpdates from the - other categories - [x] add tagging of propagated updates to test propagated updates output - [x] missing old names in deletion ppe (delete.output.md) (superseded by \#1143) - [x] delete.term has some bonkers output - [x] Make a decision about how we want to show constructors in the diff -- [x] When you delete a name with metadata, it also shows up in updates section - with the deleted metadata. -- [x] An add with new metadata is getting characterized as an update -- [x] can there be a metadata-only update where it's not a singleton old and new reference - [x] 12.patch patch needs a space - [x] This looks like garbage - [x] Extra 2 blank lines at the end of the add section diff --git a/unison-src/transcripts/diff-namespace.output.md b/unison-src/transcripts/diff-namespace.output.md index ea87bb6058..5eb4a51e72 100644 --- a/unison-src/transcripts/diff-namespace.output.md +++ b/unison-src/transcripts/diff-namespace.output.md @@ -9,7 +9,7 @@ x = 23 ⍟ I've added these definitions: - x : Nat + x : ##Nat .b1> alias.term x fslkdjflskdjflksjdf @@ -35,7 +35,7 @@ fslkdjflskdjflksjdf = 663 ⍟ I've added these definitions: - fslkdjflskdjflksjdf : Nat + fslkdjflskdjflksjdf : ##Nat .> merge b0 b1 @@ -75,10 +75,10 @@ fslkdjflskdjflksjdf = 663 Resolved name conflicts: - 1. ┌ fslkdjflskdjflksjdf#sekb3fdsvb : Nat - 2. └ fslkdjflskdjflksjdf#u520d1t9kc : Nat + 1. ┌ fslkdjflskdjflksjdf#sekb3fdsvb : ##Nat + 2. └ fslkdjflskdjflksjdf#u520d1t9kc : ##Nat ↓ - 3. fslkdjflskdjflksjdf#u520d1t9kc : Nat + 3. fslkdjflskdjflksjdf#u520d1t9kc : ##Nat Name changes: @@ -91,9 +91,8 @@ fslkdjflskdjflksjdf = 663 Things we want to test: * Diffing identical namespaces -* Adds, removes, updates (with and without metadata updates) +* Adds, removes, updates * Adds with multiple names - * Adds with multiple names and different metadata on each * Moved and copied definitions * Moves that have more that 1 initial or final name * ... terms and types @@ -120,11 +119,11 @@ structural ability X a1 a2 where x : () structural type A a structural ability X a1 a2 - b : Nat - bdependent : Nat - c : Nat - fromJust : Nat - helloWorld : Text + b : ##Nat + bdependent : ##Nat + c : ##Nat + fromJust : ##Nat + helloWorld : ##Text .ns1> alias.term fromJust fromJust' @@ -134,16 +133,6 @@ structural ability X a1 a2 where x : () Done. -.ns1> link b fromJust - - Updates: - - 1. ns1.fromJust : Nat - + 2. b : Nat - - 3. ns1.fromJust' : Nat - + 4. b : Nat - .ns1> fork .ns1 .ns2 Done. @@ -178,7 +167,7 @@ fromJust = "asldkfjasldkfj" ⍟ I've added these definitions: - fromJust : Text + fromJust : ##Text .> merge ns1b ns1 @@ -213,24 +202,17 @@ unique type Y a b = Y a b ⍟ I've added these definitions: - unique type Y a b - d : Nat - e : Nat - f : Nat + type Y a b + d : ##Nat + e : ##Nat + f : ##Nat ⍟ I've updated these names to your new definition: - b : Text - fromJust : Nat + b : ##Text + fromJust : ##Nat (The old definition was also named fromJust'.) -.ns2> links fromJust - - 1. b : Text - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - .> diff.namespace ns1 ns2 Resolved name conflicts: @@ -239,30 +221,26 @@ unique type Y a b = Y a b 2. └ fromJust#rnbo52q2sh : Text ↓ 3. fromJust#6gn1k53ie0 : Nat - - 4. ns1.b : Nat - + 5. ns2.b : Text Updates: - 6. b : Nat + 4. b : Nat ↓ - 7. b : Text + 5. b : Text - 8. fromJust' : Nat + 6. fromJust' : Nat ↓ - 9. fromJust' : Nat - - 10. ns1.b : Nat - + 11. ns2.b : Text + 7. fromJust' : Nat Added definitions: - 12. unique type Y a b - 13. Y.Y : a -> b -> Y a b - 14. d : Nat - 15. e : Nat - 16. f : Nat + 8. type Y a b + 9. Y.Y : a -> b -> Y a b + 10. d : Nat + 11. e : Nat + 12. f : Nat - 17. patch patch (added 2 updates) + 13. patch patch (added 2 updates) .> alias.term ns2.d ns2.d' @@ -284,144 +262,34 @@ unique type Y a b = Y a b 2. └ fromJust#rnbo52q2sh : Text ↓ 3. fromJust#6gn1k53ie0 : Nat - - 4. ns1.b : Nat - + 5. ns2.b : Text - - Updates: - - 6. b : Nat - ↓ - 7. b : Text - - 8. fromJust' : Nat - ↓ - 9. fromJust' : Nat - - 10. ns1.b : Nat - + 11. ns2.b : Text - - Added definitions: - - 12. unique type Y a b - 13. Y.Y : a -> b -> Y a b - 14. ┌ d : Nat - 15. └ d' : Nat - 16. e : Nat - 17. f : Nat - - 18. patch patch (added 2 updates) - - Name changes: - - Original Changes - 19. A 20. A' (added) - - 21. X 22. X' (added) - -.> link ns1.c ns2.f - - Updates: - - 1. ns2.f : Nat - + 2. c : Nat - -.> link ns2.c ns2.c - - Updates: - - 1. ns2.c : Nat - + 2. c : Nat - -.> diff.namespace ns1 ns2 - - Resolved name conflicts: - - 1. ┌ fromJust#gjmq673r1v : Nat - 2. └ fromJust#rnbo52q2sh : Text - ↓ - 3. fromJust#6gn1k53ie0 : Nat - - 4. ns1.b : Nat - + 5. ns2.b : Text Updates: - 6. b : Nat + 4. b : Nat ↓ - 7. b : Text - - 8. c : Nat - + 9. c : Nat + 5. b : Text - 10. fromJust' : Nat + 6. fromJust' : Nat ↓ - 11. fromJust' : Nat - - 12. ns1.b : Nat - + 13. ns2.b : Text + 7. fromJust' : Nat Added definitions: - 14. unique type Y a b - 15. Y.Y : a -> b -> Y a b - 16. ┌ d : Nat - 17. └ d' : Nat - 18. e : Nat - 19. f : Nat (+1 metadata) + 8. type Y a b + 9. Y.Y : a -> b -> Y a b + 10. ┌ d : Nat + 11. └ d' : Nat + 12. e : Nat + 13. f : Nat - 20. patch patch (added 2 updates) + 14. patch patch (added 2 updates) Name changes: Original Changes - 21. A 22. A' (added) + 15. A 16. A' (added) - 23. X 24. X' (added) - -.> unlink ns2.b ns2.fromJust - - I didn't make any changes. - -.> diff.namespace ns1 ns2 - - Resolved name conflicts: - - 1. ┌ fromJust#gjmq673r1v : Nat - 2. └ fromJust#rnbo52q2sh : Text - ↓ - 3. fromJust#6gn1k53ie0 : Nat - - 4. ns1.b : Nat - + 5. ns2.b : Text - - Updates: - - 6. b : Nat - ↓ - 7. b : Text - - 8. c : Nat - + 9. c : Nat - - 10. fromJust' : Nat - ↓ - 11. fromJust' : Nat - - 12. ns1.b : Nat - + 13. ns2.b : Text - - Added definitions: - - 14. unique type Y a b - 15. Y.Y : a -> b -> Y a b - 16. ┌ d : Nat - 17. └ d' : Nat - 18. e : Nat - 19. f : Nat (+1 metadata) - - 20. patch patch (added 2 updates) - - Name changes: - - Original Changes - 21. A 22. A' (added) - - 23. X 24. X' (added) + 17. X 18. X' (added) .> alias.type ns1.X ns1.X2 @@ -480,7 +348,7 @@ bdependent = "banana" ⍟ I've updated these names to your new definition: - bdependent : Text + bdependent : ##Text .> diff.namespace ns2 ns3 @@ -514,8 +382,8 @@ b = a + 1 ⍟ I've added these definitions: - a : Nat - b : Nat + a : ##Nat + b : ##Nat .> fork nsx nsy @@ -535,7 +403,7 @@ a = 444 ⍟ I've updated these names to your new definition: - a : Nat + a : ##Nat ``` ```unison @@ -547,7 +415,7 @@ a = 555 ⍟ I've updated these names to your new definition: - a : Nat + a : ##Nat .> merge nsy nsw @@ -556,7 +424,7 @@ a = 555 Added definitions: 1. a : Nat - 2. b : Nat (+1 metadata) + 2. b : Nat 3. patch patch (added 1 updates) @@ -579,14 +447,15 @@ a = 555 ↓ 2. ┌ a#mdl4vqtu00 : Nat 3. └ a#vrs8gtkl2t : Nat - - Updates: - + 4. b#unkqhuu66p : Nat + ↓ + 5. ┌ b#aapqletas7 : Nat + 6. └ b#unkqhuu66p : Nat - There were 1 auto-propagated updates. + Updates: - 5. patch patch (added 1 updates) + 7. patch patch (added 1 updates) Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you @@ -608,32 +477,29 @@ a = 555 ↓ 2. ┌ a#mdl4vqtu00 : Nat 3. └ a#vrs8gtkl2t : Nat - - Updates: - - There were 2 auto-propagated updates. + + 4. b#lhigeb1let : Nat + ↓ + 5. ┌ b#aapqletas7 : Nat + 6. └ b#unkqhuu66p : Nat Added definitions: - 4. patch patch (added 2 updates) + 7. patch patch (added 2 updates) .nsw> view a b - a#mdl4vqtu00 : Nat + a#mdl4vqtu00 : ##Nat a#mdl4vqtu00 = 444 - a#vrs8gtkl2t : Nat + a#vrs8gtkl2t : ##Nat a#vrs8gtkl2t = 555 - b#aapqletas7 : Nat - b#aapqletas7 = - use Nat + - a#vrs8gtkl2t + 1 + b#aapqletas7 : ##Nat + b#aapqletas7 = ##Nat.+ a#vrs8gtkl2t 1 - b#unkqhuu66p : Nat - b#unkqhuu66p = - use Nat + - a#mdl4vqtu00 + 1 + b#unkqhuu66p : ##Nat + b#unkqhuu66p = ##Nat.+ a#mdl4vqtu00 1 ``` ## Should be able to diff a namespace hash from history. @@ -652,7 +518,7 @@ x = 1 ⍟ These new definitions are ok to `add`: - x : Nat + x : ##Nat ``` ```ucm @@ -662,7 +528,7 @@ x = 1 ⍟ I've added these definitions: - x : Nat + x : ##Nat ``` ```unison @@ -679,7 +545,7 @@ y = 2 ⍟ These new definitions are ok to `add`: - y : Nat + y : ##Nat ``` ```ucm @@ -687,7 +553,7 @@ y = 2 ⍟ I've added these definitions: - y : Nat + y : ##Nat .hashdiff> history @@ -706,7 +572,7 @@ y = 2 Added definitions: - 1. y : Nat + 1. y : ##Nat ``` ## @@ -743,17 +609,10 @@ Resolved name conflicts: -- updates where LHS had multiple hashes and RHS has on - [x] similarly, if a conflicted name is resolved by deleting the last name to a reference, I (arya) suspect it will show up as a Remove - [d] Maybe group and/or add headings to the types, constructors, terms -- [x] check whether creating a name conflict + adding metadata puts the update - in both categories; if it does, then filter out metadataUpdates from the - other categories - [x] add tagging of propagated updates to test propagated updates output - [x] missing old names in deletion ppe (delete.output.md) (superseded by \#1143) - [x] delete.term has some bonkers output - [x] Make a decision about how we want to show constructors in the diff -- [x] When you delete a name with metadata, it also shows up in updates section - with the deleted metadata. -- [x] An add with new metadata is getting characterized as an update -- [x] can there be a metadata-only update where it's not a singleton old and new reference - [x] 12.patch patch needs a space - [x] This looks like garbage - [x] Extra 2 blank lines at the end of the add section diff --git a/unison-src/transcripts/docs.md b/unison-src/transcripts/docs.md index ccb78f12bc..7379c47198 100644 --- a/unison-src/transcripts/docs.md +++ b/unison-src/transcripts/docs.md @@ -7,14 +7,12 @@ Unison documentation is written in Unison. Documentation is a value of the following type: ```ucm -.> view builtin.Doc +.builtin> view Doc ``` You can create these `Doc` values with ordinary code, or you can use the special syntax. A value of structural type `Doc` can be created via syntax like: ```unison -use .builtin - doc1 = [: This is some documentation. It can span multiple lines. @@ -44,15 +42,13 @@ List.take.ex2 = take 2 [1,2,3,4,5] ``` ```ucm -.> add +.builtin> add ``` And now let's write our docs and reference these examples: ```unison -use .builtin - -docs.List.take = [: +List.take.doc = [: `@List.take n xs` returns the first `n` elements of `xs`. (No need to add line breaks manually. The display command will do wrapping of text for you. Indent any lines where you don't want it to do this.) ## Examples: @@ -68,28 +64,20 @@ docs.List.take = [: :] ``` -Let's add it to the codebase, and link it to the definition: - -```ucm -.> add -.> link docs.List.take builtin.List.take -``` - -Now that documentation is linked to the definition. We can view it if we like: +Let's add it to the codebase. ```ucm -.> links builtin.List.take builtin.Doc -.> display 1 +.builtin> add ``` -Or there's also a convenient function, `docs`, which shows the `Doc` values that are linked to a definition. It's implemented in terms of `links` and `display`: +We can view it with `docs`, which shows the `Doc` value that is associated with a definition. ```ucm -.> docs builtin.List.take +.builtin> docs List.take ``` Note that if we view the source of the documentation, the various references are *not* expanded. ```ucm -.> view docs.List.take +.builtin> view List.take ``` diff --git a/unison-src/transcripts/docs.output.md b/unison-src/transcripts/docs.output.md index ebe841f3f9..ff6e98f603 100644 --- a/unison-src/transcripts/docs.output.md +++ b/unison-src/transcripts/docs.output.md @@ -3,22 +3,20 @@ Unison documentation is written in Unison. Documentation is a value of the following type: ```ucm -.> view builtin.Doc +.builtin> view Doc - unique type builtin.Doc + type Doc = Blob Text | Link Link | Source Link | Signature Term | Evaluate Term - | Join [builtin.Doc] + | Join [Doc] ``` You can create these `Doc` values with ordinary code, or you can use the special syntax. A value of structural type `Doc` can be created via syntax like: ```unison -use .builtin - doc1 = [: This is some documentation. It can span multiple lines. @@ -75,7 +73,7 @@ List.take.ex2 = take 2 [1,2,3,4,5] ``` ```ucm -.> add +.builtin> add ⍟ I've added these definitions: @@ -86,9 +84,7 @@ List.take.ex2 = take 2 [1,2,3,4,5] And now let's write our docs and reference these examples: ```unison -use .builtin - -docs.List.take = [: +List.take.doc = [: `@List.take n xs` returns the first `n` elements of `xs`. (No need to add line breaks manually. The display command will do wrapping of text for you. Indent any lines where you don't want it to do this.) ## Examples: @@ -114,78 +110,39 @@ docs.List.take = [: ⍟ These new definitions are ok to `add`: - docs.List.take : Doc + List.take.doc : Doc ``` -Let's add it to the codebase, and link it to the definition: +Let's add it to the codebase. ```ucm -.> add +.builtin> add ⍟ I've added these definitions: - docs.List.take : Doc - -.> link docs.List.take builtin.List.take - - Updates: - - 1. builtin.List.take : Nat -> [a] -> [a] - + 2. docs.List.take : Doc - -``` -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 : Doc - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.> display 1 - - `builtin.List.take n xs` returns the first `n` elements of `xs`. - (No need to add line breaks manually. The display command will - do wrapping of text for you. Indent any lines where you don't - want it to do this.) - - ## Examples: - - List.take.ex1 : [Nat] - List.take.ex1 = builtin.List.take 0 [1, 2, 3, 4, 5] - 🔽 - ex1 = [] - - - List.take.ex2 : [Nat] - List.take.ex2 = builtin.List.take 2 [1, 2, 3, 4, 5] - 🔽 - ex2 = [1, 2] - + List.take.doc : Doc ``` -Or there's also a convenient function, `docs`, which shows the `Doc` values that are linked to a definition. It's implemented in terms of `links` and `display`: +We can view it with `docs`, which shows the `Doc` value that is associated with a definition. ```ucm -.> docs builtin.List.take +.builtin> docs List.take - `builtin.List.take n xs` returns the first `n` elements of `xs`. - (No need to add line breaks manually. The display command will - do wrapping of text for you. Indent any lines where you don't - want it to do this.) + `List.take n xs` returns the first `n` elements of `xs`. (No need + to add line breaks manually. The display command will do wrapping + of text for you. Indent any lines where you don't want it to do + this.) ## Examples: List.take.ex1 : [Nat] - List.take.ex1 = builtin.List.take 0 [1, 2, 3, 4, 5] + List.take.ex1 = List.take 0 [1, 2, 3, 4, 5] 🔽 ex1 = [] List.take.ex2 : [Nat] - List.take.ex2 = builtin.List.take 2 [1, 2, 3, 4, 5] + List.take.ex2 = List.take 2 [1, 2, 3, 4, 5] 🔽 ex2 = [1, 2] @@ -194,25 +151,8 @@ Or there's also a convenient function, `docs`, which shows the `Doc` values that Note that if we view the source of the documentation, the various references are *not* expanded. ```ucm -.> view docs.List.take - - docs.List.take : Doc - docs.List.take = - [: `@builtin.List.take n xs` returns the first `n` elements of - `xs`. (No need to add line breaks manually. The display command - will do wrapping of text for you. Indent any lines where you - don't want it to do this.) - - ## Examples: - - @[source] ex1 - 🔽 - @ex1 = @[evaluate] ex1 - - - @[source] ex2 - 🔽 - @ex2 = @[evaluate] ex2 - :] +.builtin> view List.take + + builtin List.take : Nat -> [a] -> [a] ``` diff --git a/unison-src/transcripts/edit-command.output.md b/unison-src/transcripts/edit-command.output.md index 5cab1ced2a..a4c428e281 100644 --- a/unison-src/transcripts/edit-command.output.md +++ b/unison-src/transcripts/edit-command.output.md @@ -60,10 +60,6 @@ mytest = [Ok "ok"] definitions currently in this namespace. ``` -```unison:added-by-ucm /private/tmp/scratch.u -test> mytest = [Ok "ok"] -``` - ```unison:added-by-ucm /private/tmp/scratch.u bar : Nat bar = 456 @@ -72,6 +68,10 @@ foo : Nat foo = 123 ``` +```unison:added-by-ucm /private/tmp/scratch.u +test> mytest = [Ok "ok"] +``` + ```ucm .> edit missing diff --git a/unison-src/transcripts/edit-namespace.md b/unison-src/transcripts/edit-namespace.md new file mode 100644 index 0000000000..653ba85e4d --- /dev/null +++ b/unison-src/transcripts/edit-namespace.md @@ -0,0 +1,41 @@ +```ucm:hide +.lib> builtins.mergeio +``` + +```unison:hide +{{ ping doc }} +nested.cycle.ping n = n Nat.+ pong n + +{{ pong doc }} +nested.cycle.pong n = n Nat.+ ping n + +toplevel = "hi" + +simple.x = 10 +simple.y = 20 + +-- Shouldn't edit things in lib +lib.project.ignoreMe = 30 +``` + +```ucm:hide +.> add +``` + +Edit current namespace + +```ucm +.simple> edit.namespace +``` + +Edit should hit things recursively + +```ucm +.> edit.namespace +``` + +Edit should handle multiple explicit paths at once. + +```ucm +.> edit.namespace nested.cycle simple +``` diff --git a/unison-src/transcripts/edit-namespace.output.md b/unison-src/transcripts/edit-namespace.output.md new file mode 100644 index 0000000000..c180a2a330 --- /dev/null +++ b/unison-src/transcripts/edit-namespace.output.md @@ -0,0 +1,114 @@ +```unison +{{ ping doc }} +nested.cycle.ping n = n Nat.+ pong n + +{{ pong doc }} +nested.cycle.pong n = n Nat.+ ping n + +toplevel = "hi" + +simple.x = 10 +simple.y = 20 + +-- Shouldn't edit things in lib +lib.project.ignoreMe = 30 +``` + +Edit current namespace + +```ucm +.simple> edit.namespace + + ☝️ + + I added 2 definitions to the top of scratch.u + + You can edit them there, then run `update` to replace the + definitions currently in this namespace. + +``` +```unison:added-by-ucm scratch.u +x : ##Nat +x = 10 + +y : ##Nat +y = 20 +``` + +Edit should hit things recursively + +```ucm +.> edit.namespace + + ☝️ + + I added 7 definitions to the top of scratch.u + + You can edit them there, then run `update` to replace the + definitions currently in this namespace. + +``` +```unison:added-by-ucm scratch.u +nested.cycle.ping : Nat -> Nat +nested.cycle.ping n = + use Nat + + n + nested.cycle.pong n + +nested.cycle.ping.doc : Doc2 +nested.cycle.ping.doc = {{ ping doc }} + +nested.cycle.pong : Nat -> Nat +nested.cycle.pong n = + use Nat + + n + nested.cycle.ping n + +nested.cycle.pong.doc : Doc2 +nested.cycle.pong.doc = {{ pong doc }} + +simple.x : Nat +simple.x = 10 + +simple.y : Nat +simple.y = 20 + +toplevel : Text +toplevel = "hi" +``` + +Edit should handle multiple explicit paths at once. + +```ucm +.> edit.namespace nested.cycle simple + + ☝️ + + I added 6 definitions to the top of scratch.u + + You can edit them there, then run `update` to replace the + definitions currently in this namespace. + +``` +```unison:added-by-ucm scratch.u +nested.cycle.ping : Nat -> Nat +nested.cycle.ping n = + use Nat + + n + nested.cycle.pong n + +nested.cycle.ping.doc : Doc2 +nested.cycle.ping.doc = {{ ping doc }} + +nested.cycle.pong : Nat -> Nat +nested.cycle.pong n = + use Nat + + n + nested.cycle.ping n + +nested.cycle.pong.doc : Doc2 +nested.cycle.pong.doc = {{ pong doc }} + +simple.x : Nat +simple.x = 10 + +simple.y : Nat +simple.y = 20 +``` + diff --git a/unison-src/transcripts/find-by-type.output.md b/unison-src/transcripts/find-by-type.output.md index 916857b524..0577051f92 100644 --- a/unison-src/transcripts/find-by-type.output.md +++ b/unison-src/transcripts/find-by-type.output.md @@ -17,7 +17,7 @@ baz = cases ⍟ I've added these definitions: - unique type A + type A bar : Text -> A baz : A -> Text foo : A diff --git a/unison-src/transcripts/find-command.md b/unison-src/transcripts/find-command.md index b5682104a1..8e60a0fd4b 100644 --- a/unison-src/transcripts/find-command.md +++ b/unison-src/transcripts/find-command.md @@ -2,7 +2,6 @@ foo = 1 lib.foo = 2 lib.bar = 3 -foo.lib.qux = 4 ``` ```ucm @@ -13,6 +12,10 @@ foo.lib.qux = 4 .> find foo ``` +```ucm +.somewhere> find.global foo +``` + ```ucm .> find bar ``` @@ -21,10 +24,6 @@ foo.lib.qux = 4 .> find baz ``` -```ucm -.> find qux -``` - ```ucm:error .> find.global nothere ``` diff --git a/unison-src/transcripts/find-command.output.md b/unison-src/transcripts/find-command.output.md index 06e0bab477..1c2618a0f2 100644 --- a/unison-src/transcripts/find-command.output.md +++ b/unison-src/transcripts/find-command.output.md @@ -2,7 +2,6 @@ foo = 1 lib.foo = 2 lib.bar = 3 -foo.lib.qux = 4 ``` ```ucm @@ -15,10 +14,9 @@ foo.lib.qux = 4 ⍟ These new definitions are ok to `add`: - foo : ##Nat - foo.lib.qux : ##Nat - lib.bar : ##Nat - lib.foo : ##Nat + foo : ##Nat + lib.bar : ##Nat + lib.foo : ##Nat ``` ```ucm @@ -26,17 +24,25 @@ foo.lib.qux = 4 ⍟ I've added these definitions: - foo : ##Nat - foo.lib.qux : ##Nat - lib.bar : ##Nat - lib.foo : ##Nat + foo : ##Nat + lib.bar : ##Nat + lib.foo : ##Nat ``` ```ucm .> find foo 1. foo : ##Nat - 2. foo.lib.qux : ##Nat + + +``` +```ucm + ☝️ The namespace .somewhere is empty. + +.somewhere> find.global foo + + 1. .foo : ##Nat + 2. .lib.foo : ##Nat ``` @@ -68,13 +74,6 @@ foo.lib.qux = 4 `find.global` can be used to search outside the current namespace. -``` -```ucm -.> find qux - - 1. foo.lib.qux : ##Nat - - ``` ```ucm .> find.global nothere diff --git a/unison-src/transcripts/fix-big-list-crash.output.md b/unison-src/transcripts/fix-big-list-crash.output.md index 9f25f705b9..1d14e77d7b 100644 --- a/unison-src/transcripts/fix-big-list-crash.output.md +++ b/unison-src/transcripts/fix-big-list-crash.output.md @@ -18,7 +18,7 @@ x = [(R,1005),(U,563),(R,417),(U,509),(L,237),(U,555),(R,397),(U,414),(L,490),(U ⍟ These new definitions are ok to `add`: - unique type Direction + type Direction x : [(Direction, Nat)] ``` diff --git a/unison-src/transcripts/fix1356.md b/unison-src/transcripts/fix1356.md deleted file mode 100644 index abe31b10a1..0000000000 --- a/unison-src/transcripts/fix1356.md +++ /dev/null @@ -1,46 +0,0 @@ -##### This transcript reproduces the failure to unlink documentation - -```ucm:hide -.> builtins.merge -``` - -Step 1: code a term and documentation for it -```unison -x = 1 -x.doc = [: I am the documentation for x:] -``` - -Step 2: add term and documentation, link, and check the documentation -```ucm -.trunk> add -.trunk> link x.doc x -.trunk> docs x -``` - -Step 2.5: We'll save this for later for some reason. -```ucm -.trunk> alias.term x.doc .backup.x.doc -``` - -Step 3: Oops I don't like the doc, so I will re-code it! -```unison -x.doc = [: I am the documentation for x, and I now look better:] -``` - -Step 4: I add it and expect to see it -```ucm -.trunk> update -.trunk> docs x -``` - -That works great. Let's relink the old doc too. - -```ucm -.trunk> link .backup.x.doc x -``` - -Let's check that we see both docs: - -```ucm -.trunk> docs x -``` diff --git a/unison-src/transcripts/fix1356.output.md b/unison-src/transcripts/fix1356.output.md deleted file mode 100644 index 195266679d..0000000000 --- a/unison-src/transcripts/fix1356.output.md +++ /dev/null @@ -1,101 +0,0 @@ -##### This transcript reproduces the failure to unlink documentation - -Step 1: code a term and documentation for it -```unison -x = 1 -x.doc = [: I am the documentation for x:] -``` - -```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`: - - x : Nat - x.doc : Doc - -``` -Step 2: add term and documentation, link, and check the documentation -```ucm - ☝️ The namespace .trunk is empty. - -.trunk> add - - ⍟ I've added these definitions: - - x : Nat - x.doc : Doc - -.trunk> link x.doc x - - Updates: - - 1. trunk.x : Nat - + 2. doc : Doc - -.trunk> docs x - - I am the documentation for x - -``` -Step 2.5: We'll save this for later for some reason. -```ucm -.trunk> alias.term x.doc .backup.x.doc - - Done. - -``` -Step 3: Oops I don't like the doc, so I will re-code it! -```unison -x.doc = [: I am the documentation for x, and I now look better:] -``` - -```ucm - - Loading changes detected in scratch.u. - - I found and typechecked these definitions in scratch.u. If you - do an `add` or `update`, here's how your codebase would - change: - - ⍟ These names already exist. You can `update` them to your - new definition: - - x.doc : Doc - -``` -Step 4: I add it and expect to see it -```ucm -.trunk> update - - Okay, I'm searching the branch for code that needs to be - updated... - - Done. - -.trunk> docs x - - I am the documentation for x, and I now look better - -``` -That works great. Let's relink the old doc too. - -```ucm -.trunk> link .backup.x.doc x - - I didn't make any changes. - -``` -Let's check that we see both docs: - -```ucm -.trunk> docs x - - I am the documentation for x, and I now look better - -``` diff --git a/unison-src/transcripts/fix1696.md b/unison-src/transcripts/fix1696.md index 043b1b60b9..c80b41a731 100644 --- a/unison-src/transcripts/fix1696.md +++ b/unison-src/transcripts/fix1696.md @@ -4,9 +4,9 @@ ``` ```unison:error -ability Ask where ask : Nat +structural ability Ask where ask : Nat -unique ability Zoot where +ability Zoot where zoot : Nat Ask.provide : '{Zoot} Nat -> '{Ask} r -> r diff --git a/unison-src/transcripts/fix1696.output.md b/unison-src/transcripts/fix1696.output.md index c8219e3276..c0a9ccce85 100644 --- a/unison-src/transcripts/fix1696.output.md +++ b/unison-src/transcripts/fix1696.output.md @@ -1,8 +1,8 @@ ```unison -ability Ask where ask : Nat +structural ability Ask where ask : Nat -unique ability Zoot where +ability Zoot where zoot : Nat Ask.provide : '{Zoot} Nat -> '{Ask} r -> r @@ -21,13 +21,9 @@ dialog = Ask.provide 'zoot '("Awesome number: " ++ Nat.toText Ask.ask ++ "!") Loading changes detected in scratch.u. - I expected to see `structural` or `unique` at the start of - this line: + The expression in red needs the {Zoot} ability, but this location does not have access to any abilities. - 1 | ability Ask where ask : Nat + 13 | dialog = Ask.provide 'zoot '("Awesome number: " ++ Nat.toText Ask.ask ++ "!") - Learn more about when to use `structural` vs `unique` in the - Unison Docs: - https://www.unison-lang.org/learn/language-reference/unique-types/ ``` diff --git a/unison-src/transcripts/fix1844.output.md b/unison-src/transcripts/fix1844.output.md index 33bb4a26bd..571daa8b9a 100644 --- a/unison-src/transcripts/fix1844.output.md +++ b/unison-src/transcripts/fix1844.output.md @@ -21,8 +21,8 @@ snoc k aN = match k with ⍟ These new definitions are ok to `add`: structural type One a - unique type Woot a b c - unique type Z + type Woot a b c + type Z snoc : One a -> aN -> Woot (One a) (One aN) ##Nat Now evaluating any watch expressions (lines starting with diff --git a/unison-src/transcripts/fix2004.md b/unison-src/transcripts/fix2004.md index a88b705f0c..4f8fd0203d 100644 --- a/unison-src/transcripts/fix2004.md +++ b/unison-src/transcripts/fix2004.md @@ -23,21 +23,21 @@ So `j1` and `j2` have common history up through `v4`, then `j1` deletes some def First, we create some common history before a fork: ```ucm -.a> alias.term .builtin.Nat.+ delete1 -.a> alias.term .builtin.Nat.* delete2 -.a> alias.term .builtin.Nat.drop delete3 -.a> alias.type .builtin.Nat Delete4 +.> alias.term builtin.Nat.+ a.delete1 +.> alias.term builtin.Nat.* a.delete2 +.> alias.term builtin.Nat.drop a.delete3 +.> alias.type builtin.Nat a.Delete4 ``` Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previously and then adding one unrelated term via a merge with little history. It's this short history merge which will become a bad LCA of the empty namespace. ```ucm .> fork a a2 -.a> delete.term.verbose delete1 -.a> delete.term.verbose delete2 -.a> delete.term.verbose delete3 -.a> delete.type.verbose Delete4 -.newbranchA> alias.term .builtin.Float.+ dontDelete +.> delete.term.verbose a.delete1 +.> delete.term.verbose a.delete2 +.> delete.term.verbose a.delete3 +.> delete.type.verbose a.Delete4 +.> alias.term .builtin.Float.+ newbranchA.dontDelete .> merge newbranchA a .a> find ``` @@ -45,12 +45,12 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ Meanwhile, `a2` adds some other unrelated terms, some via merging in namespaces with little history. When merging `a2` back into `a`, the deletes from their common history should be respected. ```ucm -.a2> alias.term .builtin.Text.take keep1 -.a2> alias.term .builtin.Text.take keep2 -.a2> alias.term .builtin.Text.take keep3 -.a2> alias.term .builtin.Text.take keep4 -.a2> alias.term .builtin.Text.take keep5 -.newbranchA2> alias.term .builtin.Text.take keep6 +.> alias.term builtin.Text.take a2.keep1 +.> alias.term builtin.Text.take a2.keep2 +.> alias.term builtin.Text.take a2.keep3 +.> alias.term builtin.Text.take a2.keep4 +.> alias.term builtin.Text.take a2.keep5 +.> alias.term builtin.Text.take newbranchA2.keep6 .> merge newbranchA2 a2 .a2> find ``` diff --git a/unison-src/transcripts/fix2004.output.md b/unison-src/transcripts/fix2004.output.md index 11fcf73e68..f2e202911e 100644 --- a/unison-src/transcripts/fix2004.output.md +++ b/unison-src/transcripts/fix2004.output.md @@ -20,21 +20,19 @@ So `j1` and `j2` have common history up through `v4`, then `j1` deletes some def First, we create some common history before a fork: ```ucm - ☝️ The namespace .a is empty. - -.a> alias.term .builtin.Nat.+ delete1 +.> alias.term builtin.Nat.+ a.delete1 Done. -.a> alias.term .builtin.Nat.* delete2 +.> alias.term builtin.Nat.* a.delete2 Done. -.a> alias.term .builtin.Nat.drop delete3 +.> alias.term builtin.Nat.drop a.delete3 Done. -.a> alias.type .builtin.Nat Delete4 +.> alias.type builtin.Nat a.Delete4 Done. @@ -46,7 +44,7 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ Done. -.a> delete.term.verbose delete1 +.> delete.term.verbose a.delete1 Name changes: @@ -57,7 +55,7 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ Tip: You can use `undo` or `reflog` to undo this change. -.a> delete.term.verbose delete2 +.> delete.term.verbose a.delete2 Name changes: @@ -68,7 +66,7 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ Tip: You can use `undo` or `reflog` to undo this change. -.a> delete.term.verbose delete3 +.> delete.term.verbose a.delete3 Name changes: @@ -79,7 +77,7 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ Tip: You can use `undo` or `reflog` to undo this change. -.a> delete.type.verbose Delete4 +.> delete.type.verbose a.Delete4 Name changes: @@ -90,9 +88,7 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ Tip: You can use `undo` or `reflog` to undo this change. - ☝️ The namespace .newbranchA is empty. - -.newbranchA> alias.term .builtin.Float.+ dontDelete +.> alias.term .builtin.Float.+ newbranchA.dontDelete Done. @@ -113,36 +109,34 @@ Now we fork `a2` off of `a`. `a` continues on, deleting the terms it added previ .a> find - 1. dontDelete : Float -> Float -> Float + 1. dontDelete : ##Float -> ##Float -> ##Float ``` Meanwhile, `a2` adds some other unrelated terms, some via merging in namespaces with little history. When merging `a2` back into `a`, the deletes from their common history should be respected. ```ucm -.a2> alias.term .builtin.Text.take keep1 +.> alias.term builtin.Text.take a2.keep1 Done. -.a2> alias.term .builtin.Text.take keep2 +.> alias.term builtin.Text.take a2.keep2 Done. -.a2> alias.term .builtin.Text.take keep3 +.> alias.term builtin.Text.take a2.keep3 Done. -.a2> alias.term .builtin.Text.take keep4 +.> alias.term builtin.Text.take a2.keep4 Done. -.a2> alias.term .builtin.Text.take keep5 +.> alias.term builtin.Text.take a2.keep5 Done. - ☝️ The namespace .newbranchA2 is empty. - -.newbranchA2> alias.term .builtin.Text.take keep6 +.> alias.term builtin.Text.take newbranchA2.keep6 Done. @@ -172,12 +166,12 @@ Meanwhile, `a2` adds some other unrelated terms, some via merging in namespaces 2. delete2 : Delete4 -> Delete4 -> Delete4 3. delete3 : Delete4 -> Delete4 -> Delete4 4. builtin type Delete4 - 5. keep1 : Delete4 -> Text -> Text - 6. keep2 : Delete4 -> Text -> Text - 7. keep3 : Delete4 -> Text -> Text - 8. keep4 : Delete4 -> Text -> Text - 9. keep5 : Delete4 -> Text -> Text - 10. keep6 : Delete4 -> Text -> Text + 5. keep1 : Delete4 -> ##Text -> ##Text + 6. keep2 : Delete4 -> ##Text -> ##Text + 7. keep3 : Delete4 -> ##Text -> ##Text + 8. keep4 : Delete4 -> ##Text -> ##Text + 9. keep5 : Delete4 -> ##Text -> ##Text + 10. keep6 : Delete4 -> ##Text -> ##Text ``` @@ -232,24 +226,24 @@ At this point, all the things that `a` has deleted (`delete1`, `delete2`, etc) s ```ucm .a> find - 1. dontDelete : Float -> Float -> Float - 2. keep1 : Delete4 -> Text -> Text - 3. keep2 : Delete4 -> Text -> Text - 4. keep3 : Delete4 -> Text -> Text - 5. keep4 : Delete4 -> Text -> Text - 6. keep5 : Delete4 -> Text -> Text - 7. keep6 : Delete4 -> Text -> Text + 1. dontDelete : ##Float -> ##Float -> ##Float + 2. keep1 : ##Nat -> ##Text -> ##Text + 3. keep2 : ##Nat -> ##Text -> ##Text + 4. keep3 : ##Nat -> ##Text -> ##Text + 5. keep4 : ##Nat -> ##Text -> ##Text + 6. keep5 : ##Nat -> ##Text -> ##Text + 7. keep6 : ##Nat -> ##Text -> ##Text .asquash> find - 1. dontDelete : Float -> Float -> Float - 2. keep1 : Delete4 -> Text -> Text - 3. keep2 : Delete4 -> Text -> Text - 4. keep3 : Delete4 -> Text -> Text - 5. keep4 : Delete4 -> Text -> Text - 6. keep5 : Delete4 -> Text -> Text - 7. keep6 : Delete4 -> Text -> Text + 1. dontDelete : ##Float -> ##Float -> ##Float + 2. keep1 : ##Nat -> ##Text -> ##Text + 3. keep2 : ##Nat -> ##Text -> ##Text + 4. keep3 : ##Nat -> ##Text -> ##Text + 5. keep4 : ##Nat -> ##Text -> ##Text + 6. keep5 : ##Nat -> ##Text -> ##Text + 7. keep6 : ##Nat -> ##Text -> ##Text ``` diff --git a/unison-src/transcripts/fix2049.output.md b/unison-src/transcripts/fix2049.output.md index 5cfb243198..db7ef61068 100644 --- a/unison-src/transcripts/fix2049.output.md +++ b/unison-src/transcripts/fix2049.output.md @@ -58,8 +58,8 @@ Fold.Stream.fold = ⍟ These new definitions are ok to `add`: - unique type Fold g a b - unique type Fold' g a b x + type Fold g a b + type Fold' g a b x structural ability Stream a Fold.Stream.fold : Fold g a b -> '{g, Stream a} r diff --git a/unison-src/transcripts/fix2254.md b/unison-src/transcripts/fix2254.md index cae8f93dbb..3b6dd15e6c 100644 --- a/unison-src/transcripts/fix2254.md +++ b/unison-src/transcripts/fix2254.md @@ -1,6 +1,6 @@ ```ucm:hide -.> builtins.merge +.a> builtins.merge ``` This transcript checks that updates to data types propagate successfully to dependent types and dependent terms that do pattern matching. First let's create some types and terms: @@ -75,14 +75,14 @@ structural type Rec = { uno : Nat, dos : Nat } combine r = uno r + dos r ``` -```ucm -.a3> add -``` - ```ucm:hide .a3> builtins.merge ``` +```ucm +.a3> add +``` + ```unison structural type Rec = { uno : Nat, dos : Nat, tres : Text } ``` diff --git a/unison-src/transcripts/fix2254.output.md b/unison-src/transcripts/fix2254.output.md index 5419e28057..61af269b2c 100644 --- a/unison-src/transcripts/fix2254.output.md +++ b/unison-src/transcripts/fix2254.output.md @@ -34,13 +34,11 @@ g = cases We'll make our edits in a fork of the `a` namespace: ```ucm - ☝️ The namespace .a is empty. - .a> add ⍟ I've added these definitions: - unique type A a b c d + type A a b c d structural type NeedsA a b f : A Nat Nat Nat Nat -> Nat f2 : A Nat Nat Nat Nat -> Nat @@ -70,11 +68,11 @@ Let's do the update now, and verify that the definitions all look good and there ⍟ I've updated these names to your new definition: - unique type A a b c d + type A a b c d .a2> view A NeedsA f f2 f3 g - unique type A a b c d + type A a b c d = B b | D d | E a d @@ -144,8 +142,6 @@ combine r = uno r + dos r ``` ```ucm - ☝️ The namespace .a3 is empty. - .a3> add ⍟ I've added these definitions: diff --git a/unison-src/transcripts/fix2268.output.md b/unison-src/transcripts/fix2268.output.md index c742b78fd2..bfb65920fd 100644 --- a/unison-src/transcripts/fix2268.output.md +++ b/unison-src/transcripts/fix2268.output.md @@ -25,8 +25,8 @@ test _ = ⍟ These new definitions are ok to `add`: - unique ability A - unique ability B + ability A + ability B test : '{B} Nat ``` diff --git a/unison-src/transcripts/fix2344.output.md b/unison-src/transcripts/fix2344.output.md index 82ca8fbf4b..6d0ae41c4f 100644 --- a/unison-src/transcripts/fix2344.output.md +++ b/unison-src/transcripts/fix2344.output.md @@ -27,7 +27,7 @@ sneezy dee _ = ⍟ These new definitions are ok to `add`: - unique ability Nate + ability Nate sneezy : (Nat ->{d} a) -> '{d, Nate} a ``` diff --git a/unison-src/transcripts/fix2350.output.md b/unison-src/transcripts/fix2350.output.md index 98d884780c..d8f6bf43b1 100644 --- a/unison-src/transcripts/fix2350.output.md +++ b/unison-src/transcripts/fix2350.output.md @@ -35,7 +35,7 @@ save a = !(save.impl a) ⍟ These new definitions are ok to `add`: - unique ability Storage d g + ability Storage d g save : a ->{g, Storage d g} d a ``` diff --git a/unison-src/transcripts/fix2353.output.md b/unison-src/transcripts/fix2353.output.md index 933a0dbda9..74c9da016f 100644 --- a/unison-src/transcripts/fix2353.output.md +++ b/unison-src/transcripts/fix2353.output.md @@ -21,8 +21,8 @@ pure.run a0 a = ⍟ These new definitions are ok to `add`: - unique ability Async t g - unique ability Exception + ability Async t g + ability Exception pure.run : a -> (∀ t. '{Async t g} a) ->{g, Exception} a ``` diff --git a/unison-src/transcripts/fix2378.output.md b/unison-src/transcripts/fix2378.output.md index 3282c9d01b..5acef2316d 100644 --- a/unison-src/transcripts/fix2378.output.md +++ b/unison-src/transcripts/fix2378.output.md @@ -49,9 +49,9 @@ x _ = Ex.catch '(C.pure.run '(A.pure.run ex)) ⍟ These new definitions are ok to `add`: - unique ability A t g - unique ability C c - unique ability Ex + ability A t g + ability C c + ability Ex A.pure.run : (∀ t. '{g, A t g} a) ->{g, Ex} a C.pure.run : (∀ c. '{g, C c} r) ->{g, Ex} r Ex.catch : '{g, Ex} a ->{g} Either () a diff --git a/unison-src/transcripts/fix2567.md b/unison-src/transcripts/fix2567.md deleted file mode 100644 index 0724325738..0000000000 --- a/unison-src/transcripts/fix2567.md +++ /dev/null @@ -1,18 +0,0 @@ -Regression test for https://github.com/unisonweb/unison/issues/2567 - -```ucm:hide -.> alias.type ##Nat .foo.bar.Nat -``` - -```unison:hide -structural ability Foo where - blah : Nat -> Nat - zing.woot : Nat -> (Nat,Nat) -> Nat -``` - -```ucm -.some.subnamespace> add -.some.subnamespace> alias.term Foo.zing.woot Foo.woot -.> view Foo -.somewhere> view .some.subnamespace.Foo -``` diff --git a/unison-src/transcripts/fix2567.output.md b/unison-src/transcripts/fix2567.output.md deleted file mode 100644 index 4e77f5561d..0000000000 --- a/unison-src/transcripts/fix2567.output.md +++ /dev/null @@ -1,36 +0,0 @@ -Regression test for https://github.com/unisonweb/unison/issues/2567 - -```unison -structural ability Foo where - blah : Nat -> Nat - zing.woot : Nat -> (Nat,Nat) -> Nat -``` - -```ucm - ☝️ The namespace .some.subnamespace is empty. - -.some.subnamespace> add - - ⍟ I've added these definitions: - - structural ability Foo - -.some.subnamespace> alias.term Foo.zing.woot Foo.woot - - Done. - -.> view Foo - - structural ability some.subnamespace.Foo where - blah : Nat ->{some.subnamespace.Foo} Nat - woot : Nat -> (Nat, Nat) ->{some.subnamespace.Foo} Nat - - ☝️ The namespace .somewhere is empty. - -.somewhere> view .some.subnamespace.Foo - - structural ability .some.subnamespace.Foo where - blah : Nat ->{.some.subnamespace.Foo} Nat - woot : Nat -> (Nat, Nat) ->{.some.subnamespace.Foo} Nat - -``` diff --git a/unison-src/transcripts/fix2628.output.md b/unison-src/transcripts/fix2628.output.md index 8faf5b36cb..64b45ed29b 100644 --- a/unison-src/transcripts/fix2628.output.md +++ b/unison-src/transcripts/fix2628.output.md @@ -9,7 +9,7 @@ unique type foo.bar.baz.MyRecord = { ⍟ I've added these definitions: - unique type foo.bar.baz.MyRecord + type foo.bar.baz.MyRecord foo.bar.baz.MyRecord.value : MyRecord -> Nat foo.bar.baz.MyRecord.value.modify : (Nat ->{g} Nat) -> MyRecord diff --git a/unison-src/transcripts/fix2712.output.md b/unison-src/transcripts/fix2712.output.md index 07dc8a9369..08cdb89a30 100644 --- a/unison-src/transcripts/fix2712.output.md +++ b/unison-src/transcripts/fix2712.output.md @@ -15,7 +15,7 @@ mapWithKey f m = Tip ⍟ These new definitions are ok to `add`: - unique type Map k v + type Map k v mapWithKey : (k ->{e} a ->{e} b) -> Map k a ->{e} Map k b ``` @@ -24,7 +24,7 @@ mapWithKey f m = Tip ⍟ I've added these definitions: - unique type Map k v + type Map k v mapWithKey : (k ->{e} a ->{e} b) -> Map k a ->{e} Map k b ``` diff --git a/unison-src/transcripts/fix2840.output.md b/unison-src/transcripts/fix2840.output.md index a8c8f1ea95..c47df9a2c7 100644 --- a/unison-src/transcripts/fix2840.output.md +++ b/unison-src/transcripts/fix2840.output.md @@ -7,9 +7,9 @@ First, a few \[hidden] definitions necessary for typechecking a simple Doc2. ⍟ I've added these definitions: - unique type Doc2 - unique type Doc2.SpecialForm - unique type Doc2.Term + type Doc2 + type Doc2.SpecialForm + type Doc2.Term structural type Optional a (also named builtin.Optional) syntax.docParagraph : [Doc2] -> Doc2 diff --git a/unison-src/transcripts/fix3196.output.md b/unison-src/transcripts/fix3196.output.md index a5c1b13506..3a5e2944d1 100644 --- a/unison-src/transcripts/fix3196.output.md +++ b/unison-src/transcripts/fix3196.output.md @@ -38,7 +38,7 @@ w2 = cases W -> W ⍟ These new definitions are ok to `add`: structural type W es - unique ability Zoot + ability Zoot ex : '{Zoot} r w1 : W {Zoot} w2 : W {g} -> W {g} diff --git a/unison-src/transcripts/fix3759.output.md b/unison-src/transcripts/fix3759.output.md index 56a11ad8ea..d4f1d9b2a1 100644 --- a/unison-src/transcripts/fix3759.output.md +++ b/unison-src/transcripts/fix3759.output.md @@ -58,9 +58,9 @@ blah.frobnicate = "Yay!" ⍟ These new definitions are ok to `add`: - unique ability Blah - unique type Oog.Foo - unique type Something + ability Blah + type Oog.Foo + type Something Something.state : Something -> Text Something.state.modify : (Text ->{g} Text) -> Something diff --git a/unison-src/transcripts/fix4415.output.md b/unison-src/transcripts/fix4415.output.md index 0cd2354230..b6d881fa2a 100644 --- a/unison-src/transcripts/fix4415.output.md +++ b/unison-src/transcripts/fix4415.output.md @@ -14,7 +14,7 @@ unique type sub.Foo = ⍟ These new definitions are ok to `add`: - unique type Foo - unique type sub.Foo + type Foo + type sub.Foo ``` diff --git a/unison-src/transcripts/fix4424.output.md b/unison-src/transcripts/fix4424.output.md index daf48abcb3..bb00ce7303 100644 --- a/unison-src/transcripts/fix4424.output.md +++ b/unison-src/transcripts/fix4424.output.md @@ -13,8 +13,8 @@ countCat = cases ⍟ I've added these definitions: - unique type Cat.Dog - unique type Rat.Dog + type Cat.Dog + type Rat.Dog countCat : Cat.Dog -> Rat.Dog ``` diff --git a/unison-src/transcripts/fix4482.md b/unison-src/transcripts/fix4482.md index 557f55f3dd..1e4a9b1a51 100644 --- a/unison-src/transcripts/fix4482.md +++ b/unison-src/transcripts/fix4482.md @@ -1,5 +1,6 @@ ```ucm:hide -.> builtins.merge +.> project.create-empty myproj +myproj/main> builtins.merge ``` ```unison @@ -11,7 +12,6 @@ mybar = bar + bar ``` ```ucm:error -.> project.create-empty myproj myproj/main> add myproj/main> upgrade foo0 foo1 ``` diff --git a/unison-src/transcripts/fix4482.output.md b/unison-src/transcripts/fix4482.output.md index 9e8666b24e..30bb9ff6b3 100644 --- a/unison-src/transcripts/fix4482.output.md +++ b/unison-src/transcripts/fix4482.output.md @@ -24,22 +24,6 @@ mybar = bar + bar ``` ```ucm -.> project.create-empty myproj - - 🎉 I've created the project myproj. - - 🎨 Type `ui` to explore this project's code in your browser. - 🔭 Discover libraries at https://share.unison-lang.org - 📖 Use `help-topic projects` to learn more about projects. - - Write your first Unison code with UCM: - - 1. Open scratch.u. - 2. Write some Unison code and save the file. - 3. In UCM, type `add` to save it to your new project. - - 🎉 🥳 Happy coding! - myproj/main> add ⍟ I've added these definitions: @@ -52,13 +36,16 @@ myproj/main> add myproj/main> upgrade foo0 foo1 - I couldn't automatically upgrade foo0 to foo1. + I couldn't automatically upgrade foo0 to foo1. However, I've + added the definitions that need attention to the top of + scratch.u. ``` ```unison:added-by-ucm scratch.u -mybar : ##Nat +mybar : Nat mybar = + use Nat + use lib.foo0.lib.bonk1 bar - ##Nat.+ bar bar + bar + bar ``` diff --git a/unison-src/transcripts/fix4515.output.md b/unison-src/transcripts/fix4515.output.md index fec0f84e0f..e2f03e9d5a 100644 --- a/unison-src/transcripts/fix4515.output.md +++ b/unison-src/transcripts/fix4515.output.md @@ -18,9 +18,9 @@ useBar = cases ⍟ These new definitions are ok to `add`: - unique type Bar - unique type Baz - unique type Foo + type Bar + type Baz + type Foo useBar : Bar -> Nat ``` @@ -29,9 +29,9 @@ myproject/main> add ⍟ I've added these definitions: - unique type Bar - unique type Baz - unique type Foo + type Bar + type Baz + type Foo useBar : Bar -> Nat ``` @@ -50,7 +50,7 @@ unique type Foo = Foo1 | Foo2 ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm diff --git a/unison-src/transcripts/fix4556.md b/unison-src/transcripts/fix4556.md new file mode 100644 index 0000000000..d4775b587b --- /dev/null +++ b/unison-src/transcripts/fix4556.md @@ -0,0 +1,22 @@ +```ucm:hide +.> builtins.merge +``` + +```unison +thing = 3 +foo.hello = 5 + thing +bar.hello = 5 + thing +hey = foo.hello +``` + +```ucm +.> add +``` + +```unison +thing = 2 +``` + +```ucm +.> update +``` diff --git a/unison-src/transcripts-using-base/update-test-to-non-test.output.md b/unison-src/transcripts/fix4556.output.md similarity index 53% rename from unison-src/transcripts-using-base/update-test-to-non-test.output.md rename to unison-src/transcripts/fix4556.output.md index 2c1c97b6aa..d65321a311 100644 --- a/unison-src/transcripts-using-base/update-test-to-non-test.output.md +++ b/unison-src/transcripts/fix4556.output.md @@ -1,7 +1,8 @@ -When updating a term from a test to a non-test, we don't delete its metadata that indicates it's a test. This is a bug. - ```unison -test> foo = [] +thing = 3 +foo.hello = 5 + thing +bar.hello = 5 + thing +hey = foo.hello ``` ```ucm @@ -14,13 +15,10 @@ test> foo = [] ⍟ These new definitions are ok to `add`: - foo : [Result] - - Now evaluating any watch expressions (lines starting with - `>`)... Ctrl+C cancels. - - 1 | test> foo = [] - + bar.hello : Nat + foo.hello : Nat + hey : Nat + thing : Nat ``` ```ucm @@ -28,11 +26,14 @@ test> foo = [] ⍟ I've added these definitions: - foo : [Result] + bar.hello : Nat + foo.hello : Nat + hey : Nat + thing : Nat ``` ```unison -foo = 1 +thing = 2 ``` ```ucm @@ -46,21 +47,19 @@ foo = 1 ⍟ These names already exist. You can `update` them to your new definition: - foo : Nat + thing : Nat ``` ```ucm -.> update.old +.> update - ⍟ I've updated these names to your new definition: - - foo : Nat + Okay, I'm searching the branch for code that needs to be + updated... -.> links foo + That's done. Now I'm making sure everything typechecks... - 1. builtin.metadata.isTest : IsTest - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. + Everything typechecks, so I'm saving the results... + + Done. ``` diff --git a/unison-src/transcripts/formatter.md b/unison-src/transcripts/formatter.md new file mode 100644 index 0000000000..07e70bfbb7 --- /dev/null +++ b/unison-src/transcripts/formatter.md @@ -0,0 +1,36 @@ +```ucm:hide +.> builtins.mergeio +``` + +```unison +-- TODO: support formatting docs with {{ }} syntax. +-- For now we just skip formatting any .doc terms. +{{ # Doc +This is a *doc*! + +term link {x} + +type link {type Optional} + +}} +x : + Nat + -> Nat +x y = + x = 1 + 1 + x + y +-- Should keep comments after + +type Optional a = More Text + | Some + | Other a + | None Nat + +ability Thing where + more : Nat -> Text -> Nat + doThing : Nat -> Int +``` + +```ucm +.> debug.format +``` diff --git a/unison-src/transcripts/formatter.output.md b/unison-src/transcripts/formatter.output.md new file mode 100644 index 0000000000..01afaa0c8f --- /dev/null +++ b/unison-src/transcripts/formatter.output.md @@ -0,0 +1,74 @@ +```unison +-- TODO: support formatting docs with {{ }} syntax. +-- For now we just skip formatting any .doc terms. +{{ # Doc +This is a *doc*! + +term link {x} + +type link {type Optional} + +}} +x : + Nat + -> Nat +x y = + x = 1 + 1 + x + y +-- Should keep comments after + +type Optional a = More Text + | Some + | Other a + | None Nat + +ability Thing where + more : Nat -> Text -> Nat + doThing : Nat -> Int +``` + +```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 Optional a + ability Thing + x : Nat -> Nat + x.doc : Doc2 + +``` +```ucm +.> debug.format + +``` +```unison:added-by-ucm scratch.u +-- TODO: support formatting docs with {{ }} syntax. +-- For now we just skip formatting any .doc terms. +{{ # Doc +This is a *doc*! + +term link {x} + +type link {type Optional} + +}} +x : Nat -> Nat +x y = + use Nat + + x = 1 + 1 + x + y +-- Should keep comments after + +type Optional a = More Text | Some | Other a | None Nat + +ability Thing where + more : Nat -> Text -> Nat + doThing : Nat -> Int +``` + diff --git a/unison-src/transcripts/fuzzy-options.output.md b/unison-src/transcripts/fuzzy-options.output.md index 3b9554ca04..d00de8b0af 100644 --- a/unison-src/transcripts/fuzzy-options.output.md +++ b/unison-src/transcripts/fuzzy-options.output.md @@ -7,12 +7,92 @@ If an argument is required but doesn't have a fuzzy resolver, the command should -- The second argument of move.term is a 'new-name' and doesn't have a fuzzy resolver .> move.term +`move.term foo bar` renames `foo` to `bar`. + +``` +If a fuzzy resolver doesn't have any options available it should print a message instead of +opening an empty fuzzy-select. + +```ucm + ☝️ The namespace .empty is empty. + +.empty> view + +⚠️ + +Sorry, I was expecting an argument for the definition to view, and I couldn't find any to suggest to you. 😅 + +``` +```unison +optionOne = 1 + +nested.optionTwo = 2 +``` + +Definition args + +```ucm + ☝️ The namespace . is empty. + +.> add + + ⍟ I've added these definitions: + + nested.optionTwo : ##Nat + optionOne : ##Nat + +.> debug.fuzzy-options view _ + + Select a definition to view: + * optionOne + * nested.optionTwo + ``` +Namespace args + +```ucm +.> add + + ⊡ Ignored previously added definitions: nested.optionTwo + optionOne + +.> debug.fuzzy-options cd _ + + Select a namespace: + * nested ``` +Project Branch args + +```ucm +.> project.create-empty myproject + + 🎉 I've created the project myproject. + 🎨 Type `ui` to explore this project's code in your browser. + 🔭 Discover libraries at https://share.unison-lang.org + 📖 Use `help-topic projects` to learn more about projects. + + Write your first Unison code with UCM: + + 1. Open scratch.u. + 2. Write some Unison code and save the file. + 3. In UCM, type `add` to save it to your new project. + + 🎉 🥳 Happy coding! +myproject/main> branch mybranch -🛑 + Done. I've created the mybranch branch based off of main. + + Tip: Use `merge /mybranch /main` to merge your work back into + the main branch. -The transcript was expecting an error in the stanza above, but did not encounter one. +.> debug.fuzzy-options switch _ + + Select a project or branch to switch to: + * myproject/main + * myproject/mybranch + * myproject + +``` diff --git a/unison-src/transcripts/globbing.md b/unison-src/transcripts/globbing.md deleted file mode 100644 index 599d72ea4a..0000000000 --- a/unison-src/transcripts/globbing.md +++ /dev/null @@ -1,67 +0,0 @@ -# Globbing - -## Overview - -This allows quickly selecting terms, types, and namespaces for any "bulk" commands. - -* Currently supports up to one wildcard PER SEGMENT; Each segment can have its own wildcard if you really want and it'll still be performant. E.g. `.base.?.to?` -* Can have a prefix, suffix or infix wildcard! E.g. `to?` or `?List` or `to?With!` -* I went with `?` instead of `*` for the wildcard symbol since `?` isn't currently a valid symbol name. This may cause some confusion since it differs from bash globbing though; so if anyone has thoughts/concerns about how to better handle this I'd love to hear them. -* Commands can select which targets they want globs to expand to; e.g. `cd` should only glob for namespace, `view` should only glob to terms & types. - -## Demo - -Add some definitions which we can match over: -```unison:hide -convertToThing = 1 -convertFromThing = 2 -otherTerm = 3 - --- Nested definitions -nested.toList = 4 -nested.toMap = 5 -othernest.toList = 6 -othernest.toMap = 7 -``` - -```ucm:hide -.> add -``` - -Globbing as a prefix, infix, or suffix wildcard. - -```ucm -.> view convert? -.> view convert?Thing -.> view ?Thing -``` - -Globbing can occur in any name segment. - -```ucm -.> view ?.toList -.> view nested.to? -``` - -You may have up to one glob per name segment. - -```ucm -.> view ?.to? -``` - - -Globbing only expands to the appropriate argument type. - -E.g. `view` should not see glob expansions for namespaces. -This should expand to only the otherTerm. - -```ucm -.> view other? -``` - -Globbing should work from within a namespace with both absolute and relative patterns. - -```ucm -.nested> view .othernest.to? -.nested> view to? -``` diff --git a/unison-src/transcripts/globbing.output.md b/unison-src/transcripts/globbing.output.md deleted file mode 100644 index 2021a94ab4..0000000000 --- a/unison-src/transcripts/globbing.output.md +++ /dev/null @@ -1,124 +0,0 @@ -# Globbing - -## Overview - -This allows quickly selecting terms, types, and namespaces for any "bulk" commands. - -* Currently supports up to one wildcard PER SEGMENT; Each segment can have its own wildcard if you really want and it'll still be performant. E.g. `.base.?.to?` -* Can have a prefix, suffix or infix wildcard! E.g. `to?` or `?List` or `to?With!` -* I went with `?` instead of `*` for the wildcard symbol since `?` isn't currently a valid symbol name. This may cause some confusion since it differs from bash globbing though; so if anyone has thoughts/concerns about how to better handle this I'd love to hear them. -* Commands can select which targets they want globs to expand to; e.g. `cd` should only glob for namespace, `view` should only glob to terms & types. - -## Demo - -Add some definitions which we can match over: -```unison -convertToThing = 1 -convertFromThing = 2 -otherTerm = 3 - --- Nested definitions -nested.toList = 4 -nested.toMap = 5 -othernest.toList = 6 -othernest.toMap = 7 -``` - -Globbing as a prefix, infix, or suffix wildcard. - -```ucm -.> view convert? - - convertFromThing : ##Nat - convertFromThing = 2 - - convertToThing : ##Nat - convertToThing = 1 - -.> view convert?Thing - - convertFromThing : ##Nat - convertFromThing = 2 - - convertToThing : ##Nat - convertToThing = 1 - -.> view ?Thing - - convertFromThing : ##Nat - convertFromThing = 2 - - convertToThing : ##Nat - convertToThing = 1 - -``` -Globbing can occur in any name segment. - -```ucm -.> view ?.toList - - nested.toList : ##Nat - nested.toList = 4 - - othernest.toList : ##Nat - othernest.toList = 6 - -.> view nested.to? - - nested.toList : ##Nat - nested.toList = 4 - - nested.toMap : ##Nat - nested.toMap = 5 - -``` -You may have up to one glob per name segment. - -```ucm -.> view ?.to? - - nested.toList : ##Nat - nested.toList = 4 - - nested.toMap : ##Nat - nested.toMap = 5 - - othernest.toList : ##Nat - othernest.toList = 6 - - othernest.toMap : ##Nat - othernest.toMap = 7 - -``` -Globbing only expands to the appropriate argument type. - -E.g. `view` should not see glob expansions for namespaces. -This should expand to only the otherTerm. - -```ucm -.> view other? - - otherTerm : ##Nat - otherTerm = 3 - -``` -Globbing should work from within a namespace with both absolute and relative patterns. - -```ucm -.nested> view .othernest.to? - - .othernest.toList : ##Nat - .othernest.toList = 6 - - .othernest.toMap : ##Nat - .othernest.toMap = 7 - -.nested> view to? - - toList : ##Nat - toList = 4 - - toMap : ##Nat - toMap = 5 - -``` diff --git a/unison-src/transcripts/higher-rank.output.md b/unison-src/transcripts/higher-rank.output.md index 119645c918..a64a48ae39 100644 --- a/unison-src/transcripts/higher-rank.output.md +++ b/unison-src/transcripts/higher-rank.output.md @@ -77,7 +77,7 @@ Functor.blah = cases Functor f -> ⍟ These new definitions are ok to `add`: - unique type Functor f + type Functor f Functor.blah : Functor f -> () Functor.map : Functor f -> (∀ a b. (a -> b) -> f a -> f b) @@ -121,8 +121,8 @@ Loc.transform2 nt = cases Loc f -> ⍟ These new definitions are ok to `add`: - unique type Loc - unique ability Remote t + type Loc + ability Remote t Loc.blah : Loc -> () Loc.transform : (∀ t a. '{Remote t} a -> '{Remote t} a) -> Loc diff --git a/unison-src/transcripts/isPropagated-exists.md b/unison-src/transcripts/isPropagated-exists.md deleted file mode 100644 index 03e5109bc8..0000000000 --- a/unison-src/transcripts/isPropagated-exists.md +++ /dev/null @@ -1,39 +0,0 @@ -This transcript tests that UCM can always access the definition of -`IsPropagated`/`isPropagated`, which is used internally. - -```ucm:hide -.> alias.term ##Nat.+ + -.> alias.type ##Nat Nat -``` - -`y` depends on `x`, -```unison:hide -x = 3 -y = x + 1 -``` - -```ucm -.> add -``` - -so the `update` of `x` causes a propagated update of `y`, and UCM links the -`isPropagated` metadata to such resulting terms: - -```unison:hide -x = 4 -``` - -```ucm -.> update.old -.> links y -.> view 1 -``` - -Well, it's hard to tell from those hashes, but those are right. We can confirm -by running `builtins.merge` to have UCM add names for them. - -```ucm -.> builtins.merge -.> links y -.> view 1 -``` diff --git a/unison-src/transcripts/isPropagated-exists.output.md b/unison-src/transcripts/isPropagated-exists.output.md deleted file mode 100644 index 750260a417..0000000000 --- a/unison-src/transcripts/isPropagated-exists.output.md +++ /dev/null @@ -1,66 +0,0 @@ -This transcript tests that UCM can always access the definition of -`IsPropagated`/`isPropagated`, which is used internally. - -`y` depends on `x`, -```unison -x = 3 -y = x + 1 -``` - -```ucm -.> add - - ⍟ I've added these definitions: - - x : Nat - y : Nat - -``` -so the `update` of `x` causes a propagated update of `y`, and UCM links the -`isPropagated` metadata to such resulting terms: - -```unison -x = 4 -``` - -```ucm -.> update.old - - ⍟ I've updated these names to your new definition: - - x : Nat - -.> links y - - 1. #cb9e3iosob : #c23jofurce - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.> view 1 - - #cb9e3iosob : #c23jofurce - #cb9e3iosob = #c23jofurce#0 - -``` -Well, it's hard to tell from those hashes, but those are right. We can confirm -by running `builtins.merge` to have UCM add names for them. - -```ucm -.> builtins.merge - - Done. - -.> links y - - 1. builtin.metadata.isPropagated : IsPropagated - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.> view 1 - - builtin.metadata.isPropagated : IsPropagated - builtin.metadata.isPropagated = IsPropagated - -``` diff --git a/unison-src/transcripts/isTest-exists.md b/unison-src/transcripts/isTest-exists.md deleted file mode 100644 index d220aeaf8f..0000000000 --- a/unison-src/transcripts/isTest-exists.md +++ /dev/null @@ -1,18 +0,0 @@ -This transcript tests that UCM can always access the definition of -`IsTest`/`isTest`, which is used internally. - -```ucm -.> builtins.merge -``` - -```unison:hide -test> pass = [Ok "Passed"] -``` - -```ucm -.> add -.> links pass -.> display 1 -``` - -The definition and type of `isTest` should exist. diff --git a/unison-src/transcripts/isTest-exists.output.md b/unison-src/transcripts/isTest-exists.output.md deleted file mode 100644 index 39b9f702b1..0000000000 --- a/unison-src/transcripts/isTest-exists.output.md +++ /dev/null @@ -1,33 +0,0 @@ -This transcript tests that UCM can always access the definition of -`IsTest`/`isTest`, which is used internally. - -```ucm -.> builtins.merge - - Done. - -``` -```unison -test> pass = [Ok "Passed"] -``` - -```ucm -.> add - - ⍟ I've added these definitions: - - pass : [Result] - -.> links pass - - 1. builtin.metadata.isTest : IsTest - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.> display 1 - - IsTest - -``` -The definition and type of `isTest should exist. diff --git a/unison-src/transcripts/kind-inference.output.md b/unison-src/transcripts/kind-inference.output.md index ee4dd35313..73fb41d2d1 100644 --- a/unison-src/transcripts/kind-inference.output.md +++ b/unison-src/transcripts/kind-inference.output.md @@ -52,8 +52,8 @@ unique type Pong = Pong (Ping Optional) ⍟ These new definitions are ok to `add`: - unique type Ping a - unique type Pong + type Ping a + type Pong ``` Catch the conflict on the kind of `a` in `Ping a`. `Ping` restricts @@ -91,8 +91,8 @@ unique ability Pong a where ⍟ These new definitions are ok to `add`: - unique type Ping a - unique ability Pong a + type Ping a + ability Pong a ``` Catch conflict between mutually recursive type and ability @@ -130,8 +130,8 @@ unique type S = S (T Nat) ⍟ These new definitions are ok to `add`: - unique type S - unique type T a + type S + type T a ``` Delay kind defaulting until all components are processed. Here `S` @@ -153,8 +153,8 @@ unique type S = S (T Optional) ⍟ These new definitions are ok to `add`: - unique type S - unique type T a + type S + type T a ``` Catch invalid instantiation of `T`'s `a` parameter in `S` diff --git a/unison-src/transcripts/link.md b/unison-src/transcripts/link.md deleted file mode 100644 index d3fde27594..0000000000 --- a/unison-src/transcripts/link.md +++ /dev/null @@ -1,73 +0,0 @@ -# Linking definitions to metadata - -```ucm:hide -.> builtins.mergeio -``` - -The `link` and `unlink` commands can be used to manage metadata linked to definitions. For example, you can link documentation to a definition: - -```unison -use .builtin - -coolFunction x = x * 2 - -coolFunction.doc = [: This is a cool function. :] -``` - -```ucm -.> add -.> link coolFunction.doc coolFunction -``` - -You can use arbitrary Unison values and link them as metadata to definitions: - -```unison -toCopyrightHolder author = match author with - Author guid name -> CopyrightHolder guid name - -alice = Author (GUID Bytes.empty) "Alice Coder" - -coolFunction.license = License [toCopyrightHolder alice] [Year 2020] licenses.mit - -licenses.mit = LicenseType [: -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -:] -``` - -```ucm -.> add -.> link coolFunction.license coolFunction -.> link alice coolFunction -``` - -We can look at the links we have: - -```ucm -.> links coolFunction -.> links coolFunction License -``` - -We can link the same metadata simultaneously to multiple definitions: - -```unison -myLibrary.f x = x + 1 -myLibrary.g x = x + 2 -myLibrary.h x = x + 3 -``` - -```ucm -.> add -.> cd myLibrary -.myLibrary> find -.myLibrary> link .alice 1-3 -.myLibrary> links f -.myLibrary> links g -.myLibrary> links h -.myLibrary> history - -.> unlink coolFunction.doc coolFunction -``` diff --git a/unison-src/transcripts/link.output.md b/unison-src/transcripts/link.output.md deleted file mode 100644 index 6fe2bdd747..0000000000 --- a/unison-src/transcripts/link.output.md +++ /dev/null @@ -1,216 +0,0 @@ -# Linking definitions to metadata - -The `link` and `unlink` commands can be used to manage metadata linked to definitions. For example, you can link documentation to a definition: - -```unison -use .builtin - -coolFunction x = x * 2 - -coolFunction.doc = [: This is a cool function. :] -``` - -```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`: - - coolFunction : Nat -> Nat - coolFunction.doc : Doc - -``` -```ucm -.> add - - ⍟ I've added these definitions: - - coolFunction : Nat -> Nat - coolFunction.doc : Doc - -.> link coolFunction.doc coolFunction - - Updates: - - 1. coolFunction : Nat -> Nat - + 2. doc : Doc - -``` -You can use arbitrary Unison values and link them as metadata to definitions: - -```unison -toCopyrightHolder author = match author with - Author guid name -> CopyrightHolder guid name - -alice = Author (GUID Bytes.empty) "Alice Coder" - -coolFunction.license = License [toCopyrightHolder alice] [Year 2020] licenses.mit - -licenses.mit = LicenseType [: -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -:] -``` - -```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`: - - alice : Author - coolFunction.license : License - licenses.mit : LicenseType - toCopyrightHolder : Author -> CopyrightHolder - -``` -```ucm -.> add - - ⍟ I've added these definitions: - - alice : Author - coolFunction.license : License - licenses.mit : LicenseType - toCopyrightHolder : Author -> CopyrightHolder - -.> link coolFunction.license coolFunction - - Updates: - - 1. coolFunction : Nat -> Nat - + 2. license : License - -.> link alice coolFunction - - Updates: - - 1. coolFunction : Nat -> Nat - + 2. alice : Author - -``` -We can look at the links we have: - -```ucm -.> links coolFunction - - 1. alice : Author - 2. coolFunction.license : License - 3. coolFunction.doc : Doc - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.> links coolFunction License - - 1. coolFunction.license : License - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -``` -We can link the same metadata simultaneously to multiple definitions: - -```unison -myLibrary.f x = x + 1 -myLibrary.g x = x + 2 -myLibrary.h x = x + 3 -``` - -```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`: - - myLibrary.f : Nat -> Nat - myLibrary.g : Nat -> Nat - myLibrary.h : Nat -> Nat - -``` -```ucm -.> add - - ⍟ I've added these definitions: - - myLibrary.f : Nat -> Nat - myLibrary.g : Nat -> Nat - myLibrary.h : Nat -> Nat - -.> cd myLibrary - -.myLibrary> find - - 1. f : Nat -> Nat - 2. g : Nat -> Nat - 3. h : Nat -> Nat - - -.myLibrary> link .alice 1-3 - - Updates: - - 1. myLibrary.f : Nat -> Nat - + 2. alice : Author - - 3. myLibrary.g : Nat -> Nat - + 4. alice : Author - - 5. myLibrary.h : Nat -> Nat - + 6. alice : Author - -.myLibrary> links f - - 1. .alice : Author - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.myLibrary> links g - - 1. .alice : Author - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.myLibrary> links h - - 1. .alice : Author - - Tip: Try using `display 1` to display the first result or - `view 1` to view its source. - -.myLibrary> history - - Note: The most recent namespace hash is immediately below this - message. - - ⊙ 1. #fa706ukb83 - - - - □ 2. #ikha0ltbmc (start of history) - -.> unlink coolFunction.doc coolFunction - - Updates: - - 1. coolFunction : Nat -> Nat - - 2. doc : Doc - -``` diff --git a/unison-src/transcripts/ls-pretty-print-scope-bug.output.md b/unison-src/transcripts/ls-pretty-print-scope-bug.output.md index 481e8a6864..567a176b64 100644 --- a/unison-src/transcripts/ls-pretty-print-scope-bug.output.md +++ b/unison-src/transcripts/ls-pretty-print-scope-bug.output.md @@ -12,7 +12,7 @@ unique type Foo = Foo ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -22,7 +22,7 @@ unique type Foo = Foo ⍟ I've added these definitions: - unique type Foo + type Foo .> fork .a.b .c.d.f @@ -45,7 +45,7 @@ unique type Foo = Foo ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -53,7 +53,7 @@ unique type Foo = Foo ⍟ I've added these definitions: - unique type Foo + type Foo ``` ```unison diff --git a/unison-src/transcripts/merge.md b/unison-src/transcripts/merge.md index 30b2d25920..25d2e2ba11 100644 --- a/unison-src/transcripts/merge.md +++ b/unison-src/transcripts/merge.md @@ -1,8 +1,4 @@ -```ucm:hide -.> builtins.merge -``` - # How merging works Suppose we have two branches, `P1` and `P2`, and a subnamespace, `foo`, which we'll refer to with `P1.foo` , `P2.foo`. This doc explains how `merge(P1,P2)` is computed, including the `merge(P1,P2).foo` subnamespace. @@ -33,6 +29,7 @@ quux.x = 4 ``` ```ucm +.P0.lib> builtins.merge .P0> add ``` @@ -55,7 +52,7 @@ quux.y = 333 ```ucm .P1> add -.P1> delete.term.verbose foo.w +.> delete.term.verbose P1.foo.w ``` We added to `foo`, `bar` and `baz`, and deleted `foo.w`, which should stay deleted in the merge. @@ -113,6 +110,7 @@ f = (x y -> y) a "woot!" ``` ```ucm +.c1.lib> builtins.merge .c1> add .> fork c1 c1a .> fork c1 c1b diff --git a/unison-src/transcripts/merge.output.md b/unison-src/transcripts/merge.output.md index 32378a7383..420ef28b23 100644 --- a/unison-src/transcripts/merge.output.md +++ b/unison-src/transcripts/merge.output.md @@ -29,7 +29,11 @@ quux.x = 4 ``` ```ucm - ☝️ The namespace .P0 is empty. + ☝️ The namespace .P0.lib is empty. + +.P0.lib> builtins.merge + + Done. .P0> add @@ -72,7 +76,7 @@ quux.y = 333 foo.y : Nat quux.y : Nat -.P1> delete.term.verbose foo.w +.> delete.term.verbose P1.foo.w Name changes: @@ -234,7 +238,11 @@ f = (x y -> y) a "woot!" ``` ```ucm - ☝️ The namespace .c1 is empty. + ☝️ The namespace .c1.lib is empty. + +.c1.lib> builtins.merge + + Done. .c1> add @@ -294,12 +302,14 @@ Now merging `c1b` into `c1a` should result in the updated version of `a` and `f` 1. a : Nat ↓ 2. a : Text - - There were 1 auto-propagated updates. + + 3. f : Text + ↓ + 4. f : Text Added definitions: - 3. patch patch (added 1 updates) + 5. patch patch (added 1 updates) Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you diff --git a/unison-src/transcripts/merges.output.md b/unison-src/transcripts/merges.output.md index 8a0ba6c83d..b922aab38d 100644 --- a/unison-src/transcripts/merges.output.md +++ b/unison-src/transcripts/merges.output.md @@ -74,7 +74,7 @@ y = "hello" ⍟ I've added these definitions: - y : Text + y : ##Text .master> merge .feature1 @@ -202,11 +202,9 @@ z = 99 .feature2> delete.term.verbose x - Name changes: + Removed definitions: - Original Changes - 1. feature2.x ┐ 2. feature2.x (removed) - 3. master.x ┘ + 1. x : Nat Tip: You can use `undo` or `reflog` to undo this change. diff --git a/unison-src/transcripts/move-all.md b/unison-src/transcripts/move-all.md index b9143232e8..1ff6b6da92 100644 --- a/unison-src/transcripts/move-all.md +++ b/unison-src/transcripts/move-all.md @@ -44,6 +44,7 @@ bonk = 5 ``` ```ucm +.z> builtins.merge .z> add .z> move bonk zonk .z> ls @@ -56,6 +57,7 @@ bonk.zonk = 5 ``` ```ucm +.a> builtins.merge .a> add .a> move bonk zonk .a> ls diff --git a/unison-src/transcripts/move-all.output.md b/unison-src/transcripts/move-all.output.md index 4fb0b402b2..466d35ec7d 100644 --- a/unison-src/transcripts/move-all.output.md +++ b/unison-src/transcripts/move-all.output.md @@ -21,8 +21,8 @@ unique type Foo.T = T ⍟ These new definitions are ok to `add`: - unique type Foo - unique type Foo.T + type Foo + type Foo.T Foo : Nat Foo.termInA : Nat @@ -32,8 +32,8 @@ unique type Foo.T = T ⍟ I've added these definitions: - unique type Foo - unique type Foo.T + type Foo + type Foo.T Foo : Nat Foo.termInA : Nat @@ -54,7 +54,7 @@ unique type Foo.T = T1 | T2 ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo.T + type Foo.T Foo.termInA : Nat (also named Foo) @@ -129,6 +129,10 @@ bonk = 5 ```ucm ☝️ The namespace .z is empty. +.z> builtins.merge + + Done. + .z> add ⍟ I've added these definitions: @@ -141,7 +145,8 @@ bonk = 5 .z> ls - 1. zonk (##Nat) + 1. builtin/ (453 terms, 70 types) + 2. zonk (Nat) ``` ## Happy Path - Just namespace @@ -167,6 +172,10 @@ bonk.zonk = 5 ```ucm ☝️ The namespace .a is empty. +.a> builtins.merge + + Done. + .a> add ⍟ I've added these definitions: @@ -179,7 +188,8 @@ bonk.zonk = 5 .a> ls - 1. zonk/ (1 term) + 1. builtin/ (453 terms, 70 types) + 2. zonk/ (1 term) .a> view zonk.zonk diff --git a/unison-src/transcripts/move-namespace.md b/unison-src/transcripts/move-namespace.md index 8728be1dab..15c66f74c2 100644 --- a/unison-src/transcripts/move-namespace.md +++ b/unison-src/transcripts/move-namespace.md @@ -1,7 +1,9 @@ # Tests for `move.namespace` ```ucm:hide -.> builtins.mergeio +.happy> builtins.merge +.history> builtins.merge +.existing> builtins.merge ``` ## Happy path diff --git a/unison-src/transcripts/move-namespace.output.md b/unison-src/transcripts/move-namespace.output.md index 3aeaa6665b..6879a09aed 100644 --- a/unison-src/transcripts/move-namespace.output.md +++ b/unison-src/transcripts/move-namespace.output.md @@ -19,18 +19,16 @@ unique type a.T = T ⍟ These new definitions are ok to `add`: - unique type a.T + type a.T a.termInA : Nat ``` ```ucm - ☝️ The namespace .happy is empty. - .happy> add ⍟ I've added these definitions: - unique type a.T + type a.T a.termInA : Nat ``` @@ -50,7 +48,7 @@ unique type a.T = T1 | T2 ⍟ These names already exist. You can `update` them to your new definition: - unique type a.T + type a.T a.termInA : Nat ``` @@ -74,7 +72,7 @@ Should be able to move the namespace, including its types, terms, and sub-namesp 1. T (type) 2. T/ (2 terms) - 3. termInA (##Nat) + 3. termInA (Nat) .happy> history b @@ -119,8 +117,6 @@ b.termInB = 10 ``` ```ucm - ☝️ The namespace .history is empty. - .history> add ⍟ I've added these definitions: @@ -215,8 +211,6 @@ b.termInB = 10 ``` ```ucm - ☝️ The namespace .existing is empty. - .existing> add ⍟ I've added these definitions: @@ -283,7 +277,7 @@ I should be able to move the root into a sub-namespace .> ls - 1. root/ (630 terms, 89 types) + 1. root/ (1364 terms, 211 types) .> history @@ -292,23 +286,22 @@ I should be able to move the root into a sub-namespace - □ 1. #4ussajn1fc (start of history) + □ 1. #2vg6il9d4g (start of history) ``` ```ucm .> ls .root.at.path - 1. builtin/ (625 terms, 88 types) - 2. existing/ (1 term) - 3. happy/ (3 terms, 1 type) - 4. history/ (1 term) + 1. existing/ (454 terms, 70 types) + 2. happy/ (456 terms, 71 types) + 3. history/ (454 terms, 70 types) .> history .root.at.path Note: The most recent namespace hash is immediately below this message. - ⊙ 1. #sm3e1ff3o3 + ⊙ 1. #m44k1k58ou - Deletes: @@ -319,7 +312,7 @@ I should be able to move the root into a sub-namespace Original name New name existing.a.termInA existing.b.termInA - ⊙ 2. #r9d6ogmf6k + ⊙ 2. #7r4j4dmhru + Adds / updates: @@ -331,26 +324,26 @@ I should be able to move the root into a sub-namespace happy.b.termInA existing.a.termInA history.b.termInA existing.a.termInA - ⊙ 3. #i3nbnio6so + ⊙ 3. #qlh1ogmt6v + Adds / updates: existing.a.termInA existing.b.termInB - ⊙ 4. #38b1mbqlu9 + ⊙ 4. #v3oiqufnsl > Moves: Original name New name history.a.termInA history.b.termInA - ⊙ 5. #8unpdmu968 + ⊙ 5. #g19oumvmue - Deletes: history.b.termInB - ⊙ 6. #6keeqlbr7c + ⊙ 6. #73204ctkae + Adds / updates: @@ -361,13 +354,13 @@ I should be able to move the root into a sub-namespace Original name New name(s) happy.b.termInA history.a.termInA - ⊙ 7. #otsrjrs2el + ⊙ 7. #cgiold3l98 + Adds / updates: history.a.termInA history.b.termInB - ⊙ 8. #irbtol8piu + ⊙ 8. #8qrf3qbi9i > Moves: @@ -377,7 +370,7 @@ I should be able to move the root into a sub-namespace happy.a.T.T2 happy.b.T.T2 happy.a.termInA happy.b.termInA - ⊙ 9. #s3ppk1c8qc + ⊙ 9. #e90bu6v600 + Adds / updates: @@ -387,7 +380,7 @@ I should be able to move the root into a sub-namespace happy.a.T.T - ⊙ 10. #8qf0jit35s + ⊙ 10. #lc2ce2arha + Adds / updates: @@ -399,7 +392,7 @@ I should be able to move the root into a sub-namespace ⠇ - ⊙ 11. #u4v65n4qcl + ⊙ 11. #9ck3j8r41m ``` @@ -420,26 +413,27 @@ I should be able to move a sub namespace _over_ the root. .> ls - 1. b/ (3 terms, 1 type) + 1. b/ (3 terms, 1 type) + 2. builtin/ (453 terms, 70 types) .> history Note: The most recent namespace hash is immediately below this message. - ⊙ 1. #ur0jj0uuhu + ⊙ 1. #ian8vro0cp + Adds / updates: b.T b.T.T1 b.T.T2 b.termInA - ⊙ 2. #8a0jmdflfd + ⊙ 2. #gt9figld7p - Deletes: a.T a.T.T1 a.T.T2 a.termInA - ⊙ 3. #3sbe4c0ql9 + ⊙ 3. #i8i5on9i6t + Adds / updates: @@ -449,7 +443,13 @@ I should be able to move a sub namespace _over_ the root. a.T.T - □ 4. #kfuu64io6v (start of history) + ⊙ 4. #ucfoesjvhd + + + Adds / updates: + + a.T a.T.T a.termInA + + □ 5. #1t2hb5o115 (start of history) ``` ```ucm diff --git a/unison-src/transcripts/name-selection.md b/unison-src/transcripts/name-selection.md index fe3e76034d..23f8713926 100644 --- a/unison-src/transcripts/name-selection.md +++ b/unison-src/transcripts/name-selection.md @@ -5,8 +5,10 @@ This transcript shows how the pretty-printer picks names for a hash when multipl 3. Otherwise if there are multiple names with a minimal number of segments, compare the names alphabetically. ```ucm:hide -.> alias.type ##Nat Nat -.> alias.term ##Nat.+ Nat.+ +.a> builtins.merge +.a2> builtins.merge +.a3> builtins.merge +.biasing> builtins.merge ``` ```unison:hide @@ -67,7 +69,7 @@ The original `a2` namespace has an unconflicted definition for `c` and `d`, but deeply.nested.term = a + 1 -deeply.nested.value = 10 +deeply.nested.num = 10 a = 10 ``` @@ -75,21 +77,21 @@ a = 10 ```ucm .biasing> add -- Despite being saved with name `a`, --- the pretty printer should prefer the suffixified 'deeply.nested.value name' over the shallow 'a'. +-- the pretty printer should prefer the suffixified 'deeply.nested.num name' over the shallow 'a'. -- It's closer to the term being printed. .biasing> view deeply.nested.term ``` -Add another term with `value` suffix to force longer suffixification of `deeply.nested.value` +Add another term with `num` suffix to force longer suffixification of `deeply.nested.num` ```unison -other.value = 20 +other.num = 20 ``` ```ucm .biasing> add --- nested.value should be preferred over the shorter name `a` due to biasing --- because `deeply.nested.value` is nearby to the term being viewed. +-- nested.num should be preferred over the shorter name `a` due to biasing +-- because `deeply.nested.num` is nearby to the term being viewed. .biasing> view deeply.nested.term ``` diff --git a/unison-src/transcripts/name-selection.output.md b/unison-src/transcripts/name-selection.output.md index 44b5c92e94..2590a3a805 100644 --- a/unison-src/transcripts/name-selection.output.md +++ b/unison-src/transcripts/name-selection.output.md @@ -12,8 +12,6 @@ b = 0 + 1 Will add `a` and `b` to the codebase and give `b` a longer (in terms of segment length alias), and show that it isn't used when viewing `a`: ```ucm - ☝️ The namespace .a is empty. - .a> add ⍟ I've added these definitions: @@ -28,7 +26,9 @@ Will add `a` and `b` to the codebase and give `b` a longer (in terms of segment .a> view a a : Nat - a = b + 1 + a = + use Nat + + b + 1 .> cd . @@ -65,8 +65,6 @@ d = c + 10 ``` ```ucm - ☝️ The namespace .a3 is empty. - .a3> add ⍟ I've added these definitions: @@ -80,1428 +78,20 @@ d = c + 10 New name conflicts: - 1. c#dcgdua2lj6 : Nat - ↓ - 2. ┌ c#dcgdua2lj6 : Nat - 3. └ c#gjmq673r1v : Nat + 1. c#dcgdua2lj6 : Nat + ↓ + 2. ┌ c#dcgdua2lj6 : Nat + 3. └ c#gjmq673r1v : Nat - 4. d#9ivhgvhthc : Nat - ↓ - 5. ┌ d#9ivhgvhthc : Nat - 6. └ d#ve16e6jmf6 : Nat + 4. d#9ivhgvhthc : Nat + ↓ + 5. ┌ d#9ivhgvhthc : Nat + 6. └ d#ve16e6jmf6 : Nat Added definitions: - 7. builtin type builtin.Any - 8. unique type builtin.io2.ArithmeticFailure - 9. unique type builtin.io2.ArrayFailure - 10. builtin type builtin.Boolean - 11. unique type builtin.io2.BufferMode - 12. builtin type builtin.Bytes - 13. builtin type builtin.Char - 14. builtin type builtin.io2.Tls.Cipher - 15. builtin type builtin.Char.Class - 16. builtin type builtin.io2.Tls.ClientConfig - 17. builtin type builtin.Code - 18. unique type builtin.Doc - 19. structural type builtin.Either a b - 20. structural ability builtin.Exception - 21. unique type builtin.io2.Failure - 22. unique type builtin.io2.FileMode - 23. builtin type builtin.Float - 24. builtin type builtin.io2.Handle - 25. builtin type builtin.crypto.HashAlgorithm - 26. builtin ability builtin.io2.IO - 27. unique type builtin.io2.IOError - 28. unique type builtin.io2.IOFailure - 29. builtin type builtin.ImmutableArray - 30. builtin type builtin.ImmutableByteArray - 31. builtin type builtin.Int - 32. unique type builtin.IsPropagated - 33. unique type builtin.IsTest - 34. unique type builtin.Link - 35. builtin type builtin.List - 36. builtin type builtin.io2.MVar - 37. unique type builtin.io2.MiscFailure - 38. builtin type builtin.MutableArray - 39. builtin type builtin.MutableByteArray - 40. builtin type builtin.Nat - 41. structural type builtin.Optional a - 42. builtin type builtin.Pattern - 43. builtin type builtin.io2.Tls.PrivateKey - 44. builtin type builtin.io2.ProcessHandle - 45. builtin type builtin.io2.Promise - 46. builtin type builtin.Ref - 47. builtin type builtin.Request - 48. unique type builtin.Test.Result - 49. unique type builtin.RewriteCase a b - 50. unique type builtin.RewriteSignature a b - 51. unique type builtin.RewriteTerm a b - 52. unique type builtin.Rewrites a - 53. unique type builtin.io2.RuntimeFailure - 54. builtin ability builtin.io2.STM - 55. unique type builtin.io2.STMFailure - 56. builtin ability builtin.Scope - 57. unique type builtin.io2.SeekMode - 58. structural type builtin.SeqView a b - 59. builtin type builtin.io2.Tls.ServerConfig - 60. builtin type builtin.io2.Tls.SignedCert - 61. builtin type builtin.io2.Socket - 62. unique type builtin.io2.StdHandle - 63. builtin type builtin.io2.TVar - 64. builtin type builtin.Link.Term - 65. builtin type builtin.Text - 66. builtin type builtin.io2.ThreadId - 67. unique type builtin.io2.ThreadKilledFailure - 68. builtin type builtin.io2.Ref.Ticket - 69. builtin type builtin.io2.Clock.internals.TimeSpec - 70. builtin type builtin.io2.Tls - 71. unique type builtin.io2.TlsFailure - 72. structural type builtin.Tuple a b - 73. builtin type builtin.Link.Type - 74. structural type builtin.Unit - 75. builtin type builtin.Value - 76. builtin type builtin.io2.Tls.Version - 77. builtin.io2.SeekMode.AbsoluteSeek : SeekMode - 78. builtin.io2.IOError.AlreadyExists : IOError - 79. builtin.io2.FileMode.Append : FileMode - 80. builtin.Doc.Blob : Text - -> Doc - 81. builtin.io2.BufferMode.BlockBuffering : BufferMode - 82. builtin.Tuple.Cons : a - -> b - -> Tuple - a b - 83. builtin.io2.IOError.EOF : IOError - 84. builtin.Doc.Evaluate : Term - -> Doc - 85. builtin.Test.Result.Fail : Text - -> Result - 86. builtin.io2.Failure.Failure : Type - -> Text - -> Any - -> Failure - 87. builtin.io2.IOError.IllegalOperation : IOError - 88. builtin.IsPropagated.IsPropagated : IsPropagated - 89. builtin.IsTest.IsTest : IsTest - 90. builtin.Doc.Join : [Doc] - -> Doc - 91. builtin.Either.Left : a - -> Either - a b - 92. builtin.io2.BufferMode.LineBuffering : BufferMode - 93. builtin.Doc.Link : Link - -> Doc - 94. builtin.io2.BufferMode.NoBuffering : BufferMode - 95. builtin.io2.IOError.NoSuchThing : IOError - 96. builtin.Optional.None : Optional - a - 97. builtin.Test.Result.Ok : Text - -> Result - 98. builtin.io2.IOError.PermissionDenied : IOError - 99. builtin.io2.FileMode.Read : FileMode - 100. builtin.io2.FileMode.ReadWrite : FileMode - 101. builtin.io2.SeekMode.RelativeSeek : SeekMode - 102. builtin.io2.IOError.ResourceBusy : IOError - 103. builtin.io2.IOError.ResourceExhausted : IOError - 104. builtin.RewriteCase.RewriteCase : a - -> b - -> RewriteCase - a b - 105. builtin.RewriteSignature.RewriteSignature : (a - -> b - -> ()) - -> RewriteSignature - a b - 106. builtin.RewriteTerm.RewriteTerm : a - -> b - -> RewriteTerm - a b - 107. builtin.Rewrites.Rewrites : a - -> Rewrites - a - 108. builtin.Either.Right : b - -> Either - a b - 109. builtin.io2.SeekMode.SeekFromEnd : SeekMode - 110. builtin.Doc.Signature : Term - -> Doc - 111. builtin.io2.BufferMode.SizedBlockBuffering : Nat - -> BufferMode - 112. builtin.Optional.Some : a - -> Optional - a - 113. builtin.Doc.Source : Link - -> Doc - 114. builtin.io2.StdHandle.StdErr : StdHandle - 115. builtin.io2.StdHandle.StdIn : StdHandle - 116. builtin.io2.StdHandle.StdOut : StdHandle - 117. builtin.Link.Term : Term - -> Link - 118. builtin.Link.Type : Type - -> Link - 119. builtin.Unit.Unit : () - 120. builtin.io2.IOError.UserError : IOError - 121. builtin.SeqView.VElem : a - -> b - -> SeqView - a b - 122. builtin.SeqView.VEmpty : SeqView - a b - 123. builtin.io2.FileMode.Write : FileMode - 124. builtin.Exception.raise : Failure - ->{Exception} x - 125. builtin.Text.!= : Text - -> Text - -> Boolean - 126. builtin.Float.* : Float - -> Float - -> Float - 127. builtin.Int.* : Int - -> Int - -> Int - 128. builtin.Nat.* : Nat - -> Nat - -> Nat - 129. builtin.Float.+ : Float - -> Float - -> Float - 130. builtin.Int.+ : Int - -> Int - -> Int - 131. builtin.Nat.+ : Nat - -> Nat - -> Nat - 132. builtin.Bytes.++ : Bytes - -> Bytes - -> Bytes - 133. builtin.List.++ : [a] - -> [a] - -> [a] - 134. builtin.Text.++ : Text - -> Text - -> Text - 135. ┌ builtin.List.+: : a - -> [a] - -> [a] - 136. └ builtin.List.cons : a - -> [a] - -> [a] - 137. builtin.Float.- : Float - -> Float - -> Float - 138. builtin.Int.- : Int - -> Int - -> Int - 139. builtin.Float./ : Float - -> Float - -> Float - 140. builtin.Int./ : Int - -> Int - -> Int - 141. builtin.Nat./ : Nat - -> Nat - -> Nat - 142. ┌ builtin.List.:+ : [a] - -> a - -> [a] - 143. └ builtin.List.snoc : [a] - -> a - -> [a] - 144. builtin.Universal.< : a - -> a - -> Boolean - 145. builtin.Universal.<= : a - -> a - -> Boolean - 146. builtin.Universal.== : a - -> a - -> Boolean - 147. builtin.Universal.> : a - -> a - -> Boolean - 148. builtin.Universal.>= : a - -> a - -> Boolean - 149. builtin.Any.Any : a - -> Any - 150. builtin.crypto.HashAlgorithm.Blake2b_256 : HashAlgorithm - 151. builtin.crypto.HashAlgorithm.Blake2b_512 : HashAlgorithm - 152. builtin.crypto.HashAlgorithm.Blake2s_256 : HashAlgorithm - 153. builtin.crypto.HashAlgorithm.Md5 : HashAlgorithm - 154. builtin.crypto.HashAlgorithm.Sha1 : HashAlgorithm - 155. builtin.crypto.HashAlgorithm.Sha2_256 : HashAlgorithm - 156. builtin.crypto.HashAlgorithm.Sha2_512 : HashAlgorithm - 157. builtin.crypto.HashAlgorithm.Sha3_256 : HashAlgorithm - 158. builtin.crypto.HashAlgorithm.Sha3_512 : HashAlgorithm - 159. builtin.Float.abs : Float - -> Float - 160. builtin.Float.acos : Float - -> Float - 161. builtin.Float.acosh : Float - -> Float - 162. builtin.Char.Class.alphanumeric : Class - 163. builtin.Char.Class.and : Class - -> Class - -> Class - 164. builtin.Int.and : Int - -> Int - -> Int - 165. builtin.Nat.and : Nat - -> Nat - -> Nat - 166. builtin.Char.Class.any : Class - 167. builtin.Text.patterns.anyChar : Pattern - Text - 168. builtin.Char.Class.anyOf : [Char] - -> Class - 169. builtin.io2.IO.array : Nat - ->{IO} MutableArray - {IO} a - 170. builtin.Scope.array : Nat - ->{Scope - s} MutableArray - (Scope - s) - a - 171. builtin.io2.IO.arrayOf : a - -> Nat - ->{IO} MutableArray - {IO} a - 172. builtin.Scope.arrayOf : a - -> Nat - ->{Scope - s} MutableArray - (Scope - s) - a - 173. builtin.Float.asin : Float - -> Float - 174. builtin.Float.asinh : Float - -> Float - 175. builtin.Bytes.at : Nat - -> Bytes - -> Optional - Nat - 176. builtin.List.at : Nat - -> [a] - -> Optional - a - 177. builtin.Float.atan : Float - -> Float - 178. builtin.Float.atan2 : Float - -> Float - -> Float - 179. builtin.Float.atanh : Float - -> Float - 180. builtin.io2.STM.atomically : '{STM} a - ->{IO} a - 181. builtin.bug : a -> b - 182. builtin.io2.IO.bytearray : Nat - ->{IO} MutableByteArray - {IO} - 183. builtin.Scope.bytearray : Nat - ->{Scope - s} MutableByteArray - (Scope - s) - 184. builtin.io2.IO.bytearrayOf : Nat - -> Nat - ->{IO} MutableByteArray - {IO} - 185. builtin.Scope.bytearrayOf : Nat - -> Nat - ->{Scope - s} MutableByteArray - (Scope - s) - 186. ┌ c#gjmq673r1v : Nat - 187. └ long.name.but.shortest.suffixification : Nat - 188. builtin.Code.cache_ : [( Term, - Code)] - ->{IO} [Term] - 189. builtin.io2.IO.process.call : Text - -> [Text] - ->{IO} Nat - 190. builtin.Pattern.capture : Pattern - a - -> Pattern - a - 191. builtin.Pattern.captureAs : a - -> Pattern - a - -> Pattern - a - 192. builtin.io2.Ref.cas : Ref - {IO} a - -> Ticket - a - -> a - ->{IO} Boolean - 193. builtin.Float.ceiling : Float - -> Int - 194. builtin.Text.patterns.char : Class - -> Pattern - Text - 195. builtin.Text.patterns.charIn : [Char] - -> Pattern - Text - 196. builtin.Text.patterns.charRange : Char - -> Char - -> Pattern - Text - 197. builtin.unsafe.coerceAbilities : (a - ->{e1} b) - -> a - -> b - 198. builtin.Universal.compare : a - -> a - -> Int - 199. builtin.Int.complement : Int - -> Int - 200. builtin.Nat.complement : Nat - -> Nat - 201. builtin.Bytes.gzip.compress : Bytes - -> Bytes - 202. builtin.Bytes.zlib.compress : Bytes - -> Bytes - 203. builtin.Char.Class.control : Class - 204. builtin.ImmutableArray.copyTo! : MutableArray - g a - -> Nat - -> ImmutableArray - a - -> Nat - -> Nat - ->{g, - Exception} () - 205. builtin.ImmutableByteArray.copyTo! : MutableByteArray - g - -> Nat - -> ImmutableByteArray - -> Nat - -> Nat - ->{g, - Exception} () - 206. builtin.MutableArray.copyTo! : MutableArray - g a - -> Nat - -> MutableArray - g a - -> Nat - -> Nat - ->{g, - Exception} () - 207. builtin.MutableByteArray.copyTo! : MutableByteArray - g - -> Nat - -> MutableByteArray - g - -> Nat - -> Nat - ->{g, - Exception} () - 208. builtin.Float.cos : Float - -> Float - 209. builtin.Float.cosh : Float - -> Float - 210. builtin.Bytes.decodeNat16be : Bytes - -> Optional - ( Nat, - Bytes) - 211. builtin.Bytes.decodeNat16le : Bytes - -> Optional - ( Nat, - Bytes) - 212. builtin.Bytes.decodeNat32be : Bytes - -> Optional - ( Nat, - Bytes) - 213. builtin.Bytes.decodeNat32le : Bytes - -> Optional - ( Nat, - Bytes) - 214. builtin.Bytes.decodeNat64be : Bytes - -> Optional - ( Nat, - Bytes) - 215. builtin.Bytes.decodeNat64le : Bytes - -> Optional - ( Nat, - Bytes) - 216. builtin.io2.Tls.decodePrivateKey : Bytes - -> [PrivateKey] - 217. builtin.Bytes.gzip.decompress : Bytes - -> Either - Text - Bytes - 218. builtin.Bytes.zlib.decompress : Bytes - -> Either - Text - Bytes - 219. builtin.io2.Tls.ClientConfig.default : Text - -> Bytes - -> ClientConfig - 220. builtin.io2.Tls.ServerConfig.default : [SignedCert] - -> PrivateKey - -> ServerConfig - 221. builtin.Code.dependencies : Code - -> [Term] - 222. builtin.Value.dependencies : Value - -> [Term] - 223. builtin.Code.deserialize : Bytes - -> Either - Text - Code - 224. builtin.Value.deserialize : Bytes - -> Either - Text - Value - 225. builtin.Text.patterns.digit : Pattern - Text - 226. builtin.Code.display : Text - -> Code - -> Text - 227. builtin.Bytes.drop : Nat - -> Bytes - -> Bytes - 228. builtin.List.drop : Nat - -> [a] - -> [a] - 229. builtin.Nat.drop : Nat - -> Nat - -> Nat - 230. builtin.Text.drop : Nat - -> Text - -> Text - 231. builtin.Bytes.empty : Bytes - 232. builtin.List.empty : [a] - 233. builtin.Text.empty : Text - 234. builtin.io2.Tls.encodeCert : SignedCert - -> Bytes - 235. builtin.Bytes.encodeNat16be : Nat - -> Bytes - 236. builtin.Bytes.encodeNat16le : Nat - -> Bytes - 237. builtin.Bytes.encodeNat32be : Nat - -> Bytes - 238. builtin.Bytes.encodeNat32le : Nat - -> Bytes - 239. builtin.Bytes.encodeNat64be : Nat - -> Bytes - 240. builtin.Bytes.encodeNat64le : Nat - -> Bytes - 241. builtin.io2.Tls.encodePrivateKey : PrivateKey - -> Bytes - 242. builtin.Text.patterns.eof : Pattern - Text - 243. builtin.Float.eq : Float - -> Float - -> Boolean - 244. builtin.Int.eq : Int - -> Int - -> Boolean - 245. builtin.Nat.eq : Nat - -> Nat - -> Boolean - 246. builtin.Text.eq : Text - -> Text - -> Boolean - 247. builtin.io2.IO.process.exitCode : ProcessHandle - ->{IO} Optional - Nat - 248. builtin.Float.exp : Float - -> Float - 249. builtin.Bytes.flatten : Bytes - -> Bytes - 250. builtin.Float.floor : Float - -> Int - 251. builtin.io2.IO.forkComp : '{IO} a - ->{IO} ThreadId - 252. builtin.MutableArray.freeze : MutableArray - g a - -> Nat - -> Nat - ->{g} ImmutableArray - a - 253. builtin.MutableByteArray.freeze : MutableByteArray - g - -> Nat - -> Nat - ->{g} ImmutableByteArray - 254. builtin.MutableArray.freeze! : MutableArray - g a - ->{g} ImmutableArray - a - 255. builtin.MutableByteArray.freeze! : MutableByteArray - g - ->{g} ImmutableByteArray - 256. builtin.Bytes.fromBase16 : Bytes - -> Either - Text - Bytes - 257. builtin.Bytes.fromBase32 : Bytes - -> Either - Text - Bytes - 258. builtin.Bytes.fromBase64 : Bytes - -> Either - Text - Bytes - 259. builtin.Bytes.fromBase64UrlUnpadded : Bytes - -> Either - Text - Bytes - 260. builtin.Text.fromCharList : [Char] - -> Text - 261. builtin.Bytes.fromList : [Nat] - -> Bytes - 262. builtin.Char.fromNat : Nat - -> Char - 263. builtin.Float.fromRepresentation : Nat - -> Float - 264. builtin.Int.fromRepresentation : Nat - -> Int - 265. builtin.Float.fromText : Text - -> Optional - Float - 266. builtin.Int.fromText : Text - -> Optional - Int - 267. builtin.Nat.fromText : Text - -> Optional - Nat - 268. builtin.Float.gt : Float - -> Float - -> Boolean - 269. builtin.Int.gt : Int - -> Int - -> Boolean - 270. builtin.Nat.gt : Nat - -> Nat - -> Boolean - 271. builtin.Text.gt : Text - -> Text - -> Boolean - 272. builtin.Float.gteq : Float - -> Float - -> Boolean - 273. builtin.Int.gteq : Int - -> Int - -> Boolean - 274. builtin.Nat.gteq : Nat - -> Nat - -> Boolean - 275. builtin.Text.gteq : Text - -> Text - -> Boolean - 276. builtin.crypto.hash : HashAlgorithm - -> a - -> Bytes - 277. builtin.crypto.hashBytes : HashAlgorithm - -> Bytes - -> Bytes - 278. builtin.crypto.hmac : HashAlgorithm - -> Bytes - -> a - -> Bytes - 279. builtin.crypto.hmacBytes : HashAlgorithm - -> Bytes - -> Bytes - -> Bytes - 280. builtin.io2.IO.clientSocket.impl : Text - -> Text - ->{IO} Either - Failure - Socket - 281. builtin.io2.IO.closeFile.impl : Handle - ->{IO} Either - Failure - () - 282. builtin.io2.IO.closeSocket.impl : Socket - ->{IO} Either - Failure - () - 283. builtin.io2.IO.createDirectory.impl : Text - ->{IO} Either - Failure - () - 284. builtin.io2.IO.createTempDirectory.impl : Text - ->{IO} Either - Failure - Text - 285. builtin.io2.Tls.decodeCert.impl : Bytes - -> Either - Failure - SignedCert - 286. builtin.io2.IO.delay.impl : Nat - ->{IO} Either - Failure - () - 287. builtin.io2.IO.directoryContents.impl : Text - ->{IO} Either - Failure - [Text] - 288. builtin.io2.IO.fileExists.impl : Text - ->{IO} Either - Failure - Boolean - 289. builtin.Text.fromUtf8.impl : Bytes - -> Either - Failure - Text - 290. builtin.io2.IO.getArgs.impl : '{IO} Either - Failure - [Text] - 291. builtin.io2.IO.getBuffering.impl : Handle - ->{IO} Either - Failure - BufferMode - 292. builtin.io2.IO.getBytes.impl : Handle - -> Nat - ->{IO} Either - Failure - Bytes - 293. builtin.io2.IO.getChar.impl : Handle - ->{IO} Either - Failure - Char - 294. builtin.io2.IO.getCurrentDirectory.impl : '{IO} Either - Failure - Text - 295. builtin.io2.IO.getEcho.impl : Handle - ->{IO} Either - Failure - Boolean - 296. builtin.io2.IO.getEnv.impl : Text - ->{IO} Either - Failure - Text - 297. builtin.io2.IO.getFileSize.impl : Text - ->{IO} Either - Failure - Nat - 298. builtin.io2.IO.getFileTimestamp.impl : Text - ->{IO} Either - Failure - Nat - 299. builtin.io2.IO.getLine.impl : Handle - ->{IO} Either - Failure - Text - 300. builtin.io2.IO.getSomeBytes.impl : Handle - -> Nat - ->{IO} Either - Failure - Bytes - 301. builtin.io2.IO.getTempDirectory.impl : '{IO} Either - Failure - Text - 302. builtin.io2.IO.handlePosition.impl : Handle - ->{IO} Either - Failure - Nat - 303. builtin.io2.Tls.handshake.impl : Tls - ->{IO} Either - Failure - () - 304. builtin.io2.IO.isDirectory.impl : Text - ->{IO} Either - Failure - Boolean - 305. builtin.io2.IO.isFileEOF.impl : Handle - ->{IO} Either - Failure - Boolean - 306. builtin.io2.IO.isFileOpen.impl : Handle - ->{IO} Either - Failure - Boolean - 307. builtin.io2.IO.isSeekable.impl : Handle - ->{IO} Either - Failure - Boolean - 308. builtin.io2.IO.kill.impl : ThreadId - ->{IO} Either - Failure - () - 309. builtin.io2.IO.listen.impl : Socket - ->{IO} Either - Failure - () - 310. builtin.io2.Tls.newClient.impl : ClientConfig - -> Socket - ->{IO} Either - Failure - Tls - 311. builtin.io2.Tls.newServer.impl : ServerConfig - -> Socket - ->{IO} Either - Failure - Tls - 312. builtin.io2.IO.openFile.impl : Text - -> FileMode - ->{IO} Either - Failure - Handle - 313. builtin.io2.MVar.put.impl : MVar a - -> a - ->{IO} Either - Failure - () - 314. builtin.io2.IO.putBytes.impl : Handle - -> Bytes - ->{IO} Either - Failure - () - 315. builtin.io2.MVar.read.impl : MVar a - ->{IO} Either - Failure - a - 316. builtin.io2.IO.ready.impl : Handle - ->{IO} Either - Failure - Boolean - 317. builtin.io2.Tls.receive.impl : Tls - ->{IO} Either - Failure - Bytes - 318. builtin.io2.IO.removeDirectory.impl : Text - ->{IO} Either - Failure - () - 319. builtin.io2.IO.removeFile.impl : Text - ->{IO} Either - Failure - () - 320. builtin.io2.IO.renameDirectory.impl : Text - -> Text - ->{IO} Either - Failure - () - 321. builtin.io2.IO.renameFile.impl : Text - -> Text - ->{IO} Either - Failure - () - 322. builtin.io2.IO.seekHandle.impl : Handle - -> SeekMode - -> Int - ->{IO} Either - Failure - () - 323. builtin.io2.Tls.send.impl : Tls - -> Bytes - ->{IO} Either - Failure - () - 324. builtin.io2.IO.serverSocket.impl : Optional - Text - -> Text - ->{IO} Either - Failure - Socket - 325. builtin.io2.IO.setBuffering.impl : Handle - -> BufferMode - ->{IO} Either - Failure - () - 326. builtin.io2.IO.setCurrentDirectory.impl : Text - ->{IO} Either - Failure - () - 327. builtin.io2.IO.setEcho.impl : Handle - -> Boolean - ->{IO} Either - Failure - () - 328. builtin.io2.IO.socketAccept.impl : Socket - ->{IO} Either - Failure - Socket - 329. builtin.io2.IO.socketPort.impl : Socket - ->{IO} Either - Failure - Nat - 330. builtin.io2.IO.socketReceive.impl : Socket - -> Nat - ->{IO} Either - Failure - Bytes - 331. builtin.io2.IO.socketSend.impl : Socket - -> Bytes - ->{IO} Either - Failure - () - 332. builtin.io2.MVar.swap.impl : MVar a - -> a - ->{IO} Either - Failure - a - 333. builtin.io2.IO.systemTime.impl : '{IO} Either - Failure - Nat - 334. builtin.io2.MVar.take.impl : MVar a - ->{IO} Either - Failure - a - 335. builtin.io2.Tls.terminate.impl : Tls - ->{IO} Either - Failure - () - 336. builtin.io2.MVar.tryPut.impl : MVar a - -> a - ->{IO} Either - Failure - Boolean - 337. builtin.io2.MVar.tryRead.impl : MVar a - ->{IO} Either - Failure - (Optional - a) - 338. builtin.Int.increment : Int - -> Int - 339. builtin.Nat.increment : Nat - -> Nat - 340. builtin.Bytes.indexOf : Bytes - -> Bytes - -> Optional - Nat - 341. builtin.Text.indexOf : Text - -> Text - -> Optional - Nat - 342. builtin.Char.Class.is : Class - -> Char - -> Boolean - 343. builtin.io2.MVar.isEmpty : MVar a - ->{IO} Boolean - 344. builtin.Int.isEven : Int - -> Boolean - 345. builtin.Nat.isEven : Nat - -> Boolean - 346. builtin.Pattern.isMatch : Pattern - a - -> a - -> Boolean - 347. builtin.Code.isMissing : Term - ->{IO} Boolean - 348. builtin.Int.isOdd : Int - -> Boolean - 349. builtin.Nat.isOdd : Nat - -> Boolean - 350. builtin.metadata.isPropagated : IsPropagated - 351. builtin.metadata.isTest : IsTest - 352. builtin.Pattern.join : [Pattern - a] - -> Pattern - a - 353. builtin.io2.IO.process.kill : ProcessHandle - ->{IO} () - 354. builtin.Int.leadingZeros : Int - -> Nat - 355. builtin.Nat.leadingZeros : Nat - -> Nat - 356. builtin.Char.Class.letter : Class - 357. builtin.Text.patterns.letter : Pattern - Text - 358. builtin.Text.patterns.literal : Text - -> Pattern - Text - 359. builtin.Value.load : Value - ->{IO} Either - [Term] - a - 360. builtin.Float.log : Float - -> Float - 361. builtin.Float.logBase : Float - -> Float - -> Float - 362. builtin.Code.lookup : Term - ->{IO} Optional - Code - 363. builtin.Char.Class.lower : Class - 364. builtin.Float.lt : Float - -> Float - -> Boolean - 365. builtin.Int.lt : Int - -> Int - -> Boolean - 366. builtin.Nat.lt : Nat - -> Nat - -> Boolean - 367. builtin.Text.lt : Text - -> Text - -> Boolean - 368. builtin.Float.lteq : Float - -> Float - -> Boolean - 369. builtin.Int.lteq : Int - -> Int - -> Boolean - 370. builtin.Nat.lteq : Nat - -> Nat - -> Boolean - 371. builtin.Text.lteq : Text - -> Text - -> Boolean - 372. builtin.Pattern.many : Pattern - a - -> Pattern - a - 373. builtin.Char.Class.mark : Class - 374. builtin.Float.max : Float - -> Float - -> Float - 375. builtin.Float.min : Float - -> Float - -> Float - 376. builtin.Int.mod : Int - -> Int - -> Int - 377. builtin.Nat.mod : Nat - -> Nat - -> Nat - 378. builtin.io2.Clock.internals.monotonic : '{IO} Either - Failure - TimeSpec - 379. builtin.Universal.murmurHash : a - -> Nat - 380. builtin.Int.negate : Int - -> Int - 381. builtin.io2.MVar.new : a - ->{IO} MVar - a - 382. builtin.io2.Promise.new : '{IO} Promise - a - 383. builtin.io2.TVar.new : a - ->{STM} TVar - a - 384. builtin.io2.MVar.newEmpty : '{IO} MVar - a - 385. builtin.io2.TVar.newIO : a - ->{IO} TVar - a - 386. builtin.Boolean.not : Boolean - -> Boolean - 387. builtin.Char.Class.not : Class - -> Class - 388. builtin.Text.patterns.notCharIn : [Char] - -> Pattern - Text - 389. builtin.Text.patterns.notCharRange : Char - -> Char - -> Pattern - Text - 390. builtin.io2.Clock.internals.nsec : TimeSpec - -> Nat - 391. builtin.Char.Class.number : Class - 392. builtin.Char.Class.or : Class - -> Class - -> Class - 393. builtin.Int.or : Int - -> Int - -> Int - 394. builtin.Nat.or : Nat - -> Nat - -> Nat - 395. builtin.Pattern.or : Pattern - a - -> Pattern - a - -> Pattern - a - 396. builtin.Int.popCount : Int - -> Nat - 397. builtin.Nat.popCount : Nat - -> Nat - 398. builtin.Float.pow : Float - -> Float - -> Float - 399. builtin.Int.pow : Int - -> Nat - -> Int - 400. builtin.Nat.pow : Nat - -> Nat - -> Nat - 401. builtin.Char.Class.printable : Class - 402. builtin.io2.Clock.internals.processCPUTime : '{IO} Either - Failure - TimeSpec - 403. builtin.Char.Class.punctuation : Class - 404. builtin.Text.patterns.punctuation : Pattern - Text - 405. builtin.io2.IO.randomBytes : Nat - ->{IO} Bytes - 406. builtin.Char.Class.range : Char - -> Char - -> Class - 407. builtin.ImmutableArray.read : ImmutableArray - a - -> Nat - ->{Exception} a - 408. builtin.MutableArray.read : MutableArray - g a - -> Nat - ->{g, - Exception} a - 409. builtin.io2.Promise.read : Promise - a - ->{IO} a - 410. builtin.Ref.read : Ref g a - ->{g} a - 411. builtin.io2.TVar.read : TVar a - ->{STM} a - 412. builtin.io2.Ref.Ticket.read : Ticket - a - -> a - 413. builtin.ImmutableByteArray.read16be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 414. builtin.MutableByteArray.read16be : MutableByteArray - g - -> Nat - ->{g, - Exception} Nat - 415. builtin.ImmutableByteArray.read24be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 416. builtin.MutableByteArray.read24be : MutableByteArray - g - -> Nat - ->{g, - Exception} Nat - 417. builtin.ImmutableByteArray.read32be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 418. builtin.MutableByteArray.read32be : MutableByteArray - g - -> Nat - ->{g, - Exception} Nat - 419. builtin.ImmutableByteArray.read40be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 420. builtin.MutableByteArray.read40be : MutableByteArray - g - -> Nat - ->{g, - Exception} Nat - 421. builtin.ImmutableByteArray.read64be : ImmutableByteArray - -> Nat - ->{Exception} Nat - 422. builtin.MutableByteArray.read64be : MutableByteArray - g - -> Nat - ->{g, - Exception} Nat - 423. builtin.ImmutableByteArray.read8 : ImmutableByteArray - -> Nat - ->{Exception} Nat - 424. builtin.MutableByteArray.read8 : MutableByteArray - g - -> Nat - ->{g, - Exception} Nat - 425. builtin.io2.Ref.readForCas : Ref - {IO} a - ->{IO} Ticket - a - 426. builtin.io2.TVar.readIO : TVar a - ->{IO} a - 427. builtin.io2.Clock.internals.realtime : '{IO} Either - Failure - TimeSpec - 428. builtin.io2.IO.ref : a - ->{IO} Ref - {IO} a - 429. builtin.Scope.ref : a - ->{Scope - s} Ref - {Scope - s} - a - 430. builtin.Text.repeat : Nat - -> Text - -> Text - 431. builtin.Pattern.replicate : Nat - -> Nat - -> Pattern - a - -> Pattern - a - 432. builtin.io2.STM.retry : '{STM} a - 433. builtin.Text.reverse : Text - -> Text - 434. builtin.Float.round : Float - -> Int - 435. builtin.Pattern.run : Pattern - a - -> a - -> Optional - ( [a], - a) - 436. builtin.Scope.run : (∀ s. - '{g, - Scope s} r) - ->{g} r - 437. builtin.io2.sandboxLinks : Term - ->{IO} [Term] - 438. builtin.io2.Clock.internals.sec : TimeSpec - -> Int - 439. builtin.Char.Class.separator : Class - 440. builtin.Code.serialize : Code - -> Bytes - 441. builtin.Value.serialize : Value - -> Bytes - 442. builtin.io2.Tls.ClientConfig.certificates.set : [SignedCert] - -> ClientConfig - -> ClientConfig - 443. builtin.io2.Tls.ServerConfig.certificates.set : [SignedCert] - -> ServerConfig - -> ServerConfig - 444. builtin.io2.TLS.ClientConfig.ciphers.set : [Cipher] - -> ClientConfig - -> ClientConfig - 445. builtin.io2.Tls.ServerConfig.ciphers.set : [Cipher] - -> ServerConfig - -> ServerConfig - 446. builtin.io2.Tls.ClientConfig.versions.set : [Version] - -> ClientConfig - -> ClientConfig - 447. builtin.io2.Tls.ServerConfig.versions.set : [Version] - -> ServerConfig - -> ServerConfig - 448. builtin.Int.shiftLeft : Int - -> Nat - -> Int - 449. builtin.Nat.shiftLeft : Nat - -> Nat - -> Nat - 450. builtin.Int.shiftRight : Int - -> Nat - -> Int - 451. builtin.Nat.shiftRight : Nat - -> Nat - -> Nat - 452. builtin.Int.signum : Int - -> Int - 453. builtin.Float.sin : Float - -> Float - 454. builtin.Float.sinh : Float - -> Float - 455. builtin.Bytes.size : Bytes - -> Nat - 456. builtin.ImmutableArray.size : ImmutableArray - a - -> Nat - 457. builtin.ImmutableByteArray.size : ImmutableByteArray - -> Nat - 458. builtin.List.size : [a] - -> Nat - 459. builtin.MutableArray.size : MutableArray - g a - -> Nat - 460. builtin.MutableByteArray.size : MutableByteArray - g - -> Nat - 461. builtin.Text.size : Text - -> Nat - 462. builtin.Text.patterns.space : Pattern - Text - 463. builtin.Float.sqrt : Float - -> Float - 464. builtin.io2.IO.process.start : Text - -> [Text] - ->{IO} ( Handle, - Handle, - Handle, - ProcessHandle) - 465. builtin.io2.IO.stdHandle : StdHandle - -> Handle - 466. builtin.Nat.sub : Nat - -> Nat - -> Int - 467. builtin.io2.TVar.swap : TVar a - -> a - ->{STM} a - 468. builtin.Char.Class.symbol : Class - 469. builtin.io2.IO.systemTimeMicroseconds : '{IO} Int - 470. builtin.io2.Clock.internals.systemTimeZone : Int - ->{IO} ( Int, - Nat, - Text) - 471. builtin.Bytes.take : Nat - -> Bytes - -> Bytes - 472. builtin.List.take : Nat - -> [a] - -> [a] - 473. builtin.Text.take : Nat - -> Text - -> Text - 474. builtin.Float.tan : Float - -> Float - 475. builtin.Float.tanh : Float - -> Float - 476. builtin.io2.Clock.internals.threadCPUTime : '{IO} Either - Failure - TimeSpec - 477. builtin.Bytes.toBase16 : Bytes - -> Bytes - 478. builtin.Bytes.toBase32 : Bytes - -> Bytes - 479. builtin.Bytes.toBase64 : Bytes - -> Bytes - 480. builtin.Bytes.toBase64UrlUnpadded : Bytes - -> Bytes - 481. builtin.Text.toCharList : Text - -> [Char] - 482. builtin.Int.toFloat : Int - -> Float - 483. builtin.Nat.toFloat : Nat - -> Float - 484. builtin.Nat.toInt : Nat - -> Int - 485. builtin.Bytes.toList : Bytes - -> [Nat] - 486. builtin.Text.toLowercase : Text - -> Text - 487. builtin.Char.toNat : Char - -> Nat - 488. builtin.Float.toRepresentation : Float - -> Nat - 489. builtin.Int.toRepresentation : Int - -> Nat - 490. builtin.Char.toText : Char - -> Text - 491. builtin.Debug.toText : a - -> Optional - (Either - Text - Text) - 492. builtin.Float.toText : Float - -> Text - 493. builtin.Handle.toText : Handle - -> Text - 494. builtin.Int.toText : Int - -> Text - 495. builtin.Nat.toText : Nat - -> Text - 496. builtin.Socket.toText : Socket - -> Text - 497. builtin.Link.Term.toText : Term - -> Text - 498. builtin.ThreadId.toText : ThreadId - -> Text - 499. builtin.Text.toUppercase : Text - -> Text - 500. builtin.Text.toUtf8 : Text - -> Bytes - 501. builtin.todo : a -> b - 502. builtin.Debug.trace : Text - -> a - -> () - 503. builtin.Int.trailingZeros : Int - -> Nat - 504. builtin.Nat.trailingZeros : Nat - -> Nat - 505. builtin.Float.truncate : Float - -> Int - 506. builtin.Int.truncate0 : Int - -> Nat - 507. builtin.io2.IO.tryEval : '{IO} a - ->{IO, - Exception} a - 508. builtin.io2.Promise.tryRead : Promise - a - ->{IO} Optional - a - 509. builtin.io2.MVar.tryTake : MVar a - ->{IO} Optional - a - 510. builtin.Text.uncons : Text - -> Optional - ( Char, - Text) - 511. builtin.Any.unsafeExtract : Any - -> a - 512. builtin.Text.unsnoc : Text - -> Optional - ( Text, - Char) - 513. builtin.Char.Class.upper : Class - 514. builtin.Code.validate : [( Term, - Code)] - ->{IO} Optional - Failure - 515. builtin.Code.validateLinks : [( Term, - Code)] - ->{Exception} Either - [Term] - [Term] - 516. builtin.io2.Value.validateSandboxed : [Term] - -> Value - ->{IO} Either - [Term] - [Term] - 517. builtin.io2.validateSandboxed : [Term] - -> a - -> Boolean - 518. builtin.Value.value : a - -> Value - 519. builtin.io2.IO.process.wait : ProcessHandle - ->{IO} Nat - 520. builtin.Debug.watch : Text - -> a - -> a - 521. builtin.Char.Class.whitespace : Class - 522. builtin.MutableArray.write : MutableArray - g a - -> Nat - -> a - ->{g, - Exception} () - 523. builtin.io2.Promise.write : Promise - a - -> a - ->{IO} Boolean - 524. builtin.Ref.write : Ref g a - -> a - ->{g} () - 525. builtin.io2.TVar.write : TVar a - -> a - ->{STM} () - 526. builtin.MutableByteArray.write16be : MutableByteArray - g - -> Nat - -> Nat - ->{g, - Exception} () - 527. builtin.MutableByteArray.write32be : MutableByteArray - g - -> Nat - -> Nat - ->{g, - Exception} () - 528. builtin.MutableByteArray.write64be : MutableByteArray - g - -> Nat - -> Nat - ->{g, - Exception} () - 529. builtin.MutableByteArray.write8 : MutableByteArray - g - -> Nat - -> Nat - ->{g, - Exception} () - 530. builtin.Int.xor : Int - -> Int - -> Int - 531. builtin.Nat.xor : Nat - -> Nat - -> Nat + 7. ┌ c#gjmq673r1v : Nat + 8. └ long.name.but.shortest.suffixification : Nat Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you @@ -1551,7 +141,7 @@ The original `a2` namespace has an unconflicted definition for `c` and `d`, but deeply.nested.term = a + 1 -deeply.nested.value = 10 +deeply.nested.num = 10 a = 10 ``` @@ -1566,37 +156,35 @@ a = 10 ⍟ These new definitions are ok to `add`: - a : Nat - deeply.nested.term : Nat - deeply.nested.value : Nat + a : Nat + deeply.nested.num : Nat + deeply.nested.term : Nat ``` ```ucm - ☝️ The namespace .biasing is empty. - .biasing> add ⍟ I've added these definitions: - a : Nat - deeply.nested.term : Nat - deeply.nested.value : Nat + a : Nat + deeply.nested.num : Nat + deeply.nested.term : Nat -- Despite being saved with name `a`, --- the pretty printer should prefer the suffixified 'deeply.nested.value name' over the shallow 'a'. +-- the pretty printer should prefer the suffixified 'deeply.nested.num name' over the shallow 'a'. -- It's closer to the term being printed. .biasing> view deeply.nested.term deeply.nested.term : Nat deeply.nested.term = use Nat + - value + 1 + num + 1 ``` -Add another term with `value` suffix to force longer suffixification of `deeply.nested.value` +Add another term with `num` suffix to force longer suffixification of `deeply.nested.num` ```unison -other.value = 20 +other.num = 20 ``` ```ucm @@ -1609,7 +197,7 @@ other.value = 20 ⍟ These new definitions are ok to `add`: - other.value : Nat + other.num : Nat ``` ```ucm @@ -1617,15 +205,15 @@ other.value = 20 ⍟ I've added these definitions: - other.value : Nat + other.num : Nat --- nested.value should be preferred over the shorter name `a` due to biasing --- because `deeply.nested.value` is nearby to the term being viewed. +-- nested.num should be preferred over the shorter name `a` due to biasing +-- because `deeply.nested.num` is nearby to the term being viewed. .biasing> view deeply.nested.term deeply.nested.term : Nat deeply.nested.term = use Nat + - nested.value + 1 + nested.num + 1 ``` diff --git a/unison-src/transcripts/numbered-args.md b/unison-src/transcripts/numbered-args.md index 86bf9a2147..f421a67177 100644 --- a/unison-src/transcripts/numbered-args.md +++ b/unison-src/transcripts/numbered-args.md @@ -1,7 +1,7 @@ # Using numbered arguments in UCM ```ucm:hide -.> builtins.merge +.temp> alias.type ##Text Text ``` First lets add some contents to our codebase. diff --git a/unison-src/transcripts/numbered-args.output.md b/unison-src/transcripts/numbered-args.output.md index 681de29068..b8dfce49f2 100644 --- a/unison-src/transcripts/numbered-args.output.md +++ b/unison-src/transcripts/numbered-args.output.md @@ -30,8 +30,6 @@ corge = "corge" ``` ```ucm - ☝️ The namespace .temp is empty. - .temp> add ⍟ I've added these definitions: @@ -56,6 +54,7 @@ list: 4. foo : Text 5. quux : Text 6. qux : Text + 7. builtin type Text ``` @@ -70,6 +69,7 @@ We can ask to `view` the second element of this list: 4. foo : Text 5. quux : Text 6. qux : Text + 7. builtin type Text .temp> view 2 @@ -89,6 +89,7 @@ And we can `view` multiple elements by separating with spaces: 4. foo : Text 5. quux : Text 6. qux : Text + 7. builtin type Text .temp> view 2 3 5 @@ -114,6 +115,7 @@ We can also ask for a range: 4. foo : Text 5. quux : Text 6. qux : Text + 7. builtin type Text .temp> view 2-4 @@ -139,6 +141,7 @@ And we can ask for multiple ranges and use mix of ranges and numbers: 4. foo : Text 5. quux : Text 6. qux : Text + 7. builtin type Text .temp> view 1-3 4 5-6 diff --git a/unison-src/transcripts/pattern-match-coverage.output.md b/unison-src/transcripts/pattern-match-coverage.output.md index 700cf2917a..0a0b290c99 100644 --- a/unison-src/transcripts/pattern-match-coverage.output.md +++ b/unison-src/transcripts/pattern-match-coverage.output.md @@ -114,7 +114,7 @@ test = cases ⍟ These new definitions are ok to `add`: - unique type V + type V test : Optional (Optional V) -> () ``` @@ -547,7 +547,7 @@ test = cases ⍟ These new definitions are ok to `add`: - unique type V + type V test : [V] -> () ``` @@ -645,7 +645,7 @@ unit2t = cases ⍟ These new definitions are ok to `add`: - unique type T + type T unit2t : 'T ``` @@ -654,7 +654,7 @@ unit2t = cases ⍟ I've added these definitions: - unique type T + type T unit2t : 'T ``` @@ -701,7 +701,7 @@ evil = bug "" ⍟ These new definitions are ok to `add`: - unique type V + type V evil : 'V ``` @@ -710,7 +710,7 @@ evil = bug "" ⍟ I've added these definitions: - unique type V + type V evil : 'V ``` @@ -743,7 +743,7 @@ unique type SomeType = A ⍟ These new definitions are ok to `add`: - unique type SomeType + type SomeType ``` ```ucm @@ -751,7 +751,7 @@ unique type SomeType = A ⍟ I've added these definitions: - unique type SomeType + type SomeType ``` ```unison @@ -771,7 +771,7 @@ get x = match x with ⍟ These new definitions are ok to `add`: - unique type R + type R get : R -> SomeType ``` @@ -789,7 +789,7 @@ unique type R = { someType : SomeType } ⍟ These new definitions are ok to `add`: - unique type R + type R R.someType : R -> SomeType R.someType.modify : (SomeType ->{g} SomeType) -> R ->{g} R R.someType.set : SomeType -> R -> R @@ -853,7 +853,7 @@ result f = handle !f with cases ⍟ These names already exist. You can `update` them to your new definition: - unique type T + type T ``` ```unison @@ -1197,7 +1197,7 @@ result f = ⍟ These new definitions are ok to `add`: - unique ability Give a + ability Give a result : '{e, Give V} r ->{e} r ``` @@ -1225,7 +1225,7 @@ result f = ⍟ These new definitions are ok to `add`: - unique ability Give a + ability Give a result : '{e, Give V} r ->{e} r ``` @@ -1312,8 +1312,8 @@ result f = ⍟ These new definitions are ok to `add`: - unique ability GiveA a - unique ability GiveB a + ability GiveA a + ability GiveB a result : '{e, GiveA V, GiveB V} r ->{e} r ``` diff --git a/unison-src/transcripts/project-merge.output.md b/unison-src/transcripts/project-merge.output.md index 9e4544f436..9523a864ca 100644 --- a/unison-src/transcripts/project-merge.output.md +++ b/unison-src/transcripts/project-merge.output.md @@ -30,7 +30,7 @@ zonk = 0 ⍟ I've added these definitions: - zonk : Nat + zonk : ##Nat .> project.create-empty foo @@ -86,7 +86,7 @@ foo/main> add ⍟ I've added these definitions: - bonk : Nat + bonk : ##Nat ``` ```ucm @@ -113,8 +113,8 @@ bar/main> merge foo/main Added definitions: - 1. bonk : Nat - 2. zonk : Nat + 1. bonk : ##Nat + 2. zonk : ##Nat Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you @@ -145,7 +145,7 @@ xonk = 1 ⍟ These new definitions are ok to `add`: - xonk : Nat + xonk : ##Nat ``` ```ucm @@ -153,7 +153,7 @@ bar/main> add ⍟ I've added these definitions: - xonk : Nat + xonk : ##Nat bar/topic> merge /main @@ -162,7 +162,7 @@ bar/topic> merge /main Added definitions: - 1. xonk : Nat + 1. xonk : ##Nat Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you @@ -180,8 +180,8 @@ bar/topic> merge /main Added definitions: - 1. bonk : Nat - 2. zonk : Nat + 1. bonk : ##Nat + 2. zonk : ##Nat Tip: You can use `todo` to see if this generated any work to do in this namespace and `test` to run the tests. Or you diff --git a/unison-src/transcripts/propagate.md b/unison-src/transcripts/propagate.md index 3eccf72a77..efa1055a87 100644 --- a/unison-src/transcripts/propagate.md +++ b/unison-src/transcripts/propagate.md @@ -1,14 +1,12 @@ # Propagating type edits ```ucm:hide -.> builtins.merge +.subpath.lib> builtins.merge ``` We introduce a type `Foo` with a function dependent `fooToInt`. ```unison -use .builtin - unique type Foo = Foo fooToInt : Foo -> Int @@ -48,35 +46,31 @@ We make a term that has a dependency on another term and also a non-redundant user-provided type signature. ```unison -use .builtin - -someTerm : Optional foo -> Optional foo -someTerm x = x +preserve.someTerm : Optional foo -> Optional foo +preserve.someTerm x = x -otherTerm : Optional baz -> Optional baz -otherTerm y = someTerm y +preserve.otherTerm : Optional baz -> Optional baz +preserve.otherTerm y = someTerm y ``` Add that to the codebase: ```ucm -.subpath.preserve> add +.subpath> add .> cd . ``` Let's now edit the dependency: ```unison -use .builtin - -someTerm : Optional x -> Optional x -someTerm _ = None +preserve.someTerm : Optional x -> Optional x +preserve.someTerm _ = None ``` Update... ```ucm -.subpath.preserve> update.old +.subpath> update.old .> cd . ``` @@ -84,8 +78,8 @@ Now the type of `someTerm` should be `Optional x -> Optional x` and the type of `otherTerm` should remain the same. ```ucm -.subpath.preserve> view someTerm -.subpath.preserve> view otherTerm +.subpath> view preserve.someTerm +.subpath> view preserve.otherTerm ``` ### Propagation only applies to the local branch @@ -94,24 +88,23 @@ Cleaning up a bit... ```ucm .> delete.namespace subpath +.subpath.lib> builtins.merge ``` Now, we make two terms, where one depends on the other. ```unison -use .builtin - -someTerm : Optional foo -> Optional foo -someTerm x = x +one.someTerm : Optional foo -> Optional foo +one.someTerm x = x -otherTerm : Optional baz -> Optional baz -otherTerm y = someTerm y +one.otherTerm : Optional baz -> Optional baz +one.otherTerm y = someTerm y ``` We'll make two copies of this namespace. ```ucm -.subpath.one> add +.subpath> add .subpath> fork one two .> cd . ``` @@ -119,8 +112,6 @@ We'll make two copies of this namespace. Now let's edit one of the terms... ```unison -use .builtin - someTerm : Optional x -> Optional x someTerm _ = None ``` @@ -134,5 +125,5 @@ someTerm _ = None The other namespace should be left alone. ```ucm -.subpath.two> view someTerm +.subpath> view two.someTerm ``` diff --git a/unison-src/transcripts/propagate.output.md b/unison-src/transcripts/propagate.output.md index e008cc8bca..bbc1d3344d 100644 --- a/unison-src/transcripts/propagate.output.md +++ b/unison-src/transcripts/propagate.output.md @@ -3,8 +3,6 @@ We introduce a type `Foo` with a function dependent `fooToInt`. ```unison -use .builtin - unique type Foo = Foo fooToInt : Foo -> Int @@ -21,31 +19,29 @@ fooToInt _ = +42 ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo fooToInt : Foo -> Int ``` And then we add it. ```ucm - ☝️ The namespace .subpath is empty. - .subpath> add ⍟ I've added these definitions: - unique type Foo + type Foo fooToInt : Foo -> Int .subpath> find.verbose - 1. -- #khopi9b7o8afgva63q9riun664i1p24ricqjbnelo7eipmnsccu3s49v78u9sd3psdfkbllbk183n4e4apco3db99k3v8fehhaasbqo - unique type Foo + 1. -- #uj8oalgadr2f52qloufah6t8vsvbc76oqijkotek87vooih7aqu44k20hrs34kartusapghp4jmfv6g1409peklv3r6a527qpk52soo + type Foo - 2. -- #khopi9b7o8afgva63q9riun664i1p24ricqjbnelo7eipmnsccu3s49v78u9sd3psdfkbllbk183n4e4apco3db99k3v8fehhaasbqo#0 + 2. -- #uj8oalgadr2f52qloufah6t8vsvbc76oqijkotek87vooih7aqu44k20hrs34kartusapghp4jmfv6g1409peklv3r6a527qpk52soo#0 Foo.Foo : Foo - 3. -- #4lcpsef0pconupgdboml883pi87fimsmlrcihnm0f2nvnboj3c8qikuebsrrpuoildl8vigcplgm9crfge5mddijb531utsjcuob5oo + 3. -- #j6hbm1gc2ak4f46b6705q90ld4bmhoi8etq2q45j081i9jgn95fvk3p6tjg67e7sm0021035i8qikmk4p6k845l5d00u26cos5731to fooToInt : Foo -> Int @@ -73,7 +69,7 @@ unique type Foo = Foo | Bar ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` and update the codebase to use the new type `Foo`... @@ -83,7 +79,7 @@ and update the codebase to use the new type `Foo`... ⍟ I've updated these names to your new definition: - unique type Foo + type Foo ``` ... it should automatically propagate the type to `fooToInt`. @@ -103,13 +99,11 @@ We make a term that has a dependency on another term and also a non-redundant user-provided type signature. ```unison -use .builtin - -someTerm : Optional foo -> Optional foo -someTerm x = x +preserve.someTerm : Optional foo -> Optional foo +preserve.someTerm x = x -otherTerm : Optional baz -> Optional baz -otherTerm y = someTerm y +preserve.otherTerm : Optional baz -> Optional baz +preserve.otherTerm y = someTerm y ``` ```ucm @@ -122,21 +116,19 @@ otherTerm y = someTerm y ⍟ These new definitions are ok to `add`: - otherTerm : Optional baz -> Optional baz - someTerm : Optional foo -> Optional foo + preserve.otherTerm : Optional baz -> Optional baz + preserve.someTerm : Optional foo -> Optional foo ``` Add that to the codebase: ```ucm - ☝️ The namespace .subpath.preserve is empty. - -.subpath.preserve> add +.subpath> add ⍟ I've added these definitions: - otherTerm : Optional baz -> Optional baz - someTerm : Optional foo -> Optional foo + preserve.otherTerm : Optional baz -> Optional baz + preserve.someTerm : Optional foo -> Optional foo .> cd . @@ -144,10 +136,8 @@ Add that to the codebase: Let's now edit the dependency: ```unison -use .builtin - -someTerm : Optional x -> Optional x -someTerm _ = None +preserve.someTerm : Optional x -> Optional x +preserve.someTerm _ = None ``` ```ucm @@ -160,17 +150,17 @@ someTerm _ = None ⍟ These new definitions are ok to `add`: - someTerm : Optional x -> Optional x + preserve.someTerm : Optional x -> Optional x ``` Update... ```ucm -.subpath.preserve> update.old +.subpath> update.old ⍟ I've updated these names to your new definition: - someTerm : Optional x -> Optional x + preserve.someTerm : Optional x -> Optional x .> cd . @@ -179,15 +169,15 @@ Now the type of `someTerm` should be `Optional x -> Optional x` and the type of `otherTerm` should remain the same. ```ucm -.subpath.preserve> view someTerm +.subpath> view preserve.someTerm - someTerm : Optional x -> Optional x - someTerm _ = None + preserve.someTerm : Optional x -> Optional x + preserve.someTerm _ = None -.subpath.preserve> view otherTerm +.subpath> view preserve.otherTerm - otherTerm : Optional baz -> Optional baz - otherTerm y = someTerm y + preserve.otherTerm : Optional baz -> Optional baz + preserve.otherTerm y = someTerm y ``` ### Propagation only applies to the local branch @@ -199,17 +189,21 @@ Cleaning up a bit... Done. + ☝️ The namespace .subpath.lib is empty. + +.subpath.lib> builtins.merge + + Done. + ``` Now, we make two terms, where one depends on the other. ```unison -use .builtin +one.someTerm : Optional foo -> Optional foo +one.someTerm x = x -someTerm : Optional foo -> Optional foo -someTerm x = x - -otherTerm : Optional baz -> Optional baz -otherTerm y = someTerm y +one.otherTerm : Optional baz -> Optional baz +one.otherTerm y = someTerm y ``` ```ucm @@ -222,21 +216,19 @@ otherTerm y = someTerm y ⍟ These new definitions are ok to `add`: - otherTerm : Optional baz -> Optional baz - someTerm : Optional foo -> Optional foo + one.otherTerm : Optional baz -> Optional baz + one.someTerm : Optional foo -> Optional foo ``` We'll make two copies of this namespace. ```ucm - ☝️ The namespace .subpath.one is empty. - -.subpath.one> add +.subpath> add ⍟ I've added these definitions: - otherTerm : Optional baz -> Optional baz - someTerm : Optional foo -> Optional foo + one.otherTerm : Optional baz -> Optional baz + one.someTerm : Optional foo -> Optional foo .subpath> fork one two @@ -248,8 +240,6 @@ We'll make two copies of this namespace. Now let's edit one of the terms... ```unison -use .builtin - someTerm : Optional x -> Optional x someTerm _ = None ``` @@ -274,15 +264,15 @@ someTerm _ = None ⍟ I've updated these names to your new definition: - someTerm : Optional x -> Optional x + someTerm : #nirp5os0q6 x -> #nirp5os0q6 x ``` The other namespace should be left alone. ```ucm -.subpath.two> view someTerm +.subpath> view two.someTerm - someTerm : Optional foo -> Optional foo - someTerm x = x + two.someTerm : Optional foo -> Optional foo + two.someTerm x = x ``` diff --git a/unison-src/transcripts/records.output.md b/unison-src/transcripts/records.output.md index f4bc2b1e8a..994735a58e 100644 --- a/unison-src/transcripts/records.output.md +++ b/unison-src/transcripts/records.output.md @@ -9,7 +9,7 @@ unique type Record1 = { a : Text } ```ucm .> view Record1 - unique type Record1 = { a : Text } + type Record1 = { a : Text } ``` ## Record with 2 fields @@ -21,7 +21,7 @@ unique type Record2 = { a : Text, b : Int } ```ucm .> view Record2 - unique type Record2 = { a : Text, b : Int } + type Record2 = { a : Text, b : Int } ``` ## Record with 3 fields @@ -33,7 +33,7 @@ unique type Record3 = { a : Text, b : Int, c : Nat } ```ucm .> view Record3 - unique type Record3 = { a : Text, b : Int, c : Nat } + type Record3 = { a : Text, b : Int, c : Nat } ``` ## Record with many fields @@ -53,7 +53,7 @@ unique type Record4 = ```ucm .> view Record4 - unique type Record4 + type Record4 = { a : Text, b : Int, c : Nat, @@ -78,7 +78,7 @@ If you `view` or `edit` it, it _should_ be treated as a record type, but it does ```ucm .> view RecordWithUserType - unique type RecordWithUserType + type RecordWithUserType = { a : Text, b : Record4, c : UserType } ``` @@ -103,7 +103,7 @@ unique type Record5 = ⍟ These new definitions are ok to `add`: - unique type Record5 + type Record5 Record5.a : Record5 -> Text Record5.a.modify : (Text ->{g} Text) -> Record5 diff --git a/unison-src/transcripts/release-draft-command.md b/unison-src/transcripts/release-draft-command.md index 1692f35e20..7a5652a079 100644 --- a/unison-src/transcripts/release-draft-command.md +++ b/unison-src/transcripts/release-draft-command.md @@ -1,7 +1,8 @@ The `release.draft` command drafts a release from the current branch. ```ucm:hide -.> builtins.merge +.> project.create-empty foo +foo/main> builtins.merge ``` Some setup: @@ -11,7 +12,6 @@ someterm = 18 ``` ```ucm -.> project.create-empty foo foo/main> add ``` diff --git a/unison-src/transcripts/release-draft-command.output.md b/unison-src/transcripts/release-draft-command.output.md index 8c0a300a04..0eb667e870 100644 --- a/unison-src/transcripts/release-draft-command.output.md +++ b/unison-src/transcripts/release-draft-command.output.md @@ -20,22 +20,6 @@ someterm = 18 ``` ```ucm -.> project.create-empty foo - - 🎉 I've created the project foo. - - 🎨 Type `ui` to explore this project's code in your browser. - 🔭 Discover libraries at https://share.unison-lang.org - 📖 Use `help-topic projects` to learn more about projects. - - Write your first Unison code with UCM: - - 1. Open scratch.u. - 2. Write some Unison code and save the file. - 3. In UCM, type `add` to save it to your new project. - - 🎉 🥳 Happy coding! - foo/main> add ⍟ I've added these definitions: diff --git a/unison-src/transcripts/reset.output.md b/unison-src/transcripts/reset.output.md index adefae3dcb..d22bd9a128 100644 --- a/unison-src/transcripts/reset.output.md +++ b/unison-src/transcripts/reset.output.md @@ -138,7 +138,7 @@ a = 5 ⍟ These new definitions are ok to `add`: - a : Nat + a : ##Nat ``` ```ucm @@ -146,7 +146,7 @@ foo/main> add ⍟ I've added these definitions: - a : Nat + a : ##Nat foo/main> branch topic @@ -180,7 +180,7 @@ a = 3 ⍟ These names already exist. You can `update` them to your new definition: - a : Nat + a : ##Nat ``` ```ucm @@ -222,7 +222,7 @@ main.a = 3 ⍟ These new definitions are ok to `add`: - main.a : Nat + main.a : ##Nat ``` ```ucm @@ -230,7 +230,7 @@ foo/main> add ⍟ I've added these definitions: - main.a : Nat + main.a : ##Nat foo/main> history @@ -279,7 +279,7 @@ foo/topic> add ⍟ I've added these definitions: - main.a : Nat + main.a : ##Nat foo/topic> reset main diff --git a/unison-src/transcripts/resolution-failures.output.md b/unison-src/transcripts/resolution-failures.output.md index 716cd838e6..af7a5f9b48 100644 --- a/unison-src/transcripts/resolution-failures.output.md +++ b/unison-src/transcripts/resolution-failures.output.md @@ -32,8 +32,8 @@ two.ambiguousTerm = "term two" ⍟ These new definitions are ok to `add`: - unique type one.AmbiguousType - unique type two.AmbiguousType + type one.AmbiguousType + type two.AmbiguousType one.ambiguousTerm : ##Text two.ambiguousTerm : ##Text @@ -43,8 +43,8 @@ two.ambiguousTerm = "term two" ⍟ I've added these definitions: - unique type one.AmbiguousType - unique type two.AmbiguousType + type one.AmbiguousType + type two.AmbiguousType one.ambiguousTerm : ##Text two.ambiguousTerm : ##Text diff --git a/unison-src/transcripts/resolve.md b/unison-src/transcripts/resolve.md index 005a90997a..fdd9f5798c 100644 --- a/unison-src/transcripts/resolve.md +++ b/unison-src/transcripts/resolve.md @@ -6,10 +6,10 @@ The `ucm` tool tracks edits to hashes in an object called a _patch_. When patches get merged, sometimes those patches will have conflicting edits. The `replace` command helps resolve such conflicts. -First, let's make a new namespace, `example.resolve`: +First, let's make a new namespace, `example.resolve` and add the builtins: -```ucm -.> cd example.resolve +```ucm:hide +.example.resolve> builtins.merge ``` Now let's add a term named `a.foo`: diff --git a/unison-src/transcripts/resolve.output.md b/unison-src/transcripts/resolve.output.md index 1583894feb..45cac4ccea 100644 --- a/unison-src/transcripts/resolve.output.md +++ b/unison-src/transcripts/resolve.output.md @@ -2,14 +2,8 @@ The `ucm` tool tracks edits to hashes in an object called a _patch_. When patches get merged, sometimes those patches will have conflicting edits. The `replace` command helps resolve such conflicts. -First, let's make a new namespace, `example.resolve`: +First, let's make a new namespace, `example.resolve` and add the builtins: -```ucm -.> cd example.resolve - - ☝️ The namespace .example.resolve is empty. - -``` Now let's add a term named `a.foo`: ```unison @@ -74,7 +68,7 @@ foo = 43 ⍟ These names already exist. You can `update` them to your new definition: - foo : Nat + foo : ##Nat ``` ```ucm @@ -82,7 +76,7 @@ foo = 43 ⍟ I've updated these names to your new definition: - foo : Nat + foo : ##Nat ``` And make a different change in the `b` namespace: @@ -106,7 +100,7 @@ foo = 44 ⍟ These names already exist. You can `update` them to your new definition: - foo : Nat + foo : ##Nat ``` ```ucm @@ -114,7 +108,7 @@ foo = 44 ⍟ I've updated these names to your new definition: - foo : Nat + foo : ##Nat ``` The `a` and `b` namespaces now each contain a patch named `patch`. We can view these: @@ -254,16 +248,10 @@ We can resolve the name conflict by deleting one of the names. Resolved name conflicts: - 1. ┌ example.resolve.c.foo#a84tg4er4k : Nat - 2. └ example.resolve.c.foo#emomp74i93 : Nat + 1. ┌ foo#a84tg4er4k : ##Nat + 2. └ foo#emomp74i93 : ##Nat ↓ - 3. example.resolve.c.foo#a84tg4er4k : Nat - - Name changes: - - Original Changes - 4. example.resolve.a.foo ┐ 5. example.resolve.c.foo#emomp74i93 (removed) - 6. example.resolve.c.foo#emomp74i93 ┘ + 3. foo#a84tg4er4k : ##Nat Tip: You can use `undo` or `reflog` to undo this change. diff --git a/unison-src/transcripts/squash.output.md b/unison-src/transcripts/squash.output.md index 728db8a7ae..ed29232210 100644 --- a/unison-src/transcripts/squash.output.md +++ b/unison-src/transcripts/squash.output.md @@ -128,7 +128,7 @@ x = 1 ⍟ I've added these definitions: - x : Nat + x : ##Nat .> fork trunk alice @@ -152,9 +152,9 @@ neatoFun x = x ⍟ I've added these definitions: - bodaciousNumero : Nat + bodaciousNumero : ##Nat neatoFun : x -> x - radNumber : Nat + radNumber : ##Nat .alice> rename.term radNumber superRadNumber @@ -178,9 +178,9 @@ no more = no more ⍟ I've added these definitions: - babyDon'tHurtMe : Text + babyDon'tHurtMe : ##Text no : more -> r - whatIsLove : Text + whatIsLove : ##Text ``` At this point, Alice and Bob both have some history beyond what's in trunk: @@ -456,12 +456,9 @@ This checks to see that squashing correctly preserves deletions: Name changes: - Original Changes - 1. builtin.Nat.+ ┐ 2. delete.builtin2.Nat.+ (removed) - 3. builtin2.Nat.+ │ - 4. delete.builtin.Nat.+ │ - 5. delete.builtin2.Nat.+ │ - 6. mybuiltin.Nat.+ ┘ + Original Changes + 1. builtin.Nat.+ ┐ 2. builtin2.Nat.+ (removed) + 3. builtin2.Nat.+ ┘ Tip: You can use `undo` or `reflog` to undo this change. @@ -469,12 +466,9 @@ This checks to see that squashing correctly preserves deletions: Name changes: - Original Changes - 1. builtin.Nat.* ┐ 2. delete.builtin2.Nat.* (removed) - 3. builtin2.Nat.* │ - 4. delete.builtin.Nat.* │ - 5. delete.builtin2.Nat.* │ - 6. mybuiltin.Nat.* ┘ + Original Changes + 1. builtin.Nat.* ┐ 2. builtin2.Nat.* (removed) + 3. builtin2.Nat.* ┘ Tip: You can use `undo` or `reflog` to undo this change. diff --git a/unison-src/transcripts/suffixes.output.md b/unison-src/transcripts/suffixes.output.md index 73b4724ee0..83719211c6 100644 --- a/unison-src/transcripts/suffixes.output.md +++ b/unison-src/transcripts/suffixes.output.md @@ -166,7 +166,7 @@ bar = 100 ⍟ I've added these definitions: - unique type A + type A bar : Nat foo.a : Nat @@ -198,7 +198,7 @@ fn = cases ⍟ These new definitions are ok to `add`: - unique type B + type B fn : B -> Text foo.baz.qux.bar : Text zoink.a : Text diff --git a/unison-src/transcripts/sum-type-update-conflicts.md b/unison-src/transcripts/sum-type-update-conflicts.md index afa47c87ee..65737ccc61 100644 --- a/unison-src/transcripts/sum-type-update-conflicts.md +++ b/unison-src/transcripts/sum-type-update-conflicts.md @@ -3,7 +3,8 @@ https://github.com/unisonweb/unison/issues/2786 ```ucm:hide -.> builtins.mergeio +.> builtins.merge +.ns> builtins.merge ``` First we add a sum-type to the codebase. diff --git a/unison-src/transcripts/sum-type-update-conflicts.output.md b/unison-src/transcripts/sum-type-update-conflicts.output.md index c2bf63eb53..6c06fb300e 100644 --- a/unison-src/transcripts/sum-type-update-conflicts.output.md +++ b/unison-src/transcripts/sum-type-update-conflicts.output.md @@ -23,13 +23,12 @@ structural type X = x ``` ```ucm - ☝️ The namespace .ns is empty. - .ns> add ⍟ I've added these definitions: structural type X + (also named builtin.Unit) .> cd . @@ -75,5 +74,6 @@ is removed in the same update that the new term is being added. ⍟ I've updated these names to your new definition: structural type X + (The old definition was also named builtin.Unit.) ``` diff --git a/unison-src/transcripts/switch-command.md b/unison-src/transcripts/switch-command.md index 97786b4ec0..d75b4a9592 100644 --- a/unison-src/transcripts/switch-command.md +++ b/unison-src/transcripts/switch-command.md @@ -1,7 +1,10 @@ The `switch` command switches to an existing project or branch. ```ucm:hide -.> builtins.merge +.> project.create-empty foo +.> project.create-empty bar +foo/main> builtins.merge +bar/main> builtins.merge ``` Setup stuff. @@ -11,8 +14,6 @@ someterm = 18 ``` ```ucm -.> project.create-empty foo -.> project.create-empty bar foo/main> add foo/main> branch bar foo/main> branch topic diff --git a/unison-src/transcripts/switch-command.output.md b/unison-src/transcripts/switch-command.output.md index 47e9497c78..a6c9dd09ce 100644 --- a/unison-src/transcripts/switch-command.output.md +++ b/unison-src/transcripts/switch-command.output.md @@ -20,38 +20,6 @@ someterm = 18 ``` ```ucm -.> project.create-empty foo - - 🎉 I've created the project foo. - - 🎨 Type `ui` to explore this project's code in your browser. - 🔭 Discover libraries at https://share.unison-lang.org - 📖 Use `help-topic projects` to learn more about projects. - - Write your first Unison code with UCM: - - 1. Open scratch.u. - 2. Write some Unison code and save the file. - 3. In UCM, type `add` to save it to your new project. - - 🎉 🥳 Happy coding! - -.> project.create-empty bar - - 🎉 I've created the project bar. - - 🎨 Type `ui` to explore this project's code in your browser. - 🔭 Discover libraries at https://share.unison-lang.org - 📖 Use `help-topic projects` to learn more about projects. - - Write your first Unison code with UCM: - - 1. Open scratch.u. - 2. Write some Unison code and save the file. - 3. In UCM, type `add` to save it to your new project. - - 🎉 🥳 Happy coding! - foo/main> add ⍟ I've added these definitions: diff --git a/unison-src/transcripts/tab-completion.output.md b/unison-src/transcripts/tab-completion.output.md index 0d2ed20936..3719ca60f7 100644 --- a/unison-src/transcripts/tab-completion.output.md +++ b/unison-src/transcripts/tab-completion.output.md @@ -14,7 +14,6 @@ Test that tab completion works as expected. .> debug.tab-complete delete. delete.branch - delete.link delete.namespace delete.namespace.force delete.patch @@ -49,7 +48,7 @@ unique type subnamespace.AType = A | B ⍟ These new definitions are ok to `add`: - unique type subnamespace.AType + type subnamespace.AType othernamespace.someName : ##Nat subnamespace.someName : ##Nat subnamespace.someOtherName : ##Nat @@ -153,7 +152,7 @@ add b = b ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo add : a -> a ``` @@ -162,7 +161,7 @@ add b = b ⍟ I've added these definitions: - unique type Foo + type Foo add : a -> a .> debug.tab-complete delete.type Foo diff --git a/unison-src/transcripts/todo.md b/unison-src/transcripts/todo.md index 87e99e2f60..f2dcd4d253 100644 --- a/unison-src/transcripts/todo.md +++ b/unison-src/transcripts/todo.md @@ -3,14 +3,14 @@ ## Simple type-changing update. ```ucm:hide -.> builtins.mergeio +.simple> builtins.merge ``` ```unison:hide x = 1 useX = x + 10 -structural type MyType = MyType Nat +type MyType = MyType Nat useMyType = match MyType 1 with MyType a -> a + 10 ``` @@ -25,7 +25,7 @@ Perform a type-changing update so dependents are added to our update frontier. ```unison:hide x = -1 -structural type MyType = MyType Text +type MyType = MyType Text ``` ```ucm:error @@ -36,9 +36,13 @@ structural type MyType = MyType Text ## A merge with conflicting updates. +```ucm:hide +.mergeA> builtins.merge +``` + ```unison:hide x = 1 -structural type MyType = MyType +type MyType = MyType ``` Set up two branches with the same starting point. @@ -52,7 +56,7 @@ Update `x` to a different term in each branch. ```unison:hide x = 2 -structural type MyType = MyType Nat +type MyType = MyType Nat ``` ```ucm:hide @@ -62,7 +66,7 @@ structural type MyType = MyType Nat ```unison:hide x = 3 -structural type MyType = MyType Int +type MyType = MyType Int ``` ```ucm:hide @@ -77,7 +81,7 @@ structural type MyType = MyType Int ## A named value that appears on the LHS of a patch isn't shown ```ucm:hide -.lhs> cd .lhs +.lhs> builtins.merge ``` ```unison @@ -109,7 +113,7 @@ oldfoo = 801 ## A type-changing update to one element of a cycle, which doesn't propagate to the other ```ucm:hide -.cycle2> builtins.mergeio +.cycle2> builtins.merge ``` ```unison diff --git a/unison-src/transcripts/todo.output.md b/unison-src/transcripts/todo.output.md index b5ede5fce7..83d95f4b7d 100644 --- a/unison-src/transcripts/todo.output.md +++ b/unison-src/transcripts/todo.output.md @@ -6,7 +6,7 @@ x = 1 useX = x + 10 -structural type MyType = MyType Nat +type MyType = MyType Nat useMyType = match MyType 1 with MyType a -> a + 10 ``` @@ -16,7 +16,7 @@ Perform a type-changing update so dependents are added to our update frontier. ```unison x = -1 -structural type MyType = MyType Text +type MyType = MyType Text ``` ```ucm @@ -24,7 +24,7 @@ structural type MyType = MyType Text ⍟ I've updated these names to your new definition: - structural type MyType + type MyType x : Int .simple> todo @@ -34,7 +34,7 @@ structural type MyType = MyType Text The namespace has 2 transitive dependent(s) left to upgrade. Your edit frontier is the dependents of these definitions: - structural type #68k40ra7l7 + type #vijug0om28 #gjmq673r1v : Nat I recommend working on them in the following order: @@ -51,7 +51,7 @@ structural type MyType = MyType Text ```unison x = 1 -structural type MyType = MyType +type MyType = MyType ``` Set up two branches with the same starting point. @@ -60,12 +60,12 @@ Update `x` to a different term in each branch. ```unison x = 2 -structural type MyType = MyType Nat +type MyType = MyType Nat ``` ```unison x = 3 -structural type MyType = MyType Int +type MyType = MyType Int ``` ```ucm @@ -76,18 +76,15 @@ structural type MyType = MyType Int New name conflicts: - 1. structural type MyType#68k40ra7l7 - + 1. type MyType#ig1g2ka7lv ↓ - 2. ┌ structural type MyType#68k40ra7l7 - - 3. └ structural type MyType#eo6rj0lj1b - + 2. ┌ type MyType#ig1g2ka7lv + 3. └ type MyType#m6mdqhqcr1 - 4. MyType.MyType#68k40ra7l7#0 : Nat -> MyType#68k40ra7l7 + 4. MyType.MyType#ig1g2ka7lv#0 : Nat -> MyType#ig1g2ka7lv ↓ - 5. ┌ MyType.MyType#68k40ra7l7#0 : Nat -> MyType#68k40ra7l7 - 6. └ MyType.MyType#eo6rj0lj1b#0 : Int -> MyType#eo6rj0lj1b + 5. ┌ MyType.MyType#ig1g2ka7lv#0 : Nat -> MyType#ig1g2ka7lv + 6. └ MyType.MyType#m6mdqhqcr1#0 : Int -> MyType#m6mdqhqcr1 7. x#dcgdua2lj6 : Nat ↓ @@ -116,17 +113,17 @@ structural type MyType = MyType Int have been merged into this one. You'll have to tell me what to use as the new definition: - The type 1. .builtin.Unit was replaced with - 2. MyType#68k40ra7l7 - 3. MyType#eo6rj0lj1b + The type 1. #8h7qq3ougl was replaced with + 2. MyType#ig1g2ka7lv + 3. MyType#m6mdqhqcr1 The term 4. #gjmq673r1v was replaced with 5. x#dcgdua2lj6 6. x#f3lgjvjqoo ❓ The term MyType.MyType has conflicting definitions: - 7. MyType.MyType#68k40ra7l7#0 - 8. MyType.MyType#eo6rj0lj1b#0 + 7. MyType.MyType#ig1g2ka7lv#0 + 8. MyType.MyType#m6mdqhqcr1#0 Tip: This occurs when merging branches that both independently introduce the same name. Use `move.term` or `delete.term` diff --git a/unison-src/transcripts/top-level-exceptions.output.md b/unison-src/transcripts/top-level-exceptions.output.md index 80b765c227..2a1241f915 100644 --- a/unison-src/transcripts/top-level-exceptions.output.md +++ b/unison-src/transcripts/top-level-exceptions.output.md @@ -9,7 +9,7 @@ FYI, here are the `Exception` and `Failure` types: structural ability builtin.Exception where raise : Failure ->{builtin.Exception} x - unique type builtin.io2.Failure + type builtin.io2.Failure = Failure Type Text Any ``` @@ -84,7 +84,7 @@ unique type RuntimeError = ⍟ These new definitions are ok to `add`: - unique type RuntimeError + type RuntimeError error : Text -> a ->{Exception} x main2 : '{Exception} r diff --git a/unison-src/transcripts/type-modifier-are-optional.md b/unison-src/transcripts/type-modifier-are-optional.md new file mode 100644 index 0000000000..abce0ad0b8 --- /dev/null +++ b/unison-src/transcripts/type-modifier-are-optional.md @@ -0,0 +1,17 @@ +# Type modifiers are optional, `unique` is the default. + +```ucm:hide +.> builtins.merge +``` + +Types and abilities may be prefixed with either `unique` or `structural`. When left unspecified, `unique` is assumed. + +```unison +type Abc = Abc +unique type Def = Def +structural type Ghi = Ghi + +ability MyAbility where const : a +unique ability MyAbilityU where const : a +structural ability MyAbilityS where const : a +``` diff --git a/unison-src/transcripts/type-modifier-are-optional.output.md b/unison-src/transcripts/type-modifier-are-optional.output.md new file mode 100644 index 0000000000..88b7844127 --- /dev/null +++ b/unison-src/transcripts/type-modifier-are-optional.output.md @@ -0,0 +1,33 @@ +# Type modifiers are optional, `unique` is the default. + +Types and abilities may be prefixed with either `unique` or `structural`. When left unspecified, `unique` is assumed. + +```unison +type Abc = Abc +unique type Def = Def +structural type Ghi = Ghi + +ability MyAbility where const : a +unique ability MyAbilityU where const : a +structural ability MyAbilityS where const : 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`: + + type Abc + type Def + structural type Ghi + (also named builtin.Unit) + ability MyAbility + structural ability MyAbilityS + ability MyAbilityU + +``` diff --git a/unison-src/transcripts/type-modifier-required.md b/unison-src/transcripts/type-modifier-required.md deleted file mode 100644 index 1b47bf78e7..0000000000 --- a/unison-src/transcripts/type-modifier-required.md +++ /dev/null @@ -1,26 +0,0 @@ -# Type modifiers are required - -```ucm:hide -.> builtins.merge -``` - -Types needs to be prefixed with either `unique` or `structural`: - -```unison:error -type Abc = Abc -``` - -Abilities needs to be prefixed with either `unique` or `structural`: - -```unison:error -ability MyAbility where const : a -``` - -There should be no errors when `unique` or `structural` is provided: - -```unison -structural type AbcS = AbcS -unique type AbcU = AbcU -structural ability MyAbilityS where const : a -unique ability MyAbilityU where const : a -``` \ No newline at end of file diff --git a/unison-src/transcripts/type-modifier-required.output.md b/unison-src/transcripts/type-modifier-required.output.md deleted file mode 100644 index 846bf7d78f..0000000000 --- a/unison-src/transcripts/type-modifier-required.output.md +++ /dev/null @@ -1,68 +0,0 @@ -# Type modifiers are required - -Types needs to be prefixed with either `unique` or `structural`: - -```unison -type Abc = Abc -``` - -```ucm - - Loading changes detected in scratch.u. - - I expected to see `structural` or `unique` at the start of - this line: - - 1 | type Abc = Abc - - Learn more about when to use `structural` vs `unique` in the - Unison Docs: - https://www.unison-lang.org/learn/language-reference/unique-types/ - -``` -Abilities needs to be prefixed with either `unique` or `structural`: - -```unison -ability MyAbility where const : a -``` - -```ucm - - Loading changes detected in scratch.u. - - I expected to see `structural` or `unique` at the start of - this line: - - 1 | ability MyAbility where const : a - - Learn more about when to use `structural` vs `unique` in the - Unison Docs: - https://www.unison-lang.org/learn/language-reference/unique-types/ - -``` -There should be no errors when `unique` or `structural` is provided: - -```unison -structural type AbcS = AbcS -unique type AbcU = AbcU -structural ability MyAbilityS where const : a -unique ability MyAbilityU where const : 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 AbcS - (also named builtin.Unit) - unique type AbcU - structural ability MyAbilityS - unique ability MyAbilityU - -``` diff --git a/unison-src/transcripts/unique-type-churn.output.md b/unison-src/transcripts/unique-type-churn.output.md index 038ec36de5..bcee03f59e 100644 --- a/unison-src/transcripts/unique-type-churn.output.md +++ b/unison-src/transcripts/unique-type-churn.output.md @@ -18,9 +18,9 @@ unique type C = C B ⍟ These new definitions are ok to `add`: - unique type A - unique type B - unique type C + type A + type B + type C ``` ```ucm @@ -28,9 +28,9 @@ unique type C = C B ⍟ I've added these definitions: - unique type A - unique type B - unique type C + type A + type B + type C ``` ```unison @@ -79,7 +79,7 @@ unique type A = A () ⍟ These names already exist. You can `update` them to your new definition: - unique type A + type A ``` ```ucm @@ -118,7 +118,7 @@ unique type A = A ⍟ These names already exist. You can `update` them to your new definition: - unique type A + type A ``` Note that `A` is back to its original hash. diff --git a/unison-src/transcripts/universal-cmp.output.md b/unison-src/transcripts/universal-cmp.output.md index b926c656d0..ec03128e87 100644 --- a/unison-src/transcripts/universal-cmp.output.md +++ b/unison-src/transcripts/universal-cmp.output.md @@ -21,7 +21,7 @@ threadEyeDeez _ = ⍟ These new definitions are ok to `add`: - unique type A + type A threadEyeDeez : ∀ _. _ ->{IO} (Boolean, Boolean) ``` @@ -30,7 +30,7 @@ threadEyeDeez _ = ⍟ I've added these definitions: - unique type A + type A threadEyeDeez : ∀ _. _ ->{IO} (Boolean, Boolean) .> run threadEyeDeez diff --git a/unison-src/transcripts/update-on-conflict.md b/unison-src/transcripts/update-on-conflict.md index 3ee0673f6c..7f3aee885e 100644 --- a/unison-src/transcripts/update-on-conflict.md +++ b/unison-src/transcripts/update-on-conflict.md @@ -2,6 +2,7 @@ ```ucm:hide .> builtins.merge +.merged> builtins.merge ``` ```unison diff --git a/unison-src/transcripts/update-on-conflict.output.md b/unison-src/transcripts/update-on-conflict.output.md index a1645940a8..b74f743d3c 100644 --- a/unison-src/transcripts/update-on-conflict.output.md +++ b/unison-src/transcripts/update-on-conflict.output.md @@ -28,8 +28,6 @@ Cause a conflict: a.x : Nat b.x : Nat - ☝️ The namespace .merged is empty. - .merged> merge .a Here's what's changed in the current namespace after the diff --git a/unison-src/transcripts/update-suffixifies-properly.md b/unison-src/transcripts/update-suffixifies-properly.md new file mode 100644 index 0000000000..a5770cd9c8 --- /dev/null +++ b/unison-src/transcripts/update-suffixifies-properly.md @@ -0,0 +1,26 @@ +```ucm:hide +.> project.create-empty myproject +myproject/main> builtins.merge +myproject/main> move.namespace builtin lib.builtin +``` + +```unison +a.x.x.x.x = 100 +b.x.x.x.x = 100 +foo = 25 +c.y.y.y.y = foo + 10 +d.y.y.y.y = foo + 10 +bar = a.x.x.x.x + c.y.y.y.y +``` + +```ucm +myproject/main> add +``` + +```unison +foo = +30 +``` + +```ucm:error +myproject/main> update +``` diff --git a/unison-src/transcripts/update-suffixifies-properly.output.md b/unison-src/transcripts/update-suffixifies-properly.output.md new file mode 100644 index 0000000000..165dda0ca1 --- /dev/null +++ b/unison-src/transcripts/update-suffixifies-properly.output.md @@ -0,0 +1,90 @@ +```unison +a.x.x.x.x = 100 +b.x.x.x.x = 100 +foo = 25 +c.y.y.y.y = foo + 10 +d.y.y.y.y = foo + 10 +bar = a.x.x.x.x + c.y.y.y.y +``` + +```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`: + + a.x.x.x.x : Nat + b.x.x.x.x : Nat + bar : Nat + c.y.y.y.y : Nat + d.y.y.y.y : Nat + foo : Nat + +``` +```ucm +myproject/main> add + + ⍟ I've added these definitions: + + a.x.x.x.x : Nat + b.x.x.x.x : Nat + bar : Nat + c.y.y.y.y : Nat + d.y.y.y.y : Nat + foo : Nat + +``` +```unison +foo = +30 +``` + +```ucm + + Loading changes detected in scratch.u. + + I found and typechecked these definitions in scratch.u. If you + do an `add` or `update`, here's how your codebase would + change: + + ⍟ These names already exist. You can `update` them to your + new definition: + + foo : Int + +``` +```ucm +myproject/main> update + + Okay, I'm searching the branch for code that needs to be + updated... + + That's done. Now I'm making sure everything typechecks... + + Typechecking failed. I've updated your scratch file with the + definitions that need fixing. Once the file is compiling, try + `update` again. + +``` +```unison:added-by-ucm scratch.u +bar : Nat +bar = + use Nat + + x + c.y.y.y.y + +d.y.y.y.y : Nat +d.y.y.y.y = + use Nat + + foo + 10 + +c.y.y.y.y : Nat +c.y.y.y.y = + use Nat + + foo + 10 + +foo = +30 +``` + diff --git a/unison-src/transcripts/update-type-add-constructor.output.md b/unison-src/transcripts/update-type-add-constructor.output.md index 8b9840e9ad..d0fb21a382 100644 --- a/unison-src/transcripts/update-type-add-constructor.output.md +++ b/unison-src/transcripts/update-type-add-constructor.output.md @@ -13,7 +13,7 @@ unique type Foo ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -21,7 +21,7 @@ unique type Foo ⍟ I've added these definitions: - unique type Foo + type Foo ``` ```unison @@ -41,7 +41,7 @@ unique type Foo ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -54,12 +54,12 @@ unique type Foo .> view Foo - unique type Foo = Bar Nat | Baz Nat Nat + type Foo = Bar Nat | Baz Nat Nat .> find.verbose 1. -- #2sffq4apsq1cts53njcunj63fa8ohov4eqn77q14s77ajicajh4g28sq5s5ai33f2k6oh6o67aarnlpu7u7s4la07ag2er33epalsog - unique type Foo + type Foo 2. -- #2sffq4apsq1cts53njcunj63fa8ohov4eqn77q14s77ajicajh4g28sq5s5ai33f2k6oh6o67aarnlpu7u7s4la07ag2er33epalsog#0 Foo.Bar : Nat -> Foo diff --git a/unison-src/transcripts/update-type-add-field.output.md b/unison-src/transcripts/update-type-add-field.output.md index 1c25ba8aec..7ee979d64e 100644 --- a/unison-src/transcripts/update-type-add-field.output.md +++ b/unison-src/transcripts/update-type-add-field.output.md @@ -12,7 +12,7 @@ unique type Foo = Bar Nat ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -20,7 +20,7 @@ unique type Foo = Bar Nat ⍟ I've added these definitions: - unique type Foo + type Foo ``` ```unison @@ -38,7 +38,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -51,12 +51,12 @@ unique type Foo = Bar Nat Nat .> view Foo - unique type Foo = Bar Nat Nat + type Foo = Bar Nat Nat .> find.verbose 1. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g - unique type Foo + type Foo 2. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g#0 Foo.Bar : Nat -> Nat -> Foo diff --git a/unison-src/transcripts/update-type-add-new-record.output.md b/unison-src/transcripts/update-type-add-new-record.output.md index 0d5ad37704..8c00d6c1de 100644 --- a/unison-src/transcripts/update-type-add-new-record.output.md +++ b/unison-src/transcripts/update-type-add-new-record.output.md @@ -12,7 +12,7 @@ unique type Foo = { bar : Nat } ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -28,6 +28,6 @@ unique type Foo = { bar : Nat } .> view Foo - unique type Foo = { bar : Nat } + type Foo = { bar : Nat } ``` diff --git a/unison-src/transcripts/update-type-add-record-field.output.md b/unison-src/transcripts/update-type-add-record-field.output.md index 17d6c5b5c6..3f52ad6a82 100644 --- a/unison-src/transcripts/update-type-add-record-field.output.md +++ b/unison-src/transcripts/update-type-add-record-field.output.md @@ -12,7 +12,7 @@ unique type Foo = { bar : Nat } ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -23,7 +23,7 @@ unique type Foo = { bar : Nat } ⍟ I've added these definitions: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -50,7 +50,7 @@ unique type Foo = { bar : Nat, baz : Int } ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -66,12 +66,12 @@ unique type Foo = { bar : Nat, baz : Int } .> view Foo - unique type Foo = { bar : Nat, baz : Int } + type Foo = { bar : Nat, baz : Int } .> find.verbose 1. -- #05gh1dur4778dauh9slaofprc5356n47qpove0c1jl0birt2fcu301js8auu5vfr5bjfga9j8ikuk07ll9fu1gj3ehrp3basguhsd58 - unique type Foo + type Foo 2. -- #77mi33dv8ac2s90852khi35km5gsamhnpada8mai0k36obbttgg17qld719ospcs1ht9ctolg3pjsqs6qjnl3hfmu493rgsher73sc0 Foo.bar : Foo -> Nat diff --git a/unison-src/transcripts/update-type-constructor-alias.output.md b/unison-src/transcripts/update-type-constructor-alias.output.md index 162d69d630..44d683227c 100644 --- a/unison-src/transcripts/update-type-constructor-alias.output.md +++ b/unison-src/transcripts/update-type-constructor-alias.output.md @@ -12,7 +12,7 @@ unique type Foo = Bar Nat ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -20,7 +20,7 @@ unique type Foo = Bar Nat ⍟ I've added these definitions: - unique type Foo + type Foo .> alias.term Foo.Bar Foo.BarAlias @@ -42,7 +42,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` Bug: we leave `Foo.BarAlias` in the namespace with a nameless decl. @@ -58,7 +58,7 @@ Bug: we leave `Foo.BarAlias` in the namespace with a nameless decl. .> find.verbose 1. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g - unique type Foo + type Foo 2. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g#0 Foo.Bar : Nat -> Nat -> Foo diff --git a/unison-src/transcripts/update-type-delete-constructor-with-dependent.output.md b/unison-src/transcripts/update-type-delete-constructor-with-dependent.output.md index 220c3e5c24..9966a32418 100644 --- a/unison-src/transcripts/update-type-delete-constructor-with-dependent.output.md +++ b/unison-src/transcripts/update-type-delete-constructor-with-dependent.output.md @@ -19,7 +19,7 @@ foo = cases ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo foo : Foo -> Nat ``` @@ -28,7 +28,7 @@ foo = cases ⍟ I've added these definitions: - unique type Foo + type Foo foo : Foo -> Nat ``` @@ -48,7 +48,7 @@ unique type Foo ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -70,6 +70,6 @@ foo = cases Bar n -> n Baz n m -> n Nat.+ m -unique type Foo = Bar Nat +type Foo = Bar Nat ``` diff --git a/unison-src/transcripts/update-type-delete-constructor.output.md b/unison-src/transcripts/update-type-delete-constructor.output.md index 1756ddac0f..c417d5f15c 100644 --- a/unison-src/transcripts/update-type-delete-constructor.output.md +++ b/unison-src/transcripts/update-type-delete-constructor.output.md @@ -14,7 +14,7 @@ unique type Foo ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -22,7 +22,7 @@ unique type Foo ⍟ I've added these definitions: - unique type Foo + type Foo ``` ```unison @@ -41,7 +41,7 @@ unique type Foo ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -54,12 +54,12 @@ unique type Foo .> view Foo - unique type Foo = Bar Nat + type Foo = Bar Nat .> find.verbose 1. -- #b509v3eg4kehsg29g6pvrogeb71ue32nm2fj9284n4i7lprsr7u9a7g6s695d09du0fsfti6rrsk1s62q5thpr1jjkqb3us3s0lrd60 - unique type Foo + type Foo 2. -- #b509v3eg4kehsg29g6pvrogeb71ue32nm2fj9284n4i7lprsr7u9a7g6s695d09du0fsfti6rrsk1s62q5thpr1jjkqb3us3s0lrd60#0 Foo.Bar : Nat -> Foo diff --git a/unison-src/transcripts/update-type-delete-record-field.output.md b/unison-src/transcripts/update-type-delete-record-field.output.md index 17eea03726..a7bd523155 100644 --- a/unison-src/transcripts/update-type-delete-record-field.output.md +++ b/unison-src/transcripts/update-type-delete-record-field.output.md @@ -12,7 +12,7 @@ unique type Foo = { bar : Nat, baz : Int } ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -26,7 +26,7 @@ unique type Foo = { bar : Nat, baz : Int } ⍟ I've added these definitions: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -50,7 +50,7 @@ unique type Foo = { bar : Nat } ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -72,12 +72,12 @@ We want the field accessors to go away; but for now they are here, causing the u .> view Foo - unique type Foo = { bar : Nat, baz : Int } + type Foo = { bar : Nat, baz : Int } .> find.verbose 1. -- #05gh1dur4778dauh9slaofprc5356n47qpove0c1jl0birt2fcu301js8auu5vfr5bjfga9j8ikuk07ll9fu1gj3ehrp3basguhsd58 - unique type Foo + type Foo 2. -- #77mi33dv8ac2s90852khi35km5gsamhnpada8mai0k36obbttgg17qld719ospcs1ht9ctolg3pjsqs6qjnl3hfmu493rgsher73sc0 Foo.bar : Foo -> Nat @@ -113,6 +113,6 @@ Foo.baz.set baz1 = cases Foo bar _ -> Foo bar baz1 Foo.baz.modify : (Int ->{g} Int) -> Foo ->{g} Foo Foo.baz.modify f = cases Foo bar baz -> Foo bar (f baz) -unique type Foo = { bar : Nat } +type Foo = { bar : Nat } ``` diff --git a/unison-src/transcripts/update-type-missing-constructor.output.md b/unison-src/transcripts/update-type-missing-constructor.output.md index e9f75186bb..52ead472eb 100644 --- a/unison-src/transcripts/update-type-missing-constructor.output.md +++ b/unison-src/transcripts/update-type-missing-constructor.output.md @@ -12,7 +12,7 @@ unique type Foo = Bar Nat ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -20,7 +20,7 @@ unique type Foo = Bar Nat ⍟ I've added these definitions: - unique type Foo + type Foo .> delete.term Foo.Bar @@ -44,13 +44,13 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm .> view Foo - unique type Foo = #b509v3eg4k#0 Nat + type Foo = #b509v3eg4k#0 Nat .> update diff --git a/unison-src/transcripts/update-type-nested-decl-aliases.output.md b/unison-src/transcripts/update-type-nested-decl-aliases.output.md index b743304900..0b373c88cd 100644 --- a/unison-src/transcripts/update-type-nested-decl-aliases.output.md +++ b/unison-src/transcripts/update-type-nested-decl-aliases.output.md @@ -17,7 +17,7 @@ structural type A = B.TheOtherAlias Foo structural type A structural type A.B - unique type Foo + type Foo ``` ```ucm @@ -27,7 +27,7 @@ structural type A = B.TheOtherAlias Foo structural type A structural type A.B - unique type Foo + type Foo ``` ```unison @@ -45,7 +45,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` Bug: we want this update to be rejected earlier, because it violates the "decl coherency" precondition that there's @@ -70,6 +70,6 @@ structural type A = B.OneAlias Foo structural type A.B = OneAlias Foo -unique type Foo = Bar Nat Nat +type Foo = Bar Nat Nat ``` diff --git a/unison-src/transcripts/update-type-no-op-record.output.md b/unison-src/transcripts/update-type-no-op-record.output.md index 27539dd990..1a7e55eb74 100644 --- a/unison-src/transcripts/update-type-no-op-record.output.md +++ b/unison-src/transcripts/update-type-no-op-record.output.md @@ -12,7 +12,7 @@ unique type Foo = { bar : Nat } ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo @@ -23,7 +23,7 @@ unique type Foo = { bar : Nat } ⍟ I've added these definitions: - unique type Foo + type Foo Foo.bar : Foo -> Nat Foo.bar.modify : (Nat ->{g} Nat) -> Foo ->{g} Foo Foo.bar.set : Nat -> Foo -> Foo diff --git a/unison-src/transcripts/update-type-stray-constructor-alias.output.md b/unison-src/transcripts/update-type-stray-constructor-alias.output.md index be0d653866..e9fe5f9662 100644 --- a/unison-src/transcripts/update-type-stray-constructor-alias.output.md +++ b/unison-src/transcripts/update-type-stray-constructor-alias.output.md @@ -12,7 +12,7 @@ unique type Foo = Bar Nat ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -20,7 +20,7 @@ unique type Foo = Bar Nat ⍟ I've added these definitions: - unique type Foo + type Foo .> alias.term Foo.Bar Stray.BarAlias @@ -42,7 +42,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` Bug: we leave `Stray.BarAlias` in the namespace with a nameless decl. @@ -58,7 +58,7 @@ Bug: we leave `Stray.BarAlias` in the namespace with a nameless decl. .> find.verbose 1. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g - unique type Foo + type Foo 2. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g#0 Foo.Bar : Nat -> Nat -> Foo diff --git a/unison-src/transcripts/update-type-stray-constructor.output.md b/unison-src/transcripts/update-type-stray-constructor.output.md index 011d4fe5b2..8f72beefd3 100644 --- a/unison-src/transcripts/update-type-stray-constructor.output.md +++ b/unison-src/transcripts/update-type-stray-constructor.output.md @@ -12,7 +12,7 @@ unique type Foo = Bar Nat ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -20,7 +20,7 @@ unique type Foo = Bar Nat ⍟ I've added these definitions: - unique type Foo + type Foo .> move.term Foo.Bar Stray.Bar @@ -44,7 +44,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` Note that the constructor name shown here (implied to be called `Foo.Stray.Bar`) doesn't really exist, it's just showing up due to a pretty-printer bug. @@ -52,7 +52,7 @@ Note that the constructor name shown here (implied to be called `Foo.Stray.Bar`) ```ucm .> view Foo - unique type Foo = Stray.Bar Nat + type Foo = Stray.Bar Nat .> update diff --git a/unison-src/transcripts/update-type-turn-constructor-into-smart-constructor.output.md b/unison-src/transcripts/update-type-turn-constructor-into-smart-constructor.output.md index 4890bbdc37..a28e27e747 100644 --- a/unison-src/transcripts/update-type-turn-constructor-into-smart-constructor.output.md +++ b/unison-src/transcripts/update-type-turn-constructor-into-smart-constructor.output.md @@ -15,7 +15,7 @@ makeFoo n = Bar (n+10) ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo makeFoo : Nat -> Foo ``` @@ -24,7 +24,7 @@ makeFoo n = Bar (n+10) ⍟ I've added these definitions: - unique type Foo + type Foo makeFoo : Nat -> Foo ``` @@ -64,12 +64,12 @@ Foo.Bar n = internal.Bar n .> view Foo - unique type Foo = internal.Bar Nat + type Foo = internal.Bar Nat .> find.verbose 1. -- #b509v3eg4kehsg29g6pvrogeb71ue32nm2fj9284n4i7lprsr7u9a7g6s695d09du0fsfti6rrsk1s62q5thpr1jjkqb3us3s0lrd60 - unique type Foo + type Foo 2. -- #36rn6jqt1k5jccb3c7vagp3jam74dngr92kgcntqhs6dbkua54verfert2i6hsku6uitt9s2jvt1msric0tgemal52d5apav6akn25o Foo.Bar : Nat -> Foo diff --git a/unison-src/transcripts/update-type-turn-non-record-into-record.output.md b/unison-src/transcripts/update-type-turn-non-record-into-record.output.md index 00ea2a292b..f23ab09cd5 100644 --- a/unison-src/transcripts/update-type-turn-non-record-into-record.output.md +++ b/unison-src/transcripts/update-type-turn-non-record-into-record.output.md @@ -12,7 +12,7 @@ unique type Foo = Nat ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo ``` ```ucm @@ -20,7 +20,7 @@ unique type Foo = Nat ⍟ I've added these definitions: - unique type Foo + type Foo ``` ```unison @@ -44,7 +44,7 @@ unique type Foo = { bar : Nat } ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -57,12 +57,12 @@ unique type Foo = { bar : Nat } .> view Foo - unique type Foo = { bar : Nat } + type Foo = { bar : Nat } .> find.verbose 1. -- #b509v3eg4kehsg29g6pvrogeb71ue32nm2fj9284n4i7lprsr7u9a7g6s695d09du0fsfti6rrsk1s62q5thpr1jjkqb3us3s0lrd60 - unique type Foo + type Foo 2. -- #ovhevqfin94qhq5fu0mujfi20mbpvg5mh4vsfklrohp84cch4lhvrn5p29cnbsqfm92l7bt8c1vpjooh72a0psbddvvten4gq2sipag Foo.bar : Foo -> Nat diff --git a/unison-src/transcripts/update-type-with-dependent-term.output.md b/unison-src/transcripts/update-type-with-dependent-term.output.md index 9a3c2124b5..e8837eb523 100644 --- a/unison-src/transcripts/update-type-with-dependent-term.output.md +++ b/unison-src/transcripts/update-type-with-dependent-term.output.md @@ -15,7 +15,7 @@ incrFoo = cases Bar n -> Bar (n+1) ⍟ These new definitions are ok to `add`: - unique type Foo + type Foo incrFoo : Foo -> Foo ``` @@ -24,7 +24,7 @@ incrFoo = cases Bar n -> Bar (n+1) ⍟ I've added these definitions: - unique type Foo + type Foo incrFoo : Foo -> Foo ``` @@ -43,7 +43,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -63,6 +63,6 @@ unique type Foo = Bar Nat Nat incrFoo : Foo -> Foo incrFoo = cases Bar n -> Bar (n Nat.+ 1) -unique type Foo = Bar Nat Nat +type Foo = Bar Nat Nat ``` diff --git a/unison-src/transcripts/update-type-with-dependent-type-to-different-kind.output.md b/unison-src/transcripts/update-type-with-dependent-type-to-different-kind.output.md index 4ee8a42019..e105b39ea2 100644 --- a/unison-src/transcripts/update-type-with-dependent-type-to-different-kind.output.md +++ b/unison-src/transcripts/update-type-with-dependent-type-to-different-kind.output.md @@ -13,8 +13,8 @@ unique type Baz = Qux Foo ⍟ These new definitions are ok to `add`: - unique type Baz - unique type Foo + type Baz + type Foo ``` ```ucm @@ -22,8 +22,8 @@ unique type Baz = Qux Foo ⍟ I've added these definitions: - unique type Baz - unique type Foo + type Baz + type Foo ``` ```unison @@ -41,7 +41,7 @@ unique type Foo a = Bar Nat a ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo a + type Foo a ``` ```ucm @@ -58,8 +58,8 @@ unique type Foo a = Bar Nat a ``` ```unison:added-by-ucm scratch.u -unique type Baz = Qux Foo +type Baz = Qux Foo -unique type Foo a = Bar Nat a +type Foo a = Bar Nat a ``` diff --git a/unison-src/transcripts/update-type-with-dependent-type.output.md b/unison-src/transcripts/update-type-with-dependent-type.output.md index cd3380e7b9..47988e1ffd 100644 --- a/unison-src/transcripts/update-type-with-dependent-type.output.md +++ b/unison-src/transcripts/update-type-with-dependent-type.output.md @@ -13,8 +13,8 @@ unique type Baz = Qux Foo ⍟ These new definitions are ok to `add`: - unique type Baz - unique type Foo + type Baz + type Foo ``` ```ucm @@ -22,8 +22,8 @@ unique type Baz = Qux Foo ⍟ I've added these definitions: - unique type Baz - unique type Foo + type Baz + type Foo ``` ```unison @@ -41,7 +41,7 @@ unique type Foo = Bar Nat Nat ⍟ These names already exist. You can `update` them to your new definition: - unique type Foo + type Foo ``` ```ucm @@ -58,22 +58,22 @@ unique type Foo = Bar Nat Nat .> view Foo - unique type Foo = Bar Nat Nat + type Foo = Bar Nat Nat .> view Baz - unique type Baz = Qux Foo + type Baz = Qux Foo .> find.verbose 1. -- #34msh9satlfog576493eo9pkjn6aj7d8fj6jfheglvgr5s39iptb81649bpkad1lqraheqb8em9ms551k01oternhknc4m7jicgtk08 - unique type Baz + type Baz 2. -- #34msh9satlfog576493eo9pkjn6aj7d8fj6jfheglvgr5s39iptb81649bpkad1lqraheqb8em9ms551k01oternhknc4m7jicgtk08#0 Baz.Qux : Foo -> Baz 3. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g - unique type Foo + type Foo 4. -- #8fk6k0j208th1ia4vnjtoc5fomd6le540prec255svg71bcfga9dofrvoq1d7v6010d6b6em4q51p8st5c5juhrev72cnnel8ko3o1g#0 Foo.Bar : Nat -> Nat -> Foo diff --git a/unison-src/transcripts/upgrade-sad-path.output.md b/unison-src/transcripts/upgrade-sad-path.output.md index 5e07710377..37f96f94ed 100644 --- a/unison-src/transcripts/upgrade-sad-path.output.md +++ b/unison-src/transcripts/upgrade-sad-path.output.md @@ -32,7 +32,9 @@ proj/main> add ```ucm proj/main> upgrade old new - I couldn't automatically upgrade old to new. + I couldn't automatically upgrade old to new. However, I've + added the definitions that need attention to the top of + scratch.u. ``` ```unison:added-by-ucm scratch.u diff --git a/unison-src/transcripts/upgrade-suffixifies-properly.md b/unison-src/transcripts/upgrade-suffixifies-properly.md new file mode 100644 index 0000000000..17e39aa6cc --- /dev/null +++ b/unison-src/transcripts/upgrade-suffixifies-properly.md @@ -0,0 +1,24 @@ +```ucm:hide +.> project.create-empty myproject +myproject/main> builtins.merge +myproject/main> move.namespace builtin lib.builtin +``` + +```unison +lib.old.foo = 25 +lib.new.foo = +30 +a.x.x.x.x = 100 +b.x.x.x.x = 100 +c.y.y.y.y = lib.old.foo + 10 +d.y.y.y.y = lib.old.foo + 10 +bar = a.x.x.x.x + c.y.y.y.y +``` + +```ucm +myproject/main> add +``` + +```ucm:error +myproject/main> upgrade old new +``` + diff --git a/unison-src/transcripts/upgrade-suffixifies-properly.output.md b/unison-src/transcripts/upgrade-suffixifies-properly.output.md new file mode 100644 index 0000000000..275d9aceb0 --- /dev/null +++ b/unison-src/transcripts/upgrade-suffixifies-properly.output.md @@ -0,0 +1,68 @@ +```unison +lib.old.foo = 25 +lib.new.foo = +30 +a.x.x.x.x = 100 +b.x.x.x.x = 100 +c.y.y.y.y = lib.old.foo + 10 +d.y.y.y.y = lib.old.foo + 10 +bar = a.x.x.x.x + c.y.y.y.y +``` + +```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`: + + a.x.x.x.x : Nat + b.x.x.x.x : Nat + bar : Nat + c.y.y.y.y : Nat + d.y.y.y.y : Nat + lib.new.foo : Int + lib.old.foo : Nat + +``` +```ucm +myproject/main> add + + ⍟ I've added these definitions: + + a.x.x.x.x : Nat + b.x.x.x.x : Nat + bar : Nat + c.y.y.y.y : Nat + d.y.y.y.y : Nat + lib.new.foo : Int + lib.old.foo : Nat + +``` +```ucm +myproject/main> upgrade old new + + I couldn't automatically upgrade old to new. However, I've + added the definitions that need attention to the top of + scratch.u. + +``` +```unison:added-by-ucm scratch.u +bar : Nat +bar = + use Nat + + x + c.y.y.y.y + +d.y.y.y.y : Nat +d.y.y.y.y = + use Nat + + foo + 10 + +c.y.y.y.y : Nat +c.y.y.y.y = + use Nat + + foo + 10 +``` + diff --git a/unison-src/transcripts/view.md b/unison-src/transcripts/view.md index 8fb9931098..89b81cf51f 100644 --- a/unison-src/transcripts/view.md +++ b/unison-src/transcripts/view.md @@ -1,7 +1,7 @@ # View commands ```ucm:hide -.> builtins.mergeio +.> builtins.merge ``` ```unison:hide diff --git a/unison-src/transcripts/view.output.md b/unison-src/transcripts/view.output.md index 4525369a6f..71ebf98da7 100644 --- a/unison-src/transcripts/view.output.md +++ b/unison-src/transcripts/view.output.md @@ -18,7 +18,7 @@ b.thing = "b" -- Should be local to namespace .a> view thing - thing : Text + thing : ##Text thing = "a" -- view.global should search globally and be absolutely qualified diff --git a/unison-syntax/src/Unison/Parser/Ann.hs b/unison-syntax/src/Unison/Parser/Ann.hs index b1d9b85e0b..feec96279c 100644 --- a/unison-syntax/src/Unison/Parser/Ann.hs +++ b/unison-syntax/src/Unison/Parser/Ann.hs @@ -10,11 +10,16 @@ data Ann = -- Used for things like Builtins which don't have a source position. Intrinsic -- { sig :: String, start :: L.Pos, end :: L.Pos } | External + | -- Indicates that the term was generated from something at this location. + -- E.g. generated record field accessors (get, modify, etc.) are generated from their field definition, so are tagged + -- with @GeneratedFrom @ + GeneratedFrom Ann | Ann {start :: L.Pos, end :: L.Pos} deriving (Eq, Ord, Show) startingLine :: Ann -> Maybe L.Line startingLine (Ann (L.line -> line) _) = Just line +startingLine (GeneratedFrom a) = startingLine a startingLine _ = Nothing instance Monoid Ann where @@ -27,6 +32,8 @@ instance Semigroup Ann where a <> External = a Intrinsic <> a = a a <> Intrinsic = a + GeneratedFrom a <> b = a <> b + a <> GeneratedFrom b = a <> b -- | Checks whether an annotation contains a given position -- i.e. pos ∈ [start, end) @@ -46,6 +53,7 @@ contains :: Ann -> L.Pos -> Bool contains Intrinsic _ = False contains External _ = False contains (Ann start end) p = start <= p && p < end +contains (GeneratedFrom ann) p = contains ann p -- | Checks whether an annotation contains another annotation. -- @@ -67,5 +75,7 @@ encompasses Intrinsic _ = Nothing encompasses External _ = Nothing encompasses _ Intrinsic = Nothing encompasses _ External = Nothing +encompasses (GeneratedFrom ann) other = encompasses ann other +encompasses ann (GeneratedFrom other) = encompasses ann other encompasses (Ann start1 end1) (Ann start2 end2) = Just $ start1 <= start2 && end1 >= end2 diff --git a/unison-syntax/src/Unison/Syntax/Lexer.hs b/unison-syntax/src/Unison/Syntax/Lexer.hs index 70018c3272..9e0beb95f5 100644 --- a/unison-syntax/src/Unison/Syntax/Lexer.hs +++ b/unison-syntax/src/Unison/Syntax/Lexer.hs @@ -1,8 +1,4 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE DeriveFoldable #-} -{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE ViewPatterns #-} module Unison.Syntax.Lexer ( Token (..), @@ -11,6 +7,7 @@ module Unison.Syntax.Lexer Err (..), Pos (..), Lexeme (..), + lexemeToHQName, lexer, simpleWordyId, simpleSymbolyId, @@ -52,10 +49,18 @@ import Text.Megaparsec.Char qualified as CP import Text.Megaparsec.Char.Lexer qualified as LP import Text.Megaparsec.Error qualified as EP import Text.Megaparsec.Internal qualified as PI +import Unison.HashQualified qualified as HQ +import Unison.HashQualified' qualified as HQ' import Unison.Lexer.Pos (Column, Line, Pos (Pos), column, line) +import Unison.Name (Name) +import Unison.Name qualified as Name +import Unison.NameSegment (NameSegment (NameSegment)) +import Unison.NameSegment qualified as NameSegment import Unison.Prelude import Unison.ShortHash (ShortHash) import Unison.ShortHash qualified as SH +import Unison.Syntax.HashQualified' qualified as HQ' (toString) +import Unison.Syntax.Name qualified as Name (unsafeFromString) import Unison.Util.Bytes qualified as Bytes import Unison.Util.Monoid (intercalateMap) @@ -129,8 +134,8 @@ data Lexeme | Reserved String -- reserved tokens such as `{`, `(`, `type`, `of`, etc | Textual String -- text literals, `"foo bar"` | Character Char -- character literals, `?X` - | WordyId String (Maybe ShortHash) -- a (non-infix) identifier - | SymbolyId String (Maybe ShortHash) -- an infix identifier + | WordyId (HQ'.HashQualified Name) -- a (non-infix) identifier + | SymbolyId (HQ'.HashQualified Name) -- an infix identifier | Blank String -- a typed hole or placeholder | Numeric String -- numeric literals, left unparsed | Bytes Bytes.Bytes -- bytes literals @@ -142,6 +147,13 @@ type IsVirtual = Bool -- is it a virtual semi or an actual semi? makePrisms ''Lexeme +lexemeToHQName :: Lexeme -> Maybe (HQ.HashQualified Name) +lexemeToHQName = \case + WordyId n -> Just (HQ'.toHQ n) + SymbolyId n -> Just (HQ'.toHQ n) + Hash sh -> Just (HQ.HashOnly sh) + _ -> Nothing + space :: P () space = LP.space @@ -303,7 +315,7 @@ lexer0' scope rem = | notLayout t1 && touches t1 t2 && isSigned num = t1 : Token - (SymbolyId (take 1 num) Nothing) + (SymbolyId (HQ'.fromName (Name.unsafeFromString (take 1 num)))) (start t2) (inc $ start t2) : Token (Numeric (drop 1 num)) (inc $ start t2) (end t2) @@ -375,10 +387,10 @@ lexemes' eof = -- ability Foo where => ability Foo where tn <- subsequentTypeName pure $ case (tn, docToks) of - (Just (WordyId tname _), ht : _) + (Just (WordyId tname), ht : _) | isTopLevel -> startToks - <> [WordyId (tname <> ".doc") Nothing <$ ht, Open "=" <$ ht] + <> [WordyId (HQ'.fromName (Name.snoc (HQ'.toName tname) (NameSegment "doc"))) <$ ht, Open "=" <$ ht] <> docToks0 <> [Close <$ last docToks] <> endToks @@ -785,8 +797,10 @@ lexemes' eof = pure $ (fmap Reserved <$> typ) <> t blank = - separated wordySep $ - char '_' *> P.optional wordyIdSeg <&> (Blank . fromMaybe "") + separated wordySep do + _ <- char '_' + seg <- P.optional wordyIdSeg + pure (Blank (maybe "" (Text.unpack . NameSegment.toText) seg)) semi = char ';' $> Semi False textual = Textual <$> quoted @@ -820,39 +834,58 @@ lexemes' eof = wordyId :: P Lexeme wordyId = P.label wordyMsg . P.try $ do dot <- P.optional (lit ".") - segs <- P.sepBy1 wordyIdSeg (P.try (char '.' <* P.lookAhead (P.satisfy wordyIdChar))) - shorthash <- P.optional shorthash - pure $ WordyId (fromMaybe "" dot <> intercalate "." segs) shorthash + segs <- Nel.fromList <$> P.sepBy1 wordyIdSeg (P.try (char '.' <* P.lookAhead (P.satisfy wordyIdChar))) + hash <- P.optional shorthash + let name = (if isJust dot then Name.makeAbsolute else id) (Name.fromSegments segs) + pure (WordyId (HQ'.fromNameHash name hash)) where wordyMsg = "identifier (ex: abba1, snake_case, .foo.bar#xyz, or 🌻)" symbolyId :: P Lexeme symbolyId = P.label symbolMsg . P.try $ do dot <- P.optional (lit ".") - segs <- P.optional segs - shorthash <- P.optional shorthash + segs <- P.optional segments + hash <- P.optional shorthash case (dot, segs) of - (_, Just segs) -> pure $ SymbolyId (fromMaybe "" dot <> segs) shorthash + (_, Just segs) -> do + let name = (if isJust dot then Name.makeAbsolute else id) (Name.fromSegments segs) + pure (SymbolyId (HQ'.fromNameHash name hash)) -- a single . or .#somehash is parsed as a symboly id - (Just dot, Nothing) -> pure $ SymbolyId dot shorthash + (Just dot, Nothing) -> do + let name = Name.fromSegment (NameSegment (Text.pack dot)) + pure (SymbolyId (HQ'.fromNameHash name hash)) (Nothing, Nothing) -> fail symbolMsg where - segs = symbolyIdSeg <|> (wordyIdSeg <+> lit "." <+> segs) + segments :: P (Nel.NonEmpty NameSegment) + segments = + symbolySegments <|> wordySegments + + symbolySegments :: P (Nel.NonEmpty NameSegment) + symbolySegments = do + seg <- symbolyIdSeg + pure (seg Nel.:| []) + + wordySegments :: P (Nel.NonEmpty NameSegment) + wordySegments = do + seg0 <- wordyIdSeg + _ <- lit "." + seg1 Nel.:| segs <- segments + pure (seg0 Nel.:| seg1 : segs) symbolMsg = "operator (examples: +, Float./, List.++#xyz)" - symbolyIdSeg :: P String + symbolyIdSeg :: P NameSegment symbolyIdSeg = do start <- pos id <- P.takeWhile1P (Just symbolMsg) symbolyIdChar when (Set.member id reservedOperators) $ do stop <- pos P.customFailure (Token (ReservedSymbolyId id) start stop) - pure id + pure (NameSegment (Text.pack id)) - wordyIdSeg :: P String + wordyIdSeg :: P NameSegment -- wordyIdSeg = litSeg <|> (P.try do -- todo - wordyIdSeg = P.try $ do + wordyIdSeg = P.try do start <- pos ch <- P.satisfy wordyIdStartChar rest <- P.many (P.satisfy wordyIdChar) @@ -860,7 +893,7 @@ lexemes' eof = when (Set.member word keywords) $ do stop <- pos P.customFailure (Token (ReservedWordyId word) start stop) - pure (ch : rest) + pure (NameSegment (Text.pack (ch : rest))) {- -- ``an-identifier-with-dashes`` @@ -1142,11 +1175,13 @@ findClose :: [String] -> Layout -> Maybe (String, Int) findClose _ [] = Nothing findClose s ((h, _) : tl) = if h `elem` s then Just (h, 1) else fmap (1 +) <$> findClose s tl -simpleWordyId :: String -> Lexeme -simpleWordyId = flip WordyId Nothing +simpleWordyId :: Name -> Lexeme +simpleWordyId name = + WordyId (HQ'.fromName name) -simpleSymbolyId :: String -> Lexeme -simpleSymbolyId = flip SymbolyId Nothing +simpleSymbolyId :: Name -> Lexeme +simpleSymbolyId name = + SymbolyId (HQ'.fromName name) notLayout :: Token Lexeme -> Bool notLayout t = case payload t of @@ -1445,8 +1480,8 @@ instance P.VisualStream [Token Lexeme] where case showEscapeChar c of Just c -> "?\\" ++ [c] Nothing -> '?' : [c] - pretty (WordyId n h) = n ++ (toList h >>= Text.unpack . SH.toText) - pretty (SymbolyId n h) = n ++ (toList h >>= Text.unpack . SH.toText) + pretty (WordyId n) = HQ'.toString n + pretty (SymbolyId n) = HQ'.toString n pretty (Blank s) = "_" ++ s pretty (Numeric n) = n pretty (Hash sh) = show sh diff --git a/unison-syntax/src/Unison/Syntax/Name.hs b/unison-syntax/src/Unison/Syntax/Name.hs index c298e74afb..2fc3d7648d 100644 --- a/unison-syntax/src/Unison/Syntax/Name.hs +++ b/unison-syntax/src/Unison/Syntax/Name.hs @@ -10,6 +10,7 @@ module Unison.Syntax.Name toString, toText, toVar, + fromVar, ) where @@ -111,3 +112,8 @@ unsafeFromText = either (error . Text.unpack) id . fromTextEither unsafeFromVar :: (Var v) => v -> Name unsafeFromVar = unsafeFromText . Var.name + +-- | Parse a name from a var, by first rendering the var as a string. +fromVar :: Var v => v -> Maybe Name +fromVar = + fromText . Var.name diff --git a/unison-syntax/src/Unison/Syntax/Parser.hs b/unison-syntax/src/Unison/Syntax/Parser.hs index 51d42470cf..7b38ffa333 100644 --- a/unison-syntax/src/Unison/Syntax/Parser.hs +++ b/unison-syntax/src/Unison/Syntax/Parser.hs @@ -44,14 +44,12 @@ module Unison.Syntax.Parser sepBy1, string, symbolyDefinitionName, - symbolyIdString, tok, tokenToPair, tupleOrParenthesized, uniqueBase32Namegen, uniqueName, wordyDefinitionName, - wordyIdString, wordyPatternName, ) where @@ -74,8 +72,10 @@ import Unison.ABT qualified as ABT import Unison.ConstructorReference (ConstructorReference) import Unison.Hash qualified as Hash import Unison.HashQualified qualified as HQ +import Unison.HashQualified' qualified as HQ' import Unison.Hashable qualified as Hashable import Unison.Name as Name +import Unison.NameSegment (NameSegment (NameSegment)) import Unison.Names (Names) import Unison.Names.ResolutionResult qualified as Names import Unison.Parser.Ann (Ann (..)) @@ -85,7 +85,7 @@ import Unison.Prelude import Unison.Reference (Reference) import Unison.Referent (Referent) import Unison.Syntax.Lexer qualified as L -import Unison.Syntax.Name qualified as Name (unsafeFromString) +import Unison.Syntax.Name qualified as Name (toVar, unsafeFromString) import Unison.Term (MatchCase (..)) import Unison.UnisonFile.Error qualified as UF import Unison.Util.Bytes (Bytes) @@ -274,8 +274,9 @@ matchToken x = P.satisfy ((==) x . L.payload) importDotId :: (Ord v) => P v m (L.Token Name) importDotId = queryToken go where - go (L.SymbolyId "." Nothing) = Just (Name.unsafeFromString ".") - go _ = Nothing + go = \case + L.SymbolyId (HQ'.NameOnly name@(Name.reverseSegments -> NameSegment "." Nel.:| [])) -> Just name + _ -> Nothing -- Consume a virtual semicolon semi :: (Ord v) => P v m (L.Token ()) @@ -288,9 +289,9 @@ semi = label "newline or semicolon" $ queryToken go closeBlock :: (Ord v) => P v m (L.Token ()) closeBlock = void <$> matchToken L.Close -wordyPatternName :: (Var v) => P v m (L.Token v) +wordyPatternName :: Var v => P v m (L.Token v) wordyPatternName = queryToken \case - L.WordyId s Nothing -> Just $ Var.nameds s + L.WordyId (HQ'.NameOnly n) -> Just $ Name.toVar n _ -> Nothing -- Parse an prefix identifier e.g. Foo or (+), discarding any hash @@ -304,44 +305,36 @@ prefixTermName :: (Var v) => P v m (L.Token v) prefixTermName = wordyTermName <|> parenthesize symbolyTermName where wordyTermName = queryToken \case - L.WordyId s Nothing -> Just $ Var.nameds s + L.WordyId (HQ'.NameOnly n) -> Just $ Name.toVar n L.Blank s -> Just $ Var.nameds ("_" <> s) _ -> Nothing symbolyTermName = queryToken \case - L.SymbolyId s Nothing -> Just $ Var.nameds s + L.SymbolyId (HQ'.NameOnly n) -> Just $ Name.toVar n _ -> Nothing -- Parse a wordy identifier e.g. Foo, discarding any hash -wordyDefinitionName :: (Var v) => P v m (L.Token v) -wordyDefinitionName = queryToken \case - L.WordyId s _ -> Just $ Var.nameds s +wordyDefinitionName :: Var v => P v m (L.Token v) +wordyDefinitionName = queryToken $ \case + L.WordyId n -> Just $ Name.toVar (HQ'.toName n) L.Blank s -> Just $ Var.nameds ("_" <> s) _ -> Nothing --- Parse a wordyId as a String, rejecting any hash -wordyIdString :: (Ord v) => P v m (L.Token String) -wordyIdString = queryToken \case - L.WordyId s Nothing -> Just s - _ -> Nothing - -- Parse a wordyId as a Name, rejecting any hash -importWordyId :: (Ord v) => P v m (L.Token Name) -importWordyId = (fmap . fmap) Name.unsafeFromString wordyIdString +importWordyId :: Ord v => P v m (L.Token Name) +importWordyId = queryToken \case + L.WordyId (HQ'.NameOnly n) -> Just n + _ -> Nothing -- The `+` in: use Foo.bar + as a Name -importSymbolyId :: (Ord v) => P v m (L.Token Name) -importSymbolyId = (fmap . fmap) Name.unsafeFromString symbolyIdString - --- Parse a symbolyId as a String, rejecting any hash -symbolyIdString :: (Ord v) => P v m (L.Token String) -symbolyIdString = queryToken \case - L.SymbolyId s Nothing -> Just s +importSymbolyId :: Ord v => P v m (L.Token Name) +importSymbolyId = queryToken \case + L.SymbolyId (HQ'.NameOnly n) -> Just n _ -> Nothing --- Parse a symboly ID like >>= or Docs.&&, discarding any hash -symbolyDefinitionName :: (Var v) => P v m (L.Token v) -symbolyDefinitionName = queryToken \case - L.SymbolyId s _ -> Just $ Var.nameds s +-- Parse a symboly ID like >>= or &&, discarding any hash +symbolyDefinitionName :: Var v => P v m (L.Token v) +symbolyDefinitionName = queryToken $ \case + L.SymbolyId n -> Just $ Name.toVar (HQ'.toName n) _ -> Nothing parenthesize :: (Ord v) => P v m a -> P v m a @@ -352,21 +345,17 @@ hqPrefixId = hqWordyId_ <|> parenthesize hqSymbolyId_ hqInfixId = hqSymbolyId_ -- Parse a hash-qualified alphanumeric identifier -hqWordyId_ :: (Ord v) => P v m (L.Token (HQ.HashQualified Name)) +hqWordyId_ :: Ord v => P v m (L.Token (HQ.HashQualified Name)) hqWordyId_ = queryToken \case - L.WordyId "" (Just h) -> Just $ HQ.HashOnly h - L.WordyId s (Just h) -> Just $ HQ.HashQualified (Name.unsafeFromString s) h - L.WordyId s Nothing -> Just $ HQ.NameOnly (Name.unsafeFromString s) + L.WordyId n -> Just $ HQ'.toHQ n L.Hash h -> Just $ HQ.HashOnly h L.Blank s | not (null s) -> Just $ HQ.NameOnly (Name.unsafeFromString ("_" <> s)) _ -> Nothing -- Parse a hash-qualified symboly ID like >>=#foo or && -hqSymbolyId_ :: (Ord v) => P v m (L.Token (HQ.HashQualified Name)) +hqSymbolyId_ :: Ord v => P v m (L.Token (HQ.HashQualified Name)) hqSymbolyId_ = queryToken \case - L.SymbolyId "" (Just h) -> Just $ HQ.HashOnly h - L.SymbolyId s (Just h) -> Just $ HQ.HashQualified (Name.unsafeFromString s) h - L.SymbolyId s Nothing -> Just $ HQ.NameOnly (Name.unsafeFromString s) + L.SymbolyId n -> Just (HQ'.toHQ n) _ -> Nothing -- Parse a reserved word @@ -416,23 +405,28 @@ string = queryToken getString getString (L.Textual s) = Just (Text.pack s) getString _ = Nothing -tupleOrParenthesized :: (Ord v) => P v m a -> (Ann -> a) -> (a -> a -> a) -> P v m a -tupleOrParenthesized p unit pair = seq' "(" go p +-- | Parses a tuple of 'a's, or a single parenthesized 'a' +-- +-- returns the result of combining elements with 'pair', alongside the annotation containing +-- the full parenthesized expression. +tupleOrParenthesized :: Ord v => P v m a -> (Ann -> a) -> (a -> a -> a) -> P v m (Ann {- spanAnn -}, a) +tupleOrParenthesized p unit pair = do + seq' "(" go p where - go _ [t] = t - go a xs = foldr pair (unit a) xs + go ann [t] = (ann, t) + go ann (t : ts) = (ann, foldr pair (unit mempty) (t Nel.:| ts)) + go ann [] = (ann, unit ann) seq :: (Ord v) => (Ann -> [a] -> a) -> P v m a -> P v m a seq = seq' "[" -seq' :: (Ord v) => String -> (Ann -> [a] -> a) -> P v m a -> P v m a +seq' :: (Ord v) => String -> (Ann -> [a] -> b) -> P v m a -> P v m b seq' openStr f p = do open <- openBlockWith openStr <* redundant es <- sepEndBy (P.try $ optional semi *> reserved "," <* redundant) p close <- redundant *> closeBlock - pure $ go open es close + pure (f (ann open <> ann close) es) where - go open elems close = f (ann open <> ann close) elems redundant = P.skipMany (P.eitherP (reserved ",") semi) chainr1 :: (Ord v) => P v m a -> P v m (a -> a -> a) -> P v m a diff --git a/unison-syntax/test/Main.hs b/unison-syntax/test/Main.hs index 5393a4d033..06fea2eeef 100644 --- a/unison-syntax/test/Main.hs +++ b/unison-syntax/test/Main.hs @@ -6,10 +6,12 @@ import Data.Maybe (fromJust) import Data.Text qualified as Text import EasyTest import System.IO.CodePage (withCP65001) +import Unison.HashQualified' qualified as HQ' import Unison.Prelude import Unison.ShortHash (ShortHash) import Unison.ShortHash qualified as ShortHash import Unison.Syntax.Lexer +import Unison.Syntax.Name qualified as Name (unsafeFromString) main :: IO () main = @@ -87,8 +89,8 @@ test = ], t ".Foo.Bar.+" [simpleSymbolyId ".Foo.Bar.+"], -- idents with hashes - t "foo#bar" [WordyId "foo" (Just "#bar")], - t "+#bar" [SymbolyId "+" (Just "#bar")], + t "foo#bar" [WordyId (HQ'.HashQualified "foo" "#bar")], + t "+#bar" [SymbolyId (HQ'.HashQualified "+" "#bar")], -- note - these are all the same, just with different spacing let ex1 = "if x then y else z" ex2 = unlines ["if", " x", "then", " y", "else z"] @@ -196,7 +198,7 @@ test = suffix <- ["0", "x", "!", "'"] -- examples of wordyIdChar let i = kw ++ suffix -- a keyword at the front of an identifier should still be an identifier - pure $ t i [simpleWordyId i], + pure $ t i [simpleWordyId (Name.unsafeFromString i)], -- Test string literals t "\"simple string without escape characters\""