From a85132ca6d4fa6fe0bfee6929b24338a69ecc172 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 23 Oct 2024 12:30:11 -0700 Subject: [PATCH 001/113] Standardize optimization flags --- .github/workflows/bundle-ucm.yaml | 2 +- lib/unison-hash/package.yaml | 2 +- lib/unison-hash/unison-hash.cabal | 4 ++-- lib/unison-hashing/package.yaml | 2 +- lib/unison-hashing/unison-hashing.cabal | 4 ++-- lib/unison-pretty-printer/package.yaml | 11 +---------- .../unison-pretty-printer.cabal | 18 ++++-------------- parser-typechecker/package.yaml | 11 +---------- .../unison-parser-typechecker.cabal | 14 +++----------- stack.yaml | 2 +- unison-cli-integration/package.yaml | 9 --------- .../unison-cli-integration.cabal | 8 +------- unison-cli-main/package.yaml | 9 --------- unison-cli-main/unison-cli-main.cabal | 8 +------- unison-cli/package.yaml | 9 --------- unison-cli/unison-cli.cabal | 12 +----------- unison-core/package.yaml | 9 --------- unison-core/unison-core1.cabal | 10 +--------- unison-runtime/package.yaml | 7 +------ unison-runtime/unison-runtime.cabal | 12 ++---------- 20 files changed, 24 insertions(+), 139 deletions(-) diff --git a/.github/workflows/bundle-ucm.yaml b/.github/workflows/bundle-ucm.yaml index 941c04bdae..deb68e6626 100644 --- a/.github/workflows/bundle-ucm.yaml +++ b/.github/workflows/bundle-ucm.yaml @@ -56,7 +56,7 @@ jobs: tries=5 for (( i = 0; i < $tries; i++ )); do stack build :unison \ - --flag unison-parser-typechecker:optimized \ + --ghc-options='-O2' \ --local-bin-path ucm-bin \ --copy-bins \ && break; diff --git a/lib/unison-hash/package.yaml b/lib/unison-hash/package.yaml index 23fc6b49e7..8b6edc958c 100644 --- a/lib/unison-hash/package.yaml +++ b/lib/unison-hash/package.yaml @@ -2,7 +2,7 @@ name: unison-hash github: unisonweb/unison copyright: Copyright (C) 2013-2021 Unison Computing, PBC and contributors -ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures +ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures dependencies: - base diff --git a/lib/unison-hash/unison-hash.cabal b/lib/unison-hash/unison-hash.cabal index 85eeb0f333..cad79645b3 100644 --- a/lib/unison-hash/unison-hash.cabal +++ b/lib/unison-hash/unison-hash.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.37.0. -- -- see: https://github.com/sol/hpack @@ -49,7 +49,7 @@ library TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures build-depends: base , bytestring diff --git a/lib/unison-hashing/package.yaml b/lib/unison-hashing/package.yaml index 7ea56e16d3..6e8e67bb68 100644 --- a/lib/unison-hashing/package.yaml +++ b/lib/unison-hashing/package.yaml @@ -2,7 +2,7 @@ name: unison-hashing github: unisonweb/unison copyright: Copyright (C) 2013-2021 Unison Computing, PBC and contributors -ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures +ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures dependencies: - base diff --git a/lib/unison-hashing/unison-hashing.cabal b/lib/unison-hashing/unison-hashing.cabal index 21350f79ca..83cd62bcba 100644 --- a/lib/unison-hashing/unison-hashing.cabal +++ b/lib/unison-hashing/unison-hashing.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.2. +-- This file has been generated from package.yaml by hpack version 0.37.0. -- -- see: https://github.com/sol/hpack @@ -48,7 +48,7 @@ library TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures build-depends: base , unison-hash diff --git a/lib/unison-pretty-printer/package.yaml b/lib/unison-pretty-printer/package.yaml index b46898a9dc..7fcd9f7855 100644 --- a/lib/unison-pretty-printer/package.yaml +++ b/lib/unison-pretty-printer/package.yaml @@ -25,16 +25,7 @@ default-extensions: - TypeApplications - ViewPatterns -ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures - -flags: - optimized: - manual: true - default: true - -when: - - condition: flag(optimized) - ghc-options: -funbox-strict-fields -O2 +ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures library: when: diff --git a/lib/unison-pretty-printer/unison-pretty-printer.cabal b/lib/unison-pretty-printer/unison-pretty-printer.cabal index c44cb02e5f..6f6792f0e9 100644 --- a/lib/unison-pretty-printer/unison-pretty-printer.cabal +++ b/lib/unison-pretty-printer/unison-pretty-printer.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.37.0. -- -- see: https://github.com/sol/hpack @@ -17,10 +17,6 @@ source-repository head type: git location: https://github.com/unisonweb/unison -flag optimized - manual: True - default: True - library exposed-modules: Unison.PrettyTerminal @@ -54,7 +50,7 @@ library TupleSections TypeApplications ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures build-depends: ListLike , ansi-terminal @@ -70,8 +66,6 @@ library , unison-syntax , unliftio default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 executable prettyprintdemo main-is: Main.hs @@ -99,14 +93,12 @@ executable prettyprintdemo TupleSections TypeApplications ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures build-depends: base , text , unison-pretty-printer default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 test-suite pretty-printer-tests type: exitcode-stdio-1.0 @@ -139,7 +131,7 @@ test-suite pretty-printer-tests TupleSections TypeApplications ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 build-depends: base , code-page @@ -149,5 +141,3 @@ test-suite pretty-printer-tests , unison-pretty-printer , unison-syntax default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 diff --git a/parser-typechecker/package.yaml b/parser-typechecker/package.yaml index 71a031c8b6..d9760e15c9 100644 --- a/parser-typechecker/package.yaml +++ b/parser-typechecker/package.yaml @@ -2,16 +2,7 @@ name: unison-parser-typechecker github: unisonweb/unison copyright: Copyright (C) 2013-2021 Unison Computing, PBC and contributors -ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures - -flags: - optimized: - manual: true - default: true - -when: - - condition: flag(optimized) - ghc-options: -funbox-strict-fields -O2 +ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures library: source-dirs: src diff --git a/parser-typechecker/unison-parser-typechecker.cabal b/parser-typechecker/unison-parser-typechecker.cabal index f08a2f969e..820c2bec16 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.37.0. -- -- see: https://github.com/sol/hpack @@ -17,10 +17,6 @@ source-repository head type: git location: https://github.com/unisonweb/unison -flag optimized - manual: True - default: True - library exposed-modules: U.Codebase.Branch.Diff @@ -195,7 +191,7 @@ library TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures build-depends: ListLike , aeson @@ -256,8 +252,6 @@ library , vector , witherable default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 test-suite parser-typechecker-tests type: exitcode-stdio-1.0 @@ -317,7 +311,7 @@ test-suite parser-typechecker-tests TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -O0 -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 + ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-missing-pattern-synonym-signatures -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 build-depends: base , code-page @@ -339,5 +333,3 @@ test-suite parser-typechecker-tests , unison-util-relation , unison-util-rope default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 diff --git a/stack.yaml b/stack.yaml index e4e4470f68..a628e395ea 100644 --- a/stack.yaml +++ b/stack.yaml @@ -74,7 +74,7 @@ allow-newer-deps: ghc-options: # All packages - "$locals": -Wall -Werror -Wno-name-shadowing -Wno-missing-pattern-synonym-signatures -fprint-expanded-synonyms -fwrite-ide-info -Wunused-packages #-freverse-errors + "$locals": -Wall -Werror -Wno-name-shadowing -Wno-missing-pattern-synonym-signatures -fprint-expanded-synonyms -fwrite-ide-info -Wunused-packages -funbox-strict-fields #-freverse-errors # See https://github.com/haskell/haskell-language-server/issues/208 "$everything": -haddock diff --git a/unison-cli-integration/package.yaml b/unison-cli-integration/package.yaml index 213bb73075..b4127e82e9 100644 --- a/unison-cli-integration/package.yaml +++ b/unison-cli-integration/package.yaml @@ -2,11 +2,6 @@ name: unison-cli-integration github: unisonweb/unison copyright: Copyright (C) 2013-2018 Unison Computing, PBC and contributors -flags: - optimized: - manual: true - default: false - ghc-options: -Wall executables: @@ -28,10 +23,6 @@ executables: build-tools: - unison-cli-main:unison -when: - - condition: flag(optimized) - ghc-options: -O2 -funbox-strict-fields - default-extensions: - ApplicativeDo - BangPatterns diff --git a/unison-cli-integration/unison-cli-integration.cabal b/unison-cli-integration/unison-cli-integration.cabal index de0ea494de..6cda3a952d 100644 --- a/unison-cli-integration/unison-cli-integration.cabal +++ b/unison-cli-integration/unison-cli-integration.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.37.0. -- -- see: https://github.com/sol/hpack @@ -15,10 +15,6 @@ source-repository head type: git location: https://github.com/unisonweb/unison -flag optimized - manual: True - default: False - executable cli-integration-tests main-is: Suite.hs other-modules: @@ -70,5 +66,3 @@ executable cli-integration-tests , process , time default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields diff --git a/unison-cli-main/package.yaml b/unison-cli-main/package.yaml index b64fe52764..820829493e 100644 --- a/unison-cli-main/package.yaml +++ b/unison-cli-main/package.yaml @@ -2,11 +2,6 @@ name: unison-cli-main github: unisonweb/unison copyright: Copyright (C) 2013-2018 Unison Computing, PBC and contributors -flags: - optimized: - manual: true - default: false - ghc-options: -Wall executables: @@ -24,10 +19,6 @@ executables: - text - unison-cli -when: - - condition: flag(optimized) - ghc-options: -O2 -funbox-strict-fields - default-extensions: - ApplicativeDo - BangPatterns diff --git a/unison-cli-main/unison-cli-main.cabal b/unison-cli-main/unison-cli-main.cabal index 4c54254978..e94c51e228 100644 --- a/unison-cli-main/unison-cli-main.cabal +++ b/unison-cli-main/unison-cli-main.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.37.0. -- -- see: https://github.com/sol/hpack @@ -17,10 +17,6 @@ source-repository head type: git location: https://github.com/unisonweb/unison -flag optimized - manual: True - default: False - executable unison main-is: Main.hs other-modules: @@ -68,5 +64,3 @@ executable unison , text , unison-cli default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields diff --git a/unison-cli/package.yaml b/unison-cli/package.yaml index 68ecf3431a..25674bff83 100644 --- a/unison-cli/package.yaml +++ b/unison-cli/package.yaml @@ -2,11 +2,6 @@ name: unison-cli github: unisonweb/unison copyright: Copyright (C) 2013-2018 Unison Computing, PBC and contributors -flags: - optimized: - manual: true - default: false - ghc-options: -Wall dependencies: @@ -148,10 +143,6 @@ executables: - unison-cli - unliftio -when: - - condition: flag(optimized) - ghc-options: -O2 -funbox-strict-fields - default-extensions: - ApplicativeDo - BangPatterns diff --git a/unison-cli/unison-cli.cabal b/unison-cli/unison-cli.cabal index d7952578d9..b64ae42c56 100644 --- a/unison-cli/unison-cli.cabal +++ b/unison-cli/unison-cli.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.37.0. -- -- see: https://github.com/sol/hpack @@ -17,10 +17,6 @@ source-repository head type: git location: https://github.com/unisonweb/unison -flag optimized - manual: True - default: False - library exposed-modules: ArgParse @@ -274,8 +270,6 @@ library , witch , witherable default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields if !os(windows) build-depends: unix @@ -333,8 +327,6 @@ executable transcripts , unison-prelude , unliftio default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields test-suite cli-tests type: exitcode-stdio-1.0 @@ -406,5 +398,3 @@ test-suite cli-tests , unison-syntax , unison-util-recursion default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields diff --git a/unison-core/package.yaml b/unison-core/package.yaml index 0df2aff34a..1b9f2d996e 100644 --- a/unison-core/package.yaml +++ b/unison-core/package.yaml @@ -81,12 +81,3 @@ default-extensions: - TupleSections - TypeApplications - ViewPatterns - -flags: - optimized: - manual: true - default: false - -when: - - condition: flag(optimized) - ghc-options: -O2 -funbox-strict-fields diff --git a/unison-core/unison-core1.cabal b/unison-core/unison-core1.cabal index e4e71afc9e..91d1b40b27 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.36.0. +-- This file has been generated from package.yaml by hpack version 0.37.0. -- -- see: https://github.com/sol/hpack @@ -17,10 +17,6 @@ source-repository head type: git location: https://github.com/unisonweb/unison -flag optimized - manual: True - default: False - library exposed-modules: Unison.ABT @@ -122,8 +118,6 @@ library , unison-util-relation , witch default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields test-suite tests type: exitcode-stdio-1.0 @@ -171,5 +165,3 @@ test-suite tests , unison-core1 , unison-prelude default-language: Haskell2010 - if flag(optimized) - ghc-options: -O2 -funbox-strict-fields diff --git a/unison-runtime/package.yaml b/unison-runtime/package.yaml index a7526e5b07..c66afb7ad6 100644 --- a/unison-runtime/package.yaml +++ b/unison-runtime/package.yaml @@ -2,19 +2,14 @@ name: unison-runtime github: unisonweb/unison copyright: Copyright (C) 2013-2024 Unison Computing, PBC and contributors -ghc-options: -Wall -O0 +ghc-options: -Wall -funbox-strict-fields -O2 flags: - optimized: - manual: true - default: true arraychecks: manual: true default: false when: - - condition: flag(optimized) - ghc-options: -funbox-strict-fields -O2 - condition: flag(arraychecks) cpp-options: -DARRAY_CHECK diff --git a/unison-runtime/unison-runtime.cabal b/unison-runtime/unison-runtime.cabal index 33650d1944..35cf87a7d7 100644 --- a/unison-runtime/unison-runtime.cabal +++ b/unison-runtime/unison-runtime.cabal @@ -21,10 +21,6 @@ flag arraychecks manual: True default: False -flag optimized - manual: True - default: True - library exposed-modules: Unison.Codebase.Execute @@ -82,7 +78,7 @@ library TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -O0 + ghc-options: -Wall -funbox-strict-fields -O2 build-depends: asn1-encoding , asn1-types @@ -137,8 +133,6 @@ library , unliftio , vector default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 if flag(arraychecks) cpp-options: -DARRAY_CHECK @@ -184,7 +178,7 @@ test-suite runtime-tests TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -O0 -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 + ghc-options: -Wall -funbox-strict-fields -O2 -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 build-depends: base , code-page @@ -207,7 +201,5 @@ test-suite runtime-tests , unison-runtime , unison-syntax default-language: Haskell2010 - if flag(optimized) - ghc-options: -funbox-strict-fields -O2 if flag(arraychecks) cpp-options: -DARRAY_CHECK From 6c988521bcb2220e71cf3fca7dca9fef7acb125f Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 23 Oct 2024 14:29:15 -0700 Subject: [PATCH 002/113] Debug entry comb --- unison-runtime/src/Unison/Runtime/Machine.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index ef59434f64..16ea8628c6 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -64,6 +64,7 @@ import Unison.Util.Text qualified as Util.Text import UnliftIO (IORef) import UnliftIO qualified import UnliftIO.Concurrent qualified as UnliftIO +import qualified Unison.Debug as Debug -- | A ref storing every currently active thread. -- This is helpful for cleaning up orphaned threads when the main process @@ -239,6 +240,7 @@ apply0 !callback !env !threadTracker !i = do let entryCix = (CIx r i 0) case unRComb $ rCombSection cmbs entryCix of Comb entryComb -> do + Debug.debugM Debug.Temp "Entry Comb" entryComb apply env denv threadTracker stk (kf k0) True ZArgs $ PAp entryCix entryComb nullSeg -- if it's cached, we can just finish From 7abbed65c2f8fb46137b03ea4c97029d9edfdfc6 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 23 Oct 2024 14:29:15 -0700 Subject: [PATCH 003/113] Don't unbox binops --- unison-runtime/src/Unison/Runtime/ANF.hs | 2 ++ unison-runtime/src/Unison/Runtime/Builtin.hs | 16 +++++----------- unison-runtime/src/Unison/Runtime/Machine.hs | 3 ++- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 61bd4ab662..229893f466 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -1904,6 +1904,8 @@ anfBlock (Boolean' b) = pure (mempty, pure $ TCon Ty.booleanRef (if b then 1 else 0) []) anfBlock (Lit' l@(T _)) = pure (mempty, pure $ TLit l) +anfBlock (Lit' l@(N _)) = + pure (mempty, pure $ TLit l) anfBlock (Lit' l) = pure (mempty, pure $ TBLit l) anfBlock (Ref' r) = pure (mempty, (Indirect (), TCom r [])) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 0a31bdce41..0a4a86b67d 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -331,11 +331,9 @@ unop :: (Var v) => POp -> Reference -> SuperNormal v unop pop rf = unop' pop rf rf unop' :: (Var v) => POp -> Reference -> Reference -> SuperNormal v -unop' pop rfi rfo = - unop0 2 $ \[x0, x, r] -> - unbox x0 rfi x - . TLetD r UN (TPrm pop [x]) - $ TCon rfo 0 [r] +unop' pop _rfi _rfo = + unop0 0 $ \[x] -> + (TPrm pop [x]) binop :: (Var v) => POp -> Reference -> SuperNormal v binop pop rf = binop' pop rf rf rf @@ -347,12 +345,8 @@ binop' :: Reference -> Reference -> SuperNormal v -binop' pop rfx rfy rfr = - binop0 3 $ \[x0, y0, x, y, r] -> - unbox x0 rfx x - . unbox y0 rfy y - . TLetD r UN (TPrm pop [x, y]) - $ TCon rfr 0 [r] +binop' pop _rfx _rfy _rfr = + binop0 0 $ \[ x, y] -> TPrm pop [x, y] cmpop :: (Var v) => POp -> Reference -> SuperNormal v cmpop pop rf = diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 16ea8628c6..853ddc09b7 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -26,6 +26,7 @@ import GHC.Conc as STM (unsafeIOToSTM) import Unison.Builtin.Decls (exceptionRef, ioFailureRef) import Unison.Builtin.Decls qualified as Rf import Unison.ConstructorReference qualified as CR +import Unison.Debug qualified as Debug import Unison.Prelude hiding (Text) import Unison.Reference ( Reference, @@ -64,7 +65,6 @@ import Unison.Util.Text qualified as Util.Text import UnliftIO (IORef) import UnliftIO qualified import UnliftIO.Concurrent qualified as UnliftIO -import qualified Unison.Debug as Debug -- | A ref storing every currently active thread. -- This is helpful for cleaning up orphaned threads when the main process @@ -241,6 +241,7 @@ apply0 !callback !env !threadTracker !i = do case unRComb $ rCombSection cmbs entryCix of Comb entryComb -> do Debug.debugM Debug.Temp "Entry Comb" entryComb + -- Debug.debugM Debug.Temp "All Combs" cmbs apply env denv threadTracker stk (kf k0) True ZArgs $ PAp entryCix entryComb nullSeg -- if it's cached, we can just finish From 792027131400e84dd689b7a36e4a053aad0e5fd3 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 23 Oct 2024 15:37:54 -0700 Subject: [PATCH 004/113] Add stack debugging --- .../src/Unison/Codebase/Runtime.hs | 4 +++- unison-runtime/src/Unison/Runtime/Machine.hs | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/parser-typechecker/src/Unison/Codebase/Runtime.hs b/parser-typechecker/src/Unison/Codebase/Runtime.hs index b9c92aec5e..4732457e28 100644 --- a/parser-typechecker/src/Unison/Codebase/Runtime.hs +++ b/parser-typechecker/src/Unison/Codebase/Runtime.hs @@ -9,6 +9,7 @@ import Unison.ABT qualified as ABT import Unison.Builtin.Decls (tupleTerm, pattern TupleTerm') import Unison.Codebase.CodeLookup qualified as CL import Unison.Codebase.CodeLookup.Util qualified as CL +import Unison.Debug qualified as Debug import Unison.Hashing.V2.Convert qualified as Hashing import Unison.Parser.Ann (Ann) import Unison.Prelude @@ -34,7 +35,7 @@ data CompileOpts = COpts } defaultCompileOpts :: CompileOpts -defaultCompileOpts = COpts { profile = False } +defaultCompileOpts = COpts {profile = False} data Runtime v = Runtime { terminate :: IO (), @@ -114,6 +115,7 @@ evaluateWatches code ppe evaluationCache rt tuf = do -- 4. evaluate it and get all the results out of the tuple, then -- create the result Map out <- evaluate rt cl ppe bigOl'LetRec + Debug.debugM Debug.Temp "evaluateWatches: out" out case out of Right (errs, out) -> do let (bindings, results) = case out of diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 853ddc09b7..2cd45dd8d4 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -23,6 +23,7 @@ import Data.Text qualified as DTx import Data.Text.IO qualified as Tx import Data.Traversable import GHC.Conc as STM (unsafeIOToSTM) +import System.IO.Unsafe (unsafePerformIO) import Unison.Builtin.Decls (exceptionRef, ioFailureRef) import Unison.Builtin.Decls qualified as Rf import Unison.ConstructorReference qualified as CR @@ -297,6 +298,20 @@ buildLit _ _ (MM r) = Foreign (Wrap Rf.termLinkRef r) buildLit _ _ (MY r) = Foreign (Wrap Rf.typeLinkRef r) buildLit _ _ (MD _) = error "buildLit: double" +debugger :: (Show a) => Stack -> String -> a -> Bool +debugger stk msg a = unsafePerformIO $ do + Debug.debugLogM Debug.Temp (msg ++ ": " ++ show a) + dumpStack stk + pure False + +dumpStack :: Stack -> IO () +dumpStack stk@(Stack _ap fp sp _ustk _bstk) + | sp - fp <= 0 = Debug.debugLogM Debug.Temp "Stack Empty" + | otherwise = do + stkResults <- for [0 .. ((sp - fp) - 1)] $ \i -> do + peekOff stk i + Debug.debugM Debug.Temp "Stack" stkResults + -- | Execute an instruction exec :: CCache -> @@ -307,6 +322,8 @@ exec :: Reference -> MInstr -> IO (DEnv, Stack, K) +exec !_ !_ !_ !stk !_ !_ instr + | debugger stk "exec" instr = undefined exec !_ !denv !_activeThreads !stk !k _ (Info tx) = do info tx stk info tx k @@ -643,6 +660,8 @@ eval :: Reference -> MSection -> IO () +eval !_ !_ !_ !stk !_ !_ section + | debugger stk "eval" section = undefined eval !env !denv !activeThreads !stk !k r (Match i (TestT df cs)) = do t <- peekOffBi stk i eval env denv activeThreads stk k r $ selectTextBranch t df cs From 49cd2de7055dc9dbc7ec84b78e43c90dbf24f016 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 09:55:27 -0700 Subject: [PATCH 005/113] Add newtype for type tags Merge Me --- unison-runtime/src/Unison/Runtime/ANF.hs | 18 ++++++---- unison-runtime/src/Unison/Runtime/Builtin.hs | 4 +-- .../src/Unison/Runtime/Foreign/Function.hs | 8 ++--- .../src/Unison/Runtime/Interface.hs | 36 +++++++++---------- unison-runtime/src/Unison/Runtime/MCode.hs | 9 ++--- .../src/Unison/Runtime/MCode/Serialize.hs | 15 +++++--- unison-runtime/src/Unison/Runtime/Machine.hs | 15 ++++---- unison-runtime/src/Unison/Runtime/Stack.hs | 23 ++++++------ 8 files changed, 72 insertions(+), 56 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 229893f466..664465164d 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -52,6 +52,7 @@ module Unison.Runtime.ANF ANormal, RTag, CTag, + PackedTag (..), Tag (..), GroupRef (..), Code (..), @@ -717,24 +718,29 @@ newtype CTag = CTag Word16 deriving stock (Eq, Ord, Show, Read) deriving newtype (EC.EnumKey) +-- | A combined tag, which is a packed representation of an RTag and a CTag +newtype PackedTag = PackedTag Word64 + deriving stock (Eq, Ord, Show, Read) + deriving newtype (EC.EnumKey) + class Tag t where rawTag :: t -> Word64 instance Tag RTag where rawTag (RTag w) = w instance Tag CTag where rawTag (CTag w) = fromIntegral w -packTags :: RTag -> CTag -> Word64 -packTags (RTag rt) (CTag ct) = ri .|. ci +packTags :: RTag -> CTag -> PackedTag +packTags (RTag rt) (CTag ct) = PackedTag (ri .|. ci) where ri = rt `shiftL` 16 ci = fromIntegral ct -unpackTags :: Word64 -> (RTag, CTag) -unpackTags w = (RTag $ w `shiftR` 16, CTag . fromIntegral $ w .&. 0xFFFF) +unpackTags :: PackedTag -> (RTag, CTag) +unpackTags (PackedTag w) = (RTag $ w `shiftR` 16, CTag . fromIntegral $ w .&. 0xFFFF) -- Masks a packed tag to extract just the constructor tag portion -maskTags :: Word64 -> Word64 -maskTags w = w .&. 0xFFFF +maskTags :: PackedTag -> Word64 +maskTags (PackedTag w) = (w .&. 0xFFFF) ensureRTag :: (Ord n, Show n, Num n) => String -> n -> r -> r ensureRTag s n x diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 0a4a86b67d..8a120bb0cc 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -2295,10 +2295,10 @@ mkForeignIOF f = mkForeign $ \a -> tryIOE (f a) handleIOE (Right a) = Right a unitValue :: Closure -unitValue = Closure.Enum Ty.unitRef 0 +unitValue = Closure.Enum Ty.unitRef (PackedTag 0) natValue :: Word64 -> Closure -natValue w = Closure.DataU1 Ty.natRef 0 (fromIntegral w) +natValue w = Closure.DataU1 Ty.natRef (PackedTag 0) (fromIntegral w) mkForeignTls :: forall a r. diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index a36a6f8b60..786a1ab50f 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -31,7 +31,7 @@ import Network.UDP (UDPSocket) import System.IO (BufferMode (..), Handle, IOMode, SeekMode) import Unison.Builtin.Decls qualified as Ty import Unison.Reference (Reference) -import Unison.Runtime.ANF (Code, Value, internalBug) +import Unison.Runtime.ANF (Code, PackedTag (..), Value, internalBug) import Unison.Runtime.Exception import Unison.Runtime.Foreign import Unison.Runtime.MCode @@ -503,10 +503,10 @@ toUnisonPair :: toUnisonPair (x, y) = DataC Ty.pairRef - 0 - [Right $ wr x, Right $ DataC Ty.pairRef 0 [Right $ wr y, Right $ un]] + (PackedTag 0) + [Right $ wr x, Right $ DataC Ty.pairRef (PackedTag 0) [Right $ wr y, Right $ un]] where - un = DataC Ty.unitRef 0 [] + un = DataC Ty.unitRef (PackedTag 0) [] wr z = Foreign $ wrapBuiltin z unwrapForeignClosure :: Closure -> a diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 95e8fc3c53..137d8b4c1b 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -473,25 +473,25 @@ checkCacheability cl ctx (r, sg) = getTermType codebaseRef >>= \case -- A term's result is cacheable iff it has no arrows in its type, -- this is sufficient since top-level definitions can't have effects without a delay. - Just typ | not (Rec.cata hasArrows typ) -> - pure (r, CodeRep sg Cacheable) + Just typ + | not (Rec.cata hasArrows typ) -> + pure (r, CodeRep sg Cacheable) _ -> pure (r, CodeRep sg Uncacheable) where - codebaseRef = backmapRef ctx r - getTermType :: CodebaseReference -> IO (Maybe (Type Symbol)) - getTermType = \case - (RF.DerivedId i) -> - getTypeOfTerm cl i >>= \case - Just t -> pure $ Just t - Nothing -> pure Nothing - RF.Builtin {} -> pure $ Nothing - hasArrows :: Type.TypeF v a Bool -> Bool - hasArrows abt = case ABT.out' abt of - (ABT.Tm f) -> case f of - Type.Arrow _ _ -> True - other -> or other - t -> or t - + codebaseRef = backmapRef ctx r + getTermType :: CodebaseReference -> IO (Maybe (Type Symbol)) + getTermType = \case + (RF.DerivedId i) -> + getTypeOfTerm cl i >>= \case + Just t -> pure $ Just t + Nothing -> pure Nothing + RF.Builtin {} -> pure $ Nothing + hasArrows :: Type.TypeF v a Bool -> Bool + hasArrows abt = case ABT.out' abt of + (ABT.Tm f) -> case f of + Type.Arrow _ _ -> True + other -> or other + t -> or t compileValue :: Reference -> [(Reference, Code)] -> Value compileValue base = @@ -1056,7 +1056,7 @@ executeMainComb :: CCache -> IO (Either (Pretty ColorText) ()) executeMainComb init cc = do - rSection <- resolveSection cc $ Ins (Pack RF.unitRef 0 ZArgs) $ Call True init init (VArg1 0) + rSection <- resolveSection cc $ Ins (Pack RF.unitRef (PackedTag 0) ZArgs) $ Call True init init (VArg1 0) result <- UnliftIO.try . eval0 cc Nothing $ rSection case result of diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 265efd163d..e9ee6ef695 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -73,6 +73,7 @@ import Unison.Runtime.ANF Direction (..), Func (..), Mem (..), + PackedTag (..), SuperGroup (..), SuperNormal (..), internalBug, @@ -481,12 +482,12 @@ data GInstr comb -- on the stack. Pack !Reference -- data type reference - !Word64 -- tag + !PackedTag -- tag !Args -- arguments to pack | -- Push a particular value onto the appropriate stack Lit !MLit -- value to push onto the stack | -- Push a particular value directly onto the boxed stack - BLit !Reference !Word64 {- packed type tag for the ref -} !MLit + BLit !Reference !PackedTag !MLit | -- Print a value on the unboxed stack Print !Int -- index of the primitive value to print | -- Put a delimiter on the continuation @@ -1468,7 +1469,7 @@ emitBLit l = case l of _ -> BLit lRef builtinTypeTag (litToMLit l) where lRef = ANF.litRef l - builtinTypeTag :: Word64 + builtinTypeTag :: PackedTag builtinTypeTag = case M.lookup (ANF.litRef l) builtinTypeNumbering of Nothing -> error "emitBLit: unknown builtin type reference" @@ -1558,7 +1559,7 @@ sectionTypes (RMatch _ pu br) = sectionTypes _ = [] instrTypes :: GInstr comb -> [Word64] -instrTypes (Pack _ w _) = [w `shiftR` 16] +instrTypes (Pack _ (PackedTag w) _) = [w `shiftR` 16] instrTypes (Reset ws) = setToList ws instrTypes (Capture w) = [w] instrTypes (SetDyn w _) = [w] diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 89930aefc3..9d614190aa 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -18,6 +18,7 @@ import Data.Primitive.PrimArray import Data.Void (Void) import Data.Word (Word64) import GHC.Exts (IsList (..)) +import Unison.Runtime.ANF (PackedTag (..)) import Unison.Runtime.MCode hiding (MatchT) import Unison.Runtime.Serialize import Unison.Util.Text qualified as Util.Text @@ -32,6 +33,12 @@ instance Tag CombT where word2tag 1 = pure CachedClosureT word2tag n = unknownTag "CombT" n +putPackedTag :: (MonadPut m) => PackedTag -> m () +putPackedTag (PackedTag w) = pWord w + +getPackedTag :: (MonadGet m) => m PackedTag +getPackedTag = PackedTag <$> gWord + putComb :: (MonadPut m) => (clos -> m ()) -> GComb clos comb -> m () putComb pClos = \case (Lam a f body) -> @@ -205,9 +212,9 @@ putInstr = \case (Capture w) -> putTag CaptureT *> pWord w (Name r a) -> putTag NameT *> putRef r *> putArgs a (Info s) -> putTag InfoT *> serialize s - (Pack r w a) -> putTag PackT *> putReference r *> pWord w *> putArgs a + (Pack r w a) -> putTag PackT *> putReference r *> putPackedTag w *> putArgs a (Lit l) -> putTag LitT *> putLit l - (BLit r tt l) -> putTag BLitT *> putReference r *> putNat tt *> putLit l + (BLit r tt l) -> putTag BLitT *> putReference r *> putPackedTag tt *> putLit l (Print i) -> putTag PrintT *> pInt i (Reset s) -> putTag ResetT *> putEnumSet pWord s (Fork i) -> putTag ForkT *> pInt i @@ -227,9 +234,9 @@ getInstr = CaptureT -> Capture <$> gWord NameT -> Name <$> getRef <*> getArgs InfoT -> Info <$> deserialize - PackT -> Pack <$> getReference <*> gWord <*> getArgs + PackT -> Pack <$> getReference <*> getPackedTag <*> getArgs LitT -> Lit <$> getLit - BLitT -> BLit <$> getReference <*> getNat <*> getLit + BLitT -> BLit <$> getReference <*> getPackedTag <*> getLit PrintT -> Print <$> gInt ResetT -> Reset <$> getEnumSet gWord ForkT -> Fork <$> gInt diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 2cd45dd8d4..cd7a3e5d8e 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -40,6 +40,7 @@ import Unison.Runtime.ANF as ANF ( Cacheability (..), Code (..), CompileExn (..), + PackedTag, SuperGroup, codeGroup, foldGroup, @@ -291,7 +292,7 @@ unitValue = Enum Rf.unitRef unitTag lookupDenv :: Word64 -> DEnv -> Closure lookupDenv p denv = fromMaybe BlackHole $ EC.lookup p denv -buildLit :: Reference -> Word64 -> MLit -> Closure +buildLit :: Reference -> PackedTag -> MLit -> Closure buildLit rf tt (MI i) = DataU1 rf tt i buildLit _ _ (MT t) = Foreign (Wrap Rf.textRef t) buildLit _ _ (MM r) = Foreign (Wrap Rf.termLinkRef r) @@ -2408,42 +2409,42 @@ compareAsNat i j = compare ni nj ni = fromIntegral i nj = fromIntegral j -floatTag :: Word64 +floatTag :: PackedTag floatTag | Just n <- M.lookup Rf.floatRef builtinTypeNumbering, rt <- toEnum (fromIntegral n) = packTags rt 0 | otherwise = error "internal error: floatTag" -natTag :: Word64 +natTag :: PackedTag natTag | Just n <- M.lookup Rf.natRef builtinTypeNumbering, rt <- toEnum (fromIntegral n) = packTags rt 0 | otherwise = error "internal error: natTag" -intTag :: Word64 +intTag :: PackedTag intTag | Just n <- M.lookup Rf.intRef builtinTypeNumbering, rt <- toEnum (fromIntegral n) = packTags rt 0 | otherwise = error "internal error: intTag" -charTag :: Word64 +charTag :: PackedTag charTag | Just n <- M.lookup Rf.charRef builtinTypeNumbering, rt <- toEnum (fromIntegral n) = packTags rt 0 | otherwise = error "internal error: charTag" -unitTag :: Word64 +unitTag :: PackedTag unitTag | Just n <- M.lookup Rf.unitRef builtinTypeNumbering, rt <- toEnum (fromIntegral n) = packTags rt 0 | otherwise = error "internal error: unitTag" -leftTag, rightTag :: Word64 +leftTag, rightTag :: PackedTag (leftTag, rightTag) | Just n <- M.lookup Rf.eitherRef builtinTypeNumbering, et <- toEnum (fromIntegral n), diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 0c8c3392b7..7c7deac4a0 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -100,6 +100,7 @@ import Data.Word import GHC.Exts as L (IsList (..)) import Unison.Prelude import Unison.Reference (Reference) +import Unison.Runtime.ANF (PackedTag) import Unison.Runtime.Array import Unison.Runtime.Foreign import Unison.Runtime.MCode @@ -166,14 +167,14 @@ data GClosure comb !CombIx {-# UNPACK #-} !(GCombInfo comb) {-# UNPACK #-} !Seg -- args - | GEnum !Reference !Word64 - | GDataU1 !Reference !Word64 {- <- packed type tag -} !Int - | GDataU2 !Reference !Word64 {- <- packed type tag -} !Int !Int - | GDataB1 !Reference !Word64 {- <- packed type tag -} !(GClosure comb) - | GDataB2 !Reference !Word64 {- <- packed type tag -} !(GClosure comb) !(GClosure comb) - | GDataUB !Reference !Word64 {- <- packed type tag -} !Int !(GClosure comb) - | GDataBU !Reference !Word64 {- <- packed type tag -} !(GClosure comb) !Int - | GDataG !Reference !Word64 {- <- packed type tag -} {-# UNPACK #-} !Seg + | GEnum !Reference !PackedTag + | GDataU1 !Reference !PackedTag !Int + | GDataU2 !Reference !PackedTag !Int !Int + | GDataB1 !Reference !PackedTag !(GClosure comb) + | GDataB2 !Reference !PackedTag !(GClosure comb) !(GClosure comb) + | GDataUB !Reference !PackedTag !Int !(GClosure comb) + | GDataBU !Reference !PackedTag !(GClosure comb) !Int + | GDataG !Reference !PackedTag {-# UNPACK #-} !Seg | -- code cont, arg size, u/b data stacks GCaptured !K !Int {-# UNPACK #-} !Seg | GForeign !Foreign @@ -228,7 +229,7 @@ traceK begin = dedup (begin, 1) | otherwise = p : dedup (r, 1) k dedup p _ = [p] -splitData :: Closure -> Maybe (Reference, Word64, SegList) +splitData :: Closure -> Maybe (Reference, PackedTag, SegList) splitData = \case (Enum r t) -> Just (r, t, []) (DataU1 r t i) -> Just (r, t, [Left i]) @@ -265,7 +266,7 @@ bsegToList = reverse . L.toList bseg :: [Closure] -> BSeg bseg = L.fromList . reverse -formData :: Reference -> Word64 -> SegList -> Closure +formData :: Reference -> PackedTag -> SegList -> Closure formData r t [] = Enum r t formData r t [Left i] = DataU1 r t i formData r t [Left i, Left j] = DataU2 r t i j @@ -284,7 +285,7 @@ frameDataSize = go 0 go sz (Push f a _ _ _ k) = go (sz + f + a) k -pattern DataC :: Reference -> Word64 -> SegList -> Closure +pattern DataC :: Reference -> PackedTag -> SegList -> Closure pattern DataC rf ct segs <- (splitData -> Just (rf, ct, segs)) where From ef778cf13467e590ff167534a1f4c38d5e928199 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 09:55:27 -0700 Subject: [PATCH 006/113] Pack type tags into boxed unboxed vals --- unison-runtime/src/Unison/Runtime/ANF.hs | 78 +-------- unison-runtime/src/Unison/Runtime/MCode.hs | 4 +- unison-runtime/src/Unison/Runtime/Machine.hs | 117 +++++-------- unison-runtime/src/Unison/Runtime/Stack.hs | 110 +++++++++---- unison-runtime/src/Unison/Runtime/TypeTags.hs | 155 ++++++++++++++++++ unison-runtime/unison-runtime.cabal | 1 + 6 files changed, 273 insertions(+), 192 deletions(-) create mode 100644 unison-runtime/src/Unison/Runtime/TypeTags.hs diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 664465164d..638a639842 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -94,7 +94,6 @@ import Control.Monad.Reader (ReaderT (..), ask, local) import Control.Monad.State (MonadState (..), State, gets, modify, runState) import Data.Bifoldable (Bifoldable (..)) import Data.Bitraversable (Bitraversable (..)) -import Data.Bits (shiftL, shiftR, (.&.), (.|.)) import Data.Functor.Compose (Compose (..)) import Data.List hiding (and, or) import Data.Map qualified as Map @@ -113,6 +112,7 @@ import Unison.Pattern qualified as P import Unison.Prelude import Unison.Reference (Id, Reference, Reference' (Builtin, DerivedId)) import Unison.Referent (Referent, pattern Con, pattern Ref) +import Unison.Runtime.TypeTags (CTag (..), PackedTag (..), RTag (..), Tag (..), maskTags, packTags, unpackTags) import Unison.Symbol (Symbol) import Unison.Term hiding (List, Ref, Text, float, fresh, resolve) import Unison.Type qualified as Ty @@ -124,7 +124,6 @@ import Unison.Util.Text qualified as Util.Text import Unison.Var (Var, typed) import Unison.Var qualified as Var import Prelude hiding (abs, and, or, seq) -import Prelude qualified -- For internal errors data CompileExn = CE CallStack (Pretty.Pretty Pretty.ColorText) @@ -707,77 +706,6 @@ data ANormalF v e | AVar v deriving (Show, Eq) --- Types representing components that will go into the runtime tag of --- a data type value. RTags correspond to references, while CTags --- correspond to constructors. -newtype RTag = RTag Word64 - deriving stock (Eq, Ord, Show, Read) - deriving newtype (EC.EnumKey) - -newtype CTag = CTag Word16 - deriving stock (Eq, Ord, Show, Read) - deriving newtype (EC.EnumKey) - --- | A combined tag, which is a packed representation of an RTag and a CTag -newtype PackedTag = PackedTag Word64 - deriving stock (Eq, Ord, Show, Read) - deriving newtype (EC.EnumKey) - -class Tag t where rawTag :: t -> Word64 - -instance Tag RTag where rawTag (RTag w) = w - -instance Tag CTag where rawTag (CTag w) = fromIntegral w - -packTags :: RTag -> CTag -> PackedTag -packTags (RTag rt) (CTag ct) = PackedTag (ri .|. ci) - where - ri = rt `shiftL` 16 - ci = fromIntegral ct - -unpackTags :: PackedTag -> (RTag, CTag) -unpackTags (PackedTag w) = (RTag $ w `shiftR` 16, CTag . fromIntegral $ w .&. 0xFFFF) - --- Masks a packed tag to extract just the constructor tag portion -maskTags :: PackedTag -> Word64 -maskTags (PackedTag w) = (w .&. 0xFFFF) - -ensureRTag :: (Ord n, Show n, Num n) => String -> n -> r -> r -ensureRTag s n x - | n > 0xFFFFFFFFFFFF = - internalBug $ s ++ "@RTag: too large: " ++ show n - | otherwise = x - -ensureCTag :: (Ord n, Show n, Num n) => String -> n -> r -> r -ensureCTag s n x - | n > 0xFFFF = - internalBug $ s ++ "@CTag: too large: " ++ show n - | otherwise = x - -instance Enum RTag where - toEnum i = ensureRTag "toEnum" i . RTag $ toEnum i - fromEnum (RTag w) = fromEnum w - -instance Enum CTag where - toEnum i = ensureCTag "toEnum" i . CTag $ toEnum i - fromEnum (CTag w) = fromEnum w - -instance Num RTag where - fromInteger i = ensureRTag "fromInteger" i . RTag $ fromInteger i - (+) = internalBug "RTag: +" - (*) = internalBug "RTag: *" - abs = internalBug "RTag: abs" - signum = internalBug "RTag: signum" - negate = internalBug "RTag: negate" - -instance Num CTag where - fromInteger i = ensureCTag "fromInteger" i . CTag $ fromInteger i - (+) = internalBug "CTag: +" - (*) = internalBug "CTag: *" - abs = internalBug "CTag: abs" - signum = internalBug "CTag: signum" - negate = internalBug "CTag: negate" - instance Functor (ANormalF v) where fmap _ (AVar v) = AVar v fmap _ (ALit l) = ALit l @@ -1296,8 +1224,8 @@ data Lit | F Double | T Util.Text.Text | C Char - | LM Referent - | LY Reference + | LM Referent -- Term Link + | LY Reference -- Type Link deriving (Show, Eq) litRef :: Lit -> Reference diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index e9ee6ef695..a4c9272ef3 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -429,8 +429,8 @@ data MLit = MI !Int | MD !Double | MT !Text - | MM !Referent - | MY !Reference + | MM !Referent -- Term Link + | MY !Reference -- Type Link deriving (Show, Eq, Ord) type Instr = GInstr CombIx diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index cd7a3e5d8e..7bd271dc14 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -57,6 +57,7 @@ import Unison.Runtime.Foreign import Unison.Runtime.Foreign.Function import Unison.Runtime.MCode import Unison.Runtime.Stack +import Unison.Runtime.TypeTags qualified as TT import Unison.ShortHash qualified as SH import Unison.Symbol (Symbol) import Unison.Type qualified as Rf @@ -281,19 +282,19 @@ jump0 !callback !env !activeThreads !clo = do (denv, kf) <- topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) stk <- bump stk - bpoke stk (Enum Rf.unitRef unitTag) + bpoke stk (Enum Rf.unitRef TT.unitTag) jump env denv activeThreads stk (kf k0) (VArg1 0) clo where k0 = CB (Hook callback) unitValue :: Closure -unitValue = Enum Rf.unitRef unitTag +unitValue = Enum Rf.unitRef TT.unitTag lookupDenv :: Word64 -> DEnv -> Closure lookupDenv p denv = fromMaybe BlackHole $ EC.lookup p denv buildLit :: Reference -> PackedTag -> MLit -> Closure -buildLit rf tt (MI i) = DataU1 rf tt i +buildLit rf tt (MI i) = DataU1 rf tt (TypedUnboxed i tt) buildLit _ _ (MT t) = Foreign (Wrap Rf.textRef t) buildLit _ _ (MM r) = Foreign (Wrap Rf.termLinkRef r) buildLit _ _ (MY r) = Foreign (Wrap Rf.typeLinkRef r) @@ -502,7 +503,7 @@ exec !_ !denv !_activeThreads !stk !k _ (BPrim2 CMPU i j) = do x <- bpeekOff stk i y <- bpeekOff stk j stk <- bump stk - upoke stk . fromEnum $ universalCompare compare x y + pokeI stk . fromEnum $ universalCompare compare x y pure (denv, stk, k) exec !_ !_ !_activeThreads !stk !k r (BPrim2 THRO i j) = do name <- peekOffBi @Util.Text.Text stk i @@ -942,29 +943,29 @@ closureArgs !_ _ = -- The former puts more work before the branch, which _may_ be better for cpu pipelining, -- but the latter avoids an unnecessary fetch from the unboxed stack in cases where all args are boxed. buildData :: - Stack -> Reference -> Tag -> Args -> IO Closure + Stack -> Reference -> PackedTag -> Args -> IO Closure buildData !_ !r !t ZArgs = pure $ Enum r t buildData !stk !r !t (VArg1 i) = do bv <- bpeekOff stk i case bv of - BlackHole -> do + UnboxedTypeTag t -> do uv <- upeekOff stk i - pure $ DataU1 r t uv + pure $ DataU1 r t (TypedUnboxed uv t) _ -> pure $ DataB1 r t bv buildData !stk !r !t (VArg2 i j) = do b1 <- bpeekOff stk i b2 <- bpeekOff stk j case (b1, b2) of - (BlackHole, BlackHole) -> do + (UnboxedTypeTag t1, UnboxedTypeTag t2) -> do u1 <- upeekOff stk i u2 <- upeekOff stk j - pure $ DataU2 r t u1 u2 - (BlackHole, _) -> do + pure $ DataU2 r t (TypedUnboxed u1 t1) (TypedUnboxed u2 t2) + (UnboxedTypeTag t1, _) -> do u1 <- upeekOff stk i - pure $ DataUB r t u1 b2 - (_, BlackHole) -> do + pure $ DataUB r t (TypedUnboxed u1 t1) b2 + (_, UnboxedTypeTag t2) -> do u2 <- upeekOff stk j - pure $ DataUB r t u2 b1 + pure $ DataBU r t b1 (TypedUnboxed u2 t2) _ -> pure $ DataB2 r t b1 b2 buildData !stk !r !t (VArgR i l) = do seg <- augSeg I stk nullSeg (Just $ ArgR i l) @@ -988,7 +989,7 @@ dumpDataNoTag :: Maybe Reference -> Stack -> Closure -> - IO (Word64, Stack) + IO (PackedTag, Stack) dumpDataNoTag !_ !stk (Enum _ t) = pure (t, stk) dumpDataNoTag !_ !stk (DataU1 _ t x) = do stk <- bump stk @@ -1508,14 +1509,14 @@ bprim1 !stk PAKT i = do pokeBi stk . Util.Text.pack . toList $ clo2char <$> s pure stk where - clo2char (DataU1 _ t i) | t == charTag = toEnum i + clo2char (DataU1 _ t i) | t == TT.charTag = toEnum i clo2char c = error $ "pack text: non-character closure: " ++ show c bprim1 !stk UPKT i = do t <- peekOffBi stk i stk <- bump stk pokeS stk . Sq.fromList - . fmap (DataU1 Rf.charRef charTag . fromEnum) + . fmap (DataU1 Rf.charRef TT.charTag . fromEnum) . Util.Text.unpack $ t pure stk @@ -1525,12 +1526,12 @@ bprim1 !stk PAKB i = do pokeBi stk . By.fromWord8s . fmap clo2w8 $ toList s pure stk where - clo2w8 (DataU1 _ t n) | t == natTag = toEnum n + clo2w8 (DataU1 _ t n) | t == TT.natTag = toEnum n clo2w8 c = error $ "pack bytes: non-natural closure: " ++ show c bprim1 !stk UPKB i = do b <- peekOffBi stk i stk <- bump stk - pokeS stk . Sq.fromList . fmap (DataU1 Rf.natRef natTag . fromEnum) $ + pokeS stk . Sq.fromList . fmap (DataU1 Rf.natRef TT.natTag . fromEnum) $ By.toWord8s b pure stk bprim1 !stk SIZB i = do @@ -1931,10 +1932,10 @@ encodeSandboxResult (Right rfs) = encodeRight . Foreign . Wrap Rf.listRef $ encodeSandboxListResult rfs encodeLeft :: Closure -> Closure -encodeLeft = DataB1 Rf.eitherRef leftTag +encodeLeft = DataB1 Rf.eitherRef TT.leftTag encodeRight :: Closure -> Closure -encodeRight = DataB1 Rf.eitherRef rightTag +encodeRight = DataB1 Rf.eitherRef TT.rightTag addRefs :: TVar Word64 -> @@ -2198,13 +2199,13 @@ reflectValue rty = goV ANF.Arr <$> traverse goV a | otherwise = die $ err $ "foreign value: " <> (show f) - reflectUData :: Word64 -> Int -> IO ANF.BLit + reflectUData :: PackedTag -> Int -> IO ANF.BLit reflectUData t v - | t == natTag = pure $ ANF.Pos (fromIntegral v) - | t == charTag = pure $ ANF.Char (toEnum v) - | t == intTag, v >= 0 = pure $ ANF.Pos (fromIntegral v) - | t == intTag, v < 0 = pure $ ANF.Neg (fromIntegral (-v)) - | t == floatTag = pure $ ANF.Float (intToDouble v) + | t == TT.natTag = pure $ ANF.Pos (fromIntegral v) + | t == TT.charTag = pure $ ANF.Char (toEnum v) + | t == TT.intTag, v >= 0 = pure $ ANF.Pos (fromIntegral v) + | t == TT.intTag, v < 0 = pure $ ANF.Neg (fromIntegral (-v)) + | t == TT.floatTag = pure $ ANF.Float (intToDouble v) | otherwise = die . err $ "unboxed data: " <> show (t, v) reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Closure) @@ -2294,13 +2295,13 @@ reifyValue0 (combs, rty, rtm) = goV goL (ANF.Quote v) = pure . Foreign $ Wrap Rf.valueRef v goL (ANF.Code g) = pure . Foreign $ Wrap Rf.codeRef g goL (ANF.BArr a) = pure . Foreign $ Wrap Rf.ibytearrayRef a - goL (ANF.Char c) = pure $ DataU1 Rf.charRef charTag (fromEnum c) + goL (ANF.Char c) = pure $ DataU1 Rf.charRef TT.charTag (fromEnum c) goL (ANF.Pos w) = - pure $ DataU1 Rf.natRef natTag (fromIntegral w) + pure $ DataU1 Rf.natRef TT.natTag (fromIntegral w) goL (ANF.Neg w) = - pure $ DataU1 Rf.intRef intTag (-fromIntegral w) + pure $ DataU1 Rf.intRef TT.intTag (-fromIntegral w) goL (ANF.Float d) = - pure $ DataU1 Rf.floatRef floatTag (doubleToInt d) + pure $ DataU1 Rf.floatRef TT.floatTag (doubleToInt d) goL (ANF.Arr a) = Foreign . Wrap Rf.iarrayRef <$> traverse goV a doubleToInt :: Double -> Int @@ -2359,8 +2360,8 @@ universalEq frn = eqc -- more accepting for those. matchTags ct1 ct2 = ct1 == ct2 - || (ct1 == intTag && ct2 == natTag) - || (ct1 == natTag && ct2 == intTag) + || (ct1 == TT.intTag && ct2 == TT.natTag) + || (ct1 == TT.natTag && ct2 == TT.intTag) arrayEq :: (Closure -> Closure -> Bool) -> PA.Array Closure -> PA.Array Closure -> Bool arrayEq eqc l r @@ -2409,50 +2410,6 @@ compareAsNat i j = compare ni nj ni = fromIntegral i nj = fromIntegral j -floatTag :: PackedTag -floatTag - | Just n <- M.lookup Rf.floatRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: floatTag" - -natTag :: PackedTag -natTag - | Just n <- M.lookup Rf.natRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: natTag" - -intTag :: PackedTag -intTag - | Just n <- M.lookup Rf.intRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: intTag" - -charTag :: PackedTag -charTag - | Just n <- M.lookup Rf.charRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: charTag" - -unitTag :: PackedTag -unitTag - | Just n <- M.lookup Rf.unitRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: unitTag" - -leftTag, rightTag :: PackedTag -(leftTag, rightTag) - | Just n <- M.lookup Rf.eitherRef builtinTypeNumbering, - et <- toEnum (fromIntegral n), - lt <- toEnum (fromIntegral Rf.eitherLeftId), - rt <- toEnum (fromIntegral Rf.eitherRightId) = - (packTags et lt, packTags et rt) - | otherwise = error "internal error: either tags" - universalCompare :: (Foreign -> Foreign -> Ordering) -> Closure -> @@ -2463,10 +2420,10 @@ universalCompare frn = cmpc False cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) cmpc _ (DataC _ ct1 [Left i]) (DataC _ ct2 [Left j]) - | ct1 == floatTag, ct2 == floatTag = compareAsFloat i j - | ct1 == natTag, ct2 == natTag = compareAsNat i j - | ct1 == intTag, ct2 == natTag = compare i j - | ct1 == natTag, ct2 == intTag = compare i j + | ct1 == TT.floatTag, ct2 == TT.floatTag = compareAsFloat i j + | ct1 == TT.natTag, ct2 == TT.natTag = compareAsNat i j + | ct1 == TT.intTag, ct2 == TT.natTag = compare i j + | ct1 == TT.natTag, ct2 == TT.intTag = compare i j cmpc tyEq (DataC rf1 ct1 vs1) (DataC rf2 ct2 vs2) = (if tyEq && ct1 /= ct2 then compare rf1 rf2 else EQ) <> compare (maskTags ct1) (maskTags ct2) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 7c7deac4a0..66449a4564 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -25,7 +25,8 @@ module Unison.Runtime.Stack DataG, Captured, Foreign, - BlackHole + BlackHole, + UnboxedTypeTag ), IxClosure, Callback (..), @@ -38,6 +39,8 @@ module Unison.Runtime.Stack Seg, USeg, BSeg, + SegList, + TypedUnboxed (..), traceK, frameDataSize, marshalToForeign, @@ -52,6 +55,8 @@ module Unison.Runtime.Stack peekOffN, pokeN, pokeOffN, + pokeI, + pokeOffI, peekBi, peekOffBi, pokeBi, @@ -75,6 +80,8 @@ module Unison.Runtime.Stack bpokeOff, upoke, upokeOff, + pokeTU, + pokeOffTU, bump, bumpn, grab, @@ -104,6 +111,7 @@ import Unison.Runtime.ANF (PackedTag) import Unison.Runtime.Array import Unison.Runtime.Foreign import Unison.Runtime.MCode +import Unison.Runtime.TypeTags qualified as TT import Unison.Type qualified as Ty import Unison.Util.EnumContainers as EC import Prelude hiding (words) @@ -168,16 +176,18 @@ data GClosure comb {-# UNPACK #-} !(GCombInfo comb) {-# UNPACK #-} !Seg -- args | GEnum !Reference !PackedTag - | GDataU1 !Reference !PackedTag !Int - | GDataU2 !Reference !PackedTag !Int !Int + | GDataU1 !Reference !PackedTag !TypedUnboxed + | GDataU2 !Reference !PackedTag !TypedUnboxed !TypedUnboxed | GDataB1 !Reference !PackedTag !(GClosure comb) | GDataB2 !Reference !PackedTag !(GClosure comb) !(GClosure comb) - | GDataUB !Reference !PackedTag !Int !(GClosure comb) - | GDataBU !Reference !PackedTag !(GClosure comb) !Int + | GDataUB !Reference !PackedTag !TypedUnboxed !(GClosure comb) + | GDataBU !Reference !PackedTag !(GClosure comb) !TypedUnboxed | GDataG !Reference !PackedTag {-# UNPACK #-} !Seg | -- code cont, arg size, u/b data stacks GCaptured !K !Int {-# UNPACK #-} !Seg | GForeign !Foreign + | -- The type tag for the value in the corresponding unboxed stack slot. + GUnboxedTypeTag !PackedTag | GBlackHole deriving stock (Show, Functor, Foldable, Traversable) @@ -220,6 +230,8 @@ pattern Foreign x = Closure (GForeign x) pattern BlackHole = Closure GBlackHole +pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) + traceK :: Reference -> K -> [(Reference, Int)] traceK begin = dedup (begin, 1) where @@ -241,14 +253,6 @@ splitData = \case (DataG r t seg) -> Just (r, t, segToList seg) _ -> Nothing --- | Converts an unboxed segment to a list of integers for a more interchangeable --- representation. The segments are stored in backwards order, so this reverses --- the contents. -ints :: ByteArray -> [Int] -ints ba = fmap (indexByteArray ba) [n - 1, n - 2 .. 0] - where - n = sizeofByteArray ba `div` 8 - -- | Converts a list of integers representing an unboxed segment back into the -- appropriate segment. Segments are stored backwards in the runtime, so this -- reverses the list. @@ -291,7 +295,14 @@ pattern DataC rf ct segs <- where DataC rf ct segs = formData rf ct segs -type SegList = [Either Int Closure] +-- | An unboxed value with an accompanying tag indicating its type. +data TypedUnboxed = TypedUnboxed !Int !PackedTag + deriving (Show, Eq, Ord) + +splitTaggedUnboxed :: TypedUnboxed -> (Int, Closure) +splitTaggedUnboxed (TypedUnboxed i t) = (i, UnboxedTypeTag t) + +type SegList = [Either TypedUnboxed Closure] pattern PApV :: CombIx -> RCombInfo Closure -> SegList -> Closure pattern PApV cix rcomb segs <- @@ -311,22 +322,28 @@ segToList (u, b) = zipWith combine (ints u) (bsegToList b) where combine i c = case c of - BlackHole -> Left i + UnboxedTypeTag t -> Left $ TypedUnboxed i t _ -> Right c +-- | Converts an unboxed segment to a list of integers for a more interchangeable +-- representation. The segments are stored in backwards order, so this reverses +-- the contents. +ints :: ByteArray -> [Int] +ints ba = fmap (indexByteArray ba) [n - 1, n - 2 .. 0] + where + n = sizeofByteArray ba `div` 8 + -- | Converts from the list representation of a segment to the efficient stack form. Segments are stored backwards, -- so this reverses the contents. segFromList :: SegList -> Seg -segFromList xs = (useg u, bseg b) - where - u = - xs <&> \case - Left i -> i - Right _ -> 0 - b = - xs <&> \case - Left _ -> BlackHole - Right c -> c +segFromList xs = + xs + <&> ( \case + Left tu -> splitTaggedUnboxed tu + Right c -> (0, c) + ) + & unzip + & \(us, bs) -> (useg us, bseg bs) {-# COMPLETE DataC, PAp, Captured, Foreign, BlackHole #-} @@ -477,6 +494,8 @@ instance Show Stack where type UElem = Int +type TypedUElem = (Int, Closure {- This closure should always be a UnboxedTypeTag -}) + type USeg = ByteArray type BElem = Closure @@ -526,12 +545,16 @@ upeekOff (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) -- | Store an unboxed value and null out the boxed stack at that location, both so we know there's no value there, -- and so garbage collection can clean up any value that was referenced there. -upoke :: Stack -> UElem -> IO () -upoke stk@(Stack _ _ sp ustk _) u = do - bpoke stk BlackHole +upoke :: Stack -> TypedUElem -> IO () +upoke !stk@(Stack _ _ sp ustk _) !(u, t) = do + bpoke stk t writeByteArray ustk sp u {-# INLINE upoke #-} +pokeTU :: Stack -> TypedUnboxed -> IO () +pokeTU stk !(TypedUnboxed u t) = upoke stk (u, UnboxedTypeTag t) +{-# INLINE pokeTU #-} + -- | Store a boxed value. -- We don't bother nulling out the unboxed stack, -- it's extra work and there's nothing to garbage collect. @@ -539,12 +562,16 @@ bpoke :: Stack -> BElem -> IO () bpoke (Stack _ _ sp _ bstk) b = writeArray bstk sp b {-# INLINE bpoke #-} -upokeOff :: Stack -> Off -> UElem -> IO () -upokeOff stk i u = do - bpokeOff stk i BlackHole +upokeOff :: Stack -> Off -> TypedUElem -> IO () +upokeOff stk i (u, t) = do + bpokeOff stk i t writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOff #-} +pokeOffTU :: Stack -> Off -> TypedUnboxed -> IO () +pokeOffTU stk i (TypedUnboxed u t) = upokeOff stk i (u, UnboxedTypeTag t) +{-# INLINE pokeOffTU #-} + bpokeOff :: Stack -> Off -> BElem -> IO () bpokeOff (Stack _ _ sp _ bstk) i b = writeArray bstk (sp - i) b {-# INLINE bpokeOff #-} @@ -748,28 +775,41 @@ peekOffD (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) pokeN :: Stack -> Word64 -> IO () pokeN stk@(Stack _ _ sp ustk _) n = do - bpoke stk BlackHole + bpoke stk (UnboxedTypeTag TT.natTag) writeByteArray ustk sp n {-# INLINE pokeN #-} pokeD :: Stack -> Double -> IO () pokeD stk@(Stack _ _ sp ustk _) d = do - bpoke stk BlackHole + bpoke stk (UnboxedTypeTag TT.floatTag) writeByteArray ustk sp d {-# INLINE pokeD #-} +-- | Note: This is for poking an unboxed value that has the UNISON type 'int', not just any unboxed data. +pokeI :: Stack -> Int -> IO () +pokeI stk@(Stack _ _ sp ustk _) i = do + bpoke stk (UnboxedTypeTag TT.intTag) + writeByteArray ustk sp i +{-# INLINE pokeI #-} + pokeOffN :: Stack -> Int -> Word64 -> IO () pokeOffN stk@(Stack _ _ sp ustk _) i n = do - bpokeOff stk i BlackHole + bpokeOff stk i (UnboxedTypeTag TT.natTag) writeByteArray ustk (sp - i) n {-# INLINE pokeOffN #-} pokeOffD :: Stack -> Int -> Double -> IO () pokeOffD stk@(Stack _ _ sp ustk _) i d = do - bpokeOff stk i BlackHole + bpokeOff stk i (UnboxedTypeTag TT.floatTag) writeByteArray ustk (sp - i) d {-# INLINE pokeOffD #-} +pokeOffI :: Stack -> Int -> Int -> IO () +pokeOffI stk@(Stack _ _ sp ustk _) i n = do + bpokeOff stk i (UnboxedTypeTag TT.intTag) + writeByteArray ustk (sp - i) n +{-# INLINE pokeOffI #-} + pokeBi :: (BuiltinForeign b) => Stack -> b -> IO () pokeBi stk x = bpoke stk (Foreign $ wrapBuiltin x) {-# INLINE pokeBi #-} diff --git a/unison-runtime/src/Unison/Runtime/TypeTags.hs b/unison-runtime/src/Unison/Runtime/TypeTags.hs new file mode 100644 index 0000000000..bbdd839b70 --- /dev/null +++ b/unison-runtime/src/Unison/Runtime/TypeTags.hs @@ -0,0 +1,155 @@ +module Unison.Runtime.TypeTags + ( Tag (..), + RTag (..), + CTag (..), + PackedTag (..), + packTags, + unpackTags, + maskTags, + floatTag, + natTag, + intTag, + charTag, + unitTag, + leftTag, + rightTag, + ) +where + +import Control.Exception (throw) +import Data.Bits (shiftL, shiftR, (.&.), (.|.)) +import Data.List hiding (and, or) +import Data.Map qualified as Map +import GHC.Stack (CallStack, callStack) +import Unison.Builtin.Decls qualified as Ty +import Unison.Prelude +import Unison.Runtime.Builtin.Types (builtinTypeNumbering) +import Unison.Type qualified as Ty +import Unison.Util.EnumContainers as EC +import Unison.Util.Pretty qualified as Pretty +import Prelude hiding (abs, and, or, seq) +import Prelude qualified + +-- For internal errors +data CompileExn = CE CallStack (Pretty.Pretty Pretty.ColorText) + deriving (Show) + +instance Exception CompileExn + +internalBug :: (HasCallStack) => String -> a +internalBug = throw . CE callStack . Pretty.lit . fromString + +-- Types representing components that will go into the runtime tag of +-- a data type value. RTags correspond to references, while CTags +-- correspond to constructors. +newtype RTag = RTag Word64 + deriving stock (Eq, Ord, Show, Read) + deriving newtype (EC.EnumKey) + +newtype CTag = CTag Word16 + deriving stock (Eq, Ord, Show, Read) + deriving newtype (EC.EnumKey) + +-- | A combined tag, which is a packed representation of an RTag and a CTag +newtype PackedTag = PackedTag Word64 + deriving stock (Eq, Ord, Show, Read) + deriving newtype (EC.EnumKey) + +class Tag t where rawTag :: t -> Word64 + +instance Tag RTag where rawTag (RTag w) = w + +instance Tag CTag where rawTag (CTag w) = fromIntegral w + +packTags :: RTag -> CTag -> PackedTag +packTags (RTag rt) (CTag ct) = PackedTag (ri .|. ci) + where + ri = rt `shiftL` 16 + ci = fromIntegral ct + +unpackTags :: PackedTag -> (RTag, CTag) +unpackTags (PackedTag w) = (RTag $ w `shiftR` 16, CTag . fromIntegral $ w .&. 0xFFFF) + +-- Masks a packed tag to extract just the constructor tag portion +maskTags :: PackedTag -> Word64 +maskTags (PackedTag w) = (w .&. 0xFFFF) + +ensureRTag :: (Ord n, Show n, Num n) => String -> n -> r -> r +ensureRTag s n x + | n > 0xFFFFFFFFFFFF = + internalBug $ s ++ "@RTag: too large: " ++ show n + | otherwise = x + +ensureCTag :: (Ord n, Show n, Num n) => String -> n -> r -> r +ensureCTag s n x + | n > 0xFFFF = + internalBug $ s ++ "@CTag: too large: " ++ show n + | otherwise = x + +instance Enum RTag where + toEnum i = ensureRTag "toEnum" i . RTag $ toEnum i + fromEnum (RTag w) = fromEnum w + +instance Enum CTag where + toEnum i = ensureCTag "toEnum" i . CTag $ toEnum i + fromEnum (CTag w) = fromEnum w + +instance Num RTag where + fromInteger i = ensureRTag "fromInteger" i . RTag $ fromInteger i + (+) = internalBug "RTag: +" + (*) = internalBug "RTag: *" + abs = internalBug "RTag: abs" + signum = internalBug "RTag: signum" + negate = internalBug "RTag: negate" + +instance Num CTag where + fromInteger i = ensureCTag "fromInteger" i . CTag $ fromInteger i + (+) = internalBug "CTag: +" + (*) = internalBug "CTag: *" + abs = internalBug "CTag: abs" + signum = internalBug "CTag: signum" + negate = internalBug "CTag: negate" + +floatTag :: PackedTag +floatTag + | Just n <- Map.lookup Ty.floatRef builtinTypeNumbering, + rt <- toEnum (fromIntegral n) = + packTags rt 0 + | otherwise = error "internal error: floatTag" + +natTag :: PackedTag +natTag + | Just n <- Map.lookup Ty.natRef builtinTypeNumbering, + rt <- toEnum (fromIntegral n) = + packTags rt 0 + | otherwise = error "internal error: natTag" + +intTag :: PackedTag +intTag + | Just n <- Map.lookup Ty.intRef builtinTypeNumbering, + rt <- toEnum (fromIntegral n) = + packTags rt 0 + | otherwise = error "internal error: intTag" + +charTag :: PackedTag +charTag + | Just n <- Map.lookup Ty.charRef builtinTypeNumbering, + rt <- toEnum (fromIntegral n) = + packTags rt 0 + | otherwise = error "internal error: charTag" + +unitTag :: PackedTag +unitTag + | Just n <- Map.lookup Ty.unitRef builtinTypeNumbering, + rt <- toEnum (fromIntegral n) = + packTags rt 0 + | otherwise = error "internal error: unitTag" + +leftTag, rightTag :: PackedTag +(leftTag, rightTag) + | Just n <- Map.lookup Ty.eitherRef builtinTypeNumbering, + et <- toEnum (fromIntegral n), + lt <- toEnum (fromIntegral Ty.eitherLeftId), + rt <- toEnum (fromIntegral Ty.eitherRightId) = + (packTags et lt, packTags et rt) + | otherwise = error "internal error: either tags" diff --git a/unison-runtime/unison-runtime.cabal b/unison-runtime/unison-runtime.cabal index 33650d1944..ba9a8b095e 100644 --- a/unison-runtime/unison-runtime.cabal +++ b/unison-runtime/unison-runtime.cabal @@ -49,6 +49,7 @@ library Unison.Runtime.Serialize Unison.Runtime.SparseVector Unison.Runtime.Stack + Unison.Runtime.TypeTags Unison.Runtime.Vector hs-source-dirs: src From 4b764078a0f9ab8f8ee6559e86bc06e344efe21e Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 12:16:34 -0700 Subject: [PATCH 007/113] Add a bunch more typed poke/peek primitives --- .../src/Unison/Runtime/Foreign/Function.hs | 62 ++++++++++--------- unison-runtime/src/Unison/Runtime/Stack.hs | 52 ++++++++++++++++ unison-runtime/src/Unison/Runtime/TypeTags.hs | 43 ++++++------- 3 files changed, 104 insertions(+), 53 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 786a1ab50f..14a654781a 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -24,7 +24,6 @@ import Data.Primitive.Array as PA import Data.Primitive.ByteArray as PA import Data.Sequence qualified as Sq import Data.Time.Clock.POSIX (POSIXTime) -import Data.Word (Word16, Word32, Word64, Word8) import GHC.IO.Exception (IOErrorType (..), IOException (..)) import Network.Socket (Socket) import Network.UDP (UDPSocket) @@ -36,6 +35,7 @@ import Unison.Runtime.Exception import Unison.Runtime.Foreign import Unison.Runtime.MCode import Unison.Runtime.Stack +import Unison.Runtime.TypeTags qualified as TT import Unison.Type ( iarrayRef, ibytearrayRef, @@ -88,38 +88,44 @@ mkForeign ev = FF readArgs writeForeign ev internalBug "mkForeign: too many arguments for foreign function" +-- newtype UnisonInt = UnisonInt Int + +-- newtype UnisonNat = UnisonNat Word64 + +-- newtype UnisonDouble = UnisonDouble Double + instance ForeignConvention Int where readForeign (i : args) stk = (args,) <$> upeekOff stk i readForeign [] _ = foreignCCError "Int" writeForeign stk i = do stk <- bump stk - stk <$ upoke stk i + stk <$ pokeI stk i -instance ForeignConvention Word64 where - readForeign (i : args) stk = (args,) <$> peekOffN stk i - readForeign [] _ = foreignCCError "Word64" - writeForeign stk n = do - stk <- bump stk - stk <$ pokeN stk n +-- instance ForeignConvention Word64 where +-- readForeign (i : args) stk = (args,) <$> peekOffN stk i +-- readForeign [] _ = foreignCCError "Word64" +-- writeForeign stk n = do +-- stk <- bump stk +-- stk <$ pokeN stk n -instance ForeignConvention Word8 where - readForeign = readForeignAs (fromIntegral :: Word64 -> Word8) - writeForeign = writeForeignAs (fromIntegral :: Word8 -> Word64) +-- instance ForeignConvention Word8 where +-- readForeign = readForeignAs (fromIntegral :: Word64 -> Word8) +-- writeForeign = writeForeignAs (fromIntegral :: Word8 -> Word64) -instance ForeignConvention Word16 where - readForeign = readForeignAs (fromIntegral :: Word64 -> Word16) - writeForeign = writeForeignAs (fromIntegral :: Word16 -> Word64) +-- instance ForeignConvention Word16 where +-- readForeign = readForeignAs (fromIntegral :: Word64 -> Word16) +-- writeForeign = writeForeignAs (fromIntegral :: Word16 -> Word64) -instance ForeignConvention Word32 where - readForeign = readForeignAs (fromIntegral :: Word64 -> Word32) - writeForeign = writeForeignAs (fromIntegral :: Word32 -> Word64) +-- instance ForeignConvention Word32 where +-- readForeign = readForeignAs (fromIntegral :: Word64 -> Word32) +-- writeForeign = writeForeignAs (fromIntegral :: Word32 -> Word64) instance ForeignConvention Char where readForeign (i : args) stk = (args,) . Char.chr <$> upeekOff stk i readForeign [] _ = foreignCCError "Char" writeForeign stk ch = do stk <- bump stk - stk <$ upoke stk (Char.ord ch) + stk <$ pokeC stk ch -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. @@ -168,18 +174,18 @@ instance (ForeignConvention a) => ForeignConvention (Maybe a) where writeForeign stk Nothing = do stk <- bump stk - stk <$ upoke stk 0 + stk <$ pokeTag stk 0 writeForeign stk (Just x) = do stk <- writeForeign stk x stk <- bump stk - stk <$ upoke stk 1 + stk <$ pokeTag stk 1 instance (ForeignConvention a, ForeignConvention b) => ForeignConvention (Either a b) where readForeign (i : args) stk = - upeekOff stk i >>= \case + peekTagOff stk i >>= \case 0 -> readForeignAs Left args stk 1 -> readForeignAs Right args stk _ -> foreignCCError "Either" @@ -188,11 +194,11 @@ instance writeForeign stk (Left a) = do stk <- writeForeign stk a stk <- bump stk - stk <$ upoke stk 0 + stk <$ pokeTag stk 0 writeForeign stk (Right b) = do stk <- writeForeign stk b stk <- bump stk - stk <$ upoke stk 1 + stk <$ pokeTag stk 1 ioeDecode :: Int -> IOErrorType ioeDecode 0 = AlreadyExists @@ -419,13 +425,13 @@ instance ForeignConvention BufferMode where writeForeign stk bm = bump stk >>= \stk -> case bm of - NoBuffering -> stk <$ upoke stk no'buf - LineBuffering -> stk <$ upoke stk line'buf - BlockBuffering Nothing -> stk <$ upoke stk block'buf + NoBuffering -> stk <$ upokeT stk no'buf TT.bufferModeTag + LineBuffering -> stk <$ upokeT stk line'buf TT.bufferModeTag + BlockBuffering Nothing -> stk <$ upokeT stk block'buf TT.bufferModeTag BlockBuffering (Just n) -> do - upoke stk n + pokeI stk n stk <- bump stk - stk <$ upoke stk sblock'buf + stk <$ upokeT stk sblock'buf TT.bufferModeTag -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 66449a4564..8751274270 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -51,6 +51,12 @@ module Unison.Runtime.Stack peekOffD, pokeD, pokeOffD, + pokeC, + pokeTag, + peekTag, + peekTagOff, + peekI, + peekOffI, peekN, peekOffN, pokeN, @@ -80,6 +86,8 @@ module Unison.Runtime.Stack bpokeOff, upoke, upokeOff, + upokeT, + upokeTOff, pokeTU, pokeOffTU, bump, @@ -103,6 +111,7 @@ module Unison.Runtime.Stack where import Control.Monad.Primitive +import Data.Char qualified as Char import Data.Word import GHC.Exts as L (IsList (..)) import Unison.Prelude @@ -520,6 +529,14 @@ peek stk = do pure (u, b) {-# INLINE peek #-} +peekI :: Stack -> IO Int +peekI (Stack _ _ sp ustk _) = readByteArray ustk sp +{-# INLINE peekI #-} + +peekOffI :: Stack -> Off -> IO Int +peekOffI (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) +{-# INLINE peekOffI #-} + bpeek :: Stack -> IO BElem bpeek (Stack _ _ sp _ bstk) = readArray bstk sp {-# INLINE bpeek #-} @@ -551,10 +568,33 @@ upoke !stk@(Stack _ _ sp ustk _) !(u, t) = do writeByteArray ustk sp u {-# INLINE upoke #-} +upokeT :: Stack -> UElem -> PackedTag -> IO () +upokeT !stk@(Stack _ _ sp ustk _) !u !t = do + bpoke stk (UnboxedTypeTag t) + writeByteArray ustk sp u +{-# INLINE upokeT #-} + pokeTU :: Stack -> TypedUnboxed -> IO () pokeTU stk !(TypedUnboxed u t) = upoke stk (u, UnboxedTypeTag t) {-# INLINE pokeTU #-} +-- | Store an unboxed tag to later match on. +-- Often used to indicate the constructor of a data type that's been unpacked onto the stack, +-- or some tag we're about to branch on. +pokeTag :: Stack -> Int -> IO () +pokeTag = + -- For now we just use ints, but maybe should have a separate type for tags so we can detect if we're leaking them. + pokeI +{-# INLINE pokeTag #-} + +peekTag :: Stack -> IO Int +peekTag = peekI +{-# INLINE peekTag #-} + +peekTagOff :: Stack -> Off -> IO Int +peekTagOff = peekOffI +{-# INLINE peekTagOff #-} + -- | Store a boxed value. -- We don't bother nulling out the unboxed stack, -- it's extra work and there's nothing to garbage collect. @@ -568,6 +608,12 @@ upokeOff stk i (u, t) = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOff #-} +upokeTOff :: Stack -> Off -> UElem -> PackedTag -> IO () +upokeTOff stk i u t = do + bpokeOff stk i (UnboxedTypeTag t) + writeByteArray (ustk stk) (sp stk - i) u +{-# INLINE upokeTOff #-} + pokeOffTU :: Stack -> Off -> TypedUnboxed -> IO () pokeOffTU stk i (TypedUnboxed u t) = upokeOff stk i (u, UnboxedTypeTag t) {-# INLINE pokeOffTU #-} @@ -785,6 +831,12 @@ pokeD stk@(Stack _ _ sp ustk _) d = do writeByteArray ustk sp d {-# INLINE pokeD #-} +pokeC :: Stack -> Char -> IO () +pokeC stk@(Stack _ _ sp ustk _) c = do + bpoke stk (UnboxedTypeTag TT.charTag) + writeByteArray ustk sp (Char.ord c) +{-# INLINE pokeC #-} + -- | Note: This is for poking an unboxed value that has the UNISON type 'int', not just any unboxed data. pokeI :: Stack -> Int -> IO () pokeI stk@(Stack _ _ sp ustk _) i = do diff --git a/unison-runtime/src/Unison/Runtime/TypeTags.hs b/unison-runtime/src/Unison/Runtime/TypeTags.hs index bbdd839b70..3e8929d944 100644 --- a/unison-runtime/src/Unison/Runtime/TypeTags.hs +++ b/unison-runtime/src/Unison/Runtime/TypeTags.hs @@ -11,6 +11,7 @@ module Unison.Runtime.TypeTags intTag, charTag, unitTag, + bufferModeTag, leftTag, rightTag, ) @@ -21,6 +22,7 @@ import Data.Bits (shiftL, shiftR, (.&.), (.|.)) import Data.List hiding (and, or) import Data.Map qualified as Map import GHC.Stack (CallStack, callStack) +import U.Codebase.Reference (Reference) import Unison.Builtin.Decls qualified as Ty import Unison.Prelude import Unison.Runtime.Builtin.Types (builtinTypeNumbering) @@ -111,39 +113,22 @@ instance Num CTag where negate = internalBug "CTag: negate" floatTag :: PackedTag -floatTag - | Just n <- Map.lookup Ty.floatRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: floatTag" +floatTag = mkSimpleTag "floatTag" Ty.floatRef natTag :: PackedTag -natTag - | Just n <- Map.lookup Ty.natRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: natTag" +natTag = mkSimpleTag "natTag" Ty.natRef intTag :: PackedTag -intTag - | Just n <- Map.lookup Ty.intRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: intTag" +intTag = mkSimpleTag "intTag" Ty.intRef charTag :: PackedTag -charTag - | Just n <- Map.lookup Ty.charRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: charTag" +charTag = mkSimpleTag "charTag" Ty.charRef unitTag :: PackedTag -unitTag - | Just n <- Map.lookup Ty.unitRef builtinTypeNumbering, - rt <- toEnum (fromIntegral n) = - packTags rt 0 - | otherwise = error "internal error: unitTag" +unitTag = mkSimpleTag "unitTag" Ty.unitRef + +bufferModeTag :: PackedTag +bufferModeTag = mkSimpleTag "bufferModeTag" Ty.bufferModeRef leftTag, rightTag :: PackedTag (leftTag, rightTag) @@ -153,3 +138,11 @@ leftTag, rightTag :: PackedTag rt <- toEnum (fromIntegral Ty.eitherRightId) = (packTags et lt, packTags et rt) | otherwise = error "internal error: either tags" + +-- | Construct a tag for a single-constructor builtin type +mkSimpleTag :: String -> Reference -> PackedTag +mkSimpleTag msg r + | Just n <- Map.lookup r builtinTypeNumbering, + rt <- toEnum (fromIntegral n) = + packTags rt 0 + | otherwise = internalBug $ "internal error: " <> msg From 34a113d25a0da5c4aac1790ff89631b1d68098d7 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 17:44:19 -0700 Subject: [PATCH 008/113] Patterns for unboxed type closures --- unison-runtime/src/Unison/Runtime/Machine.hs | 126 +++++++++---------- unison-runtime/src/Unison/Runtime/Stack.hs | 65 +++++++++- 2 files changed, 119 insertions(+), 72 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 7bd271dc14..76beae06e7 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -15,7 +15,6 @@ import Data.Bitraversable (Bitraversable (..)) import Data.Bits import Data.Map.Strict qualified as M import Data.Ord (comparing) -import Data.Primitive.ByteArray qualified as BA import Data.Sequence qualified as Sq import Data.Set qualified as S import Data.Set qualified as Set @@ -1065,22 +1064,22 @@ uprim1 :: Stack -> UPrim1 -> Int -> IO Stack uprim1 !stk DECI !i = do m <- upeekOff stk i stk <- bump stk - upoke stk (m - 1) + pokeI stk (m - 1) pure stk uprim1 !stk INCI !i = do m <- upeekOff stk i stk <- bump stk - upoke stk (m + 1) + pokeI stk (m + 1) pure stk uprim1 !stk NEGI !i = do m <- upeekOff stk i stk <- bump stk - upoke stk (-m) + pokeI stk (-m) pure stk uprim1 !stk SGNI !i = do m <- upeekOff stk i stk <- bump stk - upoke stk (signum m) + pokeI stk (signum m) pure stk uprim1 !stk ABSF !i = do d <- peekOffD stk i @@ -1195,17 +1194,17 @@ uprim1 !stk NTOF !i = do uprim1 !stk LZRO !i = do n <- peekOffN stk i stk <- bump stk - upoke stk (countLeadingZeros n) + unsafePokeIasN stk (countLeadingZeros n) pure stk uprim1 !stk TZRO !i = do n <- peekOffN stk i stk <- bump stk - upoke stk (countTrailingZeros n) + unsafePokeIasN stk (countTrailingZeros n) pure stk uprim1 !stk POPC !i = do n <- peekOffN stk i stk <- bump stk - upoke stk (popCount n) + unsafePokeIasN stk (popCount n) pure stk uprim1 !stk COMN !i = do n <- peekOffN stk i @@ -1219,43 +1218,43 @@ uprim2 !stk ADDI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m + n) + pokeI stk (m + n) pure stk uprim2 !stk SUBI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m - n) + pokeI stk (m - n) pure stk uprim2 !stk MULI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m * n) + pokeI stk (m * n) pure stk uprim2 !stk DIVI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m `div` n) + pokeI stk (m `div` n) pure stk uprim2 !stk MODI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m `mod` n) + pokeI stk (m `mod` n) pure stk uprim2 !stk SHLI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m `shiftL` n) + pokeI stk (m `shiftL` n) pure stk uprim2 !stk SHRI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk (m `shiftR` n) + pokeI stk (m `shiftR` n) pure stk uprim2 !stk SHRN !i !j = do m <- peekOffN stk i @@ -1267,7 +1266,7 @@ uprim2 !stk POWI !i !j = do m <- upeekOff stk i n <- peekOffN stk j stk <- bump stk - upoke stk (m ^ n) + pokeI stk (m ^ n) pure stk uprim2 !stk EQLI !i !j = do m <- upeekOff stk i @@ -1393,12 +1392,12 @@ bprim1 :: bprim1 !stk SIZT i = do t <- peekOffBi stk i stk <- bump stk - upoke stk $ Util.Text.size t + unsafePokeIasN stk $ Util.Text.size t pure stk bprim1 !stk SIZS i = do s <- peekOffS stk i stk <- bump stk - upoke stk $ Sq.length s + unsafePokeIasN stk $ Sq.length s pure stk bprim1 !stk ITOT i = do n <- upeekOff stk i @@ -1423,7 +1422,7 @@ bprim1 !stk USNC i = pure stk Just (t, c) -> do stk <- bumpn stk 3 - upokeOff stk 2 $ fromEnum c -- char value + pokeOffC stk 2 $ c -- char value pokeOffBi stk 1 t -- remaining text upoke stk 1 -- 'Just' tag pure stk @@ -1436,7 +1435,7 @@ bprim1 !stk UCNS i = Just (c, t) -> do stk <- bumpn stk 3 pokeOffBi stk 2 t -- remaining text - upokeOff stk 1 $ fromEnum c -- char value + pokeOffC stk 1 $ c -- char value upoke stk 1 -- 'Just' tag pure stk bprim1 !stk TTOI i = @@ -1509,14 +1508,15 @@ bprim1 !stk PAKT i = do pokeBi stk . Util.Text.pack . toList $ clo2char <$> s pure stk where - clo2char (DataU1 _ t i) | t == TT.charTag = toEnum i + clo2char :: Closure -> Char + clo2char (CharClosure c) = c clo2char c = error $ "pack text: non-character closure: " ++ show c bprim1 !stk UPKT i = do t <- peekOffBi stk i stk <- bump stk pokeS stk . Sq.fromList - . fmap (DataU1 Rf.charRef TT.charTag . fromEnum) + . fmap CharClosure . Util.Text.unpack $ t pure stk @@ -1526,18 +1526,20 @@ bprim1 !stk PAKB i = do pokeBi stk . By.fromWord8s . fmap clo2w8 $ toList s pure stk where - clo2w8 (DataU1 _ t n) | t == TT.natTag = toEnum n + -- TODO: Should we have a tag for bytes specifically? + clo2w8 :: Closure -> Word8 + clo2w8 (NatClosure n) = toEnum . fromEnum $ n clo2w8 c = error $ "pack bytes: non-natural closure: " ++ show c bprim1 !stk UPKB i = do b <- peekOffBi stk i stk <- bump stk - pokeS stk . Sq.fromList . fmap (DataU1 Rf.natRef TT.natTag . fromEnum) $ + pokeS stk . Sq.fromList . fmap (NatClosure . toEnum @Word64 . fromEnum @Word8) $ By.toWord8s b pure stk bprim1 !stk SIZB i = do b <- peekOffBi stk i stk <- bump stk - upoke stk $ By.size b + unsafePokeIasN stk $ By.size b pure stk bprim1 !stk FLTB i = do b <- peekOffBi stk i @@ -2295,21 +2297,12 @@ reifyValue0 (combs, rty, rtm) = goV goL (ANF.Quote v) = pure . Foreign $ Wrap Rf.valueRef v goL (ANF.Code g) = pure . Foreign $ Wrap Rf.codeRef g goL (ANF.BArr a) = pure . Foreign $ Wrap Rf.ibytearrayRef a - goL (ANF.Char c) = pure $ DataU1 Rf.charRef TT.charTag (fromEnum c) - goL (ANF.Pos w) = - pure $ DataU1 Rf.natRef TT.natTag (fromIntegral w) - goL (ANF.Neg w) = - pure $ DataU1 Rf.intRef TT.intTag (-fromIntegral w) - goL (ANF.Float d) = - pure $ DataU1 Rf.floatRef TT.floatTag (doubleToInt d) + goL (ANF.Char c) = pure $ CharClosure c + goL (ANF.Pos w) = pure $ NatClosure w + goL (ANF.Neg w) = pure $ IntClosure (negate (fromIntegral w :: Int)) + goL (ANF.Float d) = pure $ DoubleClosure d goL (ANF.Arr a) = Foreign . Wrap Rf.iarrayRef <$> traverse goV a -doubleToInt :: Double -> Int -doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 - -intToDouble :: Int -> Double -intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 - -- Universal comparison functions closureNum :: Closure -> Int @@ -2419,34 +2412,35 @@ universalCompare frn = cmpc False where cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) - cmpc _ (DataC _ ct1 [Left i]) (DataC _ ct2 [Left j]) - | ct1 == TT.floatTag, ct2 == TT.floatTag = compareAsFloat i j - | ct1 == TT.natTag, ct2 == TT.natTag = compareAsNat i j - | ct1 == TT.intTag, ct2 == TT.natTag = compare i j - | ct1 == TT.natTag, ct2 == TT.intTag = compare i j - cmpc tyEq (DataC rf1 ct1 vs1) (DataC rf2 ct2 vs2) = - (if tyEq && ct1 /= ct2 then compare rf1 rf2 else EQ) - <> compare (maskTags ct1) (maskTags ct2) - -- when comparing corresponding `Any` values, which have - -- existentials inside check that type references match - <> cmpValList (tyEq || rf1 == Rf.anyRef) vs1 vs2 - cmpc tyEq (PApV cix1 _ segs1) (PApV cix2 _ segs2) = - compare cix1 cix2 - <> cmpValList tyEq segs1 segs2 - cmpc _ (CapV k1 a1 vs1) (CapV k2 a2 vs2) = - compare k1 k2 - <> compare a1 a2 - <> cmpValList True vs1 vs2 - cmpc tyEq (Foreign fl) (Foreign fr) - | Just sl <- maybeUnwrapForeign Rf.listRef fl, - Just sr <- maybeUnwrapForeign Rf.listRef fr = - fold (Sq.zipWith (cmpc tyEq) sl sr) - <> compare (length sl) (length sr) - | Just al <- maybeUnwrapForeign Rf.iarrayRef fl, - Just ar <- maybeUnwrapForeign Rf.iarrayRef fr = - arrayCmp (cmpc tyEq) al ar - | otherwise = frn fl fr - cmpc _ c d = comparing closureNum c d + cmpc tyEq = \cases + (DataC _ ct1 [Left (TypedUnboxed i _)]) (DataC _ ct2 [Left (TypedUnboxed j _)]) + | ct1 == TT.floatTag, ct2 == TT.floatTag -> compareAsFloat i j + | ct1 == TT.natTag, ct2 == TT.natTag -> compareAsNat i j + | ct1 == TT.intTag, ct2 == TT.natTag -> compare i j + | ct1 == TT.natTag, ct2 == TT.intTag -> compare i j + (DataC rf1 ct1 vs1) (DataC rf2 ct2 vs2) -> + (if tyEq && ct1 /= ct2 then compare rf1 rf2 else EQ) + <> compare (maskTags ct1) (maskTags ct2) + -- when comparing corresponding `Any` values, which have + -- existentials inside check that type references match + <> cmpValList (tyEq || rf1 == Rf.anyRef) vs1 vs2 + (PApV cix1 _ segs1) (PApV cix2 _ segs2) -> + compare cix1 cix2 + <> cmpValList tyEq segs1 segs2 + (CapV k1 a1 vs1) (CapV k2 a2 vs2) -> + compare k1 k2 + <> compare a1 a2 + <> cmpValList True vs1 vs2 + (Foreign fl) (Foreign fr) + | Just sl <- maybeUnwrapForeign Rf.listRef fl, + Just sr <- maybeUnwrapForeign Rf.listRef fr -> + fold (Sq.zipWith (cmpc tyEq) sl sr) + <> compare (length sl) (length sr) + | Just al <- maybeUnwrapForeign Rf.iarrayRef fl, + Just ar <- maybeUnwrapForeign Rf.iarrayRef fr -> + arrayCmp (cmpc tyEq) al ar + | otherwise -> frn fl fr + c d -> comparing closureNum c d -- Written this way to maintain back-compat with the -- old val lists which were separated by unboxed/boxed. cmpValList tyEq vs1 vs2 = diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 8751274270..e752cda9fc 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -26,7 +26,11 @@ module Unison.Runtime.Stack Captured, Foreign, BlackHole, - UnboxedTypeTag + UnboxedTypeTag, + CharClosure, + NatClosure, + DoubleClosure, + IntClosure ), IxClosure, Callback (..), @@ -52,6 +56,7 @@ module Unison.Runtime.Stack pokeD, pokeOffD, pokeC, + pokeOffC, pokeTag, peekTag, peekTagOff, @@ -87,7 +92,8 @@ module Unison.Runtime.Stack upoke, upokeOff, upokeT, - upokeTOff, + upokeOffT, + unsafePokeIasN, pokeTU, pokeOffTU, bump, @@ -112,6 +118,7 @@ where import Control.Monad.Primitive import Data.Char qualified as Char +import Data.Primitive.ByteArray qualified as BA import Data.Word import GHC.Exts as L (IsList (..)) import Unison.Prelude @@ -305,9 +312,42 @@ pattern DataC rf ct segs <- DataC rf ct segs = formData rf ct segs -- | An unboxed value with an accompanying tag indicating its type. -data TypedUnboxed = TypedUnboxed !Int !PackedTag +data TypedUnboxed = TypedUnboxed {getTUInt :: !Int, getTUTag :: !PackedTag} deriving (Show, Eq, Ord) +pattern CharClosure :: Char -> Closure +pattern CharClosure c <- (unpackUnboxedClosure TT.charTag -> Just (Char.chr -> c)) + where + CharClosure c = DataU1 Ty.charRef TT.charTag (TypedUnboxed (Char.ord c) TT.charTag) + +pattern NatClosure :: Word64 -> Closure +pattern NatClosure n <- (unpackUnboxedClosure TT.natTag -> Just (toEnum -> n)) + where + NatClosure n = DataU1 Ty.natRef TT.natTag (TypedUnboxed (fromEnum n) TT.natTag) + +pattern DoubleClosure :: Double -> Closure +pattern DoubleClosure d <- (unpackUnboxedClosure TT.floatTag -> Just (intToDouble -> d)) + where + DoubleClosure d = DataU1 Ty.floatRef TT.floatTag (TypedUnboxed (doubleToInt d) TT.floatTag) + +pattern IntClosure :: Int -> Closure +pattern IntClosure i <- (unpackUnboxedClosure TT.intTag -> Just i) + where + IntClosure i = DataU1 Ty.intRef TT.intTag (TypedUnboxed i TT.intTag) + +doubleToInt :: Double -> Int +doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 + +intToDouble :: Int -> Double +intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 + +unpackUnboxedClosure :: PackedTag -> Closure -> Maybe Int +unpackUnboxedClosure expectedTag = \case + DataU1 _ref tag (TypedUnboxed i _) + | tag == expectedTag -> Just i + _ -> Nothing +{-# INLINE unpackUnboxedClosure #-} + splitTaggedUnboxed :: TypedUnboxed -> (Int, Closure) splitTaggedUnboxed (TypedUnboxed i t) = (i, UnboxedTypeTag t) @@ -574,6 +614,14 @@ upokeT !stk@(Stack _ _ sp ustk _) !u !t = do writeByteArray ustk sp u {-# INLINE upokeT #-} +-- | Sometimes we get back an int from a foreign call which we want to use as a Nat. +-- If we know it's positive and smaller than 2^63 then we can safely store the Int directly as a Nat without +-- checks. +unsafePokeIasN :: Stack -> Int -> IO () +unsafePokeIasN stk n = do + upokeT stk n TT.natTag +{-# INLINE unsafePokeIasN #-} + pokeTU :: Stack -> TypedUnboxed -> IO () pokeTU stk !(TypedUnboxed u t) = upoke stk (u, UnboxedTypeTag t) {-# INLINE pokeTU #-} @@ -608,11 +656,11 @@ upokeOff stk i (u, t) = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOff #-} -upokeTOff :: Stack -> Off -> UElem -> PackedTag -> IO () -upokeTOff stk i u t = do +upokeOffT :: Stack -> Off -> UElem -> PackedTag -> IO () +upokeOffT stk i u t = do bpokeOff stk i (UnboxedTypeTag t) writeByteArray (ustk stk) (sp stk - i) u -{-# INLINE upokeTOff #-} +{-# INLINE upokeOffT #-} pokeOffTU :: Stack -> Off -> TypedUnboxed -> IO () pokeOffTU stk i (TypedUnboxed u t) = upokeOff stk i (u, UnboxedTypeTag t) @@ -862,6 +910,11 @@ pokeOffI stk@(Stack _ _ sp ustk _) i n = do writeByteArray ustk (sp - i) n {-# INLINE pokeOffI #-} +pokeOffC :: Stack -> Int -> Char -> IO () +pokeOffC stk i c = do + upokeOffT stk i (Char.ord c) TT.charTag +{-# INLINE pokeOffC #-} + pokeBi :: (BuiltinForeign b) => Stack -> b -> IO () pokeBi stk x = bpoke stk (Foreign $ wrapBuiltin x) {-# INLINE pokeBi #-} From eae00c5d2f0c892fef0f79bd8590bca783526a95 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 18:03:28 -0700 Subject: [PATCH 009/113] Fix a bunch of poke types --- unison-runtime/src/Unison/Runtime/MCode.hs | 8 +- unison-runtime/src/Unison/Runtime/Machine.hs | 86 +++++++++++--------- unison-runtime/src/Unison/Runtime/Stack.hs | 12 +++ 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index a4c9272ef3..28e3c1b718 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -427,6 +427,8 @@ data BPrim2 data MLit = MI !Int + | MN !Word64 + | MC !Char | MD !Double | MT !Text | MM !Referent -- Term Link @@ -1449,9 +1451,9 @@ emitSumCase rns grpr grpn rec ctx v (ccs, TAbss vs bo) = emitSection rns grpr grpn rec (sumCtx ctx v $ zip vs ccs) bo litToMLit :: ANF.Lit -> MLit -litToMLit (ANF.I i) = MI $ fromIntegral i -litToMLit (ANF.N n) = MI $ fromIntegral n -litToMLit (ANF.C c) = MI $ fromEnum c +litToMLit (ANF.I i) = MI (fromIntegral i) +litToMLit (ANF.N n) = MN n +litToMLit (ANF.C c) = MC c litToMLit (ANF.F d) = MD d litToMLit (ANF.T t) = MT t litToMLit (ANF.LM r) = MM r diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 76beae06e7..261d1bef60 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -15,6 +15,7 @@ import Data.Bitraversable (Bitraversable (..)) import Data.Bits import Data.Map.Strict qualified as M import Data.Ord (comparing) +import Data.Primitive.ByteArray qualified as BA import Data.Sequence qualified as Sq import Data.Set qualified as S import Data.Set qualified as Set @@ -39,7 +40,7 @@ import Unison.Runtime.ANF as ANF ( Cacheability (..), Code (..), CompileExn (..), - PackedTag, + PackedTag (..), SuperGroup, codeGroup, foldGroup, @@ -541,7 +542,15 @@ exec !_ !denv !_activeThreads !stk !k _ (Print i) = do pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (Lit (MI n)) = do stk <- bump stk - upoke stk n + pokeI stk n + pure (denv, stk, k) +exec !_ !denv !_activeThreads !stk !k _ (Lit (MC c)) = do + stk <- bump stk + pokeC stk c + pure (denv, stk, k) +exec !_ !denv !_activeThreads !stk !k _ (Lit (MN n)) = do + stk <- bump stk + pokeN stk n pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (Lit (MD d)) = do stk <- bump stk @@ -611,14 +620,14 @@ encodeExn stk exc = do case exc of Right () -> do stk <- bump stk - stk <$ upoke stk 1 + stk <$ pokeTag stk 1 Left exn -> do -- If we hit an exception, we have one unused slot on the stack -- from where the result _would_ have been placed. -- So here we bump one less than it looks like we should, and re-use -- that slot. stk <- bumpn stk 3 - upoke stk 0 + pokeTag stk 0 bpokeOff stk 1 $ Foreign (Wrap Rf.typeLinkRef link) pokeOffBi stk 2 msg stk <$ bpokeOff stk 3 extra @@ -644,7 +653,7 @@ encodeExn stk exc = do | otherwise = (Rf.miscFailureRef, disp exn, unitValue) numValue :: Maybe Reference -> Closure -> IO Word64 -numValue _ (DataU1 _ _ i) = pure (fromIntegral i) +numValue _ (DataU1 _ _ i) = pure (fromIntegral $ getTUInt i) numValue mr clo = die $ "numValue: bad closure: " @@ -678,7 +687,7 @@ eval !env !denv !activeThreads !stk !k r (NMatch mr i br) = do eval env denv activeThreads stk k r $ selectBranch n br eval !env !denv !activeThreads !stk !k r (RMatch i pu br) = do (t, stk) <- dumpDataNoTag Nothing stk =<< bpeekOff stk i - if t == 0 + if t == PackedTag 0 then eval env denv activeThreads stk k r pu else case ANF.unpackTags t of (ANF.rawTag -> e, ANF.rawTag -> t) @@ -992,12 +1001,12 @@ dumpDataNoTag :: dumpDataNoTag !_ !stk (Enum _ t) = pure (t, stk) dumpDataNoTag !_ !stk (DataU1 _ t x) = do stk <- bump stk - upoke stk x + pokeTU stk x pure (t, stk) dumpDataNoTag !_ !stk (DataU2 _ t x y) = do stk <- bumpn stk 2 - upokeOff stk 1 y - upoke stk x + pokeOffTU stk 1 y + pokeTU stk x pure (t, stk) dumpDataNoTag !_ !stk (DataB1 _ t x) = do stk <- bump stk @@ -1010,13 +1019,13 @@ dumpDataNoTag !_ !stk (DataB2 _ t x y) = do pure (t, stk) dumpDataNoTag !_ !stk (DataUB _ t x y) = do stk <- bumpn stk 2 - upoke stk x + pokeTU stk x bpokeOff stk 1 y pure (t, stk) dumpDataNoTag !_ !stk (DataBU _ t x y) = do stk <- bumpn stk 2 bpoke stk x - upokeOff stk 1 y + pokeOffTU stk 1 y pure (t, stk) dumpDataNoTag !_ !stk (DataG _ t seg) = do stk <- dumpSeg stk seg S @@ -1089,22 +1098,22 @@ uprim1 !stk ABSF !i = do uprim1 !stk CEIL !i = do d <- peekOffD stk i stk <- bump stk - upoke stk (ceiling d) + pokeI stk (ceiling d) pure stk uprim1 !stk FLOR !i = do d <- peekOffD stk i stk <- bump stk - upoke stk (floor d) + pokeI stk (floor d) pure stk uprim1 !stk TRNF !i = do d <- peekOffD stk i stk <- bump stk - upoke stk (truncate d) + pokeI stk (truncate d) pure stk uprim1 !stk RNDF !i = do d <- peekOffD stk i stk <- bump stk - upoke stk (round d) + pokeI stk (round d) pure stk uprim1 !stk EXPF !i = do d <- peekOffD stk i @@ -1272,19 +1281,19 @@ uprim2 !stk EQLI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk $ if m == n then 1 else 0 + pokeBool stk $ m == n pure stk uprim2 !stk LEQI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upoke stk $ if m <= n then 1 else 0 + pokeBool stk $ m <= n pure stk uprim2 !stk LEQN !i !j = do m <- peekOffN stk i n <- peekOffN stk j stk <- bump stk - upoke stk $ if m <= n then 1 else 0 + pokeBool stk $ m <= n pure stk uprim2 !stk DIVN !i !j = do m <- peekOffN stk i @@ -1350,13 +1359,13 @@ uprim2 !stk EQLF !i !j = do x <- peekOffD stk i y <- peekOffD stk j stk <- bump stk - upoke stk (if x == y then 1 else 0) + pokeBool stk $ x == y pure stk uprim2 !stk LEQF !i !j = do x <- peekOffD stk i y <- peekOffD stk j stk <- bump stk - upoke stk (if x <= y then 1 else 0) + pokeBool stk $ x <= y pure stk uprim2 !stk ATN2 !i !j = do x <- peekOffD stk i @@ -1418,25 +1427,25 @@ bprim1 !stk USNC i = peekOffBi stk i >>= \t -> case Util.Text.unsnoc t of Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk Just (t, c) -> do stk <- bumpn stk 3 pokeOffC stk 2 $ c -- char value pokeOffBi stk 1 t -- remaining text - upoke stk 1 -- 'Just' tag + pokeTag stk 1 -- 'Just' tag pure stk bprim1 !stk UCNS i = peekOffBi stk i >>= \t -> case Util.Text.uncons t of Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk Just (c, t) -> do stk <- bumpn stk 3 pokeOffBi stk 2 t -- remaining text pokeOffC stk 1 $ c -- char value - upoke stk 1 -- 'Just' tag + pokeTag stk 1 -- 'Just' tag pure stk bprim1 !stk TTOI i = peekOffBi stk i >>= \t -> case readm $ Util.Text.unpack t of @@ -1444,12 +1453,12 @@ bprim1 !stk TTOI i = | fromIntegral (minBound :: Int) <= n, n <= fromIntegral (maxBound :: Int) -> do stk <- bumpn stk 2 - upoke stk 1 - upokeOff stk 1 (fromInteger n) + pokeTag stk 1 + pokeOffI stk 1 (fromInteger n) pure stk _ -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk where readm ('+' : s) = readMaybe s @@ -1460,47 +1469,47 @@ bprim1 !stk TTON i = | 0 <= n, n <= fromIntegral (maxBound :: Word) -> do stk <- bumpn stk 2 - upoke stk 1 + pokeTag stk 1 pokeOffN stk 1 (fromInteger n) pure stk _ -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk bprim1 !stk TTOF i = peekOffBi stk i >>= \t -> case readMaybe $ Util.Text.unpack t of Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk Just f -> do stk <- bumpn stk 2 - upoke stk 1 + pokeTag stk 1 pokeOffD stk 1 f pure stk bprim1 !stk VWLS i = peekOffS stk i >>= \case Sq.Empty -> do stk <- bump stk - upoke stk 0 -- 'Empty' tag + pokeTag stk 0 -- 'Empty' tag pure stk x Sq.:<| xs -> do stk <- bumpn stk 3 pokeOffS stk 2 xs -- remaining seq bpokeOff stk 1 x -- head - upoke stk 1 -- ':<|' tag + pokeTag stk 1 -- ':<|' tag pure stk bprim1 !stk VWRS i = peekOffS stk i >>= \case Sq.Empty -> do stk <- bump stk - upoke stk 0 -- 'Empty' tag + pokeTag stk 0 -- 'Empty' tag pure stk xs Sq.:|> x -> do stk <- bumpn stk 3 bpokeOff stk 2 x -- last pokeOffS stk 1 xs -- remaining seq - upoke stk 1 -- ':|>' tag + pokeTag stk 1 -- ':|>' tag pure stk bprim1 !stk PAKT i = do s <- peekOffS stk i @@ -2201,8 +2210,8 @@ reflectValue rty = goV ANF.Arr <$> traverse goV a | otherwise = die $ err $ "foreign value: " <> (show f) - reflectUData :: PackedTag -> Int -> IO ANF.BLit - reflectUData t v + reflectUData :: PackedTag -> TypedUnboxed -> IO ANF.BLit + reflectUData t (TypedUnboxed v _t) | t == TT.natTag = pure $ ANF.Pos (fromIntegral v) | t == TT.charTag = pure $ ANF.Char (toEnum v) | t == TT.intTag, v >= 0 = pure $ ANF.Pos (fromIntegral v) @@ -2210,6 +2219,9 @@ reflectValue rty = goV | t == TT.floatTag = pure $ ANF.Float (intToDouble v) | otherwise = die . err $ "unboxed data: " <> show (t, v) + intToDouble :: Int -> Double + intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 + reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Closure) reifyValue cc val = do erc <- diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index e752cda9fc..8d0effaee2 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -57,6 +57,7 @@ module Unison.Runtime.Stack pokeOffD, pokeC, pokeOffC, + pokeBool, pokeTag, peekTag, peekTagOff, @@ -248,6 +249,10 @@ pattern BlackHole = Closure GBlackHole pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) +{-# COMPLETE PAp, Enum, DataU1, DataU2, DataB1, DataB2, DataUB, DataBU, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} + +{-# COMPLETE DataC, Captured, Foreign, UnboxedTypeTag, BlackHole #-} + traceK :: Reference -> K -> [(Reference, Int)] traceK begin = dedup (begin, 1) where @@ -643,6 +648,13 @@ peekTagOff :: Stack -> Off -> IO Int peekTagOff = peekOffI {-# INLINE peekTagOff #-} +pokeBool :: Stack -> Bool -> IO () +pokeBool stk b = + -- Currently this is implemented as a tag, which is branched on to put a packed bool constructor on the stack, but + -- we'll want to change it to have its own unboxed type tag eventually. + pokeTag stk $ if b then 1 else 0 +{-# INLINE pokeBool #-} + -- | Store a boxed value. -- We don't bother nulling out the unboxed stack, -- it's extra work and there's nothing to garbage collect. From b6f67fa3ebb435113d2ec059b27cef50cea9b3d6 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 18:23:28 -0700 Subject: [PATCH 010/113] Finish re-writing upokes in Machine --- unison-runtime/src/Unison/Runtime/ANF.hs | 7 +- unison-runtime/src/Unison/Runtime/MCode.hs | 2 + unison-runtime/src/Unison/Runtime/Machine.hs | 84 +++++++++++--------- unison-runtime/src/Unison/Runtime/Stack.hs | 7 ++ 4 files changed, 61 insertions(+), 39 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 638a639842..2c2cb73c18 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -57,6 +57,7 @@ module Unison.Runtime.ANF GroupRef (..), Code (..), UBValue, + UnboxedValue(..), ValList, Value (..), Cont (..), @@ -1470,7 +1471,11 @@ data GroupRef = GR Reference Word64 deriving (Show) -- | A value which is either unboxed or boxed. -type UBValue = Either Word64 Value +type UBValue = Either UnboxedValue Value + +-- | An unboxed value and its packed tag +data UnboxedValue = UnboxedValue {uvValue :: Word64, uvTag :: PackedTag} + deriving (Show) -- | A list of either unboxed or boxed values. -- Each slot is one of unboxed or boxed but not both. diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 28e3c1b718..27438d6ed6 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -489,6 +489,8 @@ data GInstr comb | -- Push a particular value onto the appropriate stack Lit !MLit -- value to push onto the stack | -- Push a particular value directly onto the boxed stack + -- TODO: We don't actually need the ref/packed tag here, + -- we can always infer them from the constructor of MLit. BLit !Reference !PackedTag !MLit | -- Print a value on the unboxed stack Print !Int -- index of the primitive value to print diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 261d1bef60..05ffcd562b 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -294,7 +294,9 @@ lookupDenv :: Word64 -> DEnv -> Closure lookupDenv p denv = fromMaybe BlackHole $ EC.lookup p denv buildLit :: Reference -> PackedTag -> MLit -> Closure -buildLit rf tt (MI i) = DataU1 rf tt (TypedUnboxed i tt) +buildLit _ _ (MI i) = IntClosure i +buildLit _ _ (MN n) = NatClosure n +buildLit _ _ (MC c) = CharClosure c buildLit _ _ (MT t) = Foreign (Wrap Rf.textRef t) buildLit _ _ (MM r) = Foreign (Wrap Rf.termLinkRef r) buildLit _ _ (MY r) = Foreign (Wrap Rf.typeLinkRef r) @@ -356,7 +358,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 MISS i) _ -> error "exec:BPrim1:MISS: Expected Ref" m <- readTVarIO (intermed env) stk <- bump stk - if (link `M.member` m) then upoke stk 1 else upoke stk 0 + pokeTag stk $ if (link `M.member` m) then 1 else 0 pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 CACH i) | sandboxed env = die "attempted to use sandboxed operation: cache" @@ -377,7 +379,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 CVLD i) codeValidate (second codeGroup <$> news) env >>= \case Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure (denv, stk, k) Just (Failure ref msg clo) -> do stk <- bumpn stk 3 @@ -385,7 +387,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 CVLD i) pokeOffBi stk 1 msg bpokeOff stk 2 clo stk <- bump stk - upoke stk 1 + pokeTag stk 1 pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 LKUP i) | sandboxed env = die "attempted to use sandboxed operation: lookup" @@ -404,8 +406,8 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LKUP i) Just sn <- EC.lookup w numberedTermLookup -> do pokeBi stk (CodeRep (ANF.Rec [] sn) Uncacheable) stk <- bump stk - stk <$ upoke stk 1 - | otherwise -> stk <$ upoke stk 0 + stk <$ pokeTag stk 1 + | otherwise -> stk <$ pokeTag stk 0 Just sg -> do let ch | Just n <- M.lookup link rfn, @@ -414,7 +416,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LKUP i) | otherwise = Uncacheable pokeBi stk (CodeRep sg ch) stk <- bump stk - stk <$ upoke stk 1 + stk <$ pokeTag stk 1 pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (BPrim1 TLTT i) = do clink <- bpeekOff stk i @@ -435,10 +437,10 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LOAD i) pokeOffS stk 1 $ Sq.fromList $ Foreign . Wrap Rf.termLinkRef . Ref <$> miss - upoke stk 0 + pokeTag stk 0 Right x -> do bpokeOff stk 1 x - upoke stk 1 + pokeTag stk 1 pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 VALU i) = do m <- readTVarIO (tagRefs env) @@ -453,15 +455,15 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 DBTX i) clo <- bpeekOff stk i stk <- bump stk stk <- case tracer env False clo of - NoTrace -> stk <$ upoke stk 0 + NoTrace -> stk <$ pokeTag stk 0 MsgTrace _ _ tx -> do pokeBi stk (Util.Text.pack tx) stk <- bump stk - stk <$ upoke stk 1 + stk <$ pokeTag stk 1 SimpleTrace tx -> do pokeBi stk (Util.Text.pack tx) stk <- bump stk - stk <$ upoke stk 2 + stk <$ pokeTag stk 2 pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 SDBL i) | sandboxed env = @@ -480,7 +482,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim2 SDBX i j) = do l <- decodeSandboxArgument s b <- checkSandboxing env l c stk <- bump stk - upoke stk $ if b then 1 else 0 + pokeBool stk $ b pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim2 SDBV i j) | sandboxed env = @@ -497,7 +499,7 @@ exec !_ !denv !_activeThreads !stk !k _ (BPrim2 EQLU i j) = do x <- bpeekOff stk i y <- bpeekOff stk j stk <- bump stk - upoke stk $ if universalEq (==) x y then 1 else 0 + pokeBool stk $ universalEq (==) x y pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (BPrim2 CMPU i j) = do x <- bpeekOff stk i @@ -1577,7 +1579,7 @@ bprim2 !stk EQLU i j = do x <- bpeekOff stk i y <- bpeekOff stk j stk <- bump stk - upoke stk $ if universalEq (==) x y then 1 else 0 + pokeBool stk $ universalEq (==) x y pure stk bprim2 !stk IXOT i j = do x <- peekOffBi stk i @@ -1585,11 +1587,11 @@ bprim2 !stk IXOT i j = do case Util.Text.indexOf x y of Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk Just i -> do stk <- bumpn stk 2 - upoke stk 1 + pokeTag stk 1 pokeOffN stk 1 i pure stk bprim2 !stk IXOB i j = do @@ -1598,11 +1600,11 @@ bprim2 !stk IXOB i j = do case By.indexOf x y of Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk Just i -> do stk <- bumpn stk 2 - upoke stk 1 + pokeTag stk 1 pokeOffN stk 1 i pure stk bprim2 !stk DRPT i j = do @@ -1634,19 +1636,19 @@ bprim2 !stk EQLT i j = do x <- peekOffBi @Util.Text.Text stk i y <- peekOffBi stk j stk <- bump stk - upoke stk $ if x == y then 1 else 0 + pokeBool stk $ x == y pure stk bprim2 !stk LEQT i j = do x <- peekOffBi @Util.Text.Text stk i y <- peekOffBi stk j stk <- bump stk - upoke stk $ if x <= y then 1 else 0 + pokeBool stk $ x <= y pure stk bprim2 !stk LEST i j = do x <- peekOffBi @Util.Text.Text stk i y <- peekOffBi stk j stk <- bump stk - upoke stk $ if x < y then 1 else 0 + pokeBool stk $ x < y pure stk bprim2 !stk DRPS i j = do n <- upeekOff stk i @@ -1692,13 +1694,13 @@ bprim2 !stk IDXS i j = do case Sq.lookup n s of Nothing -> do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk Just x -> do stk <- bump stk bpoke stk x stk <- bump stk - upoke stk 1 + pokeTag stk 1 pure stk bprim2 !stk SPLL i j = do n <- upeekOff stk i @@ -1706,7 +1708,7 @@ bprim2 !stk SPLL i j = do if Sq.length s < n then do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk else do stk <- bumpn stk 2 @@ -1714,7 +1716,7 @@ bprim2 !stk SPLL i j = do pokeOffS stk 1 r pokeS stk l stk <- bump stk - upoke stk 1 + pokeTag stk 1 pure stk bprim2 !stk SPLR i j = do n <- upeekOff stk i @@ -1722,7 +1724,7 @@ bprim2 !stk SPLR i j = do if Sq.length s < n then do stk <- bump stk - upoke stk 0 + pokeTag stk 0 pure stk else do stk <- bumpn stk 2 @@ -1730,7 +1732,7 @@ bprim2 !stk SPLR i j = do pokeOffS stk 1 r pokeS stk l stk <- bump stk - upoke stk 1 + pokeTag stk 1 pure stk bprim2 !stk TAKB i j = do n <- upeekOff stk i @@ -1753,11 +1755,11 @@ bprim2 !stk IDXB i j = do b <- peekOffBi stk j stk <- bump stk stk <- case By.at n b of - Nothing -> stk <$ upoke stk 0 + Nothing -> stk <$ pokeTag stk 0 Just x -> do - upoke stk $ fromIntegral x + pokeByte stk x stk <- bump stk - stk <$ upoke stk 1 + stk <$ pokeTag stk 1 pure stk bprim2 !stk CATB i j = do l <- peekOffBi stk i @@ -1784,7 +1786,7 @@ yield !env !denv !activeThreads !stk !k = leap denv k leap !denv0 (Mark a ps cs k) = do let denv = cs <> EC.withoutKeys denv0 ps clo = denv0 EC.! EC.findMin ps - bpoke stk . DataB1 Rf.effectRef 0 =<< bpeek stk + bpoke stk . DataB1 Rf.effectRef (PackedTag 0) =<< bpeek stk stk <- adjustArgs stk a apply env denv activeThreads stk k False (VArg1 0) clo leap !denv (Push fsz asz (CIx ref _ _) f nx k) = do @@ -2167,12 +2169,12 @@ reflectValue rty = goV goV :: Closure -> IO ANF.Value goV (PApV cix _rComb args) = - ANF.Partial (goIx cix) <$> traverse (bitraverse (pure . fromIntegral) goV) args + ANF.Partial (goIx cix) <$> traverse (bitraverse (pure . typedUnboxedToUnboxedValue) goV) args goV (DataC _ t [Left w]) = ANF.BLit <$> reflectUData t w goV (DataC r t segs) = - ANF.Data r (maskTags t) <$> traverse (bitraverse (pure . fromIntegral) goV) segs + ANF.Data r (maskTags t) <$> traverse (bitraverse (pure . typedUnboxedToUnboxedValue) goV) segs goV (CapV k _ segs) = - ANF.Cont <$> traverse (bitraverse (pure . fromIntegral) goV) segs <*> goK k + ANF.Cont <$> traverse (bitraverse (pure . typedUnboxedToUnboxedValue) goV) segs <*> goK k goV (Foreign f) = ANF.BLit <$> goF f goV BlackHole = die $ err "black hole" @@ -2222,6 +2224,9 @@ reflectValue rty = goV intToDouble :: Int -> Double intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 + typedUnboxedToUnboxedValue :: TypedUnboxed -> ANF.UnboxedValue + typedUnboxedToUnboxedValue (TypedUnboxed v t) = ANF.UnboxedValue (fromIntegral v) t + reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Closure) reifyValue cc val = do erc <- @@ -2260,7 +2265,7 @@ reifyValue0 (combs, rty, rtm) = goV goV (ANF.Partial gr vs) = goIx gr >>= \case - (cix, RComb (Comb rcomb)) -> PApV cix rcomb <$> traverse (bitraverse (pure . fromIntegral) goV) vs + (cix, RComb (Comb rcomb)) -> PApV cix rcomb <$> traverse (bitraverse (pure . unboxedValueToTypedUnboxed) goV) vs (_, RComb (CachedClosure _ clo)) | [] <- vs -> pure clo | otherwise -> die . err $ msg @@ -2268,8 +2273,8 @@ reifyValue0 (combs, rty, rtm) = goV msg = "reifyValue0: non-trivial partial application to cached value" goV (ANF.Data r t0 vs) = do t <- flip packTags (fromIntegral t0) . fromIntegral <$> refTy r - DataC r t <$> traverse (bitraverse (pure . fromIntegral) goV) vs - goV (ANF.Cont vs k) = cv <$> goK k <*> traverse (bitraverse (pure . fromIntegral) goV) vs + DataC r t <$> traverse (bitraverse (pure . unboxedValueToTypedUnboxed) goV) vs + goV (ANF.Cont vs k) = cv <$> goK k <*> traverse (bitraverse (pure . unboxedValueToTypedUnboxed) goV) vs where cv k s = CapV k a s where @@ -2315,6 +2320,9 @@ reifyValue0 (combs, rty, rtm) = goV goL (ANF.Float d) = pure $ DoubleClosure d goL (ANF.Arr a) = Foreign . Wrap Rf.iarrayRef <$> traverse goV a + unboxedValueToTypedUnboxed :: ANF.UnboxedValue -> TypedUnboxed + unboxedValueToTypedUnboxed (ANF.UnboxedValue v t) = (TypedUnboxed (fromIntegral v) t) + -- Universal comparison functions closureNum :: Closure -> Int diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 8d0effaee2..35ded45840 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -69,6 +69,7 @@ module Unison.Runtime.Stack pokeOffN, pokeI, pokeOffI, + pokeByte, peekBi, peekOffBi, pokeBi, @@ -904,6 +905,12 @@ pokeI stk@(Stack _ _ sp ustk _) i = do writeByteArray ustk sp i {-# INLINE pokeI #-} +pokeByte :: Stack -> Word8 -> IO () +pokeByte stk b = do + -- NOTE: currently we just store bytes as ints, but we should have a separate type runtime type tag for them. + pokeI stk (fromIntegral b) +{-# INLINE pokeByte #-} + pokeOffN :: Stack -> Int -> Word64 -> IO () pokeOffN stk@(Stack _ _ sp ustk _) i n = do bpokeOff stk i (UnboxedTypeTag TT.natTag) From 1897ec00ab1cf7aedfafc1531e6eed498de9a015 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 09:51:36 -0700 Subject: [PATCH 011/113] Finish propagating runtime type tags --- unison-runtime/src/Unison/Runtime/Builtin.hs | 8 ++-- .../src/Unison/Runtime/Decompile.hs | 24 ++++-------- .../src/Unison/Runtime/Foreign/Function.hs | 39 +++++++++---------- .../src/Unison/Runtime/MCode/Serialize.hs | 27 ++++++++----- unison-runtime/src/Unison/Runtime/Stack.hs | 33 ++++++++++++---- 5 files changed, 74 insertions(+), 57 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 8a120bb0cc..64aa2b913e 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -2298,7 +2298,7 @@ unitValue :: Closure unitValue = Closure.Enum Ty.unitRef (PackedTag 0) natValue :: Word64 -> Closure -natValue w = Closure.DataU1 Ty.natRef (PackedTag 0) (fromIntegral w) +natValue w = Closure.NatClosure w mkForeignTls :: forall a r. @@ -3212,12 +3212,12 @@ declareForeigns = do \(beg, end) -> evaluate . TPat.cpattern . TPat.Char . TPat.Not $ TPat.CharRange beg end declareForeign Untracked "Text.patterns.charIn" boxDirect . mkForeign $ \ccs -> do cs <- for ccs $ \case - Closure.DataU1 _ _ i -> pure (toEnum i) + Closure.CharClosure c -> pure c _ -> die "Text.patterns.charIn: non-character closure" evaluate . TPat.cpattern . TPat.Char $ TPat.CharSet cs declareForeign Untracked "Text.patterns.notCharIn" boxDirect . mkForeign $ \ccs -> do cs <- for ccs $ \case - Closure.DataU1 _ _ i -> pure (toEnum i) + Closure.CharClosure c -> pure c _ -> die "Text.patterns.notCharIn: non-character closure" evaluate . TPat.cpattern . TPat.Char . TPat.Not $ TPat.CharSet cs declareForeign Untracked "Pattern.many" boxDirect . mkForeign $ @@ -3250,7 +3250,7 @@ declareForeigns = do declareForeign Untracked "Char.Class.range" (wordWordDirect charRef charRef) . mkForeign $ \(a, b) -> pure $ TPat.CharRange a b declareForeign Untracked "Char.Class.anyOf" boxDirect . mkForeign $ \ccs -> do cs <- for ccs $ \case - Closure.DataU1 _ _ i -> pure (toEnum i) + Closure.CharClosure c -> pure c _ -> die "Text.patterns.charIn: non-character closure" evaluate $ TPat.CharSet cs declareForeign Untracked "Char.Class.alphanumeric" direct . mkForeign $ \() -> pure (TPat.CharClass TPat.AlphaNum) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 564c08e16b..f85f08df1c 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -35,6 +35,7 @@ import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) import Unison.Runtime.MCode (CombIx (..)) import Unison.Runtime.Stack ( Closure (..), + getTUInt, pattern DataC, pattern PApV, ) @@ -62,13 +63,9 @@ import Unison.Term qualified as Term import Unison.Type ( anyRef, booleanRef, - charRef, - floatRef, iarrayRef, ibytearrayRef, - intRef, listRef, - natRef, termLinkRef, typeLinkRef, ) @@ -76,7 +73,7 @@ import Unison.Util.Bytes qualified as By import Unison.Util.Pretty (indentN, lines, lit, syntaxToColor, wrap) import Unison.Util.Text qualified as Text import Unison.Var (Var) -import Unsafe.Coerce -- for Int -> Double +-- for Int -> Double import Prelude hiding (lines) con :: (Var v) => Reference -> Word64 -> Term v () @@ -153,10 +150,14 @@ decompile :: Closure -> DecompResult v decompile backref topTerms = \case + CharClosure c -> pure (char () c) + NatClosure n -> pure (nat () n) + IntClosure i -> pure (int () (fromIntegral i)) + DoubleClosure f -> pure (float () f) DataC rf (maskTags -> ct) [] | rf == booleanRef -> tag2bool ct - DataC rf (maskTags -> ct) [Left i] -> - decompileUnboxed rf ct i + DataC rf _ [Left i] -> + err (BadUnboxed rf) . nat () $ fromIntegral $ getTUInt i (DataC rf _ [Right b]) | rf == anyRef -> app () (builtin () "Any.Any") <$> decompile backref topTerms b @@ -197,15 +198,6 @@ substitute = align [] -- this should not happen align vts tm ts = apps' (substs vts tm) ts -decompileUnboxed :: - (Var v) => Reference -> Word64 -> Int -> DecompResult v -decompileUnboxed r _ i - | r == natRef = pure . nat () $ fromIntegral i - | r == intRef = pure . int () $ fromIntegral i - | r == floatRef = pure . float () $ unsafeCoerce i - | r == charRef = pure . char () $ toEnum i - | otherwise = err (BadUnboxed r) . nat () $ fromIntegral i - decompileForeign :: (Var v) => (Reference -> Maybe Reference) -> diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 14a654781a..86dd05618a 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -24,6 +24,7 @@ import Data.Primitive.Array as PA import Data.Primitive.ByteArray as PA import Data.Sequence qualified as Sq import Data.Time.Clock.POSIX (POSIXTime) +import Data.Word (Word16, Word32, Word64, Word8) import GHC.IO.Exception (IOErrorType (..), IOException (..)) import Network.Socket (Socket) import Network.UDP (UDPSocket) @@ -88,12 +89,6 @@ mkForeign ev = FF readArgs writeForeign ev internalBug "mkForeign: too many arguments for foreign function" --- newtype UnisonInt = UnisonInt Int - --- newtype UnisonNat = UnisonNat Word64 - --- newtype UnisonDouble = UnisonDouble Double - instance ForeignConvention Int where readForeign (i : args) stk = (args,) <$> upeekOff stk i readForeign [] _ = foreignCCError "Int" @@ -101,24 +96,26 @@ instance ForeignConvention Int where stk <- bump stk stk <$ pokeI stk i --- instance ForeignConvention Word64 where --- readForeign (i : args) stk = (args,) <$> peekOffN stk i --- readForeign [] _ = foreignCCError "Word64" --- writeForeign stk n = do --- stk <- bump stk --- stk <$ pokeN stk n +instance ForeignConvention Word64 where + readForeign (i : args) stk = (args,) <$> peekOffN stk i + readForeign [] _ = foreignCCError "Word64" + writeForeign stk n = do + stk <- bump stk + stk <$ pokeN stk n + +-- We don't have a clear mapping from these types to Unison types, most are just mapped to Nats. --- instance ForeignConvention Word8 where --- readForeign = readForeignAs (fromIntegral :: Word64 -> Word8) --- writeForeign = writeForeignAs (fromIntegral :: Word8 -> Word64) +instance ForeignConvention Word8 where + readForeign = readForeignAs (fromIntegral :: Word64 -> Word8) + writeForeign = writeForeignAs (fromIntegral :: Word8 -> Word64) --- instance ForeignConvention Word16 where --- readForeign = readForeignAs (fromIntegral :: Word64 -> Word16) --- writeForeign = writeForeignAs (fromIntegral :: Word16 -> Word64) +instance ForeignConvention Word16 where + readForeign = readForeignAs (fromIntegral :: Word64 -> Word16) + writeForeign = writeForeignAs (fromIntegral :: Word16 -> Word64) --- instance ForeignConvention Word32 where --- readForeign = readForeignAs (fromIntegral :: Word64 -> Word32) --- writeForeign = writeForeignAs (fromIntegral :: Word32 -> Word64) +instance ForeignConvention Word32 where + readForeign = readForeignAs (fromIntegral :: Word64 -> Word32) + writeForeign = writeForeignAs (fromIntegral :: Word32 -> Word64) instance ForeignConvention Char where readForeign (i : args) stk = (args,) . Char.chr <$> upeekOff stk i diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 9d614190aa..749ca48a5b 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -22,6 +22,7 @@ import Unison.Runtime.ANF (PackedTag (..)) import Unison.Runtime.MCode hiding (MatchT) import Unison.Runtime.Serialize import Unison.Util.Text qualified as Util.Text +import Prelude hiding (getChar, putChar) data CombT = LamT | CachedClosureT @@ -318,24 +319,30 @@ putCombIx (CIx r n i) = putReference r *> pWord n *> pWord i getCombIx :: (MonadGet m) => m CombIx getCombIx = CIx <$> getReference <*> gWord <*> gWord -data MLitT = MIT | MDT | MTT | MMT | MYT +data MLitT = MIT | MNT | MCT | MDT | MTT | MMT | MYT instance Tag MLitT where tag2word MIT = 0 - tag2word MDT = 1 - tag2word MTT = 2 - tag2word MMT = 3 - tag2word MYT = 4 + tag2word MNT = 1 + tag2word MCT = 2 + tag2word MDT = 3 + tag2word MTT = 4 + tag2word MMT = 5 + tag2word MYT = 6 word2tag 0 = pure MIT - word2tag 1 = pure MDT - word2tag 2 = pure MTT - word2tag 3 = pure MMT - word2tag 4 = pure MYT + word2tag 1 = pure MNT + word2tag 2 = pure MCT + word2tag 3 = pure MDT + word2tag 4 = pure MTT + word2tag 5 = pure MMT + word2tag 6 = pure MYT word2tag n = unknownTag "MLitT" n putLit :: (MonadPut m) => MLit -> m () putLit (MI i) = putTag MIT *> pInt i +putLit (MN n) = putTag MNT *> pWord n +putLit (MC c) = putTag MCT *> putChar c putLit (MD d) = putTag MDT *> putFloat d putLit (MT t) = putTag MTT *> putText (Util.Text.toText t) putLit (MM r) = putTag MMT *> putReferent r @@ -345,6 +352,8 @@ getLit :: (MonadGet m) => m MLit getLit = getTag >>= \case MIT -> MI <$> gInt + MNT -> MN <$> gWord + MCT -> MC <$> getChar MDT -> MD <$> getFloat MTT -> MT . Util.Text.fromText <$> getText MMT -> MM <$> getReferent diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 35ded45840..3894c0753c 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -205,6 +205,8 @@ data GClosure comb GCaptured !K !Int {-# UNPACK #-} !Seg | GForeign !Foreign | -- The type tag for the value in the corresponding unboxed stack slot. + -- We should consider adding separate constructors for common builtin type tags. + -- GHC will optimize nullary constructors into singletons. GUnboxedTypeTag !PackedTag | GBlackHole deriving stock (Show, Functor, Foldable, Traversable) @@ -250,6 +252,23 @@ pattern BlackHole = Closure GBlackHole pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) +-- We can avoid allocating a closure for common type tags on each poke by having shared top-level closures for them. +natTypeTag :: Closure +natTypeTag = UnboxedTypeTag TT.natTag +{-# NOINLINE natTypeTag #-} + +intTypeTag :: Closure +intTypeTag = UnboxedTypeTag TT.intTag +{-# NOINLINE intTypeTag #-} + +charTypeTag :: Closure +charTypeTag = UnboxedTypeTag TT.charTag +{-# NOINLINE charTypeTag #-} + +floatTypeTag :: Closure +floatTypeTag = UnboxedTypeTag TT.floatTag +{-# NOINLINE floatTypeTag #-} + {-# COMPLETE PAp, Enum, DataU1, DataU2, DataB1, DataB2, DataUB, DataBU, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} {-# COMPLETE DataC, Captured, Foreign, UnboxedTypeTag, BlackHole #-} @@ -882,26 +901,26 @@ peekOffD (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) pokeN :: Stack -> Word64 -> IO () pokeN stk@(Stack _ _ sp ustk _) n = do - bpoke stk (UnboxedTypeTag TT.natTag) + bpoke stk natTypeTag writeByteArray ustk sp n {-# INLINE pokeN #-} pokeD :: Stack -> Double -> IO () pokeD stk@(Stack _ _ sp ustk _) d = do - bpoke stk (UnboxedTypeTag TT.floatTag) + bpoke stk floatTypeTag writeByteArray ustk sp d {-# INLINE pokeD #-} pokeC :: Stack -> Char -> IO () pokeC stk@(Stack _ _ sp ustk _) c = do - bpoke stk (UnboxedTypeTag TT.charTag) + bpoke stk charTypeTag writeByteArray ustk sp (Char.ord c) {-# INLINE pokeC #-} -- | Note: This is for poking an unboxed value that has the UNISON type 'int', not just any unboxed data. pokeI :: Stack -> Int -> IO () pokeI stk@(Stack _ _ sp ustk _) i = do - bpoke stk (UnboxedTypeTag TT.intTag) + bpoke stk intTypeTag writeByteArray ustk sp i {-# INLINE pokeI #-} @@ -913,19 +932,19 @@ pokeByte stk b = do pokeOffN :: Stack -> Int -> Word64 -> IO () pokeOffN stk@(Stack _ _ sp ustk _) i n = do - bpokeOff stk i (UnboxedTypeTag TT.natTag) + bpokeOff stk i natTypeTag writeByteArray ustk (sp - i) n {-# INLINE pokeOffN #-} pokeOffD :: Stack -> Int -> Double -> IO () pokeOffD stk@(Stack _ _ sp ustk _) i d = do - bpokeOff stk i (UnboxedTypeTag TT.floatTag) + bpokeOff stk i floatTypeTag writeByteArray ustk (sp - i) d {-# INLINE pokeOffD #-} pokeOffI :: Stack -> Int -> Int -> IO () pokeOffI stk@(Stack _ _ sp ustk _) i n = do - bpokeOff stk i (UnboxedTypeTag TT.intTag) + bpokeOff stk i intTypeTag writeByteArray ustk (sp - i) n {-# INLINE pokeOffI #-} From fbc5cc2b8d68e2d1933d324336ba686d8b847b2c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 24 Oct 2024 09:55:27 -0700 Subject: [PATCH 012/113] Pass type of unboxed values to decompilation --- .../src/Unison/Runtime/Decompile.hs | 28 +++++++++++------ unison-runtime/src/Unison/Runtime/Machine.hs | 4 +-- unison-runtime/src/Unison/Runtime/Stack.hs | 30 ++++++++++++++++++- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index f85f08df1c..c3e46591e1 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -35,10 +35,13 @@ import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) import Unison.Runtime.MCode (CombIx (..)) import Unison.Runtime.Stack ( Closure (..), + TypedUnboxed (..), getTUInt, pattern DataC, pattern PApV, ) +-- for Int -> Double + import Unison.Syntax.NamePrinter (prettyReference) import Unison.Term ( Term, @@ -73,7 +76,6 @@ import Unison.Util.Bytes qualified as By import Unison.Util.Pretty (indentN, lines, lit, syntaxToColor, wrap) import Unison.Util.Text qualified as Text import Unison.Var (Var) --- for Int -> Double import Prelude hiding (lines) con :: (Var v) => Reference -> Word64 -> Term v () @@ -144,6 +146,7 @@ renderDecompError Cont = "A continuation value was encountered" renderDecompError Exn = "An exception value was encountered" decompile :: + forall v. (Var v) => (Reference -> Maybe Reference) -> (Word64 -> Word64 -> Maybe (Term v ())) -> @@ -161,29 +164,36 @@ decompile backref topTerms = \case (DataC rf _ [Right b]) | rf == anyRef -> app () (builtin () "Any.Any") <$> decompile backref topTerms b - (DataC rf (maskTags -> ct) vs) - -- Only match lists of boxed args. - | ([], bs) <- partitionEithers vs -> - apps' (con rf ct) <$> traverse (decompile backref topTerms) bs - (PApV (CIx rf rt k) _ (partitionEithers -> ([], bs))) + (DataC rf (maskTags -> ct) vs) -> + apps' (con rf ct) <$> traverse decompUB vs + (PApV (CIx rf rt k) _ vs) | rf == Builtin "jumpCont" -> err Cont $ bug "" | Builtin nm <- rf -> - apps' (builtin () nm) <$> traverse (decompile backref topTerms) bs + apps' (builtin () nm) <$> traverse decompUB vs | Just t <- topTerms rt k -> Term.etaReduceEtaVars . substitute t - <$> traverse (decompile backref topTerms) bs + <$> traverse decompUB vs | k > 0, Just _ <- topTerms rt 0 -> err (UnkLocal rf k) $ bug "" | otherwise -> err (UnkComb rf) $ ref () rf (PAp (CIx rf _ _) _ _) -> err (BadPAp rf) $ bug "" - (DataC rf _ _) -> err (BadData rf) $ bug "" BlackHole -> err Exn $ bug "" (Captured {}) -> err Cont $ bug "" (Foreign f) -> decompileForeign backref topTerms f + where + decompileTypedUnboxed = \case + UnboxedNat i -> pure (nat () $ fromIntegral i) + UnboxedInt i -> pure (int () $ fromIntegral i) + UnboxedDouble i -> pure (float () i) + UnboxedChar i -> pure (char () i) + TypedUnboxed i _ -> err (BadUnboxed anyRef) $ nat () $ fromIntegral i + + decompUB :: (Either TypedUnboxed Closure) -> DecompResult v + decompUB = either decompileTypedUnboxed (decompile backref topTerms) tag2bool :: (Var v) => Word64 -> DecompResult v tag2bool 0 = pure (boolean () False) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 05ffcd562b..c81bf5a1ec 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1226,10 +1226,10 @@ uprim1 !stk COMN !i = do uprim2 :: Stack -> UPrim2 -> Int -> Int -> IO Stack uprim2 !stk ADDI !i !j = do - m <- upeekOff stk i + (m, t) <- peekOff stk i n <- upeekOff stk j stk <- bump stk - pokeI stk (m + n) + upokeT stk (m + n) t pure stk uprim2 !stk SUBI !i !j = do m <- upeekOff stk i diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 3894c0753c..9ae8e4b6e4 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -44,7 +44,15 @@ module Unison.Runtime.Stack USeg, BSeg, SegList, - TypedUnboxed (..), + TypedUnboxed + ( TypedUnboxed, + getTUInt, + getTUTag, + UnboxedChar, + UnboxedNat, + UnboxedInt, + UnboxedDouble + ), traceK, frameDataSize, marshalToForeign, @@ -373,6 +381,26 @@ unpackUnboxedClosure expectedTag = \case _ -> Nothing {-# INLINE unpackUnboxedClosure #-} +pattern UnboxedChar :: Char -> TypedUnboxed +pattern UnboxedChar c <- TypedUnboxed (Char.chr -> c) ((== TT.charTag) -> True) + where + UnboxedChar c = TypedUnboxed (Char.ord c) TT.charTag + +pattern UnboxedNat :: Word64 -> TypedUnboxed +pattern UnboxedNat n <- TypedUnboxed (toEnum -> n) ((== TT.natTag) -> True) + where + UnboxedNat n = TypedUnboxed (fromEnum n) TT.natTag + +pattern UnboxedInt :: Int -> TypedUnboxed +pattern UnboxedInt i <- TypedUnboxed i ((== TT.intTag) -> True) + where + UnboxedInt i = TypedUnboxed i TT.intTag + +pattern UnboxedDouble :: Double -> TypedUnboxed +pattern UnboxedDouble d <- TypedUnboxed (intToDouble -> d) ((== TT.floatTag) -> True) + where + UnboxedDouble d = TypedUnboxed (doubleToInt d) TT.floatTag + splitTaggedUnboxed :: TypedUnboxed -> (Int, Closure) splitTaggedUnboxed (TypedUnboxed i t) = (i, UnboxedTypeTag t) From e11b12c4a7a23254b8da87b06e74ede54e9f4c91 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 10:28:43 -0700 Subject: [PATCH 013/113] Add new Nat instrs to fix runtime types for Nat arithmetic --- unison-runtime/src/Unison/Runtime/MCode.hs | 216 ++++++++-------- unison-runtime/src/Unison/Runtime/Machine.hs | 54 +++- .../src/Unison/Runtime/Serialize.hs | 240 ++++++++++-------- 3 files changed, 290 insertions(+), 220 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 27438d6ed6..8808a4bac4 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -290,101 +290,109 @@ countArgs (VArgV {}) = internalBug "countArgs: DArgV" data UPrim1 = -- integral - DECI - | INCI - | NEGI - | SGNI -- decrement,increment,negate,signum - | LZRO - | TZRO - | COMN - | POPC -- leading/trailingZeroes,complement + DECI -- decrement + | DECN + | INCI -- increment + | INCN + | NEGI -- negate + | SGNI -- signum + | LZRO -- leadingZeroes + | TZRO -- trailingZeroes + | COMN -- complement + | POPC -- popCount -- floating - | ABSF - | EXPF - | LOGF - | SQRT -- abs,exp,log,sqrt - | COSF - | ACOS - | COSH - | ACSH -- cos,acos,cosh,acosh - | SINF - | ASIN - | SINH - | ASNH -- sin,asin,sinh,asinh - | TANF - | ATAN - | TANH - | ATNH -- tan,atan,tanh,atanh - | ITOF - | NTOF - | CEIL - | FLOR -- intToFloat,natToFloat,ceiling,floor - | TRNF - | RNDF -- truncate,round + | ABSF -- abs + | EXPF -- exp + | LOGF -- log + | SQRT -- sqrt + | COSF -- cos + | ACOS -- acos + | COSH -- cosh + | ACSH -- acosh + | SINF -- sin + | ASIN -- asin + | SINH -- sinh + | ASNH -- asinh + | TANF -- tan + | ATAN -- atan + | TANH -- tanh + | ATNH -- atanh + | ITOF -- intToFloat + | NTOF -- natToFloat + | CEIL -- ceiling + | FLOR -- floor + | TRNF -- truncate + | RNDF -- round deriving (Show, Eq, Ord) data UPrim2 = -- integral - ADDI - | SUBI + ADDI -- + + | ADDN + | SUBI -- - + | SUBN | MULI - | DIVI - | MODI -- +,-,*,/,mod + | MULN + | DIVI -- / | DIVN + | MODI -- mod | MODN - | SHLI - | SHRI + | SHLI -- shiftl + | SHLN + | SHRI -- shiftr | SHRN - | POWI -- shiftl,shiftr,shiftr,pow - | EQLI - | LEQI - | LEQN -- ==,<=,<= - | ANDN - | IORN - | XORN -- and,or,xor + | POWI -- pow + | POWN + | EQLI -- == + | EQLN + | LEQI -- <= + | LEQN + | ANDN -- and + | IORN -- or + | XORN -- xor -- floating - | EQLF - | LEQF -- ==,<= - | ADDF - | SUBF + | EQLF -- == + | LEQF -- <= + | ADDF -- + + | SUBF -- - | MULF - | DIVF - | ATN2 -- +,-,*,/,atan2 - | POWF - | LOGB - | MAXF - | MINF -- pow,low,max,min + | DIVF -- / + | ATN2 -- atan2 + | POWF -- pow + | LOGB -- logBase + | MAXF -- max + | MINF -- min deriving (Show, Eq, Ord) data BPrim1 = -- text - SIZT - | USNC - | UCNS -- size,unsnoc,uncons - | ITOT - | NTOT - | FTOT -- intToText,natToText,floatToText - | TTOI - | TTON - | TTOF -- textToInt,textToNat,textToFloat - | PAKT - | UPKT -- pack,unpack + SIZT -- size + | USNC -- unsnoc + | UCNS -- uncons + | ITOT -- intToText + | NTOT -- natToText + | FTOT -- floatToText + | TTOI -- textToInt + | TTON -- textToNat + | TTOF -- textToFloat + | PAKT -- pack + | UPKT -- unpack -- sequence - | VWLS - | VWRS - | SIZS -- viewl,viewr,size - | PAKB - | UPKB - | SIZB -- pack,unpack,size + | VWLS -- viewl + | VWRS -- viewr + | SIZS -- size + | PAKB -- pack + | UPKB -- unpack + | SIZB -- size | FLTB -- flatten -- code - | MISS - | CACH - | LKUP - | LOAD -- isMissing,cache_,lookup,load + | MISS -- isMissing + | CACH -- cache + | LKUP -- lookup + | LOAD -- load | CVLD -- validate - | VALU - | TLTT -- value, Term.Link.toText + | VALU -- value + | TLTT -- Term.Link.toText -- debug | DBTX -- debug text | SDBL -- sandbox link list @@ -392,30 +400,30 @@ data BPrim1 data BPrim2 = -- universal - EQLU - | CMPU -- ==,compare + EQLU -- == + | CMPU -- compare -- text - | DRPT - | CATT - | TAKT -- drop,append,take + | DRPT -- drop + | CATT -- append + | TAKT -- take | IXOT -- indexof - | EQLT - | LEQT - | LEST -- ==,<=,< + | EQLT -- == + | LEQT -- <= + | LEST -- < -- sequence - | DRPS - | CATS - | TAKS -- drop,append,take - | CONS - | SNOC - | IDXS -- cons,snoc,index - | SPLL - | SPLR -- splitLeft,splitRight + | DRPS -- drop + | CATS -- append + | TAKS -- take + | CONS -- cons + | SNOC -- snoc + | IDXS -- index + | SPLL -- splitLeft + | SPLR -- splitRight -- bytes - | TAKB - | DRPB - | IDXB - | CATB -- take,drop,index,append + | TAKB -- take + | DRPB -- drop + | IDXB -- index + | CATB -- append | IXOB -- indexof -- general | THRO -- throw @@ -1165,31 +1173,31 @@ emitLet rns grpr grpn rec d vcs ctx bnd emitPOp :: ANF.POp -> Args -> Instr -- Integral emitPOp ANF.ADDI = emitP2 ADDI -emitPOp ANF.ADDN = emitP2 ADDI +emitPOp ANF.ADDN = emitP2 ADDN emitPOp ANF.SUBI = emitP2 SUBI -emitPOp ANF.SUBN = emitP2 SUBI +emitPOp ANF.SUBN = emitP2 SUBN emitPOp ANF.MULI = emitP2 MULI -emitPOp ANF.MULN = emitP2 MULI +emitPOp ANF.MULN = emitP2 MULN emitPOp ANF.DIVI = emitP2 DIVI emitPOp ANF.DIVN = emitP2 DIVN emitPOp ANF.MODI = emitP2 MODI -- TODO: think about how these behave emitPOp ANF.MODN = emitP2 MODN -- TODO: think about how these behave emitPOp ANF.POWI = emitP2 POWI -emitPOp ANF.POWN = emitP2 POWI +emitPOp ANF.POWN = emitP2 POWN emitPOp ANF.SHLI = emitP2 SHLI -emitPOp ANF.SHLN = emitP2 SHLI -- Note: left shift behaves uniformly +emitPOp ANF.SHLN = emitP2 SHLN -- Note: left shift behaves uniformly emitPOp ANF.SHRI = emitP2 SHRI emitPOp ANF.SHRN = emitP2 SHRN emitPOp ANF.LEQI = emitP2 LEQI emitPOp ANF.LEQN = emitP2 LEQN emitPOp ANF.EQLI = emitP2 EQLI -emitPOp ANF.EQLN = emitP2 EQLI +emitPOp ANF.EQLN = emitP2 EQLN emitPOp ANF.SGNI = emitP1 SGNI emitPOp ANF.NEGI = emitP1 NEGI emitPOp ANF.INCI = emitP1 INCI -emitPOp ANF.INCN = emitP1 INCI +emitPOp ANF.INCN = emitP1 INCN emitPOp ANF.DECI = emitP1 DECI -emitPOp ANF.DECN = emitP1 DECI +emitPOp ANF.DECN = emitP1 DECN emitPOp ANF.TZRO = emitP1 TZRO emitPOp ANF.LZRO = emitP1 LZRO emitPOp ANF.POPC = emitP1 POPC diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index c81bf5a1ec..7972383b0c 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1073,15 +1073,25 @@ peekForeign stk i = uprim1 :: Stack -> UPrim1 -> Int -> IO Stack uprim1 !stk DECI !i = do - m <- upeekOff stk i + m <- peekOffI stk i stk <- bump stk pokeI stk (m - 1) pure stk +uprim1 !stk DECN !i = do + m <- peekOffN stk i + stk <- bump stk + pokeN stk (m - 1) + pure stk uprim1 !stk INCI !i = do - m <- upeekOff stk i + m <- peekOffI stk i stk <- bump stk pokeI stk (m + 1) pure stk +uprim1 !stk INCN !i = do + m <- peekOffN stk i + stk <- bump stk + pokeN stk (m + 1) + pure stk uprim1 !stk NEGI !i = do m <- upeekOff stk i stk <- bump stk @@ -1226,10 +1236,16 @@ uprim1 !stk COMN !i = do uprim2 :: Stack -> UPrim2 -> Int -> Int -> IO Stack uprim2 !stk ADDI !i !j = do - (m, t) <- peekOff stk i + m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk - upokeT stk (m + n) t + pokeI stk (m + n) + pure stk +uprim2 !stk ADDN !i !j = do + m <- peekOffN stk i + n <- peekOffN stk j + stk <- bump stk + pokeN stk (m + n) pure stk uprim2 !stk SUBI !i !j = do m <- upeekOff stk i @@ -1237,12 +1253,24 @@ uprim2 !stk SUBI !i !j = do stk <- bump stk pokeI stk (m - n) pure stk +uprim2 !stk SUBN !i !j = do + m <- peekOffN stk i + n <- peekOffN stk j + stk <- bump stk + pokeN stk (m - n) + pure stk uprim2 !stk MULI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk pokeI stk (m * n) pure stk +uprim2 !stk MULN !i !j = do + m <- peekOffN stk i + n <- peekOffN stk j + stk <- bump stk + pokeN stk (m * n) + pure stk uprim2 !stk DIVI !i !j = do m <- upeekOff stk i n <- upeekOff stk j @@ -1261,6 +1289,12 @@ uprim2 !stk SHLI !i !j = do stk <- bump stk pokeI stk (m `shiftL` n) pure stk +uprim2 !stk SHLN !i !j = do + m <- peekOffN stk i + n <- upeekOff stk j + stk <- bump stk + pokeN stk (m `shiftL` n) + pure stk uprim2 !stk SHRI !i !j = do m <- upeekOff stk i n <- upeekOff stk j @@ -1279,12 +1313,24 @@ uprim2 !stk POWI !i !j = do stk <- bump stk pokeI stk (m ^ n) pure stk +uprim2 !stk POWN !i !j = do + m <- peekOffN stk i + n <- peekOffN stk j + stk <- bump stk + pokeN stk (m ^ n) + pure stk uprim2 !stk EQLI !i !j = do m <- upeekOff stk i n <- upeekOff stk j stk <- bump stk pokeBool stk $ m == n pure stk +uprim2 !stk EQLN !i !j = do + m <- peekOffN stk i + n <- peekOffN stk j + stk <- bump stk + pokeBool stk $ m == n + pure stk uprim2 !stk LEQI !i !j = do m <- upeekOff stk i n <- upeekOff stk j diff --git a/unison-runtime/src/Unison/Runtime/Serialize.hs b/unison-runtime/src/Unison/Runtime/Serialize.hs index 394b846a0b..b93dfd3fef 100644 --- a/unison-runtime/src/Unison/Runtime/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/Serialize.hs @@ -296,126 +296,142 @@ getConstructorReference = instance Tag UPrim1 where tag2word DECI = 0 - tag2word INCI = 1 - tag2word NEGI = 2 - tag2word SGNI = 3 - tag2word LZRO = 4 - tag2word TZRO = 5 - tag2word COMN = 6 - tag2word POPC = 7 - tag2word ABSF = 8 - tag2word EXPF = 9 - tag2word LOGF = 10 - tag2word SQRT = 11 - tag2word COSF = 12 - tag2word ACOS = 13 - tag2word COSH = 14 - tag2word ACSH = 15 - tag2word SINF = 16 - tag2word ASIN = 17 - tag2word SINH = 18 - tag2word ASNH = 19 - tag2word TANF = 20 - tag2word ATAN = 21 - tag2word TANH = 22 - tag2word ATNH = 23 - tag2word ITOF = 24 - tag2word NTOF = 25 - tag2word CEIL = 26 - tag2word FLOR = 27 - tag2word TRNF = 28 - tag2word RNDF = 29 + tag2word DECN = 1 + tag2word INCI = 2 + tag2word INCN = 3 + tag2word NEGI = 4 + tag2word SGNI = 5 + tag2word LZRO = 6 + tag2word TZRO = 7 + tag2word COMN = 8 + tag2word POPC = 9 + tag2word ABSF = 10 + tag2word EXPF = 11 + tag2word LOGF = 12 + tag2word SQRT = 13 + tag2word COSF = 14 + tag2word ACOS = 15 + tag2word COSH = 16 + tag2word ACSH = 17 + tag2word SINF = 18 + tag2word ASIN = 19 + tag2word SINH = 20 + tag2word ASNH = 21 + tag2word TANF = 22 + tag2word ATAN = 23 + tag2word TANH = 24 + tag2word ATNH = 25 + tag2word ITOF = 26 + tag2word NTOF = 27 + tag2word CEIL = 28 + tag2word FLOR = 29 + tag2word TRNF = 30 + tag2word RNDF = 31 word2tag 0 = pure DECI - word2tag 1 = pure INCI - word2tag 2 = pure NEGI - word2tag 3 = pure SGNI - word2tag 4 = pure LZRO - word2tag 5 = pure TZRO - word2tag 6 = pure COMN - word2tag 7 = pure POPC - word2tag 8 = pure ABSF - word2tag 9 = pure EXPF - word2tag 10 = pure LOGF - word2tag 11 = pure SQRT - word2tag 12 = pure COSF - word2tag 13 = pure ACOS - word2tag 14 = pure COSH - word2tag 15 = pure ACSH - word2tag 16 = pure SINF - word2tag 17 = pure ASIN - word2tag 18 = pure SINH - word2tag 19 = pure ASNH - word2tag 20 = pure TANF - word2tag 21 = pure ATAN - word2tag 22 = pure TANH - word2tag 23 = pure ATNH - word2tag 24 = pure ITOF - word2tag 25 = pure NTOF - word2tag 26 = pure CEIL - word2tag 27 = pure FLOR - word2tag 28 = pure TRNF - word2tag 29 = pure RNDF + word2tag 1 = pure DECN + word2tag 2 = pure INCI + word2tag 3 = pure INCN + word2tag 4 = pure NEGI + word2tag 5 = pure SGNI + word2tag 6 = pure LZRO + word2tag 7 = pure TZRO + word2tag 8 = pure COMN + word2tag 9 = pure POPC + word2tag 10 = pure ABSF + word2tag 11 = pure EXPF + word2tag 12 = pure LOGF + word2tag 13 = pure SQRT + word2tag 14 = pure COSF + word2tag 15 = pure ACOS + word2tag 16 = pure COSH + word2tag 17 = pure ACSH + word2tag 18 = pure SINF + word2tag 19 = pure ASIN + word2tag 20 = pure SINH + word2tag 21 = pure ASNH + word2tag 22 = pure TANF + word2tag 23 = pure ATAN + word2tag 24 = pure TANH + word2tag 25 = pure ATNH + word2tag 26 = pure ITOF + word2tag 27 = pure NTOF + word2tag 28 = pure CEIL + word2tag 29 = pure FLOR + word2tag 30 = pure TRNF + word2tag 31 = pure RNDF word2tag n = unknownTag "UPrim1" n instance Tag UPrim2 where tag2word ADDI = 0 - tag2word SUBI = 1 - tag2word MULI = 2 - tag2word DIVI = 3 - tag2word MODI = 4 - tag2word DIVN = 5 - tag2word MODN = 6 - tag2word SHLI = 7 - tag2word SHRI = 8 - tag2word SHRN = 9 - tag2word POWI = 10 - tag2word EQLI = 11 - tag2word LEQI = 12 - tag2word LEQN = 13 - tag2word ANDN = 14 - tag2word IORN = 15 - tag2word XORN = 16 - tag2word EQLF = 17 - tag2word LEQF = 18 - tag2word ADDF = 19 - tag2word SUBF = 20 - tag2word MULF = 21 - tag2word DIVF = 22 - tag2word ATN2 = 23 - tag2word POWF = 24 - tag2word LOGB = 25 - tag2word MAXF = 26 - tag2word MINF = 27 + tag2word ADDN = 1 + tag2word SUBI = 2 + tag2word SUBN = 3 + tag2word MULI = 4 + tag2word MULN = 5 + tag2word DIVI = 6 + tag2word MODI = 7 + tag2word DIVN = 8 + tag2word MODN = 9 + tag2word SHLI = 10 + tag2word SHLN = 11 + tag2word SHRI = 12 + tag2word SHRN = 13 + tag2word POWI = 14 + tag2word POWN = 15 + tag2word EQLI = 16 + tag2word EQLN = 17 + tag2word LEQI = 18 + tag2word LEQN = 19 + tag2word ANDN = 20 + tag2word IORN = 21 + tag2word XORN = 22 + tag2word EQLF = 23 + tag2word LEQF = 24 + tag2word ADDF = 25 + tag2word SUBF = 26 + tag2word MULF = 27 + tag2word DIVF = 28 + tag2word ATN2 = 29 + tag2word POWF = 30 + tag2word LOGB = 31 + tag2word MAXF = 32 + tag2word MINF = 33 word2tag 0 = pure ADDI - word2tag 1 = pure SUBI - word2tag 2 = pure MULI - word2tag 3 = pure DIVI - word2tag 4 = pure MODI - word2tag 5 = pure DIVN - word2tag 6 = pure MODN - word2tag 7 = pure SHLI - word2tag 8 = pure SHRI - word2tag 9 = pure SHRN - word2tag 10 = pure POWI - word2tag 11 = pure EQLI - word2tag 12 = pure LEQI - word2tag 13 = pure LEQN - word2tag 14 = pure ANDN - word2tag 15 = pure IORN - word2tag 16 = pure XORN - word2tag 17 = pure EQLF - word2tag 18 = pure LEQF - word2tag 19 = pure ADDF - word2tag 20 = pure SUBF - word2tag 21 = pure MULF - word2tag 22 = pure DIVF - word2tag 23 = pure ATN2 - word2tag 24 = pure POWF - word2tag 25 = pure LOGB - word2tag 26 = pure MAXF - word2tag 27 = pure MINF + word2tag 1 = pure ADDN + word2tag 2 = pure SUBI + word2tag 3 = pure SUBN + word2tag 4 = pure MULI + word2tag 5 = pure MULN + word2tag 6 = pure DIVI + word2tag 7 = pure MODI + word2tag 8 = pure DIVN + word2tag 9 = pure MODN + word2tag 10 = pure SHLI + word2tag 11 = pure SHLN + word2tag 12 = pure SHRI + word2tag 13 = pure SHRN + word2tag 14 = pure POWI + word2tag 15 = pure POWN + word2tag 16 = pure EQLI + word2tag 17 = pure EQLN + word2tag 18 = pure LEQI + word2tag 19 = pure LEQN + word2tag 20 = pure ANDN + word2tag 21 = pure IORN + word2tag 22 = pure XORN + word2tag 23 = pure EQLF + word2tag 24 = pure LEQF + word2tag 25 = pure ADDF + word2tag 26 = pure SUBF + word2tag 27 = pure MULF + word2tag 28 = pure DIVF + word2tag 29 = pure ATN2 + word2tag 30 = pure POWF + word2tag 31 = pure LOGB + word2tag 32 = pure MAXF + word2tag 33 = pure MINF word2tag n = unknownTag "UPrim2" n instance Tag BPrim1 where From 5dbe3dfe855625d3582ae6e0af1487afa5be6db1 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 11:10:25 -0700 Subject: [PATCH 014/113] Fix SubN --- unison-runtime/src/Unison/Runtime/Machine.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 7972383b0c..c21d3ba44a 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1254,10 +1254,10 @@ uprim2 !stk SUBI !i !j = do pokeI stk (m - n) pure stk uprim2 !stk SUBN !i !j = do - m <- peekOffN stk i - n <- peekOffN stk j + m <- peekOffI stk i + n <- peekOffI stk j stk <- bump stk - pokeN stk (m - n) + pokeI stk (m - n) pure stk uprim2 !stk MULI !i !j = do m <- upeekOff stk i From 5770fd4b3ae5f526ea809ae27f27da0c729ad46c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 13:33:54 -0700 Subject: [PATCH 015/113] Add instruction comments --- unison-runtime/src/Unison/Runtime/ANF.hs | 228 +++++++++++------------ 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 2c2cb73c18..6293837f03 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -57,7 +57,7 @@ module Unison.Runtime.ANF GroupRef (..), Code (..), UBValue, - UnboxedValue(..), + UnboxedValue (..), ValList, Value (..), Cont (..), @@ -1244,139 +1244,139 @@ litRef (LY _) = Ty.typeLinkRef -- formats that we want to control and version. data POp = -- Int - ADDI - | SUBI + ADDI -- + + | SUBI -- - | MULI - | DIVI -- +,-,*,/ - | SGNI - | NEGI - | MODI -- sgn,neg,mod - | POWI - | SHLI - | SHRI -- pow,shiftl,shiftr - | INCI - | DECI - | LEQI - | EQLI -- inc,dec,<=,== + | DIVI -- / + | SGNI -- sgn + | NEGI -- neg + | MODI -- mod + | POWI -- pow + | SHLI -- shiftl + | SHRI -- shiftr + | INCI -- inc + | DECI -- dec + | LEQI -- <= + | EQLI -- == -- Nat - | ADDN - | SUBN + | ADDN -- + + | SUBN -- - | MULN - | DIVN -- +,-,*,/ - | MODN - | TZRO - | LZRO - | POPC -- mod,trailing/leadingZeros,popCount - | POWN - | SHLN - | SHRN -- pow,shiftl,shiftr - | ANDN - | IORN - | XORN - | COMN -- and,or,xor,complement - | INCN - | DECN - | LEQN - | EQLN -- inc,dec,<=,== + | DIVN -- / + | MODN -- mod + | TZRO -- trailingZeros + | LZRO -- leadingZeros + | POPC -- popCount + | POWN -- pow + | SHLN -- shiftl + | SHRN -- shiftr + | ANDN -- and + | IORN -- or + | XORN -- xor + | COMN -- complement + | INCN -- inc + | DECN -- dec + | LEQN -- <= + | EQLN -- == -- Float - | ADDF - | SUBF + | ADDF -- + + | SUBF -- - | MULF - | DIVF -- +,-,*,/ - | MINF - | MAXF - | LEQF - | EQLF -- min,max,<=,== - | POWF - | EXPF - | SQRT - | LOGF -- pow,exp,sqrt,log + | DIVF -- / + | MINF -- min + | MAXF -- max + | LEQF -- <= + | EQLF -- == + | POWF -- pow + | EXPF -- exp + | SQRT -- sqrt + | LOGF -- log | LOGB -- logBase - | ABSF - | CEIL - | FLOR - | TRNF -- abs,ceil,floor,truncate + | ABSF -- abs + | CEIL -- ceil + | FLOR -- floor + | TRNF -- truncate | RNDF -- round -- Trig - | COSF - | ACOS - | COSH - | ACSH -- cos,acos,cosh,acosh - | SINF - | ASIN - | SINH - | ASNH -- sin,asin,sinh,asinh - | TANF - | ATAN - | TANH - | ATNH -- tan,atan,tanh,atanh + | COSF -- cos + | ACOS -- acos + | COSH -- cosh + | ACSH -- acosh + | SINF -- sin + | ASIN -- asin + | SINH -- sinh + | ASNH -- asinh + | TANF -- tan + | ATAN -- atan + | TANH -- tanh + | ATNH -- atanh | ATN2 -- atan2 -- Text - | CATT - | TAKT - | DRPT - | SIZT -- ++,take,drop,size + | CATT -- ++ + | TAKT -- take + | DRPT -- drop + | SIZT -- size | IXOT -- indexOf - | UCNS - | USNC - | EQLT - | LEQT -- uncons,unsnoc,==,<= - | PAKT - | UPKT -- pack,unpack + | UCNS -- uncons + | USNC -- unsnoc + | EQLT -- == + | LEQT -- <= + | PAKT -- pack + | UPKT -- unpack -- Sequence - | CATS - | TAKS - | DRPS - | SIZS -- ++,take,drop,size - | CONS - | SNOC - | IDXS - | BLDS -- cons,snoc,at,build - | VWLS - | VWRS - | SPLL - | SPLR -- viewl,viewr,splitl,splitr + | CATS -- ++ + | TAKS -- take + | DRPS -- drop + | SIZS -- size + | CONS -- cons + | SNOC -- snoc + | IDXS -- at + | BLDS -- build + | VWLS -- viewl + | VWRS -- viewr + | SPLL -- splitl + | SPLR -- splitr -- Bytes - | PAKB - | UPKB - | TAKB - | DRPB -- pack,unpack,take,drop + | PAKB -- pack + | UPKB -- unpack + | TAKB -- take + | DRPB -- drop | IXOB -- indexOf - | IDXB - | SIZB - | FLTB - | CATB -- index,size,flatten,append + | IDXB -- index + | SIZB -- size + | FLTB -- flatten + | CATB -- append -- Conversion - | ITOF - | NTOF - | ITOT - | NTOT - | TTOI - | TTON - | TTOF - | FTOT + | ITOF -- intToFloat + | NTOF -- natToFloat + | ITOT -- intToText + | NTOT -- natToText + | TTOI -- textToInt + | TTON -- textToNat + | TTOF -- textToFloat + | FTOT -- floatToText | -- Concurrency - FORK + FORK -- fork | -- Universal operations - EQLU - | CMPU - | EROR + EQLU -- == + | CMPU -- compare + | EROR -- error | -- Code - MISS - | CACH - | LKUP - | LOAD -- isMissing,cache_,lookup,load - | CVLD - | SDBX -- validate, sandbox - | VALU - | TLTT -- value, Term.Link.toText + MISS -- isMissing + | CACH -- cache_ + | LKUP -- lookup + | LOAD -- load + | CVLD -- validate + | SDBX -- sandbox + | VALU -- value + | TLTT -- Term.Link.toText -- Debug - | PRNT - | INFO - | TRCE - | DBTX + | PRNT -- print + | INFO -- info + | TRCE -- trace + | DBTX -- debugText | -- STM - ATOM + ATOM -- atomically | TFRC -- try force | SDBL -- sandbox link list | SDBV -- sandbox check for Values From 8d5934382df7bed5f3c74ab7e8b011a031f3a1a7 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 13:28:56 -0700 Subject: [PATCH 016/113] Remove most unboxes --- unison-runtime/src/Unison/Runtime/Builtin.hs | 255 +++++++----------- .../src/Unison/Runtime/Foreign/Function.hs | 5 +- unison-runtime/src/Unison/Runtime/Machine.hs | 4 +- unison-runtime/src/Unison/Runtime/Stack.hs | 10 + 4 files changed, 118 insertions(+), 156 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 64aa2b913e..8ce2171e87 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -348,36 +348,32 @@ binop' :: binop' pop _rfx _rfy _rfr = binop0 0 $ \[ x, y] -> TPrm pop [x, y] +-- | Lift a comparison op. cmpop :: (Var v) => POp -> Reference -> SuperNormal v -cmpop pop rf = - binop0 3 $ \[x0, y0, x, y, b] -> - unbox x0 rf x - . unbox y0 rf y - . TLetD b UN (TPrm pop [x, y]) +cmpop pop _rf = + binop0 1 $ \[x, y, b] -> + TLetD b UN (TPrm pop [x, y]) $ boolift b +-- | Like `cmpop`, but swaps the arguments. cmpopb :: (Var v) => POp -> Reference -> SuperNormal v -cmpopb pop rf = - binop0 3 $ \[x0, y0, x, y, b] -> - unbox x0 rf x - . unbox y0 rf y - . TLetD b UN (TPrm pop [y, x]) +cmpopb pop _rf = + binop0 1 $ \[ x, y, b] -> + TLetD b UN (TPrm pop [y, x]) $ boolift b +-- | Like `cmpop`, but negates the result. cmpopn :: (Var v) => POp -> Reference -> SuperNormal v -cmpopn pop rf = - binop0 3 $ \[x0, y0, x, y, b] -> - unbox x0 rf x - . unbox y0 rf y - . TLetD b UN (TPrm pop [x, y]) +cmpopn pop _rf = + binop0 1 $ \[ x, y, b] -> + TLetD b UN (TPrm pop [x, y]) $ notlift b +-- | Like `cmpop`, but swaps arguments then negates the result. cmpopbn :: (Var v) => POp -> Reference -> SuperNormal v -cmpopbn pop rf = - binop0 3 $ \[x0, y0, x, y, b] -> - unbox x0 rf x - . unbox y0 rf y - . TLetD b UN (TPrm pop [y, x]) +cmpopbn pop _rf = + binop0 3 $ \[x, y, b] -> + TLetD b UN (TPrm pop [y, x]) $ notlift b addi, subi, muli, divi, modi, shli, shri, powi :: (Var v) => SuperNormal v @@ -507,20 +503,18 @@ i2f = unop' ITOF Ty.intRef Ty.floatRef n2f = unop' NTOF Ty.natRef Ty.floatRef trni :: (Var v) => SuperNormal v -trni = unop0 3 $ \[x0, x, z, b] -> - unbox x0 Ty.intRef x - . TLetD z UN (TLit $ I 0) +trni = unop0 2 $ \[x, z, b] -> + TLetD z UN (TLit $ I 0) . TLetD b UN (TPrm LEQI [x, z]) . TMatch b $ MatchIntegral - (mapSingleton 1 $ TCon Ty.natRef 0 [z]) - (Just $ TCon Ty.natRef 0 [x]) + (mapSingleton 1 $ TVar z) + (Just $ TVar x) modular :: (Var v) => POp -> (Bool -> ANormal v) -> SuperNormal v modular pop ret = - unop0 3 $ \[x0, x, m, t] -> - unbox x0 Ty.intRef x - . TLetD t UN (TLit $ I 2) + unop0 2 $ \[x, m, t] -> + TLetD t UN (TLit $ I 2) . TLetD m UN (TPrm pop [x, t]) . TMatch m $ MatchIntegral @@ -534,42 +528,30 @@ evnn = modular MODN (\b -> if b then fls else tru) oddn = modular MODN (\b -> if b then tru else fls) dropn :: (Var v) => SuperNormal v -dropn = binop0 4 $ \[x0, y0, x, y, b, r] -> - unbox x0 Ty.natRef x - . unbox y0 Ty.natRef y - . TLetD b UN (TPrm LEQN [x, y]) - . TLet - (Indirect 1) - r - UN - ( TMatch b $ +dropn = binop0 1 $ \[x, y, b] -> + TLetD b UN (TPrm LEQN [x, y]) + $ ( TMatch b $ MatchIntegral (mapSingleton 1 $ TLit $ N 0) (Just $ TPrm SUBN [x, y]) ) - $ TCon Ty.natRef 0 [r] appendt, taket, dropt, indext, indexb, sizet, unconst, unsnoct :: (Var v) => SuperNormal v appendt = binop0 0 $ \[x, y] -> TPrm CATT [x, y] -taket = binop0 1 $ \[x0, y, x] -> - unbox x0 Ty.natRef x $ +taket = binop0 0 $ \[x, y] -> TPrm TAKT [x, y] -dropt = binop0 1 $ \[x0, y, x] -> - unbox x0 Ty.natRef x $ +dropt = binop0 0 $ \[x, y] -> TPrm DRPT [x, y] -atb = binop0 4 $ \[n0, b, n, t, r0, r] -> - unbox n0 Ty.natRef n - . TLetD t UN (TPrm IDXB [n, b]) +atb = binop0 2 $ \[n, b, t, r] -> + TLetD t UN (TPrm IDXB [n, b]) . TMatch t . MatchSum $ mapFromList [ (0, ([], none)), ( 1, ( [UN], - TAbs r0 - . TLetD r BX (TCon Ty.natRef 0 [r0]) - $ some r + TAbs r $ some r ) ) ] @@ -655,18 +637,11 @@ coerceType fromType toType = unop0 1 $ \[x, r] -> TCon toType 0 [r] takes, drops, sizes, ats, emptys :: (Var v) => SuperNormal v -takes = binop0 1 $ \[x0, y, x] -> - unbox x0 Ty.natRef x $ - TPrm TAKS [x, y] -drops = binop0 1 $ \[x0, y, x] -> - unbox x0 Ty.natRef x $ - TPrm DRPS [x, y] -sizes = unop0 1 $ \[x, r] -> - TLetD r UN (TPrm SIZS [x]) $ - TCon Ty.natRef 0 [r] -ats = binop0 3 $ \[x0, y, x, t, r] -> - unbox x0 Ty.natRef x - . TLetD t UN (TPrm IDXS [x, y]) +takes = binop0 0 $ \[x, y] -> TPrm TAKS [x, y] +drops = binop0 0 $ \[x, y] -> TPrm DRPS [x, y] +sizes = unop0 0 $ \[x] -> (TPrm SIZS [x]) +ats = binop0 2 $ \[x, y, t, r] -> + TLetD t UN (TPrm IDXS [x, y]) . TMatch t . MatchSum $ mapFromList @@ -694,18 +669,16 @@ viewrs = unop0 3 $ \[s, u, i, l] -> ] splitls, splitrs :: (Var v) => SuperNormal v -splitls = binop0 4 $ \[n0, s, n, t, l, r] -> - unbox n0 Ty.natRef n - . TLetD t UN (TPrm SPLL [n, s]) +splitls = binop0 3 $ \[n, s, t, l, r] -> + TLetD t UN (TPrm SPLL [n, s]) . TMatch t . MatchSum $ mapFromList [ (0, ([], seqViewEmpty)), (1, ([BX, BX], TAbss [l, r] $ seqViewElem l r)) ] -splitrs = binop0 4 $ \[n0, s, n, t, l, r] -> - unbox n0 Ty.natRef n - . TLetD t UN (TPrm SPLR [n, s]) +splitrs = binop0 3 $ \[n, s, t, l, r] -> + TLetD t UN (TPrm SPLR [n, s]) . TMatch t . MatchSum $ mapFromList @@ -749,27 +722,15 @@ emptyb = appendb = binop0 0 $ \[x, y] -> TPrm CATB [x, y] takeb, dropb, atb, sizeb, flattenb :: SuperNormal Symbol -takeb = binop0 1 $ \[n0, b, n] -> - unbox n0 Ty.natRef n $ - TPrm TAKB [n, b] -dropb = binop0 1 $ \[n0, b, n] -> - unbox n0 Ty.natRef n $ - TPrm DRPB [n, b] -sizeb = unop0 1 $ \[b, n] -> - TLetD n UN (TPrm SIZB [b]) $ - TCon Ty.natRef 0 [n] +takeb = binop0 0 $ \[n, b] -> TPrm TAKB [n, b] +dropb = binop0 0 $ \[n, b] -> TPrm DRPB [n, b] +sizeb = unop0 0 $ \[b] -> (TPrm SIZB [b]) flattenb = unop0 0 $ \[b] -> TPrm FLTB [b] i2t, n2t, f2t :: SuperNormal Symbol -i2t = unop0 1 $ \[n0, n] -> - unbox n0 Ty.intRef n $ - TPrm ITOT [n] -n2t = unop0 1 $ \[n0, n] -> - unbox n0 Ty.natRef n $ - TPrm NTOT [n] -f2t = unop0 1 $ \[f0, f] -> - unbox f0 Ty.floatRef f $ - TPrm FTOT [f] +i2t = unop0 0 $ \[n] -> TPrm ITOT [n] +n2t = unop0 0 $ \[n] -> TPrm NTOT [n] +f2t = unop0 0 $ \[f] -> TPrm FTOT [f] t2i, t2n, t2f :: SuperNormal Symbol t2i = unop0 3 $ \[x, t, n0, n] -> @@ -1088,11 +1049,10 @@ seek'handle instr = ([BX, BX, BX],) . TAbss [arg1, arg2, arg3] . unenum 3 arg2 Ty.seekModeRef seek - . unbox arg3 Ty.intRef nat - . TLetD result UN (TFOp instr [arg1, seek, nat]) + . TLetD result UN (TFOp instr [arg1, seek, arg3]) $ outIoFailUnit stack1 stack2 stack3 unit fail result where - (arg1, arg2, arg3, seek, nat, stack1, stack2, stack3, unit, fail, result) = fresh + (arg1, arg2, arg3, seek, stack1, stack2, stack3, unit, fail, result) = fresh no'buf, line'buf, block'buf, sblock'buf :: (Enum e) => e no'buf = toEnum $ fromIntegral Ty.bufferModeNoBufferingId @@ -1113,8 +1073,7 @@ box b u ty = TLetD b BX (TCon ty 0 [u]) time'zone :: ForeignOp time'zone instr = ([BX],) - . TAbss [bsecs] - . unbox bsecs Ty.intRef secs + . TAbss [secs] . TLets Direct [offset, summer, name] [UN, UN, BX] (TFOp instr [secs]) . box bsummer summer Ty.natRef . box boffset offset Ty.intRef @@ -1123,7 +1082,7 @@ time'zone instr = . TLetD p1 BX (TCon Ty.pairRef 0 [bsummer, p2]) $ TCon Ty.pairRef 0 [boffset, p1] where - (secs, bsecs, offset, boffset, summer, bsummer, name, un, p2, p1) = fresh + (secs, offset, boffset, summer, bsummer, name, un, p2, p1) = fresh start'process :: ForeignOp start'process instr = @@ -1266,11 +1225,10 @@ inBx arg result cont instr = $ TLetD result UN (TFOp instr [arg]) cont -- Nat -> ... -inNat :: forall v. (Var v) => v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inNat arg nat result cont instr = +inNat :: forall v. (Var v) => v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +inNat nat result cont instr = ([BX],) - . TAbs arg - . unbox arg Ty.natRef nat + . TAbs nat $ TLetD result UN (TFOp instr [nat]) cont -- Maybe a -> b -> ... @@ -1315,28 +1273,24 @@ set'echo instr = (arg1, arg2, bol, stack1, stack2, stack3, unit, fail, result) = fresh -- a -> Nat -> ... -inBxNat :: forall v. (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxNat arg1 arg2 nat result cont instr = +inBxNat :: forall v. (Var v) => v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +inBxNat arg1 arg2 result cont instr = ([BX, BX],) . TAbss [arg1, arg2] - . unbox arg2 Ty.natRef nat - $ TLetD result UN (TFOp instr [arg1, nat]) cont + $ TLetD result UN (TFOp instr [arg1, arg2]) cont inBxNatNat :: - (Var v) => v -> v -> v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxNatNat arg1 arg2 arg3 nat1 nat2 result cont instr = + (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +inBxNatNat arg1 arg2 arg3 result cont instr = ([BX, BX, BX],) . TAbss [arg1, arg2, arg3] - . unbox arg2 Ty.natRef nat1 - . unbox arg3 Ty.natRef nat2 - $ TLetD result UN (TFOp instr [arg1, nat1, nat2]) cont + $ TLetD result UN (TFOp instr [arg1, arg2, arg3]) cont -inBxNatBx :: (Var v) => v -> v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxNatBx arg1 arg2 arg3 nat result cont instr = +inBxNatBx :: (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +inBxNatBx arg1 arg2 arg3 result cont instr = ([BX, BX, BX],) . TAbss [arg1, arg2, arg3] - . unbox arg2 Ty.natRef nat - $ TLetD result UN (TFOp instr [arg1, nat, arg3]) cont + $ TLetD result UN (TFOp instr [arg1, arg2, arg3]) cont -- a -> IOMode -> ... inBxIomr :: forall v. (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) @@ -1714,59 +1668,63 @@ boxBoxBoxToBool = -- Works for an type that's packed into a word, just -- pass `wordDirect Ty.natRef`, `wordDirect Ty.floatRef` -- etc +-- +-- TODO: Do we still need this? wordDirect :: Reference -> ForeignOp -wordDirect wordType instr = +wordDirect _wordType instr = ([BX],) - . TAbss [b1] - . unbox b1 wordType ub1 + . TAbss [ub1] $ TFOp instr [ub1] where - (b1, ub1) = fresh + ub1 = fresh1 -- Nat -> Bool +-- +-- TODO: Do we still need this? boxWordToBool :: Reference -> ForeignOp -boxWordToBool wordType instr = +boxWordToBool _wordType instr = ([BX, BX],) - . TAbss [b1, w1] - . unbox w1 wordType uw1 + . TAbss [b1, uw1] $ TLetD result UN (TFOp instr [b1, uw1]) (boolift result) where - (b1, w1, uw1, result) = fresh + (b1, uw1, result) = fresh -- Nat -> Nat -> c +-- +-- TODO: Do we still need this? wordWordDirect :: Reference -> Reference -> ForeignOp -wordWordDirect word1 word2 instr = +wordWordDirect _word1 _word2 instr = ([BX, BX],) - . TAbss [b1, b2] - . unbox b1 word1 ub1 - . unbox b2 word2 ub2 + . TAbss [ub1, ub2] $ TFOp instr [ub1, ub2] where - (b1, b2, ub1, ub2) = fresh + (ub1, ub2) = fresh -- Nat -> a -> c -- Works for an type that's packed into a word, just -- pass `wordBoxDirect Ty.natRef`, `wordBoxDirect Ty.floatRef` -- etc +-- +-- TODO: Do we still need this? wordBoxDirect :: Reference -> ForeignOp -wordBoxDirect wordType instr = +wordBoxDirect _wordType instr = ([BX, BX],) - . TAbss [b1, b2] - . unbox b1 wordType ub1 + . TAbss [ub1, b2] $ TFOp instr [ub1, b2] where - (b1, b2, ub1) = fresh + (b2, ub1) = fresh -- a -> Nat -> c -- works for any second argument type that is packed into a word +-- +-- TODO: Do we still need this? boxWordDirect :: Reference -> ForeignOp -boxWordDirect wordType instr = +boxWordDirect _wordType instr = ([BX, BX],) - . TAbss [b1, b2] - . unbox b2 wordType ub2 + . TAbss [b1, ub2] $ TFOp instr [b1, ub2] where - (b1, b2, ub2) = fresh + (b1, ub2) = fresh -- a -> b -> c boxBoxDirect :: ForeignOp @@ -1947,12 +1905,10 @@ natNatToBox = wordWordDirect Ty.natRef Ty.natRef natNatBoxToBox :: ForeignOp natNatBoxToBox instr = ([BX, BX, BX],) - . TAbss [a1, a2, a3] - . unbox a1 Ty.natRef ua1 - . unbox a2 Ty.natRef ua2 + . TAbss [ua1, ua2, a3] $ TFOp instr [ua1, ua2, a3] where - (a1, a2, a3, ua1, ua2) = fresh + (a3, ua1, ua2) = fresh -- a -> Nat -> c -- Nat only @@ -1962,63 +1918,60 @@ boxNatToBox = boxWordDirect Ty.natRef -- a -> Nat -> Either Failure b boxNatToEFBox :: ForeignOp boxNatToEFBox = - inBxNat arg1 arg2 nat result $ + inBxNat arg1 arg2 result $ outIoFail stack1 stack2 stack3 any fail result where - (arg1, arg2, nat, stack1, stack2, stack3, any, fail, result) = fresh + (arg1, arg2, stack1, stack2, stack3, any, fail, result) = fresh -- a -> Nat ->{Exception} b boxNatToExnBox :: ForeignOp boxNatToExnBox = - inBxNat arg1 arg2 nat result $ + inBxNat arg1 arg2 result $ outIoExnBox stack1 stack2 stack3 fail any result where - (arg1, arg2, nat, stack1, stack2, stack3, any, fail, result) = fresh + (arg1, arg2, stack1, stack2, stack3, any, fail, result) = fresh -- a -> Nat -> b ->{Exception} () boxNatBoxToExnUnit :: ForeignOp boxNatBoxToExnUnit = - inBxNatBx arg1 arg2 arg3 nat result $ + inBxNatBx arg1 arg2 arg3 result $ outIoExnUnit stack1 stack2 stack3 any fail result where - (arg1, arg2, arg3, nat, stack1, stack2, stack3, any, fail, result) = fresh + (arg1, arg2, arg3, stack1, stack2, stack3, any, fail, result) = fresh -- a -> Nat ->{Exception} Nat boxNatToExnNat :: ForeignOp boxNatToExnNat = - inBxNat arg1 arg2 nat result $ + inBxNat arg1 arg2 result $ outIoExnNat stack1 stack2 stack3 any fail result where - (arg1, arg2, nat, stack1, stack2, stack3, any, fail, result) = fresh + (arg1, arg2, stack1, stack2, stack3, any, fail, result) = fresh -- a -> Nat -> Nat ->{Exception} () boxNatNatToExnUnit :: ForeignOp boxNatNatToExnUnit = - inBxNatNat arg1 arg2 arg3 nat1 nat2 result $ + inBxNatNat arg1 arg2 arg3 result $ outIoExnUnit stack1 stack2 stack3 any fail result where - (arg1, arg2, arg3, nat1, nat2, result, stack1, stack2, stack3, any, fail) = fresh + (arg1, arg2, arg3, result, stack1, stack2, stack3, any, fail) = fresh -- a -> Nat -> Nat ->{Exception} b boxNatNatToExnBox :: ForeignOp boxNatNatToExnBox = - inBxNatNat arg1 arg2 arg3 nat1 nat2 result $ + inBxNatNat arg1 arg2 arg3 result $ outIoExnBox stack1 stack2 stack3 any fail result where - (arg1, arg2, arg3, nat1, nat2, result, stack1, stack2, stack3, any, fail) = fresh + (arg1, arg2, arg3, result, stack1, stack2, stack3, any, fail) = fresh -- a -> Nat -> b -> Nat -> Nat ->{Exception} () boxNatBoxNatNatToExnUnit :: ForeignOp boxNatBoxNatNatToExnUnit instr = ([BX, BX, BX, BX, BX],) - . TAbss [a0, a1, a2, a3, a4] - . unbox a1 Ty.natRef ua1 - . unbox a3 Ty.natRef ua3 - . unbox a4 Ty.natRef ua4 + . TAbss [a0, ua1, a2, ua3, ua4] . TLetD result UN (TFOp instr [a0, ua1, a2, ua3, ua4]) $ outIoExnUnit stack1 stack2 stack3 any fail result where - (a0, a1, a2, a3, a4, ua1, ua3, ua4, result, stack1, stack2, stack3, any, fail) = fresh + (a0, a2, ua1, ua3, ua4, result, stack1, stack2, stack3, any, fail) = fresh -- a ->{Exception} Either b c boxToExnEBoxBox :: ForeignOp @@ -2039,7 +1992,7 @@ boxToExnEBoxBox instr = -- Nat -> Either Failure () natToEFUnit :: ForeignOp natToEFUnit = - inNat arg nat result + inNat nat result . TMatch result . MatchSum $ mapFromList @@ -2051,7 +2004,7 @@ natToEFUnit = ) ] where - (arg, nat, result, fail, stack1, stack2, stack3, unit) = fresh + (nat, result, fail, stack1, stack2, stack3, unit) = fresh -- a -> Either b c boxToEBoxBox :: ForeignOp diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 86dd05618a..8e592cb123 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -17,7 +17,6 @@ import Control.Concurrent.MVar (MVar) import Control.Concurrent.STM (TVar) import Control.Exception (evaluate) import Data.Atomics (Ticket) -import Data.Char qualified as Char import Data.Foldable (toList) import Data.IORef (IORef) import Data.Primitive.Array as PA @@ -90,7 +89,7 @@ mkForeign ev = FF readArgs writeForeign ev "mkForeign: too many arguments for foreign function" instance ForeignConvention Int where - readForeign (i : args) stk = (args,) <$> upeekOff stk i + readForeign (i : args) stk = (args,) <$> peekOffI stk i readForeign [] _ = foreignCCError "Int" writeForeign stk i = do stk <- bump stk @@ -118,7 +117,7 @@ instance ForeignConvention Word32 where writeForeign = writeForeignAs (fromIntegral :: Word32 -> Word64) instance ForeignConvention Char where - readForeign (i : args) stk = (args,) . Char.chr <$> upeekOff stk i + readForeign (i : args) stk = (args,) <$> peekOffC stk i readForeign [] _ = foreignCCError "Char" writeForeign stk ch = do stk <- bump stk diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index c21d3ba44a..280013507a 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -958,9 +958,9 @@ buildData !_ !r !t ZArgs = pure $ Enum r t buildData !stk !r !t (VArg1 i) = do bv <- bpeekOff stk i case bv of - UnboxedTypeTag t -> do + UnboxedTypeTag ut -> do uv <- upeekOff stk i - pure $ DataU1 r t (TypedUnboxed uv t) + pure $ DataU1 r t (TypedUnboxed uv ut) _ -> pure $ DataB1 r t bv buildData !stk !r !t (VArg2 i j) = do b1 <- bpeekOff stk i diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 9ae8e4b6e4..dd8b1ed692 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -61,6 +61,8 @@ module Unison.Runtime.Stack nullSeg, peekD, peekOffD, + peekC, + peekOffC, pokeD, pokeOffD, pokeC, @@ -919,6 +921,10 @@ peekD :: Stack -> IO Double peekD (Stack _ _ sp ustk _) = readByteArray ustk sp {-# INLINE peekD #-} +peekC :: Stack -> IO Char +peekC (Stack _ _ sp ustk _) = Char.chr <$> readByteArray ustk sp +{-# INLINE peekC #-} + peekOffN :: Stack -> Int -> IO Word64 peekOffN (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) {-# INLINE peekOffN #-} @@ -927,6 +933,10 @@ peekOffD :: Stack -> Int -> IO Double peekOffD (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) {-# INLINE peekOffD #-} +peekOffC :: Stack -> Int -> IO Char +peekOffC (Stack _ _ sp ustk _) i = Char.chr <$> readByteArray ustk (sp - i) +{-# INLINE peekOffC #-} + pokeN :: Stack -> Word64 -> IO () pokeN stk@(Stack _ _ sp ustk _) n = do bpoke stk natTypeTag From 0ec982a1181728d7b4392d7f7ba2cb89926d65af Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 14:28:25 -0700 Subject: [PATCH 017/113] Undo most natRef boxing --- unison-runtime/src/Unison/Runtime/Builtin.hs | 58 ++++++++------------ 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 8ce2171e87..351faa53f9 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -556,7 +556,7 @@ atb = binop0 2 $ \[n, b, t, r] -> ) ] -indext = binop0 3 $ \[x, y, t, r0, r] -> +indext = binop0 2 $ \[x, y, t, r] -> TLetD t UN (TPrm IXOT [x, y]) . TMatch t . MatchSum @@ -564,14 +564,12 @@ indext = binop0 3 $ \[x, y, t, r0, r] -> [ (0, ([], none)), ( 1, ( [UN], - TAbs r0 - . TLetD r BX (TCon Ty.natRef 0 [r0]) - $ some r + TAbs r $ some r ) ) ] -indexb = binop0 3 $ \[x, y, t, i, r] -> +indexb = binop0 2 $ \[x, y, t, r] -> TLetD t UN (TPrm IXOB [x, y]) . TMatch t . MatchSum @@ -579,16 +577,12 @@ indexb = binop0 3 $ \[x, y, t, i, r] -> [ (0, ([], none)), ( 1, ( [UN], - TAbs i - . TLetD r BX (TCon Ty.natRef 0 [i]) - $ some r + TAbs r $ some r ) ) ] -sizet = unop0 1 $ \[x, r] -> - TLetD r UN (TPrm SIZT [x]) $ - TCon Ty.natRef 0 [r] +sizet = unop0 0 $ \[x] -> TPrm SIZT [x] unconst = unop0 7 $ \[x, t, c0, c, y, p, u, yp] -> TLetD t UN (TPrm UCNS [x]) @@ -747,7 +741,7 @@ t2i = unop0 3 $ \[x, t, n0, n] -> ) ) ] -t2n = unop0 3 $ \[x, t, n0, n] -> +t2n = unop0 2 $ \[x, t, n] -> TLetD t UN (TPrm TTON [x]) . TMatch t . MatchSum @@ -755,9 +749,7 @@ t2n = unop0 3 $ \[x, t, n0, n] -> [ (0, ([], none)), ( 1, ( [UN], - TAbs n0 - . TLetD n BX (TCon Ty.natRef 0 [n0]) - $ some n + TAbs n $ some n ) ) ] @@ -1155,8 +1147,7 @@ get'buffering'output eitherResult stack1 stack2 stack3 resultTag anyVar failVar sblock'buf --> [UN] --> TAbs stack1 - . TLetD stack2 BX (TCon Ty.natRef 0 [stack1]) - . TLetD successVar BX (TCon Ty.bufferModeRef sblock'buf [stack2]) + . TLetD successVar BX (TCon Ty.bufferModeRef sblock'buf [stack1]) $ right successVar ] ) @@ -1183,10 +1174,9 @@ murmur'hash instr = ([BX],) . TAbss [x] . TLetD vl BX (TPrm VALU [x]) - . TLetD result UN (TFOp instr [vl]) - $ TCon Ty.natRef 0 [result] + $ TFOp instr [vl] where - (x, vl, result) = fresh + (x, vl) = fresh crypto'hmac :: ForeignOp crypto'hmac instr = @@ -1327,15 +1317,13 @@ outMaybeNat tag result n = [ (0, ([], none)), ( 1, ( [UN], - TAbs result - . TLetD n BX (TCon Ty.natRef 0 [n]) - $ some n + TAbs result $ some n ) ) ] -outMaybeNTup :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> v -> ANormal v -outMaybeNTup a b n u bp p result = +outMaybeNTup :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v +outMaybeNTup a b u bp p result = TMatch result . MatchSum $ mapFromList [ (0, ([], none)), @@ -1344,8 +1332,7 @@ outMaybeNTup a b n u bp p result = TAbss [a, b] . TLetD u BX (TCon Ty.unitRef 0 []) . TLetD bp BX (TCon Ty.pairRef 0 [b, u]) - . TLetD n BX (TCon Ty.natRef 0 [a]) - . TLetD p BX (TCon Ty.pairRef 0 [n, bp]) + . TLetD p BX (TCon Ty.pairRef 0 [a, bp]) $ some p ) ) @@ -1385,8 +1372,7 @@ outIoFailNat stack1 stack2 stack3 fail extra result = ( 1, ([UN],) . TAbs stack3 - . TLetD extra BX (TCon Ty.natRef 0 [stack3]) - $ right extra + $ right stack3 ) ] @@ -1430,9 +1416,10 @@ outIoExnNat stack1 stack2 stack3 any fail result = mapFromList [ exnCase stack1 stack2 stack3 any fail, ( 1, + -- TODO: Can I simplify this? ([UN],) . TAbs stack1 - $ TCon Ty.natRef 0 [stack1] + $ TVar stack1 ) ] @@ -1603,7 +1590,7 @@ boxToInt = inBx arg result (TCon Ty.intRef 0 [result]) -- a -> Nat boxToNat :: ForeignOp -boxToNat = inBx arg result (TCon Ty.natRef 0 [result]) +boxToNat = inBx arg result (TVar result) where (arg, result) = fresh @@ -1635,10 +1622,9 @@ boxBoxToNat :: ForeignOp boxBoxToNat instr = ([BX, BX],) . TAbss [arg1, arg2] - . TLetD result UN (TFOp instr [arg1, arg2]) - $ TCon Ty.natRef 0 [result] + $ (TFOp instr [arg1, arg2]) where - (arg1, arg2, result) = fresh + (arg1, arg2) = fresh -- a -> b -> Option c @@ -1792,9 +1778,9 @@ boxToMaybeNat = inBx arg tag $ outMaybeNat tag result n -- a -> Maybe (Nat, b) boxToMaybeNTup :: ForeignOp boxToMaybeNTup = - inBx arg result $ outMaybeNTup a b c u bp p result + inBx arg result $ outMaybeNTup a b u bp p result where - (arg, a, b, c, u, bp, p, result) = fresh + (arg, a, b, u, bp, p, result) = fresh -- a -> b -> Maybe (c, d) boxBoxToMaybeTup :: ForeignOp From 15e8ac2d64a987ce1df70bbd0d1da20688a2135b Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 14:33:09 -0700 Subject: [PATCH 018/113] Remove most int/float/char reboxings --- unison-runtime/src/Unison/Runtime/Builtin.hs | 37 ++++++++------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 351faa53f9..62416dfacb 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -584,7 +584,7 @@ indexb = binop0 2 $ \[x, y, t, r] -> sizet = unop0 0 $ \[x] -> TPrm SIZT [x] -unconst = unop0 7 $ \[x, t, c0, c, y, p, u, yp] -> +unconst = unop0 6 $ \[x, t, c, y, p, u, yp] -> TLetD t UN (TPrm UCNS [x]) . TMatch t . MatchSum @@ -592,17 +592,16 @@ unconst = unop0 7 $ \[x, t, c0, c, y, p, u, yp] -> [ (0, ([], none)), ( 1, ( [UN, BX], - TAbss [c0, y] + TAbss [c, y] . TLetD u BX (TCon Ty.unitRef 0 []) . TLetD yp BX (TCon Ty.pairRef 0 [y, u]) - . TLetD c BX (TCon Ty.charRef 0 [c0]) . TLetD p BX (TCon Ty.pairRef 0 [c, yp]) $ some p ) ) ] -unsnoct = unop0 7 $ \[x, t, c0, c, y, p, u, cp] -> +unsnoct = unop0 6 $ \[x, t, c, y, p, u, cp] -> TLetD t UN (TPrm USNC [x]) . TMatch t . MatchSum @@ -610,9 +609,8 @@ unsnoct = unop0 7 $ \[x, t, c0, c, y, p, u, cp] -> [ (0, ([], none)), ( 1, ( [BX, UN], - TAbss [y, c0] + TAbss [y, c] . TLetD u BX (TCon Ty.unitRef 0 []) - . TLetD c BX (TCon Ty.charRef 0 [c0]) . TLetD cp BX (TCon Ty.pairRef 0 [c, u]) . TLetD p BX (TCon Ty.pairRef 0 [y, cp]) $ some p @@ -727,7 +725,7 @@ n2t = unop0 0 $ \[n] -> TPrm NTOT [n] f2t = unop0 0 $ \[f] -> TPrm FTOT [f] t2i, t2n, t2f :: SuperNormal Symbol -t2i = unop0 3 $ \[x, t, n0, n] -> +t2i = unop0 2 $ \[x, t, n] -> TLetD t UN (TPrm TTOI [x]) . TMatch t . MatchSum @@ -735,9 +733,7 @@ t2i = unop0 3 $ \[x, t, n0, n] -> [ (0, ([], none)), ( 1, ( [UN], - TAbs n0 - . TLetD n BX (TCon Ty.intRef 0 [n0]) - $ some n + TAbs n $ some n ) ) ] @@ -753,7 +749,7 @@ t2n = unop0 2 $ \[x, t, n] -> ) ) ] -t2f = unop0 3 $ \[x, t, f0, f] -> +t2f = unop0 2 $ \[x, t, f] -> TLetD t UN (TPrm TTOF [x]) . TMatch t . MatchSum @@ -761,9 +757,7 @@ t2f = unop0 3 $ \[x, t, f0, f] -> [ (0, ([], none)), ( 1, ( [UN], - TAbs f0 - . TLetD f BX (TCon Ty.floatRef 0 [f0]) - $ some f + TAbs f $ some f ) ) ] @@ -774,10 +768,9 @@ equ = binop0 1 $ \[x, y, b] -> boolift b cmpu :: SuperNormal Symbol -cmpu = binop0 2 $ \[x, y, c, i] -> +cmpu = binop0 1 $ \[x, y, c] -> TLetD c UN (TPrm CMPU [x, y]) - . TLetD i UN (TPrm DECI [c]) - $ TCon Ty.intRef 0 [i] + $ (TPrm DECI [c]) ltu :: SuperNormal Symbol ltu = binop0 1 $ \[x, y, c] -> @@ -1383,8 +1376,7 @@ outIoFailChar stack1 stack2 stack3 fail extra result = [ failureCase stack1 stack2 stack3 extra fail, ( 1, ([UN],) - . TAbs stack3 - . TLetD extra BX (TCon Ty.charRef 0 [stack3]) + . TAbs extra $ right extra ) ] @@ -1569,8 +1561,7 @@ unitToEFNat = -- () -> Int unitToInt :: ForeignOp unitToInt = - inUnit unit result $ - TCon Ty.intRef 0 [result] + inUnit unit result $ TVar result where (unit, result) = fresh @@ -1583,8 +1574,10 @@ unitToEFBox = (unit, stack1, stack2, stack3, fail, any, result) = fresh -- a -> Int +-- +-- TODO: Probably don't need all these boxing type wrapper things now. boxToInt :: ForeignOp -boxToInt = inBx arg result (TCon Ty.intRef 0 [result]) +boxToInt = inBx arg result (TVar result) where (arg, result) = fresh From 25aeb88ad0c11c7da939616e207a971e3d559ba3 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 14:59:37 -0700 Subject: [PATCH 019/113] Fix bad args --- unison-runtime/src/Unison/Runtime/Builtin.hs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 62416dfacb..44462549a6 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -372,7 +372,7 @@ cmpopn pop _rf = -- | Like `cmpop`, but swaps arguments then negates the result. cmpopbn :: (Var v) => POp -> Reference -> SuperNormal v cmpopbn pop _rf = - binop0 3 $ \[x, y, b] -> + binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [y, x]) $ notlift b @@ -1310,7 +1310,10 @@ outMaybeNat tag result n = [ (0, ([], none)), ( 1, ( [UN], - TAbs result $ some n + -- TODO: Fix this? + TAbs result + . TLetD n BX (TCon Ty.natRef 0 [n]) + $ some n ) ) ] From fd87e56e4d51a72bd75ba62252ad447a353996dc Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 25 Oct 2024 14:59:37 -0700 Subject: [PATCH 020/113] Add new Elem type for combined unboxed/boxed types --- .../src/Unison/Runtime/Decompile.hs | 3 +- unison-runtime/src/Unison/Runtime/MCode.hs | 2 +- unison-runtime/src/Unison/Runtime/Machine.hs | 14 ++--- unison-runtime/src/Unison/Runtime/Stack.hs | 52 ++++++++++--------- 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index c3e46591e1..45857dc4ca 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -36,6 +36,7 @@ import Unison.Runtime.MCode (CombIx (..)) import Unison.Runtime.Stack ( Closure (..), TypedUnboxed (..), + USeq, getTUInt, pattern DataC, pattern PApV, @@ -252,5 +253,5 @@ decompileBytes = decompileHashAlgorithm :: (Var v) => HashAlgorithm -> Term v () decompileHashAlgorithm (HashAlgorithm r _) = ref () r -unwrapSeq :: Foreign -> Maybe (Seq Closure) +unwrapSeq :: Foreign -> Maybe USeq unwrapSeq = maybeUnwrapForeign listRef diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 8808a4bac4..d86f5a7715 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -1515,7 +1515,7 @@ emitClosures grpr grpn rec ctx args k = let cix = (CIx grpr grpn n) in Ins (Name (Env cix cix) ZArgs) <$> allocate (Var a BX ctx) as k | otherwise = - internalBug $ "emitClosures: unknown reference: " ++ show a + internalBug $ "emitClosures: unknown reference: " ++ show a ++ show grpr emitArgs :: (Var v) => Word64 -> Ctx v -> [v] -> Args emitArgs grpn ctx args diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 280013507a..e0056806ff 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -369,7 +369,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 CACH i) stk <- bump stk pokeS stk - (Sq.fromList $ Foreign . Wrap Rf.termLinkRef . Ref <$> unknown) + (Sq.fromList $ RTValue 0 . Foreign . Wrap Rf.termLinkRef . Ref <$> unknown) pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 CVLD i) | sandboxed env = die "attempted to use sandboxed operation: validate" @@ -436,7 +436,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LOAD i) Left miss -> do pokeOffS stk 1 $ Sq.fromList $ - Foreign . Wrap Rf.termLinkRef . Ref <$> miss + RTValue 0 . Foreign . Wrap Rf.termLinkRef . Ref <$> miss pokeTag stk 0 Right x -> do bpokeOff stk 1 x @@ -1717,14 +1717,14 @@ bprim2 !stk TAKS i j = do pokeS stk $ if n < 0 then s else Sq.take n s pure stk bprim2 !stk CONS i j = do - x <- bpeekOff stk i + x <- peekOff stk i s <- peekOffS stk j stk <- bump stk pokeS stk $ x Sq.<| s pure stk bprim2 !stk SNOC i j = do s <- peekOffS stk i - x <- bpeekOff stk j + x <- peekOff stk j stk <- bump stk pokeS stk $ s Sq.|> x pure stk @@ -1744,7 +1744,7 @@ bprim2 !stk IDXS i j = do pure stk Just x -> do stk <- bump stk - bpoke stk x + poke stk x stk <- bump stk pokeTag stk 1 pure stk @@ -1965,9 +1965,9 @@ refLookup s m r error $ "refLookup:" ++ s ++ ": unknown reference: " ++ show r decodeCacheArgument :: - Sq.Seq Closure -> IO [(Reference, Code)] + USeq -> IO [(Reference, Code)] decodeCacheArgument s = for (toList s) $ \case - DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _) -> + (RTValue _i (DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _))) -> case unwrapForeign x of Ref r -> pure (r, unwrapForeign y) _ -> die "decodeCacheArgument: Con reference" diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index dd8b1ed692..707553b7eb 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -44,6 +44,8 @@ module Unison.Runtime.Stack USeg, BSeg, SegList, + Elem (..), + USeq, TypedUnboxed ( TypedUnboxed, getTUInt, @@ -101,8 +103,7 @@ module Unison.Runtime.Stack bpeekOff, bpoke, bpokeOff, - upoke, - upokeOff, + pokeOff, upokeT, upokeOffT, unsafePokeIasN, @@ -196,6 +197,9 @@ instance Ord K where newtype Closure = Closure {unClosure :: (GClosure (RComb Closure))} deriving stock (Show, Eq, Ord) +-- | Implementation for Unison sequences. +type USeq = Seq Elem + type IxClosure = GClosure CombIx data GClosure comb @@ -598,7 +602,9 @@ instance Show Stack where type UElem = Int -type TypedUElem = (Int, Closure {- This closure should always be a UnboxedTypeTag -}) +-- | A runtime value, which is either a boxed or unboxed value, but we may not know which. +data Elem = Elem !UElem !BElem + deriving (Show) type USeg = ByteArray @@ -606,8 +612,6 @@ type BElem = Closure type BSeg = Array Closure -type Elem = (UElem, BElem) - type Seg = (USeg, BSeg) alloc :: IO Stack @@ -621,7 +625,7 @@ peek :: Stack -> IO Elem peek stk = do u <- upeek stk b <- bpeek stk - pure (u, b) + pure (Elem u b) {-# INLINE peek #-} peekI :: Stack -> IO Int @@ -644,7 +648,7 @@ peekOff :: Stack -> Off -> IO Elem peekOff stk i = do u <- upeekOff stk i b <- bpeekOff stk i - pure (u, b) + pure $ Elem u b {-# INLINE peekOff #-} bpeekOff :: Stack -> Off -> IO BElem @@ -655,20 +659,18 @@ upeekOff :: Stack -> Off -> IO UElem upeekOff (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) {-# INLINE upeekOff #-} --- | Store an unboxed value and null out the boxed stack at that location, both so we know there's no value there, --- and so garbage collection can clean up any value that was referenced there. -upoke :: Stack -> TypedUElem -> IO () -upoke !stk@(Stack _ _ sp ustk _) !(u, t) = do - bpoke stk t - writeByteArray ustk sp u -{-# INLINE upoke #-} - upokeT :: Stack -> UElem -> PackedTag -> IO () upokeT !stk@(Stack _ _ sp ustk _) !u !t = do bpoke stk (UnboxedTypeTag t) writeByteArray ustk sp u {-# INLINE upokeT #-} +poke :: Stack -> Elem -> IO () +poke (Stack _ _ sp ustk bstk) (Elem u b) = do + writeByteArray ustk sp u + writeArray bstk sp b +{-# INLINE poke #-} + -- | Sometimes we get back an int from a foreign call which we want to use as a Nat. -- If we know it's positive and smaller than 2^63 then we can safely store the Int directly as a Nat without -- checks. @@ -678,7 +680,7 @@ unsafePokeIasN stk n = do {-# INLINE unsafePokeIasN #-} pokeTU :: Stack -> TypedUnboxed -> IO () -pokeTU stk !(TypedUnboxed u t) = upoke stk (u, UnboxedTypeTag t) +pokeTU stk !(TypedUnboxed u t) = poke stk (Elem u (UnboxedTypeTag t)) {-# INLINE pokeTU #-} -- | Store an unboxed tag to later match on. @@ -712,11 +714,11 @@ bpoke :: Stack -> BElem -> IO () bpoke (Stack _ _ sp _ bstk) b = writeArray bstk sp b {-# INLINE bpoke #-} -upokeOff :: Stack -> Off -> TypedUElem -> IO () -upokeOff stk i (u, t) = do +pokeOff :: Stack -> Off -> Elem -> IO () +pokeOff stk i (Elem u t) = do bpokeOff stk i t writeByteArray (ustk stk) (sp stk - i) u -{-# INLINE upokeOff #-} +{-# INLINE pokeOff #-} upokeOffT :: Stack -> Off -> UElem -> PackedTag -> IO () upokeOffT stk i u t = do @@ -725,7 +727,7 @@ upokeOffT stk i u t = do {-# INLINE upokeOffT #-} pokeOffTU :: Stack -> Off -> TypedUnboxed -> IO () -pokeOffTU stk i (TypedUnboxed u t) = upokeOff stk i (u, UnboxedTypeTag t) +pokeOffTU stk i (TypedUnboxed u t) = pokeOff stk i (Elem u (UnboxedTypeTag t)) {-# INLINE pokeOffTU #-} bpokeOff :: Stack -> Off -> BElem -> IO () @@ -1007,16 +1009,16 @@ peekOffBi :: (BuiltinForeign b) => Stack -> Int -> IO b peekOffBi stk i = unwrapForeign . marshalToForeign <$> bpeekOff stk i {-# INLINE peekOffBi #-} -peekOffS :: Stack -> Int -> IO (Seq Closure) +peekOffS :: Stack -> Int -> IO USeq peekOffS stk i = unwrapForeign . marshalToForeign <$> bpeekOff stk i {-# INLINE peekOffS #-} -pokeS :: Stack -> Seq Closure -> IO () +pokeS :: Stack -> USeq -> IO () pokeS stk s = bpoke stk (Foreign $ Wrap Ty.listRef s) {-# INLINE pokeS #-} -pokeOffS :: Stack -> Int -> Seq Closure -> IO () +pokeOffS :: Stack -> Int -> USeq -> IO () pokeOffS stk i s = bpokeOff stk i (Foreign $ Wrap Ty.listRef s) {-# INLINE pokeOffS #-} @@ -1075,8 +1077,8 @@ closureTermRefs f = \case (Captured k _ (_useg, bseg)) -> contTermRefs f k <> foldMap (closureTermRefs f) bseg (Foreign fo) - | Just (cs :: Seq Closure) <- maybeUnwrapForeign Ty.listRef fo -> - foldMap (closureTermRefs f) cs + | Just (cs :: USeq) <- maybeUnwrapForeign Ty.listRef fo -> + foldMap (\(Elem _i clos) -> closureTermRefs f clos) cs _ -> mempty contTermRefs :: (Monoid m) => (Reference -> m) -> K -> m From 495f937e50ffb76d73de8b27cb80f7b5139ca0b2 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 11:09:42 -0700 Subject: [PATCH 021/113] WIP --- .../src/Unison/Runtime/Foreign/Function.hs | 12 ++--- .../src/Unison/Runtime/Interface.hs | 8 ++-- unison-runtime/src/Unison/Runtime/Machine.hs | 47 ++++++++++--------- unison-runtime/src/Unison/Runtime/Stack.hs | 19 +++++++- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 8e592cb123..3c1e2cc193 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -433,11 +433,11 @@ instance ForeignConvention BufferMode where -- the typechecker a bit and avoid a bunch of annoying type annotations. instance ForeignConvention [Closure] where readForeign (i : args) stk = - (args,) . toList <$> peekOffS stk i + (args,) . fmap getBoxedElem . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[Closure]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (Sq.fromList l) + stk <$ pokeS stk (Sq.fromList $ fmap boxedElem l) instance ForeignConvention [Foreign] where readForeign = readForeignAs (fmap marshalToForeign) @@ -517,25 +517,25 @@ unwrapForeignClosure = unwrapForeign . marshalToForeign instance {-# OVERLAPPABLE #-} (BuiltinForeign a, BuiltinForeign b) => ForeignConvention [(a, b)] where readForeign (i : args) stk = (args,) - . fmap fromUnisonPair + . fmap (fromUnisonPair . getBoxedElem) . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[(a,b)]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (toUnisonPair <$> Sq.fromList l) + stk <$ pokeS stk (Elem 0 . toUnisonPair <$> Sq.fromList l) instance {-# OVERLAPPABLE #-} (BuiltinForeign b) => ForeignConvention [b] where readForeign (i : args) stk = (args,) - . fmap unwrapForeignClosure + . fmap (unwrapForeignClosure . getBoxedElem) . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[b]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (Foreign . wrapBuiltin <$> Sq.fromList l) + stk <$ pokeS stk (boxedElem . Foreign . wrapBuiltin <$> Sq.fromList l) foreignCCError :: String -> IO a foreignCCError nm = diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 137d8b4c1b..a83f4fc17a 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -505,7 +505,7 @@ compileValue base = cpair (r, sg) = pair (rf r) (code sg) decompileCtx :: - EnumMap Word64 Reference -> EvalCtx -> Closure -> DecompResult Symbol + EnumMap Word64 Reference -> EvalCtx -> Elem -> DecompResult Symbol decompileCtx crs ctx = decompile ib $ backReferenceTm crs fr ir dt where ib = intermedToBase ctx @@ -851,8 +851,8 @@ prepareEvaluation ppe tm ctx = do Just r -> r Nothing -> error "prepareEvaluation: could not remap main ref" -watchHook :: IORef Closure -> Stack -> IO () -watchHook r stk = bpeek stk >>= writeIORef r +watchHook :: IORef Elem -> Stack -> IO () +watchHook r stk = peek stk >>= writeIORef r backReferenceTm :: EnumMap Word64 Reference -> @@ -1022,7 +1022,7 @@ evalInContext :: Word64 -> IO (Either Error ([Error], Term Symbol)) evalInContext ppe ctx activeThreads w = do - r <- newIORef BlackHole + r <- newIORef (boxedElem BlackHole) crs <- readTVarIO (combRefs $ ccache ctx) let hook = watchHook r decom = decompileCtx crs ctx diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index e0056806ff..094c23c02f 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -13,6 +13,7 @@ import Control.Exception import Control.Lens import Data.Bitraversable (Bitraversable (..)) import Data.Bits +import Data.Char qualified as Char import Data.Map.Strict qualified as M import Data.Ord (comparing) import Data.Primitive.ByteArray qualified as BA @@ -369,7 +370,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 CACH i) stk <- bump stk pokeS stk - (Sq.fromList $ RTValue 0 . Foreign . Wrap Rf.termLinkRef . Ref <$> unknown) + (Sq.fromList $ boxedElem . Foreign . Wrap Rf.termLinkRef . Ref <$> unknown) pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 CVLD i) | sandboxed env = die "attempted to use sandboxed operation: validate" @@ -436,7 +437,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LOAD i) Left miss -> do pokeOffS stk 1 $ Sq.fromList $ - RTValue 0 . Foreign . Wrap Rf.termLinkRef . Ref <$> miss + boxedElem . Foreign . Wrap Rf.termLinkRef . Ref <$> miss pokeTag stk 0 Right x -> do bpokeOff stk 1 x @@ -927,19 +928,19 @@ moveArgs !stk (VArgV i) = do l = fsize stk - i {-# INLINE moveArgs #-} -closureArgs :: Stack -> Args -> IO [Closure] +closureArgs :: Stack -> Args -> IO [Elem] closureArgs !_ ZArgs = pure [] closureArgs !stk (VArg1 i) = do - x <- bpeekOff stk i + x <- peekOff stk i pure [x] closureArgs !stk (VArg2 i j) = do - x <- bpeekOff stk i - y <- bpeekOff stk j + x <- peekOff stk i + y <- peekOff stk j pure [x, y] closureArgs !stk (VArgR i l) = - for (take l [i ..]) (bpeekOff stk) + for (take l [i ..]) (peekOff stk) closureArgs !stk (VArgN bs) = - for (PA.primArrayToList bs) (bpeekOff stk) + for (PA.primArrayToList bs) (peekOff stk) closureArgs !_ _ = error "closure arguments can only be boxed." {-# INLINE closureArgs #-} @@ -1544,7 +1545,7 @@ bprim1 !stk VWLS i = x Sq.:<| xs -> do stk <- bumpn stk 3 pokeOffS stk 2 xs -- remaining seq - bpokeOff stk 1 x -- head + pokeOff stk 1 x -- head pokeTag stk 1 -- ':<|' tag pure stk bprim1 !stk VWRS i = @@ -1555,7 +1556,7 @@ bprim1 !stk VWRS i = pure stk xs Sq.:|> x -> do stk <- bumpn stk 3 - bpokeOff stk 2 x -- last + pokeOff stk 2 x -- last pokeOffS stk 1 xs -- remaining seq pokeTag stk 1 -- ':|>' tag pure stk @@ -1565,15 +1566,17 @@ bprim1 !stk PAKT i = do pokeBi stk . Util.Text.pack . toList $ clo2char <$> s pure stk where - clo2char :: Closure -> Char - clo2char (CharClosure c) = c + clo2char :: Elem -> Char + clo2char (Elem _ (CharClosure c)) = c + clo2char (Elem c tt) | tt == charTypeTag = Char.chr $ c clo2char c = error $ "pack text: non-character closure: " ++ show c bprim1 !stk UPKT i = do t <- peekOffBi stk i stk <- bump stk pokeS stk . Sq.fromList - . fmap CharClosure + -- TODO: Should this be unboxed chars? + . fmap (boxedElem . CharClosure) . Util.Text.unpack $ t pure stk @@ -1584,13 +1587,15 @@ bprim1 !stk PAKB i = do pure stk where -- TODO: Should we have a tag for bytes specifically? - clo2w8 :: Closure -> Word8 - clo2w8 (NatClosure n) = toEnum . fromEnum $ n + clo2w8 :: Elem -> Word8 + clo2w8 (Elem _ (NatClosure n)) = toEnum . fromEnum $ n + clo2w8 (Elem n tt) | tt == natTypeTag = toEnum $ n clo2w8 c = error $ "pack bytes: non-natural closure: " ++ show c bprim1 !stk UPKB i = do b <- peekOffBi stk i stk <- bump stk - pokeS stk . Sq.fromList . fmap (NatClosure . toEnum @Word64 . fromEnum @Word8) $ + -- TODO: Should this be unboxed nats/bytes? + pokeS stk . Sq.fromList . fmap (boxedElem . NatClosure . toEnum @Word64 . fromEnum @Word8) $ By.toWord8s b pure stk bprim1 !stk SIZB i = do @@ -1967,22 +1972,22 @@ refLookup s m r decodeCacheArgument :: USeq -> IO [(Reference, Code)] decodeCacheArgument s = for (toList s) $ \case - (RTValue _i (DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _))) -> + (Elem _unboxed (DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _))) -> case unwrapForeign x of Ref r -> pure (r, unwrapForeign y) _ -> die "decodeCacheArgument: Con reference" _ -> die "decodeCacheArgument: unrecognized value" -decodeSandboxArgument :: Sq.Seq Closure -> IO [Reference] +decodeSandboxArgument :: USeq -> IO [Reference] decodeSandboxArgument s = fmap join . for (toList s) $ \case - Foreign x -> case unwrapForeign x of + Elem _ (Foreign x) -> case unwrapForeign x of Ref r -> pure [r] _ -> pure [] -- constructor _ -> die "decodeSandboxArgument: unrecognized value" -encodeSandboxListResult :: [Reference] -> Sq.Seq Closure +encodeSandboxListResult :: [Reference] -> Sq.Seq Elem encodeSandboxListResult = - Sq.fromList . fmap (Foreign . Wrap Rf.termLinkRef . Ref) + Sq.fromList . fmap (boxedElem . Foreign . Wrap Rf.termLinkRef . Ref) encodeSandboxResult :: Either [Reference] [Reference] -> Closure encodeSandboxResult (Left rfs) = diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 707553b7eb..e3d1527155 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -45,6 +45,8 @@ module Unison.Runtime.Stack BSeg, SegList, Elem (..), + boxedElem, + unboxedElem, USeq, TypedUnboxed ( TypedUnboxed, @@ -65,6 +67,7 @@ module Unison.Runtime.Stack peekOffD, peekC, peekOffC, + poke, pokeD, pokeOffD, pokeC, @@ -126,6 +129,12 @@ module Unison.Runtime.Stack adjustArgs, fsize, asize, + + -- * Unboxed type tags + natTypeTag, + intTypeTag, + charTypeTag, + floatTypeTag, ) where @@ -603,9 +612,17 @@ instance Show Stack where type UElem = Int -- | A runtime value, which is either a boxed or unboxed value, but we may not know which. -data Elem = Elem !UElem !BElem +data Elem = Elem {getUnboxedElem :: !UElem, getBoxedElem :: !BElem} deriving (Show) +-- | Lift a boxed elem into an Elem +boxedElem :: BElem -> Elem +boxedElem = Elem 0 + +-- | Lift an unboxed elem into an Elem +unboxedElem :: UElem -> Elem +unboxedElem u = Elem u BlackHole + type USeg = ByteArray type BElem = Closure From 19662df117e4d9dbcc1246eb5bc326722846d7e8 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 11:19:57 -0700 Subject: [PATCH 022/113] Elem -> Val --- .../src/Unison/Runtime/Foreign/Function.hs | 12 ++-- .../src/Unison/Runtime/Interface.hs | 4 +- unison-runtime/src/Unison/Runtime/Machine.hs | 30 ++++----- unison-runtime/src/Unison/Runtime/Stack.hs | 64 +++++++++---------- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 3c1e2cc193..afc16be5ad 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -433,11 +433,11 @@ instance ForeignConvention BufferMode where -- the typechecker a bit and avoid a bunch of annoying type annotations. instance ForeignConvention [Closure] where readForeign (i : args) stk = - (args,) . fmap getBoxedElem . toList <$> peekOffS stk i + (args,) . fmap getBoxedVal . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[Closure]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (Sq.fromList $ fmap boxedElem l) + stk <$ pokeS stk (Sq.fromList $ fmap boxedVal l) instance ForeignConvention [Foreign] where readForeign = readForeignAs (fmap marshalToForeign) @@ -517,25 +517,25 @@ unwrapForeignClosure = unwrapForeign . marshalToForeign instance {-# OVERLAPPABLE #-} (BuiltinForeign a, BuiltinForeign b) => ForeignConvention [(a, b)] where readForeign (i : args) stk = (args,) - . fmap (fromUnisonPair . getBoxedElem) + . fmap (fromUnisonPair . getBoxedVal) . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[(a,b)]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (Elem 0 . toUnisonPair <$> Sq.fromList l) + stk <$ pokeS stk (boxedVal . toUnisonPair <$> Sq.fromList l) instance {-# OVERLAPPABLE #-} (BuiltinForeign b) => ForeignConvention [b] where readForeign (i : args) stk = (args,) - . fmap (unwrapForeignClosure . getBoxedElem) + . fmap (unwrapForeignClosure . getBoxedVal) . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[b]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (boxedElem . Foreign . wrapBuiltin <$> Sq.fromList l) + stk <$ pokeS stk (boxedVal . Foreign . wrapBuiltin <$> Sq.fromList l) foreignCCError :: String -> IO a foreignCCError nm = diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index a83f4fc17a..27532c38ec 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -505,7 +505,7 @@ compileValue base = cpair (r, sg) = pair (rf r) (code sg) decompileCtx :: - EnumMap Word64 Reference -> EvalCtx -> Elem -> DecompResult Symbol + EnumMap Word64 Reference -> EvalCtx -> Val -> DecompResult Symbol decompileCtx crs ctx = decompile ib $ backReferenceTm crs fr ir dt where ib = intermedToBase ctx @@ -851,7 +851,7 @@ prepareEvaluation ppe tm ctx = do Just r -> r Nothing -> error "prepareEvaluation: could not remap main ref" -watchHook :: IORef Elem -> Stack -> IO () +watchHook :: IORef Val -> Stack -> IO () watchHook r stk = peek stk >>= writeIORef r backReferenceTm :: diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 094c23c02f..6c0e961b8d 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -370,7 +370,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 CACH i) stk <- bump stk pokeS stk - (Sq.fromList $ boxedElem . Foreign . Wrap Rf.termLinkRef . Ref <$> unknown) + (Sq.fromList $ boxedVal . Foreign . Wrap Rf.termLinkRef . Ref <$> unknown) pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 CVLD i) | sandboxed env = die "attempted to use sandboxed operation: validate" @@ -437,7 +437,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LOAD i) Left miss -> do pokeOffS stk 1 $ Sq.fromList $ - boxedElem . Foreign . Wrap Rf.termLinkRef . Ref <$> miss + boxedVal . Foreign . Wrap Rf.termLinkRef . Ref <$> miss pokeTag stk 0 Right x -> do bpokeOff stk 1 x @@ -928,7 +928,7 @@ moveArgs !stk (VArgV i) = do l = fsize stk - i {-# INLINE moveArgs #-} -closureArgs :: Stack -> Args -> IO [Elem] +closureArgs :: Stack -> Args -> IO [Val] closureArgs !_ ZArgs = pure [] closureArgs !stk (VArg1 i) = do x <- peekOff stk i @@ -1566,9 +1566,9 @@ bprim1 !stk PAKT i = do pokeBi stk . Util.Text.pack . toList $ clo2char <$> s pure stk where - clo2char :: Elem -> Char - clo2char (Elem _ (CharClosure c)) = c - clo2char (Elem c tt) | tt == charTypeTag = Char.chr $ c + clo2char :: Val -> Char + clo2char (Val _ (CharClosure c)) = c + clo2char (Val c tt) | tt == charTypeTag = Char.chr $ c clo2char c = error $ "pack text: non-character closure: " ++ show c bprim1 !stk UPKT i = do t <- peekOffBi stk i @@ -1576,7 +1576,7 @@ bprim1 !stk UPKT i = do pokeS stk . Sq.fromList -- TODO: Should this be unboxed chars? - . fmap (boxedElem . CharClosure) + . fmap (boxedVal . CharClosure) . Util.Text.unpack $ t pure stk @@ -1587,15 +1587,15 @@ bprim1 !stk PAKB i = do pure stk where -- TODO: Should we have a tag for bytes specifically? - clo2w8 :: Elem -> Word8 - clo2w8 (Elem _ (NatClosure n)) = toEnum . fromEnum $ n - clo2w8 (Elem n tt) | tt == natTypeTag = toEnum $ n + clo2w8 :: Val -> Word8 + clo2w8 (Val _ (NatClosure n)) = toEnum . fromEnum $ n + clo2w8 (Val n tt) | tt == natTypeTag = toEnum $ n clo2w8 c = error $ "pack bytes: non-natural closure: " ++ show c bprim1 !stk UPKB i = do b <- peekOffBi stk i stk <- bump stk -- TODO: Should this be unboxed nats/bytes? - pokeS stk . Sq.fromList . fmap (boxedElem . NatClosure . toEnum @Word64 . fromEnum @Word8) $ + pokeS stk . Sq.fromList . fmap (boxedVal . NatClosure . toEnum @Word64 . fromEnum @Word8) $ By.toWord8s b pure stk bprim1 !stk SIZB i = do @@ -1972,7 +1972,7 @@ refLookup s m r decodeCacheArgument :: USeq -> IO [(Reference, Code)] decodeCacheArgument s = for (toList s) $ \case - (Elem _unboxed (DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _))) -> + (Val _unboxed (DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _))) -> case unwrapForeign x of Ref r -> pure (r, unwrapForeign y) _ -> die "decodeCacheArgument: Con reference" @@ -1980,14 +1980,14 @@ decodeCacheArgument s = for (toList s) $ \case decodeSandboxArgument :: USeq -> IO [Reference] decodeSandboxArgument s = fmap join . for (toList s) $ \case - Elem _ (Foreign x) -> case unwrapForeign x of + Val _ (Foreign x) -> case unwrapForeign x of Ref r -> pure [r] _ -> pure [] -- constructor _ -> die "decodeSandboxArgument: unrecognized value" -encodeSandboxListResult :: [Reference] -> Sq.Seq Elem +encodeSandboxListResult :: [Reference] -> Sq.Seq Val encodeSandboxListResult = - Sq.fromList . fmap (boxedElem . Foreign . Wrap Rf.termLinkRef . Ref) + Sq.fromList . fmap (boxedVal . Foreign . Wrap Rf.termLinkRef . Ref) encodeSandboxResult :: Either [Reference] [Reference] -> Closure encodeSandboxResult (Left rfs) = diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index e3d1527155..056585fd03 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -44,9 +44,9 @@ module Unison.Runtime.Stack USeg, BSeg, SegList, - Elem (..), - boxedElem, - unboxedElem, + Val (..), + boxedVal, + unboxedVal, USeq, TypedUnboxed ( TypedUnboxed, @@ -207,7 +207,7 @@ newtype Closure = Closure {unClosure :: (GClosure (RComb Closure))} deriving stock (Show, Eq, Ord) -- | Implementation for Unison sequences. -type USeq = Seq Elem +type USeq = Seq Val type IxClosure = GClosure CombIx @@ -609,23 +609,23 @@ instance Show Stack where show (Stack ap fp sp _ _) = "Stack " ++ show ap ++ " " ++ show fp ++ " " ++ show sp -type UElem = Int +type UVal = Int -- | A runtime value, which is either a boxed or unboxed value, but we may not know which. -data Elem = Elem {getUnboxedElem :: !UElem, getBoxedElem :: !BElem} +data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} deriving (Show) --- | Lift a boxed elem into an Elem -boxedElem :: BElem -> Elem -boxedElem = Elem 0 +-- | Lift a boxed val into an Val +boxedVal :: BVal -> Val +boxedVal = Val 0 --- | Lift an unboxed elem into an Elem -unboxedElem :: UElem -> Elem -unboxedElem u = Elem u BlackHole +-- | Lift an unboxed val into an Val +unboxedVal :: UVal -> Val +unboxedVal u = Val u BlackHole type USeg = ByteArray -type BElem = Closure +type BVal = Closure type BSeg = Array Closure @@ -638,11 +638,11 @@ alloc = do pure $ Stack {ap = -1, fp = -1, sp = -1, ustk, bstk} {-# INLINE alloc #-} -peek :: Stack -> IO Elem +peek :: Stack -> IO Val peek stk = do u <- upeek stk b <- bpeek stk - pure (Elem u b) + pure (Val u b) {-# INLINE peek #-} peekI :: Stack -> IO Int @@ -653,37 +653,37 @@ peekOffI :: Stack -> Off -> IO Int peekOffI (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) {-# INLINE peekOffI #-} -bpeek :: Stack -> IO BElem +bpeek :: Stack -> IO BVal bpeek (Stack _ _ sp _ bstk) = readArray bstk sp {-# INLINE bpeek #-} -upeek :: Stack -> IO UElem +upeek :: Stack -> IO UVal upeek (Stack _ _ sp ustk _) = readByteArray ustk sp {-# INLINE upeek #-} -peekOff :: Stack -> Off -> IO Elem +peekOff :: Stack -> Off -> IO Val peekOff stk i = do u <- upeekOff stk i b <- bpeekOff stk i - pure $ Elem u b + pure $ Val u b {-# INLINE peekOff #-} -bpeekOff :: Stack -> Off -> IO BElem +bpeekOff :: Stack -> Off -> IO BVal bpeekOff (Stack _ _ sp _ bstk) i = readArray bstk (sp - i) {-# INLINE bpeekOff #-} -upeekOff :: Stack -> Off -> IO UElem +upeekOff :: Stack -> Off -> IO UVal upeekOff (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) {-# INLINE upeekOff #-} -upokeT :: Stack -> UElem -> PackedTag -> IO () +upokeT :: Stack -> UVal -> PackedTag -> IO () upokeT !stk@(Stack _ _ sp ustk _) !u !t = do bpoke stk (UnboxedTypeTag t) writeByteArray ustk sp u {-# INLINE upokeT #-} -poke :: Stack -> Elem -> IO () -poke (Stack _ _ sp ustk bstk) (Elem u b) = do +poke :: Stack -> Val -> IO () +poke (Stack _ _ sp ustk bstk) (Val u b) = do writeByteArray ustk sp u writeArray bstk sp b {-# INLINE poke #-} @@ -697,7 +697,7 @@ unsafePokeIasN stk n = do {-# INLINE unsafePokeIasN #-} pokeTU :: Stack -> TypedUnboxed -> IO () -pokeTU stk !(TypedUnboxed u t) = poke stk (Elem u (UnboxedTypeTag t)) +pokeTU stk !(TypedUnboxed u t) = poke stk (Val u (UnboxedTypeTag t)) {-# INLINE pokeTU #-} -- | Store an unboxed tag to later match on. @@ -727,27 +727,27 @@ pokeBool stk b = -- | Store a boxed value. -- We don't bother nulling out the unboxed stack, -- it's extra work and there's nothing to garbage collect. -bpoke :: Stack -> BElem -> IO () +bpoke :: Stack -> BVal -> IO () bpoke (Stack _ _ sp _ bstk) b = writeArray bstk sp b {-# INLINE bpoke #-} -pokeOff :: Stack -> Off -> Elem -> IO () -pokeOff stk i (Elem u t) = do +pokeOff :: Stack -> Off -> Val -> IO () +pokeOff stk i (Val u t) = do bpokeOff stk i t writeByteArray (ustk stk) (sp stk - i) u {-# INLINE pokeOff #-} -upokeOffT :: Stack -> Off -> UElem -> PackedTag -> IO () +upokeOffT :: Stack -> Off -> UVal -> PackedTag -> IO () upokeOffT stk i u t = do bpokeOff stk i (UnboxedTypeTag t) writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOffT #-} pokeOffTU :: Stack -> Off -> TypedUnboxed -> IO () -pokeOffTU stk i (TypedUnboxed u t) = pokeOff stk i (Elem u (UnboxedTypeTag t)) +pokeOffTU stk i (TypedUnboxed u t) = pokeOff stk i (Val u (UnboxedTypeTag t)) {-# INLINE pokeOffTU #-} -bpokeOff :: Stack -> Off -> BElem -> IO () +bpokeOff :: Stack -> Off -> BVal -> IO () bpokeOff (Stack _ _ sp _ bstk) i b = writeArray bstk (sp - i) b {-# INLINE bpokeOff #-} @@ -1095,7 +1095,7 @@ closureTermRefs f = \case contTermRefs f k <> foldMap (closureTermRefs f) bseg (Foreign fo) | Just (cs :: USeq) <- maybeUnwrapForeign Ty.listRef fo -> - foldMap (\(Elem _i clos) -> closureTermRefs f clos) cs + foldMap (\(Val _i clos) -> closureTermRefs f clos) cs _ -> mempty contTermRefs :: (Monoid m) => (Reference -> m) -> K -> m From dd183b9999cfb5996e05e6b61c5254f80b556e87 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 11:49:34 -0700 Subject: [PATCH 023/113] Add pattern matching for unboxed Val types --- unison-runtime/src/Unison/Runtime/Stack.hs | 62 +++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 056585fd03..228569517f 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -44,7 +44,13 @@ module Unison.Runtime.Stack USeg, BSeg, SegList, - Val (..), + Val + ( .., + CharVal, + NatVal, + DoubleVal, + IntVal + ), boxedVal, unboxedVal, USeq, @@ -383,6 +389,50 @@ pattern IntClosure i <- (unpackUnboxedClosure TT.intTag -> Just i) where IntClosure i = DataU1 Ty.intRef TT.intTag (TypedUnboxed i TT.intTag) +matchCharVal :: Val -> Maybe Char +matchCharVal = \case + (Val u (UnboxedTypeTag tt)) | tt == TT.charTag -> Just (Char.chr u) + (Val _ (CharClosure c)) -> Just c + _ -> Nothing + +pattern CharVal :: Char -> Val +pattern CharVal c <- (matchCharVal -> Just c) + where + CharVal c = Val (Char.ord c) (UnboxedTypeTag TT.charTag) + +matchNatVal :: Val -> Maybe Word64 +matchNatVal = \case + (Val u (UnboxedTypeTag tt)) | tt == TT.natTag -> Just (toEnum u) + (Val _ (NatClosure n)) -> Just n + _ -> Nothing + +pattern NatVal :: Word64 -> Val +pattern NatVal n <- (matchNatVal -> Just n) + where + NatVal n = Val (fromEnum n) (UnboxedTypeTag TT.natTag) + +matchDoubleVal :: Val -> Maybe Double +matchDoubleVal = \case + (Val u (UnboxedTypeTag tt)) | tt == TT.floatTag -> Just (intToDouble u) + (Val _ (DoubleClosure d)) -> Just d + _ -> Nothing + +pattern DoubleVal :: Double -> Val +pattern DoubleVal d <- (matchDoubleVal -> Just d) + where + DoubleVal d = Val (doubleToInt d) (UnboxedTypeTag TT.floatTag) + +matchIntVal :: Val -> Maybe Int +matchIntVal = \case + (Val u (UnboxedTypeTag tt)) | tt == TT.intTag -> Just u + (Val _ (IntClosure i)) -> Just i + _ -> Nothing + +pattern IntVal :: Int -> Val +pattern IntVal i <- (matchIntVal -> Just i) + where + IntVal i = Val i (UnboxedTypeTag TT.intTag) + doubleToInt :: Double -> Int doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 @@ -419,7 +469,7 @@ pattern UnboxedDouble d <- TypedUnboxed (intToDouble -> d) ((== TT.floatTag) -> splitTaggedUnboxed :: TypedUnboxed -> (Int, Closure) splitTaggedUnboxed (TypedUnboxed i t) = (i, UnboxedTypeTag t) -type SegList = [Either TypedUnboxed Closure] +type SegList = [Val] pattern PApV :: CombIx -> RCombInfo Closure -> SegList -> Closure pattern PApV cix rcomb segs <- @@ -615,6 +665,14 @@ type UVal = Int data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} deriving (Show) +-- | The Eq instance for Val is a little strange because it takes into account the fact that if a Val is boxed, the +-- unboxed side is garbage and should not be compared. +instance Eq Val where + (Val u (ut@UnboxedTypeTag {})) == (Val v (vt@UnboxedTypeTag {})) = u == v && ut == vt + (Val _ (UnboxedTypeTag {})) == (Val _ _) = False + (Val _ _) == (Val _ (UnboxedTypeTag {})) = False + (Val _ x) == (Val _ y) = x == y + -- | Lift a boxed val into an Val boxedVal :: BVal -> Val boxedVal = Val 0 From 782ccfeae317ef63b933a74fee402588bee4250c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 11:49:34 -0700 Subject: [PATCH 024/113] Propagate Val to ANF reification/reflection --- .../src/Unison/Runtime/Decompile.hs | 79 +++++++++---------- .../src/Unison/Runtime/Foreign/Function.hs | 6 +- unison-runtime/src/Unison/Runtime/Machine.hs | 8 +- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 45857dc4ca..ff441877c1 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -37,12 +37,14 @@ import Unison.Runtime.Stack ( Closure (..), TypedUnboxed (..), USeq, + Val (..), getTUInt, pattern DataC, pattern PApV, ) -- for Int -> Double +import Unison.Runtime.TypeTags qualified as TT import Unison.Syntax.NamePrinter (prettyReference) import Unison.Term ( Term, @@ -90,7 +92,7 @@ err err x = (singleton err, x) data DecompError = BadBool !Word64 - | BadUnboxed !Reference + | BadUnboxed !TT.PackedTag | BadForeign !Reference | BadData !Reference | BadPAp !Reference @@ -151,50 +153,41 @@ decompile :: (Var v) => (Reference -> Maybe Reference) -> (Word64 -> Word64 -> Maybe (Term v ())) -> - Closure -> + Val -> DecompResult v decompile backref topTerms = \case - CharClosure c -> pure (char () c) - NatClosure n -> pure (nat () n) - IntClosure i -> pure (int () (fromIntegral i)) - DoubleClosure f -> pure (float () f) - DataC rf (maskTags -> ct) [] - | rf == booleanRef -> tag2bool ct - DataC rf _ [Left i] -> - err (BadUnboxed rf) . nat () $ fromIntegral $ getTUInt i - (DataC rf _ [Right b]) - | rf == anyRef -> - app () (builtin () "Any.Any") <$> decompile backref topTerms b - (DataC rf (maskTags -> ct) vs) -> - apps' (con rf ct) <$> traverse decompUB vs - (PApV (CIx rf rt k) _ vs) - | rf == Builtin "jumpCont" -> - err Cont $ bug "" - | Builtin nm <- rf -> - apps' (builtin () nm) <$> traverse decompUB vs - | Just t <- topTerms rt k -> - Term.etaReduceEtaVars . substitute t - <$> traverse decompUB vs - | k > 0, - Just _ <- topTerms rt 0 -> - err (UnkLocal rf k) $ bug "" - | otherwise -> err (UnkComb rf) $ ref () rf - (PAp (CIx rf _ _) _ _) -> - err (BadPAp rf) $ bug "" - BlackHole -> err Exn $ bug "" - (Captured {}) -> err Cont $ bug "" - (Foreign f) -> - decompileForeign backref topTerms f - where - decompileTypedUnboxed = \case - UnboxedNat i -> pure (nat () $ fromIntegral i) - UnboxedInt i -> pure (int () $ fromIntegral i) - UnboxedDouble i -> pure (float () i) - UnboxedChar i -> pure (char () i) - TypedUnboxed i _ -> err (BadUnboxed anyRef) $ nat () $ fromIntegral i - - decompUB :: (Either TypedUnboxed Closure) -> DecompResult v - decompUB = either decompileTypedUnboxed (decompile backref topTerms) + CharVal c -> pure (char () c) + NatVal n -> pure (nat () n) + IntVal i -> pure (int () (fromIntegral i)) + DoubleVal f -> pure (float () f) + Val i (UnboxedTypeTag tt) -> + err (BadUnboxed tt) . nat () $ fromIntegral $ i + Val _u clos -> case clos of + DataC rf (maskTags -> ct) [] + | rf == booleanRef -> tag2bool ct + (DataC rf _ [b]) + | rf == anyRef -> + app () (builtin () "Any.Any") <$> decompile backref topTerms b + (DataC rf (maskTags -> ct) vs) -> + apps' (con rf ct) <$> traverse (decompile backref topTerms) vs + (PApV (CIx rf rt k) _ vs) + | rf == Builtin "jumpCont" -> + err Cont $ bug "" + | Builtin nm <- rf -> + apps' (builtin () nm) <$> traverse (decompile backref topTerms) vs + | Just t <- topTerms rt k -> + Term.etaReduceEtaVars . substitute t + <$> traverse (decompile backref topTerms) vs + | k > 0, + Just _ <- topTerms rt 0 -> + err (UnkLocal rf k) $ bug "" + | otherwise -> err (UnkComb rf) $ ref () rf + (PAp (CIx rf _ _) _ _) -> + err (BadPAp rf) $ bug "" + BlackHole -> err Exn $ bug "" + (Captured {}) -> err Cont $ bug "" + (Foreign f) -> + decompileForeign backref topTerms f tag2bool :: (Var v) => Word64 -> DecompResult v tag2bool 0 = pure (boolean () False) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index afc16be5ad..e5274689c1 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -483,9 +483,9 @@ instance ForeignConvention (PA.MutableByteArray s) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mbytearrayRef) -instance ForeignConvention (PA.Array Closure) where - readForeign = readForeignAs (unwrapForeign . marshalToForeign) - writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) +-- instance ForeignConvention (PA.Array Closure) where +-- readForeign = readForeignAs (unwrapForeign . marshalToForeign) +-- writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) instance ForeignConvention PA.ByteArray where readForeign = readForeignAs (unwrapForeign . marshalToForeign) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 6c0e961b8d..781dd60b84 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -440,7 +440,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LOAD i) boxedVal . Foreign . Wrap Rf.termLinkRef . Ref <$> miss pokeTag stk 0 Right x -> do - bpokeOff stk 1 x + pokeOff stk 1 x pokeTag stk 1 pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 VALU i) = do @@ -2207,7 +2207,7 @@ cacheAdd l cc = do then [] <$ cacheAdd0 tys l'' (expandSandbox sand l') cc else pure $ S.toList missing -reflectValue :: EnumMap Word64 Reference -> Closure -> IO ANF.Value +reflectValue :: EnumMap Word64 Reference -> Val -> IO ANF.Value reflectValue rty = goV where err s = "reflectValue: cannot prepare value for serialization: " ++ s @@ -2278,7 +2278,7 @@ reflectValue rty = goV typedUnboxedToUnboxedValue :: TypedUnboxed -> ANF.UnboxedValue typedUnboxedToUnboxedValue (TypedUnboxed v t) = ANF.UnboxedValue (fromIntegral v) t -reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Closure) +reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Val) reifyValue cc val = do erc <- atomically $ do @@ -2298,7 +2298,7 @@ reifyValue cc val = do reifyValue0 :: (EnumMap Word64 MCombs, M.Map Reference Word64, M.Map Reference Word64) -> ANF.Value -> - IO Closure + IO Val reifyValue0 (combs, rty, rtm) = goV where err s = "reifyValue: cannot restore value: " ++ s From 9210a88d2bec22948a76da16f61f13a4dad8d3aa Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 12:05:46 -0700 Subject: [PATCH 025/113] WIP: Fix reify/reflect to work with Vals --- unison-runtime/src/Unison/Runtime/ANF.hs | 24 ++---- .../src/Unison/Runtime/ANF/Serialize.hs | 25 +++--- unison-runtime/src/Unison/Runtime/Machine.hs | 81 ++++++++++--------- unison-runtime/src/Unison/Runtime/Stack.hs | 75 ++++++++++------- 4 files changed, 105 insertions(+), 100 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 6293837f03..db76277817 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -56,8 +56,6 @@ module Unison.Runtime.ANF Tag (..), GroupRef (..), Code (..), - UBValue, - UnboxedValue (..), ValList, Value (..), Cont (..), @@ -90,7 +88,7 @@ module Unison.Runtime.ANF where import Control.Exception (throw) -import Control.Lens (foldMapOf, folded, snoc, unsnoc, _Right) +import Control.Lens (snoc, unsnoc) import Control.Monad.Reader (ReaderT (..), ask, local) import Control.Monad.State (MonadState (..), State, gets, modify, runState) import Data.Bifoldable (Bifoldable (..)) @@ -1470,16 +1468,9 @@ type ANFD v = Compose (ANFM v) (Directed ()) data GroupRef = GR Reference Word64 deriving (Show) --- | A value which is either unboxed or boxed. -type UBValue = Either UnboxedValue Value - --- | An unboxed value and its packed tag -data UnboxedValue = UnboxedValue {uvValue :: Word64, uvTag :: PackedTag} - deriving (Show) - -- | A list of either unboxed or boxed values. -- Each slot is one of unboxed or boxed but not both. -type ValList = [UBValue] +type ValList = [Value] data Value = Partial GroupRef ValList @@ -1537,11 +1528,12 @@ data BLit | Quote Value | Code Code | BArr PA.ByteArray - | Pos Word64 + | Arr (PA.Array Value) + | -- Despite the following being in the Boxed Literal type, they all represent unboxed values + Pos Word64 | Neg Word64 | Char Char | Float Double - | Arr (PA.Array Value) deriving (Show) groupVars :: ANFM v (Set v) @@ -1960,11 +1952,11 @@ valueTermLinks = Set.toList . valueLinks f valueLinks :: (Monoid a) => (Bool -> Reference -> a) -> Value -> a valueLinks f (Partial (GR cr _) vs) = - f False cr <> foldMapOf (folded . _Right) (valueLinks f) vs + f False cr <> foldMap (valueLinks f) vs valueLinks f (Data dr _ vs) = - f True dr <> foldMapOf (folded . _Right) (valueLinks f) vs + f True dr <> foldMap (valueLinks f) vs valueLinks f (Cont vs k) = - foldMapOf (folded . _Right) (valueLinks f) vs <> contLinks f k + foldMap (valueLinks f) vs <> contLinks f k valueLinks f (BLit l) = blitLinks f l contLinks :: (Monoid a) => (Bool -> Reference -> a) -> Cont -> a diff --git a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs index c46b612b73..fb1c53b9e4 100644 --- a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs @@ -853,23 +853,19 @@ putValue :: (MonadPut m) => Version -> Value -> m () putValue v (Partial gr vs) = putTag PartialT *> putGroupRef gr - *> putFoldable (putUBValue v) vs + *> putFoldable (putValue v) vs putValue v (Data r t vs) = putTag DataT *> putReference r *> putWord64be t - *> putFoldable (putUBValue v) vs + *> putFoldable (putValue v) vs putValue v (Cont bs k) = putTag ContT - *> putFoldable (putUBValue v) bs + *> putFoldable (putValue v) bs *> putCont v k putValue v (BLit l) = putTag BLitT *> putBLit v l -putUBValue :: (MonadPut m) => Version -> UBValue -> m () -putUBValue _v Left {} = exn "putUBValue: Unboxed values no longer supported" -putUBValue v (Right a) = putValue v a - getValue :: (MonadGet m) => Version -> m Value getValue v = getTag >>= \case @@ -878,11 +874,11 @@ getValue v = vn < 4 -> do gr <- getGroupRef getList getWord64be >>= assertEmptyUnboxed - bs <- getList getUBValue + bs <- getList (getValue v) pure $ Partial gr bs | otherwise -> do gr <- getGroupRef - vs <- getList getUBValue + vs <- getList (getValue v) pure $ Partial gr vs DataT | Transfer vn <- v, @@ -890,29 +886,26 @@ getValue v = r <- getReference w <- getWord64be getList getWord64be >>= assertEmptyUnboxed - vs <- getList getUBValue + vs <- getList (getValue v) pure $ Data r w vs | otherwise -> do r <- getReference w <- getWord64be - vs <- getList getUBValue + vs <- getList (getValue v) pure $ Data r w vs ContT | Transfer vn <- v, vn < 4 -> do getList getWord64be >>= assertEmptyUnboxed - bs <- getList getUBValue + bs <- getList (getValue v) k <- getCont v pure $ Cont bs k | otherwise -> do - bs <- getList getUBValue + bs <- getList (getValue v) k <- getCont v pure $ Cont bs k BLitT -> BLit <$> getBLit v where - -- Only Boxed values are supported. - getUBValue :: (MonadGet m) => m UBValue - getUBValue = Right <$> getValue v assertEmptyUnboxed :: (MonadGet m) => [a] -> m () assertEmptyUnboxed [] = pure () assertEmptyUnboxed _ = exn "getValue: unboxed values no longer supported" diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 781dd60b84..ba57972750 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -445,7 +445,7 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 LOAD i) pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (BPrim1 VALU i) = do m <- readTVarIO (tagRefs env) - c <- bpeekOff stk i + c <- peekOff stk i stk <- bump stk pokeBi stk =<< reflectValue m c pure (denv, stk, k) @@ -2218,22 +2218,27 @@ reflectValue rty = goV goIx (CIx r _ i) = ANF.GR r i - goV :: Closure -> IO ANF.Value - goV (PApV cix _rComb args) = - ANF.Partial (goIx cix) <$> traverse (bitraverse (pure . typedUnboxedToUnboxedValue) goV) args - goV (DataC _ t [Left w]) = ANF.BLit <$> reflectUData t w - goV (DataC r t segs) = - ANF.Data r (maskTags t) <$> traverse (bitraverse (pure . typedUnboxedToUnboxedValue) goV) segs - goV (CapV k _ segs) = - ANF.Cont <$> traverse (bitraverse (pure . typedUnboxedToUnboxedValue) goV) segs <*> goK k - goV (Foreign f) = ANF.BLit <$> goF f - goV BlackHole = die $ err "black hole" + goV :: Val -> IO ANF.Value + goV = \case + -- For back-compatibility we reflect all Unboxed values into boxed literals, we could change this in the future, + -- but there's not much of a big reason to. + UnboxedVal tu -> ANF.BLit <$> reflectUData tu + BoxedVal clos -> + case clos of + (PApV cix _rComb args) -> + ANF.Partial (goIx cix) <$> traverse goV args + (DataC r t segs) -> + ANF.Data r (maskTags t) <$> traverse goV segs + (CapV k _ segs) -> + ANF.Cont <$> traverse goV segs <*> goK k + (Foreign f) -> ANF.BLit <$> goF f + BlackHole -> die $ err "black hole" goK (CB _) = die $ err "callback continuation" goK KE = pure ANF.KE goK (Mark a ps de k) = do ps <- traverse refTy (EC.setToList ps) - de <- traverse (\(k, v) -> (,) <$> refTy k <*> goV v) (mapToList de) + de <- traverse (\(k, v) -> (,) <$> refTy k <*> goV (boxedVal v {- TODO: Double check this -})) (mapToList de) ANF.Mark (fromIntegral a) ps (M.fromList de) <$> goK k goK (Push f a cix _ _rsect k) = ANF.Push @@ -2263,8 +2268,9 @@ reflectValue rty = goV ANF.Arr <$> traverse goV a | otherwise = die $ err $ "foreign value: " <> (show f) - reflectUData :: PackedTag -> TypedUnboxed -> IO ANF.BLit - reflectUData t (TypedUnboxed v _t) + -- For back-compatibility reasons all unboxed values are uplifted to boxed when serializing to ANF. + reflectUData :: TypedUnboxed -> IO ANF.BLit + reflectUData (TypedUnboxed v t) | t == TT.natTag = pure $ ANF.Pos (fromIntegral v) | t == TT.charTag = pure $ ANF.Char (toEnum v) | t == TT.intTag, v >= 0 = pure $ ANF.Pos (fromIntegral v) @@ -2275,9 +2281,6 @@ reflectValue rty = goV intToDouble :: Int -> Double intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 - typedUnboxedToUnboxedValue :: TypedUnboxed -> ANF.UnboxedValue - typedUnboxedToUnboxedValue (TypedUnboxed v t) = ANF.UnboxedValue (fromIntegral v) t - reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Val) reifyValue cc val = do erc <- @@ -2314,18 +2317,22 @@ reifyValue0 (combs, rty, rtm) = goV let cix = (CIx r n i) in (cix, rCombSection combs cix) + goV :: ANF.Value -> IO Val goV (ANF.Partial gr vs) = goIx gr >>= \case - (cix, RComb (Comb rcomb)) -> PApV cix rcomb <$> traverse (bitraverse (pure . unboxedValueToTypedUnboxed) goV) vs + (cix, RComb (Comb rcomb)) -> boxedVal . PApV cix rcomb <$> traverse goV vs (_, RComb (CachedClosure _ clo)) - | [] <- vs -> pure clo + | [] <- vs -> pure $ boxedVal clo | otherwise -> die . err $ msg where msg = "reifyValue0: non-trivial partial application to cached value" goV (ANF.Data r t0 vs) = do t <- flip packTags (fromIntegral t0) . fromIntegral <$> refTy r - DataC r t <$> traverse (bitraverse (pure . unboxedValueToTypedUnboxed) goV) vs - goV (ANF.Cont vs k) = cv <$> goK k <*> traverse (bitraverse (pure . unboxedValueToTypedUnboxed) goV) vs + boxedVal . DataC r t <$> traverse goV vs + goV (ANF.Cont vs k) = do + k' <- goK k + vs' <- traverse goV vs + pure . boxedVal $ cv k' vs' where cv k s = CapV k a s where @@ -2357,22 +2364,22 @@ reifyValue0 (combs, rty, rtm) = goV "tried to reify a continuation with a cached value resumption" ++ show r - goL (ANF.Text t) = pure . Foreign $ Wrap Rf.textRef t - goL (ANF.List l) = Foreign . Wrap Rf.listRef <$> traverse goV l - goL (ANF.TmLink r) = pure . Foreign $ Wrap Rf.termLinkRef r - goL (ANF.TyLink r) = pure . Foreign $ Wrap Rf.typeLinkRef r - goL (ANF.Bytes b) = pure . Foreign $ Wrap Rf.bytesRef b - goL (ANF.Quote v) = pure . Foreign $ Wrap Rf.valueRef v - goL (ANF.Code g) = pure . Foreign $ Wrap Rf.codeRef g - goL (ANF.BArr a) = pure . Foreign $ Wrap Rf.ibytearrayRef a - goL (ANF.Char c) = pure $ CharClosure c - goL (ANF.Pos w) = pure $ NatClosure w - goL (ANF.Neg w) = pure $ IntClosure (negate (fromIntegral w :: Int)) - goL (ANF.Float d) = pure $ DoubleClosure d - goL (ANF.Arr a) = Foreign . Wrap Rf.iarrayRef <$> traverse goV a - - unboxedValueToTypedUnboxed :: ANF.UnboxedValue -> TypedUnboxed - unboxedValueToTypedUnboxed (ANF.UnboxedValue v t) = (TypedUnboxed (fromIntegral v) t) + goL :: ANF.BLit -> IO Val + goL (ANF.Text t) = pure . boxedVal . Foreign $ Wrap Rf.textRef t + goL (ANF.List l) = boxedVal . Foreign . Wrap Rf.listRef <$> traverse goV l + goL (ANF.TmLink r) = pure . boxedVal . Foreign $ Wrap Rf.termLinkRef r + goL (ANF.TyLink r) = pure . boxedVal . Foreign $ Wrap Rf.typeLinkRef r + goL (ANF.Bytes b) = pure . boxedVal . Foreign $ Wrap Rf.bytesRef b + goL (ANF.Quote v) = pure . boxedVal . Foreign $ Wrap Rf.valueRef v + goL (ANF.Code g) = pure . boxedVal . Foreign $ Wrap Rf.codeRef g + goL (ANF.BArr a) = pure . boxedVal . Foreign $ Wrap Rf.ibytearrayRef a + goL (ANF.Char c) = pure $ CharVal c + goL (ANF.Pos w) = + -- TODO: Should this be a Nat or an Int? + pure $ NatVal w + goL (ANF.Neg w) = pure $ IntVal (negate (fromIntegral w :: Int)) + goL (ANF.Float d) = pure $ DoubleVal d + goL (ANF.Arr a) = boxedVal . Foreign . Wrap Rf.iarrayRef <$> traverse goV a -- Universal comparison functions diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 228569517f..2422fa1477 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -49,10 +49,11 @@ module Unison.Runtime.Stack CharVal, NatVal, DoubleVal, - IntVal + IntVal, + UnboxedVal, + BoxedVal ), boxedVal, - unboxedVal, USeq, TypedUnboxed ( TypedUnboxed, @@ -314,15 +315,18 @@ traceK begin = dedup (begin, 1) splitData :: Closure -> Maybe (Reference, PackedTag, SegList) splitData = \case (Enum r t) -> Just (r, t, []) - (DataU1 r t i) -> Just (r, t, [Left i]) - (DataU2 r t i j) -> Just (r, t, [Left i, Left j]) - (DataB1 r t x) -> Just (r, t, [Right x]) - (DataB2 r t x y) -> Just (r, t, [Right x, Right y]) - (DataUB r t u b) -> Just (r, t, [Left u, Right b]) - (DataBU r t b u) -> Just (r, t, [Right b, Left u]) + (DataU1 r t u) -> Just (r, t, [typedUnboxedToVal u]) + (DataU2 r t i j) -> Just (r, t, [typedUnboxedToVal i, typedUnboxedToVal j]) + (DataB1 r t x) -> Just (r, t, [boxedVal x]) + (DataB2 r t x y) -> Just (r, t, [boxedVal x, boxedVal y]) + (DataUB r t u b) -> Just (r, t, [typedUnboxedToVal u, boxedVal b]) + (DataBU r t b u) -> Just (r, t, [boxedVal b, typedUnboxedToVal u]) (DataG r t seg) -> Just (r, t, segToList seg) _ -> Nothing +typedUnboxedToVal :: TypedUnboxed -> Val +typedUnboxedToVal (TypedUnboxed i t) = Val i (UnboxedTypeTag t) + -- | Converts a list of integers representing an unboxed segment back into the -- appropriate segment. Segments are stored backwards in the runtime, so this -- reverses the list. @@ -342,12 +346,12 @@ bseg = L.fromList . reverse formData :: Reference -> PackedTag -> SegList -> Closure formData r t [] = Enum r t -formData r t [Left i] = DataU1 r t i -formData r t [Left i, Left j] = DataU2 r t i j -formData r t [Right x] = DataB1 r t x -formData r t [Right x, Right y] = DataB2 r t x y -formData r t [Left u, Right b] = DataUB r t u b -formData r t [Right b, Left u] = DataBU r t b u +formData r t [UnboxedVal tu] = DataU1 r t tu +formData r t [UnboxedVal i, UnboxedVal j] = DataU2 r t i j +formData r t [UnboxedVal u, Val _ b] = DataUB r t u b +formData r t [Val _ b, UnboxedVal u] = DataBU r t b u +formData r t [Val _ x] = DataB1 r t x +formData r t [Val _ x, Val _ y] = DataB2 r t x y formData r t segList = DataG r t (segFromList segList) frameDataSize :: K -> Int @@ -466,9 +470,6 @@ pattern UnboxedDouble d <- TypedUnboxed (intToDouble -> d) ((== TT.floatTag) -> where UnboxedDouble d = TypedUnboxed (doubleToInt d) TT.floatTag -splitTaggedUnboxed :: TypedUnboxed -> (Int, Closure) -splitTaggedUnboxed (TypedUnboxed i t) = (i, UnboxedTypeTag t) - type SegList = [Val] pattern PApV :: CombIx -> RCombInfo Closure -> SegList -> Closure @@ -486,11 +487,7 @@ pattern CapV k a segs <- Captured k a (segToList -> segs) -- so this reverses the contents segToList :: Seg -> SegList segToList (u, b) = - zipWith combine (ints u) (bsegToList b) - where - combine i c = case c of - UnboxedTypeTag t -> Left $ TypedUnboxed i t - _ -> Right c + zipWith Val (ints u) (bsegToList b) -- | Converts an unboxed segment to a list of integers for a more interchangeable -- representation. The segments are stored in backwards order, so this reverses @@ -505,11 +502,9 @@ ints ba = fmap (indexByteArray ba) [n - 1, n - 2 .. 0] segFromList :: SegList -> Seg segFromList xs = xs - <&> ( \case - Left tu -> splitTaggedUnboxed tu - Right c -> (0, c) - ) - & unzip + & foldMap + ( \(Val unboxed boxed) -> ([unboxed], [boxed]) + ) & \(us, bs) -> (useg us, bseg bs) {-# COMPLETE DataC, PAp, Captured, Foreign, BlackHole #-} @@ -665,6 +660,28 @@ type UVal = Int data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} deriving (Show) +valToTypedUnboxed :: Val -> Maybe TypedUnboxed +valToTypedUnboxed (Val u (UnboxedTypeTag t)) = Just $ TypedUnboxed u t +valToTypedUnboxed _ = Nothing + +-- | TODO: We need to either adjust this to catch `DataU1` closures as well, or stop creating DataU1 closures for +-- unboxed values in the first place. +pattern UnboxedVal :: TypedUnboxed -> Val +pattern UnboxedVal t <- (valToTypedUnboxed -> Just t) + where + UnboxedVal (TypedUnboxed i t) = Val i (UnboxedTypeTag t) + +valToBoxed :: Val -> Maybe Closure +valToBoxed UnboxedVal {} = Nothing +valToBoxed (Val _ b) = Just b + +pattern BoxedVal :: Closure -> Val +pattern BoxedVal b <- (valToBoxed -> Just b) + where + BoxedVal b = Val 0 b + +{-# COMPLETE UnboxedVal, BoxedVal #-} + -- | The Eq instance for Val is a little strange because it takes into account the fact that if a Val is boxed, the -- unboxed side is garbage and should not be compared. instance Eq Val where @@ -677,10 +694,6 @@ instance Eq Val where boxedVal :: BVal -> Val boxedVal = Val 0 --- | Lift an unboxed val into an Val -unboxedVal :: UVal -> Val -unboxedVal u = Val u BlackHole - type USeg = ByteArray type BVal = Closure From 5e2d9990b690d24519eab40de30c4c0ce023dcfe Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 16:41:41 -0700 Subject: [PATCH 026/113] Runtime Val WIP --- .../src/Unison/Runtime/Decompile.hs | 11 +-- .../src/Unison/Runtime/Exception.hs | 2 +- .../src/Unison/Runtime/Interface.hs | 8 +-- unison-runtime/src/Unison/Runtime/Machine.hs | 68 ++++++++++--------- unison-runtime/src/Unison/Runtime/Stack.hs | 17 +++-- 5 files changed, 54 insertions(+), 52 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index ff441877c1..582433ac11 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -35,10 +35,8 @@ import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) import Unison.Runtime.MCode (CombIx (..)) import Unison.Runtime.Stack ( Closure (..), - TypedUnboxed (..), USeq, Val (..), - getTUInt, pattern DataC, pattern PApV, ) @@ -76,7 +74,7 @@ import Unison.Type typeLinkRef, ) import Unison.Util.Bytes qualified as By -import Unison.Util.Pretty (indentN, lines, lit, syntaxToColor, wrap) +import Unison.Util.Pretty (indentN, lines, lit, shown, syntaxToColor, wrap) import Unison.Util.Text qualified as Text import Unison.Var (Var) import Prelude hiding (lines) @@ -107,6 +105,9 @@ type DecompResult v = (Set DecompError, Term v ()) prf :: Reference -> Error prf = syntaxToColor . prettyReference 10 +printPackedTag :: TT.PackedTag -> Error +printPackedTag t = shown $ TT.unpackTags t + renderDecompError :: DecompError -> Error renderDecompError (BadBool n) = lines @@ -115,8 +116,8 @@ renderDecompError (BadBool n) = ] renderDecompError (BadUnboxed rf) = lines - [ wrap "An apparent numeric type had an unrecognized reference:", - indentN 2 $ prf rf + [ wrap "An apparent numeric type had an unrecognized packed tag:", + indentN 2 $ printPackedTag rf ] renderDecompError (BadForeign rf) = lines diff --git a/unison-runtime/src/Unison/Runtime/Exception.hs b/unison-runtime/src/Unison/Runtime/Exception.hs index 16a149d953..7d0d7bd5ea 100644 --- a/unison-runtime/src/Unison/Runtime/Exception.hs +++ b/unison-runtime/src/Unison/Runtime/Exception.hs @@ -10,7 +10,7 @@ import Unison.Util.Pretty as P data RuntimeExn = PE CallStack (P.Pretty P.ColorText) - | BU [(Reference, Int)] Text Closure + | BU [(Reference, Int)] Text Val deriving (Show) instance Exception RuntimeExn diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 27532c38ec..3352ba98dc 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -498,7 +498,7 @@ compileValue base = flip pair (rf base) . ANF.BLit . List . Seq.fromList . fmap cpair where rf = ANF.BLit . TmLink . RF.Ref - cons x y = Data RF.pairRef 0 [Right x, Right y] + cons x y = Data RF.pairRef 0 [x, y] tt = Data RF.unitRef 0 [] code sg = ANF.BLit (Code sg) pair x y = cons x (cons y tt) @@ -1022,7 +1022,7 @@ evalInContext :: Word64 -> IO (Either Error ([Error], Term Symbol)) evalInContext ppe ctx activeThreads w = do - r <- newIORef (boxedElem BlackHole) + r <- newIORef (boxedVal BlackHole) crs <- readTVarIO (combRefs $ ccache ctx) let hook = watchHook r decom = decompileCtx crs ctx @@ -1034,14 +1034,14 @@ evalInContext ppe ctx activeThreads w = do where tr = first (backmapRef ctx) <$> tr0 - debugText fancy c = case decom c of + debugText fancy val = case decom val of (errs, dv) | null errs -> SimpleTrace . debugTextFormat fancy $ pretty ppe dv | otherwise -> MsgTrace (debugTextFormat fancy $ tabulateErrors errs) - (show c) + (show val) (debugTextFormat fancy $ pretty ppe dv) result <- diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index ba57972750..7d0f4c6a0c 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -11,7 +11,6 @@ import Control.Concurrent (ThreadId) import Control.Concurrent.STM as STM import Control.Exception import Control.Lens -import Data.Bitraversable (Bitraversable (..)) import Data.Bits import Data.Char qualified as Char import Data.Map.Strict qualified as M @@ -107,7 +106,7 @@ data Tracer data CCache = CCache { foreignFuncs :: EnumMap Word64 ForeignFunc, sandboxed :: Bool, - tracer :: Bool -> Closure -> Tracer, + tracer :: Bool -> Val -> Tracer, -- Combinators in their original form, where they're easier to serialize into SCache srcCombs :: TVar (EnumMap Word64 Combs), combs :: TVar (EnumMap Word64 MCombs), @@ -453,9 +452,9 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim1 DBTX i) | sandboxed env = die "attempted to use sandboxed operation: Debug.toText" | otherwise = do - clo <- bpeekOff stk i + val <- peekOff stk i stk <- bump stk - stk <- case tracer env False clo of + stk <- case tracer env False val of NoTrace -> stk <$ pokeTag stk 0 MsgTrace _ _ tx -> do pokeBi stk (Util.Text.pack tx) @@ -510,13 +509,13 @@ exec !_ !denv !_activeThreads !stk !k _ (BPrim2 CMPU i j) = do pure (denv, stk, k) exec !_ !_ !_activeThreads !stk !k r (BPrim2 THRO i j) = do name <- peekOffBi @Util.Text.Text stk i - x <- bpeekOff stk j + x <- peekOff stk j throwIO (BU (traceK r k) (Util.Text.toText name) x) exec !env !denv !_activeThreads !stk !k _ (BPrim2 TRCE i j) | sandboxed env = die "attempted to use sandboxed operation: trace" | otherwise = do tx <- peekOffBi stk i - clo <- bpeekOff stk j + clo <- peekOff stk j case tracer env True clo of NoTrace -> pure () SimpleTrace str -> do @@ -633,27 +632,27 @@ encodeExn stk exc = do pokeTag stk 0 bpokeOff stk 1 $ Foreign (Wrap Rf.typeLinkRef link) pokeOffBi stk 2 msg - stk <$ bpokeOff stk 3 extra + stk <$ pokeOff stk 3 extra where disp e = Util.Text.pack $ show e (link, msg, extra) | Just (ioe :: IOException) <- fromException exn = - (Rf.ioFailureRef, disp ioe, unitValue) + (Rf.ioFailureRef, disp ioe, boxedVal unitValue) | Just re <- fromException exn = case re of PE _stk msg -> - (Rf.runtimeFailureRef, Util.Text.pack $ toPlainUnbroken msg, unitValue) - BU _ tx cl -> (Rf.runtimeFailureRef, Util.Text.fromText tx, cl) + (Rf.runtimeFailureRef, Util.Text.pack $ toPlainUnbroken msg, boxedVal unitValue) + BU _ tx val -> (Rf.runtimeFailureRef, Util.Text.fromText tx, val) | Just (ae :: ArithException) <- fromException exn = - (Rf.arithmeticFailureRef, disp ae, unitValue) + (Rf.arithmeticFailureRef, disp ae, boxedVal unitValue) | Just (nae :: NestedAtomically) <- fromException exn = - (Rf.stmFailureRef, disp nae, unitValue) + (Rf.stmFailureRef, disp nae, boxedVal unitValue) | Just (be :: BlockedIndefinitelyOnSTM) <- fromException exn = - (Rf.stmFailureRef, disp be, unitValue) + (Rf.stmFailureRef, disp be, boxedVal unitValue) | Just (be :: BlockedIndefinitelyOnMVar) <- fromException exn = - (Rf.ioFailureRef, disp be, unitValue) + (Rf.ioFailureRef, disp be, boxedVal unitValue) | Just (ie :: AsyncException) <- fromException exn = - (Rf.threadKilledFailureRef, disp ie, unitValue) - | otherwise = (Rf.miscFailureRef, disp exn, unitValue) + (Rf.threadKilledFailureRef, disp ie, boxedVal unitValue) + | otherwise = (Rf.miscFailureRef, disp exn, boxedVal unitValue) numValue :: Maybe Reference -> Closure -> IO Word64 numValue _ (DataU1 _ _ i) = pure (fromIntegral $ getTUInt i) @@ -2397,8 +2396,15 @@ universalEq :: Bool universalEq frn = eqc where + eql :: (a -> b -> Bool) -> [a] -> [b] -> Bool eql cm l r = length l == length r && and (zipWith cm l r) - eqc (DataC _ ct1 [Left w1]) (DataC _ ct2 [Left w2]) = + eqVal :: Val -> Val -> Bool + eqVal (Val u (ut@UnboxedTypeTag {})) (Val v (vt@UnboxedTypeTag {})) = u == v && ut == vt + eqVal (Val _ (UnboxedTypeTag {})) (Val _ _) = False + eqVal (Val _ _) (Val _ (UnboxedTypeTag {})) = False + eqVal (Val _ x) (Val _ y) = eqc x y + eqc :: Closure -> Closure -> Bool + eqc (DataC _ ct1 [w1]) (DataC _ ct2 [w2]) = matchTags ct1 ct2 && w1 == w2 eqc (DataC _ ct1 vs1) (DataC _ ct2 vs2) = ct1 == ct2 @@ -2419,13 +2425,8 @@ universalEq frn = eqc length sl == length sr && and (Sq.zipWith eqc sl sr) | otherwise = frn fl fr eqc c d = closureNum c == closureNum d - -- Written this way to maintain back-compat with the - -- old val lists which were separated by unboxed/boxed. - eqValList vs1 vs2 = - let (us1, bs1) = partitionEithers vs1 - (us2, bs2) = partitionEithers vs2 - in eql (==) us1 us2 - && eql eqc bs1 bs2 + eqValList :: [Val] -> [Val] -> Bool + eqValList vs1 vs2 = eql eqVal vs1 vs2 -- serialization doesn't necessarily preserve Int tags, so be -- more accepting for those. @@ -2488,14 +2489,11 @@ universalCompare :: Ordering universalCompare frn = cmpc False where + cmpl :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) + cmpc :: Bool -> Closure -> Closure -> Ordering cmpc tyEq = \cases - (DataC _ ct1 [Left (TypedUnboxed i _)]) (DataC _ ct2 [Left (TypedUnboxed j _)]) - | ct1 == TT.floatTag, ct2 == TT.floatTag -> compareAsFloat i j - | ct1 == TT.natTag, ct2 == TT.natTag -> compareAsNat i j - | ct1 == TT.intTag, ct2 == TT.natTag -> compare i j - | ct1 == TT.natTag, ct2 == TT.intTag -> compare i j (DataC rf1 ct1 vs1) (DataC rf2 ct2 vs2) -> (if tyEq && ct1 /= ct2 then compare rf1 rf2 else EQ) <> compare (maskTags ct1) (maskTags ct2) @@ -2519,11 +2517,15 @@ universalCompare frn = cmpc False arrayCmp (cmpc tyEq) al ar | otherwise -> frn fl fr c d -> comparing closureNum c d - -- Written this way to maintain back-compat with the - -- old val lists which were separated by unboxed/boxed. + cmpValList :: Bool -> [Val] -> [Val] -> Ordering cmpValList tyEq vs1 vs2 = - let (us1, bs1) = (partitionEithers vs1) - (us2, bs2) = (partitionEithers vs2) + -- Written in a strange way way to maintain back-compat with the + -- old val lists which had boxed/unboxed separated + let partitionVals = foldMap \case + UnboxedVal tu -> ([tu], mempty) + BoxedVal b -> (mempty, [b]) + (us1, bs1) = partitionVals vs1 + (us2, bs2) = partitionVals vs2 in cmpl compare us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 arrayCmp :: diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 2422fa1477..c0ae916c2e 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -371,7 +371,11 @@ pattern DataC rf ct segs <- -- | An unboxed value with an accompanying tag indicating its type. data TypedUnboxed = TypedUnboxed {getTUInt :: !Int, getTUTag :: !PackedTag} - deriving (Show, Eq, Ord) + deriving (Show, Eq) + +instance Ord TypedUnboxed where + -- Compare type tags first. + compare (TypedUnboxed i t) (TypedUnboxed i' t') = compare t t' <> compare i i' pattern CharClosure :: Char -> Closure pattern CharClosure c <- (unpackUnboxedClosure TT.charTag -> Just (Char.chr -> c)) @@ -658,6 +662,9 @@ type UVal = Int -- | A runtime value, which is either a boxed or unboxed value, but we may not know which. data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} + -- The Eq instance for Val is deliberately omitted because you need to take into account the fact that if a Val is boxed, the + -- unboxed side is garbage and should not be compared. + -- See universalEq. deriving (Show) valToTypedUnboxed :: Val -> Maybe TypedUnboxed @@ -682,14 +689,6 @@ pattern BoxedVal b <- (valToBoxed -> Just b) {-# COMPLETE UnboxedVal, BoxedVal #-} --- | The Eq instance for Val is a little strange because it takes into account the fact that if a Val is boxed, the --- unboxed side is garbage and should not be compared. -instance Eq Val where - (Val u (ut@UnboxedTypeTag {})) == (Val v (vt@UnboxedTypeTag {})) = u == v && ut == vt - (Val _ (UnboxedTypeTag {})) == (Val _ _) = False - (Val _ _) == (Val _ (UnboxedTypeTag {})) = False - (Val _ x) == (Val _ y) = x == y - -- | Lift a boxed val into an Val boxedVal :: BVal -> Val boxedVal = Val 0 From 8a1b0c854b9b05201b5381020fda634edc8f6018 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 28 Oct 2024 16:46:34 -0700 Subject: [PATCH 027/113] Assert that Mark denv in Closure Vals --- unison-runtime/src/Unison/Runtime/Machine.hs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 7d0f4c6a0c..0a24e82cb9 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2343,7 +2343,7 @@ reifyValue0 (combs, rty, rtm) = goV goK (ANF.Mark a ps de k) = mrk <$> traverse refTy ps - <*> traverse (\(k, v) -> (,) <$> refTy k <*> goV v) (M.toList de) + <*> traverse (\(k, v) -> (,) <$> refTy k <*> (expectClosure <$> goV v)) (M.toList de) <*> goK k where mrk ps de k = @@ -2362,6 +2362,9 @@ reifyValue0 (combs, rty, rtm) = goV die . err $ "tried to reify a continuation with a cached value resumption" ++ show r + expectClosure :: Val -> Closure + expectClosure v@(UnboxedVal {}) = error $ "expectClosure: Expected a closure val, but got:" <> show v + expectClosure (BoxedVal c) = c goL :: ANF.BLit -> IO Val goL (ANF.Text t) = pure . boxedVal . Foreign $ Wrap Rf.textRef t @@ -2405,7 +2408,7 @@ universalEq frn = eqc eqVal (Val _ x) (Val _ y) = eqc x y eqc :: Closure -> Closure -> Bool eqc (DataC _ ct1 [w1]) (DataC _ ct2 [w2]) = - matchTags ct1 ct2 && w1 == w2 + matchTags ct1 ct2 && eqVal w1 w2 eqc (DataC _ ct1 vs1) (DataC _ ct2 vs2) = ct1 == ct2 && eqValList vs1 vs2 From 47bf0df87e26ac4d8fc894141aaefadee3bd9f23 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 09:56:45 -0700 Subject: [PATCH 028/113] Finish fixing foreigns --- unison-runtime/src/Unison/Runtime/Decompile.hs | 2 +- .../src/Unison/Runtime/Foreign/Function.hs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 582433ac11..1e21a760e5 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -221,7 +221,7 @@ decompileForeign backref topTerms f pure $ typeLink () l | Just (a :: Array Closure) <- maybeUnwrapForeign iarrayRef f = app () (ref () iarrayFromListRef) . list () - <$> traverse (decompile backref topTerms) (toList a) + <$> traverse (decompile backref topTerms . BoxedVal) (toList a) | Just (a :: ByteArray) <- maybeUnwrapForeign ibytearrayRef f = pure $ app diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index e5274689c1..230f350503 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -483,9 +483,9 @@ instance ForeignConvention (PA.MutableByteArray s) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mbytearrayRef) --- instance ForeignConvention (PA.Array Closure) where --- readForeign = readForeignAs (unwrapForeign . marshalToForeign) --- writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) +instance ForeignConvention (PA.Array Closure) where + readForeign = readForeignAs (unwrapForeign . marshalToForeign) + writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) instance ForeignConvention PA.ByteArray where readForeign = readForeignAs (unwrapForeign . marshalToForeign) @@ -495,8 +495,8 @@ instance {-# OVERLAPPABLE #-} (BuiltinForeign b) => ForeignConvention b where readForeign = readForeignBuiltin writeForeign = writeForeignBuiltin -fromUnisonPair :: Closure -> (a, b) -fromUnisonPair (DataC _ _ [Right x, Right (DataC _ _ [Right y, Right _])]) = +fromUnisonPair :: (BuiltinForeign a, BuiltinForeign b) => Closure -> (a, b) +fromUnisonPair (DataC _ _ [BoxedVal x, BoxedVal (DataC _ _ [BoxedVal y, BoxedVal _unit])]) = (unwrapForeignClosure x, unwrapForeignClosure y) fromUnisonPair _ = error "fromUnisonPair: invalid closure" @@ -506,7 +506,7 @@ toUnisonPair (x, y) = DataC Ty.pairRef (PackedTag 0) - [Right $ wr x, Right $ DataC Ty.pairRef (PackedTag 0) [Right $ wr y, Right $ un]] + [BoxedVal $ wr x, BoxedVal $ DataC Ty.pairRef (PackedTag 0) [BoxedVal $ wr y, BoxedVal $ un]] where un = DataC Ty.unitRef (PackedTag 0) [] wr z = Foreign $ wrapBuiltin z From 3ba902622b88e962f66e1b646fe382ba10887784 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 10:15:05 -0700 Subject: [PATCH 029/113] Remove unboxing in casts --- unison-runtime/src/Unison/Runtime/Builtin.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 44462549a6..82a993f397 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -823,10 +823,9 @@ andb = binop0 0 $ \[p, q] -> -- no-op on the representation. Ideally this will be inlined and -- eliminated so that no instruction is necessary. cast :: Reference -> Reference -> SuperNormal Symbol -cast ri ro = - unop0 1 $ \[x0, x] -> - unbox x0 ri x $ - TCon ro 0 [x] +cast _ri _ro = + -- TODO: Is there a way to avoid providing anything at all here? + unop0 0 $ \[x] -> TVar x -- This version of unsafeCoerce is the identity function. It works -- only if the two types being coerced between are actually the same, From 6f2e5c57098a5cae45a8326a47f98acd269e56e3 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 10:15:05 -0700 Subject: [PATCH 030/113] Support unboxed vals in dumpData --- unison-runtime/src/Unison/Runtime/Machine.hs | 88 +++++++++++--------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 0a24e82cb9..1632313abe 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -681,14 +681,14 @@ eval !env !denv !activeThreads !stk !k r (Match i br) = do n <- peekOffN stk i eval env denv activeThreads stk k r $ selectBranch n br eval !env !denv !activeThreads !stk !k r (DMatch mr i br) = do - (t, stk) <- dumpDataNoTag mr stk =<< bpeekOff stk i + (t, stk) <- dumpDataNoTag mr stk =<< peekOff stk i eval env denv activeThreads stk k r $ selectBranch (maskTags t) br eval !env !denv !activeThreads !stk !k r (NMatch mr i br) = do n <- numValue mr =<< bpeekOff stk i eval env denv activeThreads stk k r $ selectBranch n br eval !env !denv !activeThreads !stk !k r (RMatch i pu br) = do - (t, stk) <- dumpDataNoTag Nothing stk =<< bpeekOff stk i + (t, stk) <- dumpDataNoTag Nothing stk =<< peekOff stk i if t == PackedTag 0 then eval env denv activeThreads stk k r pu else case ANF.unpackTags t of @@ -998,45 +998,53 @@ buildData !stk !r !t (VArgV i) = do dumpDataNoTag :: Maybe Reference -> Stack -> - Closure -> + Val -> IO (PackedTag, Stack) -dumpDataNoTag !_ !stk (Enum _ t) = pure (t, stk) -dumpDataNoTag !_ !stk (DataU1 _ t x) = do - stk <- bump stk - pokeTU stk x - pure (t, stk) -dumpDataNoTag !_ !stk (DataU2 _ t x y) = do - stk <- bumpn stk 2 - pokeOffTU stk 1 y - pokeTU stk x - pure (t, stk) -dumpDataNoTag !_ !stk (DataB1 _ t x) = do - stk <- bump stk - bpoke stk x - pure (t, stk) -dumpDataNoTag !_ !stk (DataB2 _ t x y) = do - stk <- bumpn stk 2 - bpokeOff stk 1 y - bpoke stk x - pure (t, stk) -dumpDataNoTag !_ !stk (DataUB _ t x y) = do - stk <- bumpn stk 2 - pokeTU stk x - bpokeOff stk 1 y - pure (t, stk) -dumpDataNoTag !_ !stk (DataBU _ t x y) = do - stk <- bumpn stk 2 - bpoke stk x - pokeOffTU stk 1 y - pure (t, stk) -dumpDataNoTag !_ !stk (DataG _ t seg) = do - stk <- dumpSeg stk seg S - pure (t, stk) -dumpDataNoTag !mr !_ clo = - die $ - "dumpDataNoTag: bad closure: " - ++ show clo - ++ maybe "" (\r -> "\nexpected type: " ++ show r) mr +dumpDataNoTag !mr !stk = \case + -- Normally we want to avoid dumping unboxed values since it's unnecessary, but sometimes we don't know the type of + -- the incoming value and end up dumping unboxed values, so we just push them back to the stack as-is. e.g. in type-casts/coercions + val@(UnboxedVal tu) -> do + stk <- bump stk + poke stk val + pure (getTUTag tu, stk) + (BoxedVal clos) -> case clos of + (Enum _ t) -> pure (t, stk) + (DataU1 _ t x) -> do + stk <- bump stk + pokeTU stk x + pure (t, stk) + (DataU2 _ t x y) -> do + stk <- bumpn stk 2 + pokeOffTU stk 1 y + pokeTU stk x + pure (t, stk) + (DataB1 _ t x) -> do + stk <- bump stk + bpoke stk x + pure (t, stk) + (DataB2 _ t x y) -> do + stk <- bumpn stk 2 + bpokeOff stk 1 y + bpoke stk x + pure (t, stk) + (DataUB _ t x y) -> do + stk <- bumpn stk 2 + pokeTU stk x + bpokeOff stk 1 y + pure (t, stk) + (DataBU _ t x y) -> do + stk <- bumpn stk 2 + bpoke stk x + pokeOffTU stk 1 y + pure (t, stk) + (DataG _ t seg) -> do + stk <- dumpSeg stk seg S + pure (t, stk) + clo -> + die $ + "dumpDataNoTag: bad closure: " + ++ show clo + ++ maybe "" (\r -> "\nexpected type: " ++ show r) mr {-# INLINE dumpDataNoTag #-} -- Note: although the representation allows it, it is impossible From 926941b7451b0c5a72d965fd120225b56d7f83fd Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 10:34:19 -0700 Subject: [PATCH 031/113] Replace boxed casting with coerceType --- unison-runtime/src/Unison/Runtime/Builtin.hs | 25 ++++++++------------ 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 82a993f397..7ae40acc97 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -299,10 +299,10 @@ notlift :: (Var v) => v -> ANormal v notlift v = TMatch v $ MatchIntegral (mapFromList [(1, fls), (0, tru)]) Nothing -unbox :: (Var v) => v -> Reference -> v -> ANormal v -> ANormal v -unbox v0 r v b = - TMatch v0 $ - MatchData r (mapSingleton 0 $ ([UN], TAbs v b)) Nothing +-- unbox :: (Var v) => v -> Reference -> v -> ANormal v -> ANormal v +-- unbox v0 r v b = +-- TMatch v0 $ +-- MatchData r (mapSingleton 0 $ ([UN], TAbs v b)) Nothing unenum :: (Var v) => Int -> v -> Reference -> v -> ANormal v -> ANormal v unenum n v0 r v nx = @@ -623,11 +623,6 @@ appends = binop0 0 $ \[x, y] -> TPrm CATS [x, y] conss = binop0 0 $ \[x, y] -> TPrm CONS [x, y] snocs = binop0 0 $ \[x, y] -> TPrm SNOC [x, y] -coerceType :: (Var v) => Reference -> Reference -> SuperNormal v -coerceType fromType toType = unop0 1 $ \[x, r] -> - unbox x fromType r $ - TCon toType 0 [r] - takes, drops, sizes, ats, emptys :: (Var v) => SuperNormal v takes = binop0 0 $ \[x, y] -> TPrm TAKS [x, y] drops = binop0 0 $ \[x, y] -> TPrm DRPS [x, y] @@ -822,9 +817,9 @@ andb = binop0 0 $ \[p, q] -> -- unsafeCoerce, used for numeric types where conversion is a -- no-op on the representation. Ideally this will be inlined and -- eliminated so that no instruction is necessary. -cast :: Reference -> Reference -> SuperNormal Symbol -cast _ri _ro = - -- TODO: Is there a way to avoid providing anything at all here? +coerceType :: Reference -> Reference -> SuperNormal Symbol +coerceType _ri _ro = + -- TODO: Fix this with a proper type-coercion unop0 0 $ \[x] -> TVar x -- This version of unsafeCoerce is the identity function. It works @@ -2061,7 +2056,7 @@ builtinLookup = ("Nat.complement", (Untracked, compln)), ("Nat.pow", (Untracked, pown)), ("Nat.drop", (Untracked, dropn)), - ("Nat.toInt", (Untracked, cast Ty.natRef Ty.intRef)), + ("Nat.toInt", (Untracked, coerceType Ty.natRef Ty.intRef)), ("Nat.toFloat", (Untracked, n2f)), ("Nat.toText", (Untracked, n2t)), ("Nat.fromText", (Untracked, t2n)), @@ -2131,8 +2126,8 @@ builtinLookup = ("Debug.trace", (Tracked, gen'trace)), ("Debug.toText", (Tracked, debug'text)), ("unsafe.coerceAbilities", (Untracked, poly'coerce)), - ("Char.toNat", (Untracked, cast Ty.charRef Ty.natRef)), - ("Char.fromNat", (Untracked, cast Ty.natRef Ty.charRef)), + ("Char.toNat", (Untracked, coerceType Ty.charRef Ty.natRef)), + ("Char.fromNat", (Untracked, coerceType Ty.natRef Ty.charRef)), ("Bytes.empty", (Untracked, emptyb)), ("Bytes.fromList", (Untracked, packb)), ("Bytes.toList", (Untracked, unpackb)), From 2f9a562e3736321a89968c79c82ef471ac16dd23 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 10:34:19 -0700 Subject: [PATCH 032/113] Fix numValue calculation --- unison-runtime/src/Unison/Runtime/Builtin.hs | 2 ++ unison-runtime/src/Unison/Runtime/Machine.hs | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 7ae40acc97..e507576252 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -821,6 +821,8 @@ coerceType :: Reference -> Reference -> SuperNormal Symbol coerceType _ri _ro = -- TODO: Fix this with a proper type-coercion unop0 0 $ \[x] -> TVar x + -- unbox x0 ri x $ + -- TCon ro 0 [x] -- This version of unsafeCoerce is the identity function. It works -- only if the two types being coerced between are actually the same, diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 1632313abe..5004bc610a 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -654,8 +654,9 @@ encodeExn stk exc = do (Rf.threadKilledFailureRef, disp ie, boxedVal unitValue) | otherwise = (Rf.miscFailureRef, disp exn, boxedVal unitValue) -numValue :: Maybe Reference -> Closure -> IO Word64 -numValue _ (DataU1 _ _ i) = pure (fromIntegral $ getTUInt i) +numValue :: Maybe Reference -> Val -> IO Word64 +numValue _ (UnboxedVal tu) = pure (fromIntegral $ getTUInt tu) +numValue _ (BoxedVal (DataU1 _ _ i)) = pure (fromIntegral $ getTUInt i) numValue mr clo = die $ "numValue: bad closure: " @@ -685,7 +686,7 @@ eval !env !denv !activeThreads !stk !k r (DMatch mr i br) = do eval env denv activeThreads stk k r $ selectBranch (maskTags t) br eval !env !denv !activeThreads !stk !k r (NMatch mr i br) = do - n <- numValue mr =<< bpeekOff stk i + n <- numValue mr =<< peekOff stk i eval env denv activeThreads stk k r $ selectBranch n br eval !env !denv !activeThreads !stk !k r (RMatch i pu br) = do (t, stk) <- dumpDataNoTag Nothing stk =<< peekOff stk i From 5d90b70835a613592a1d3db41e5aad24100304ec Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 11:48:03 -0700 Subject: [PATCH 033/113] Improve stack debugging --- unison-runtime/src/Unison/Runtime/Machine.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 5004bc610a..62661bd31c 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -304,17 +304,17 @@ buildLit _ _ (MD _) = error "buildLit: double" debugger :: (Show a) => Stack -> String -> a -> Bool debugger stk msg a = unsafePerformIO $ do - Debug.debugLogM Debug.Temp (msg ++ ": " ++ show a) dumpStack stk + Debug.debugLogM Debug.Temp (msg ++ ": " ++ show a) pure False dumpStack :: Stack -> IO () dumpStack stk@(Stack _ap fp sp _ustk _bstk) - | sp - fp <= 0 = Debug.debugLogM Debug.Temp "Stack Empty" + | sp - fp < 0 = Debug.debugLogM Debug.Temp "Stack before 👇: Empty" | otherwise = do stkResults <- for [0 .. ((sp - fp) - 1)] $ \i -> do peekOff stk i - Debug.debugM Debug.Temp "Stack" stkResults + Debug.debugM Debug.Temp "Stack before 👇:" stkResults -- | Execute an instruction exec :: From 3a993eb75b6115d8bee16f0c60ea5b4cd09df8ab Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 15:33:36 -0700 Subject: [PATCH 034/113] Fix buggy outMaybeNat --- unison-runtime/src/Unison/Runtime/Builtin.hs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index e507576252..d0f2f515d0 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -1299,17 +1299,15 @@ outMaybe maybe result = (1, ([BX], TAbs maybe $ some maybe)) ] -outMaybeNat :: (Var v) => v -> v -> v -> ANormal v -outMaybeNat tag result n = +outMaybeNat :: (Var v) => v -> v -> ANormal v +outMaybeNat tag result = TMatch tag . MatchSum $ mapFromList [ (0, ([], none)), ( 1, ( [UN], -- TODO: Fix this? - TAbs result - . TLetD n BX (TCon Ty.natRef 0 [n]) - $ some n + TAbs result $ some result ) ) ] @@ -1763,9 +1761,9 @@ boxToMaybeBox = -- a -> Maybe Nat boxToMaybeNat :: ForeignOp -boxToMaybeNat = inBx arg tag $ outMaybeNat tag result n +boxToMaybeNat = inBx arg tag $ outMaybeNat tag result where - (arg, tag, result, n) = fresh + (arg, tag, result) = fresh -- a -> Maybe (Nat, b) boxToMaybeNTup :: ForeignOp From f844e5705fe8507537a288530ffe71904c3e2a35 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 16:37:36 -0700 Subject: [PATCH 035/113] Switch resolve to handle Vals --- unison-runtime/src/Unison/Runtime/Machine.hs | 79 ++++++++++---------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 62661bd31c..eaa2a8c952 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -245,7 +245,7 @@ apply0 !callback !env !threadTracker !i = do Comb entryComb -> do Debug.debugM Debug.Temp "Entry Comb" entryComb -- Debug.debugM Debug.Temp "All Combs" cmbs - apply env denv threadTracker stk (kf k0) True ZArgs $ + apply env denv threadTracker stk (kf k0) True ZArgs . BoxedVal $ PAp entryCix entryComb nullSeg -- if it's cached, we can just finish CachedClosure _ clo -> bump stk >>= \stk -> bpoke stk clo @@ -262,7 +262,7 @@ apply1 :: IO () apply1 callback env threadTracker clo = do stk <- alloc - apply env mempty threadTracker stk k0 True ZArgs clo + apply env mempty threadTracker stk k0 True ZArgs $ BoxedVal clo where k0 = CB $ Hook callback @@ -333,7 +333,8 @@ exec !_ !denv !_activeThreads !stk !k _ (Info tx) = do info tx k pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (Name r args) = do - stk <- name stk args =<< resolve env denv stk r + v <- resolve env denv stk r + stk <- name stk args v pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (SetDyn p i) = do clo <- bpeekOff stk i @@ -700,7 +701,7 @@ eval !env !denv !activeThreads !stk !k r (RMatch i pu br) = do eval !env !denv !activeThreads !stk !k _ (Yield args) | asize stk > 0, VArg1 i <- args = - bpeekOff stk i >>= apply env denv activeThreads stk k False ZArgs + peekOff stk i >>= apply env denv activeThreads stk k False ZArgs | otherwise = do stk <- moveArgs stk args stk <- frameArgs stk @@ -793,14 +794,14 @@ enter !env !denv !activeThreads !stk !k !ck !args = \case {-# INLINE enter #-} -- fast path by-name delaying -name :: Stack -> Args -> Closure -> IO Stack -name !stk !args clo = case clo of - PAp cix comb seg -> do +name :: Stack -> Args -> Val -> IO Stack +name !stk !args = \case + BoxedVal (PAp cix comb seg) -> do seg <- closeArgs I stk seg args stk <- bump stk bpoke stk $ PAp cix comb seg pure stk - _ -> die $ "naming non-function: " ++ show clo + v -> die $ "naming non-function: " ++ show v {-# INLINE name #-} -- slow path application @@ -812,37 +813,40 @@ apply :: K -> Bool -> Args -> - Closure -> + Val -> IO () -apply !env !denv !activeThreads !stk !k !ck !args = \case - (PAp cix@(CIx combRef _ _) comb seg) -> - case comb of - LamI a f entry - | ck || a <= ac -> do - stk <- ensure stk f - stk <- moveArgs stk args - stk <- dumpSeg stk seg A - stk <- acceptArgs stk a - eval env denv activeThreads stk k combRef entry - | otherwise -> do - seg <- closeArgs C stk seg args - stk <- discardFrame =<< frameArgs stk - stk <- bump stk - bpoke stk $ PAp cix comb seg - yield env denv activeThreads stk k - where - ac = asize stk + countArgs args + scount seg - clo -> zeroArgClosure clo +apply !_env !_denv !_activeThreads !stk !_k !_ck !args !val + | debugger stk "apply" (args, val) = undefined +apply !env !denv !activeThreads !stk !k !ck !args !val = + case val of + BoxedVal (PAp cix@(CIx combRef _ _) comb seg) -> + case comb of + LamI a f entry + | ck || a <= ac -> do + stk <- ensure stk f + stk <- moveArgs stk args + stk <- dumpSeg stk seg A + stk <- acceptArgs stk a + eval env denv activeThreads stk k combRef entry + | otherwise -> do + seg <- closeArgs C stk seg args + stk <- discardFrame =<< frameArgs stk + stk <- bump stk + bpoke stk $ PAp cix comb seg + yield env denv activeThreads stk k + where + ac = asize stk + countArgs args + scount seg + v -> zeroArgClosure v where - zeroArgClosure :: Closure -> IO () - zeroArgClosure clo + zeroArgClosure :: Val -> IO () + zeroArgClosure v | ZArgs <- args, asize stk == 0 = do stk <- discardFrame stk stk <- bump stk - bpoke stk clo + poke stk v yield env denv activeThreads stk k - | otherwise = die $ "applying non-function: " ++ show clo + | otherwise = die $ "applying non-function: " ++ show v {-# INLINE apply #-} jump :: @@ -898,7 +902,6 @@ repush !env !activeThreads !stk = go go !_ (CB _) !_ = die "repush: impossible" {-# INLINE repush #-} --- TODO: Double-check this one moveArgs :: Stack -> Args -> @@ -1847,7 +1850,7 @@ yield !env !denv !activeThreads !stk !k = leap denv k clo = denv0 EC.! EC.findMin ps bpoke stk . DataB1 Rf.effectRef (PackedTag 0) =<< bpeek stk stk <- adjustArgs stk a - apply env denv activeThreads stk k False (VArg1 0) clo + apply env denv activeThreads stk k False (VArg1 0) (BoxedVal clo) leap !denv (Push fsz asz (CIx ref _ _) f nx k) = do stk <- restoreFrame stk fsz asz stk <- ensure stk f @@ -1931,11 +1934,11 @@ discardCont denv stk k p = <&> \(_, denv, stk, k) -> (denv, stk, k) {-# INLINE discardCont #-} -resolve :: CCache -> DEnv -> Stack -> MRef -> IO Closure -resolve _ _ _ (Env cix mcomb) = pure $ mCombClosure cix mcomb -resolve _ _ stk (Stk i) = bpeekOff stk i +resolve :: CCache -> DEnv -> Stack -> MRef -> IO Val +resolve _ _ _ (Env cix mcomb) = pure . boxedVal $ mCombClosure cix mcomb +resolve _ _ stk (Stk i) = peekOff stk i resolve env denv _ (Dyn i) = case EC.lookup i denv of - Just clo -> pure clo + Just clo -> pure . boxedVal $ clo Nothing -> unhandledErr "resolve" env i unhandledErr :: String -> CCache -> Word64 -> IO a From c7a510bb3f14f2e39c8fd875655f4c5d846963d5 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 16:48:37 -0700 Subject: [PATCH 036/113] Fix universalEq/compare to work on unboxed values too. --- unison-runtime/src/Unison/Runtime/Machine.hs | 33 +++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index eaa2a8c952..1a478d9586 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -63,6 +63,7 @@ import Unison.Symbol (Symbol) import Unison.Type qualified as Rf import Unison.Util.Bytes qualified as By import Unison.Util.EnumContainers as EC +import Unison.Util.Monoid qualified as Monoid import Unison.Util.Pretty (toPlainUnbroken) import Unison.Util.Text qualified as Util.Text import UnliftIO (IORef) @@ -497,14 +498,14 @@ exec !env !denv !_activeThreads !stk !k _ (BPrim2 SDBV i j) bpoke stk $ encodeSandboxResult res pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (BPrim2 EQLU i j) = do - x <- bpeekOff stk i - y <- bpeekOff stk j + x <- peekOff stk i + y <- peekOff stk j stk <- bump stk pokeBool stk $ universalEq (==) x y pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (BPrim2 CMPU i j) = do - x <- bpeekOff stk i - y <- bpeekOff stk j + x <- peekOff stk i + y <- peekOff stk j stk <- bump stk pokeI stk . fromEnum $ universalCompare compare x y pure (denv, stk, k) @@ -1638,8 +1639,8 @@ bprim2 :: Int -> IO Stack bprim2 !stk EQLU i j = do - x <- bpeekOff stk i - y <- bpeekOff stk j + x <- peekOff stk i + y <- peekOff stk j stk <- bump stk pokeBool stk $ universalEq (==) x y pure stk @@ -2406,10 +2407,10 @@ closureNum BlackHole {} = error "BlackHole" universalEq :: (Foreign -> Foreign -> Bool) -> - Closure -> - Closure -> + Val -> + Val -> Bool -universalEq frn = eqc +universalEq frn = eqVal where eql :: (a -> b -> Bool) -> [a] -> [b] -> Bool eql cm l r = length l == length r && and (zipWith cm l r) @@ -2499,11 +2500,19 @@ compareAsNat i j = compare ni nj universalCompare :: (Foreign -> Foreign -> Ordering) -> - Closure -> - Closure -> + Val -> + Val -> Ordering -universalCompare frn = cmpc False +universalCompare frn = cmpVal False where + cmpVal :: Bool -> Val -> Val -> Ordering + cmpVal tyEq = \cases + (UnboxedVal tu1) (UnboxedVal tu2) -> + Monoid.whenM tyEq (compare (maskTags $ getTUTag tu1) (maskTags $ getTUTag tu2)) + <> compare (getTUInt tu1) (getTUInt tu2) + (BoxedVal c1) (BoxedVal c2) -> cmpc tyEq c1 c2 + (UnboxedVal _) (BoxedVal _) -> LT + (BoxedVal _) (UnboxedVal _) -> GT cmpl :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) From bb942173088531ddf3189b968adf67f6fef89da8 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 16:53:02 -0700 Subject: [PATCH 037/113] Closure -> Val in apps --- unison-runtime/src/Unison/Runtime/Machine.hs | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 1a478d9586..e6ee90f55c 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -259,11 +259,11 @@ apply1 :: (Stack -> IO ()) -> CCache -> ActiveThreads -> - Closure -> + Val -> IO () apply1 callback env threadTracker clo = do stk <- alloc - apply env mempty threadTracker stk k0 True ZArgs $ BoxedVal clo + apply env mempty threadTracker stk k0 True ZArgs $ clo where k0 = CB $ Hook callback @@ -595,23 +595,23 @@ exec !env !denv !_activeThreads !stk !k _ (ForeignCall _ w args) exec !env !denv !activeThreads !stk !k _ (Fork i) | sandboxed env = die "attempted to use sandboxed operation: fork" | otherwise = do - tid <- forkEval env activeThreads =<< bpeekOff stk i + tid <- forkEval env activeThreads =<< peekOff stk i stk <- bump stk bpoke stk . Foreign . Wrap Rf.threadIdRef $ tid pure (denv, stk, k) exec !env !denv !activeThreads !stk !k _ (Atomically i) | sandboxed env = die $ "attempted to use sandboxed operation: atomically" | otherwise = do - c <- bpeekOff stk i + v <- peekOff stk i stk <- bump stk - atomicEval env activeThreads (bpoke stk) c + atomicEval env activeThreads (poke stk) v pure (denv, stk, k) exec !env !denv !activeThreads !stk !k _ (TryForce i) | sandboxed env = die $ "attempted to use sandboxed operation: tryForce" | otherwise = do - c <- bpeekOff stk i + v <- peekOff stk i stk <- bump stk -- Bump the boxed stack to make a slot for the result, which will be written in the callback if we succeed. - ev <- Control.Exception.try $ nestEval env activeThreads (bpoke stk) c + ev <- Control.Exception.try $ nestEval env activeThreads (poke stk) v stk <- encodeExn stk ev pure (denv, stk, k) {-# INLINE exec #-} @@ -731,7 +731,7 @@ eval !_ !_ !_ !_activeThreads !_ _ Exit = pure () eval !_ !_ !_ !_activeThreads !_ _ (Die s) = die s {-# NOINLINE eval #-} -forkEval :: CCache -> ActiveThreads -> Closure -> IO ThreadId +forkEval :: CCache -> ActiveThreads -> Val -> IO ThreadId forkEval env activeThreads clo = do threadId <- @@ -757,15 +757,15 @@ forkEval env activeThreads clo = UnliftIO.atomicModifyIORef' activeThreads (\ids -> (Set.delete myThreadId ids, ())) {-# INLINE forkEval #-} -nestEval :: CCache -> ActiveThreads -> (Closure -> IO ()) -> Closure -> IO () -nestEval env activeThreads write clo = apply1 readBack env activeThreads clo +nestEval :: CCache -> ActiveThreads -> (Val -> IO ()) -> Val -> IO () +nestEval env activeThreads write val = apply1 readBack env activeThreads val where - readBack stk = bpeek stk >>= write + readBack stk = peek stk >>= write {-# INLINE nestEval #-} -atomicEval :: CCache -> ActiveThreads -> (Closure -> IO ()) -> Closure -> IO () -atomicEval env activeThreads write clo = - atomically . unsafeIOToSTM $ nestEval env activeThreads write clo +atomicEval :: CCache -> ActiveThreads -> (Val -> IO ()) -> Val -> IO () +atomicEval env activeThreads write val = + atomically . unsafeIOToSTM $ nestEval env activeThreads write val {-# INLINE atomicEval #-} -- fast path application From 5af46ff0ebe694e581b0913434472645e9a1d55c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 17:12:39 -0700 Subject: [PATCH 038/113] Use Vals instead of Closures almost everywhere --- .../src/Unison/Runtime/Interface.hs | 2 +- unison-runtime/src/Unison/Runtime/MCode.hs | 44 +++++------ .../src/Unison/Runtime/MCode/Serialize.hs | 4 +- unison-runtime/src/Unison/Runtime/Machine.hs | 73 +++++++++---------- unison-runtime/src/Unison/Runtime/Stack.hs | 30 ++++++-- 5 files changed, 85 insertions(+), 68 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 3352ba98dc..c76fd2d6d1 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -1358,7 +1358,7 @@ restoreCache (SCache cs crs cacheableCombs trs ftm fty int rtm rty sbs) = do srcCombs = let builtinCombs = mapWithKey (\k v -> emitComb @Symbol rns (rf k) k mempty (0, v)) numberedTermLookup in builtinCombs <> cs - combs :: EnumMap Word64 (RCombs Closure) + combs :: EnumMap Word64 (RCombs Val) combs = srcCombs & absurdCombs diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index d86f5a7715..d700478329 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -445,7 +445,7 @@ data MLit type Instr = GInstr CombIx -type RInstr clos = GInstr (RComb clos) +type RInstr val = GInstr (RComb val) -- Instructions for manipulating the data stack in the main portion of -- a block @@ -516,7 +516,7 @@ data GInstr comb type Section = GSection CombIx -type RSection clos = GSection (RComb clos) +type RSection val = GSection (RComb val) data GSection comb = -- Apply a function to arguments. This is the 'slow path', and @@ -618,18 +618,18 @@ data GCombInfo comb !(GSection comb) -- Entry deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) -data GComb clos comb +data GComb val comb = Comb {-# UNPACK #-} !(GCombInfo comb) | -- A pre-evaluated comb, typically a pure top-level const - CachedClosure !Word64 {- top level comb ix -} !clos + CachedVal !Word64 {- top level comb ix -} !val deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) pattern Lam :: - Int -> Int -> GSection comb -> GComb clos comb + Int -> Int -> GSection comb -> GComb val comb pattern Lam a f sect = Comb (LamI a f sect) -- it seems GHC can't figure this out itself -{-# COMPLETE CachedClosure, Lam #-} +{-# COMPLETE CachedVal, Lam #-} instance Bifunctor GComb where bimap = bimapDefault @@ -638,26 +638,26 @@ instance Bifoldable GComb where bifoldMap = bifoldMapDefault instance Bitraversable GComb where - bitraverse f _ (CachedClosure cix c) = CachedClosure cix <$> f c + bitraverse f _ (CachedVal cix c) = CachedVal cix <$> f c bitraverse _ f (Lam a fr s) = Lam a fr <$> traverse f s -type RCombs clos = GCombs clos (RComb clos) +type RCombs val = GCombs val (RComb val) -- | The fixed point of a GComb where all references to a Comb are themselves Combs. -newtype RComb clos = RComb {unRComb :: GComb clos (RComb clos)} +newtype RComb val = RComb {unRComb :: GComb val (RComb val)} -type RCombInfo clos = GCombInfo (RComb clos) +type RCombInfo val = GCombInfo (RComb val) -instance Show (RComb clos) where +instance Show (RComb val) where show _ = "" -- | Map of combinators, parameterized by comb reference type -type GCombs clos comb = EnumMap Word64 (GComb clos comb) +type GCombs val comb = EnumMap Word64 (GComb val comb) -- | A reference to a combinator, parameterized by comb type Ref = GRef CombIx -type RRef clos = GRef (RComb clos) +type RRef val = GRef (RComb val) data GRef comb = Stk !Int -- stack reference to a closure @@ -667,7 +667,7 @@ data GRef comb type Branch = GBranch CombIx -type RBranch clos = GBranch (RComb clos) +type RBranch val = GBranch (RComb val) data GBranch comb = -- if tag == n then t else f @@ -792,10 +792,10 @@ emitCombs rns grpr grpn (Rec grp ent) = -- tying the knot recursively when necessary. resolveCombs :: -- Existing in-scope combs that might be referenced - Maybe (EnumMap Word64 (RCombs clos)) -> + Maybe (EnumMap Word64 (RCombs val)) -> -- Combinators which need their knots tied. - EnumMap Word64 (GCombs clos CombIx) -> - EnumMap Word64 (RCombs clos) + EnumMap Word64 (GCombs val CombIx) -> + EnumMap Word64 (RCombs val) resolveCombs mayExisting combs = -- Fixed point lookup; -- We make sure not to force resolved Combs or we'll loop forever. @@ -1537,13 +1537,13 @@ demuxArgs = \case [(i, _), (j, _)] -> VArg2 i j args -> VArgN $ PA.primArrayFromList (fst <$> args) -combDeps :: GComb clos comb -> [Word64] +combDeps :: GComb val comb -> [Word64] combDeps (Lam _ _ s) = sectionDeps s -combDeps (CachedClosure {}) = [] +combDeps (CachedVal {}) = [] combTypes :: GComb any comb -> [Word64] combTypes (Lam _ _ s) = sectionTypes s -combTypes (CachedClosure {}) = [] +combTypes (CachedVal {}) = [] sectionDeps :: GSection comb -> [Word64] sectionDeps (App _ (Env (CIx _ w _) _) _) = [w] @@ -1608,7 +1608,7 @@ prettyCombs w es = id (mapToList es) -prettyComb :: (Show clos, Show comb) => Word64 -> Word64 -> GComb clos comb -> ShowS +prettyComb :: (Show val, Show comb) => Word64 -> Word64 -> GComb val comb -> ShowS prettyComb w i = \case (Lam a _ s) -> shows w @@ -1617,7 +1617,7 @@ prettyComb w i = \case . shows a . showString ":\n" . prettySection 2 s - (CachedClosure a b) -> + (CachedVal a b) -> shows w . showString ":" . shows i diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 749ca48a5b..f915a4d035 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -44,8 +44,8 @@ putComb :: (MonadPut m) => (clos -> m ()) -> GComb clos comb -> m () putComb pClos = \case (Lam a f body) -> putTag LamT *> pInt a *> pInt f *> putSection body - (CachedClosure w c) -> - putTag CachedClosureT *> putNat w *> pClos c + (CachedVal w v) -> + putTag CachedClosureT *> putNat w *> pClos v getComb :: (MonadGet m) => m (GComb Void CombIx) getComb = diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index e6ee90f55c..4798a4433b 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -82,21 +82,21 @@ type ActiveThreads = Maybe (IORef (Set ThreadId)) type Tag = Word64 -- dynamic environment -type DEnv = EnumMap Word64 Closure +type DEnv = EnumMap Word64 Val -type MCombs = RCombs Closure +type MCombs = RCombs Val type Combs = GCombs Void CombIx -type MSection = RSection Closure +type MSection = RSection Val -type MBranch = RBranch Closure +type MBranch = RBranch Val -type MInstr = RInstr Closure +type MInstr = RInstr Val -type MComb = RComb Closure +type MComb = RComb Val -type MRef = RRef Closure +type MRef = RRef Val data Tracer = NoTrace @@ -200,10 +200,10 @@ eval0 !env !activeThreads !co = do topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) eval env denv activeThreads stk (k KE) dummyRef co -mCombClosure :: CombIx -> MComb -> Closure -mCombClosure cix (RComb (Comb comb)) = - PAp cix comb nullSeg -mCombClosure _ (RComb (CachedClosure _ clo)) = clo +mCombVal :: CombIx -> MComb -> Val +mCombVal cix (RComb (Comb comb)) = + BoxedVal (PAp cix comb nullSeg) +mCombVal _ (RComb (CachedVal _ clo)) = clo topDEnv :: EnumMap Word64 MCombs -> @@ -215,7 +215,7 @@ topDEnv combs rfTy rfTm rcrf <- Builtin (DTx.pack "raise"), Just j <- M.lookup rcrf rfTm, cix <- CIx rcrf j 0, - clo <- mCombClosure cix $ rCombSection combs cix = + clo <- mCombVal cix $ rCombSection combs cix = ( EC.mapSingleton n clo, Mark 0 (EC.setSingleton n) mempty ) @@ -249,7 +249,7 @@ apply0 !callback !env !threadTracker !i = do apply env denv threadTracker stk (kf k0) True ZArgs . BoxedVal $ PAp entryCix entryComb nullSeg -- if it's cached, we can just finish - CachedClosure _ clo -> bump stk >>= \stk -> bpoke stk clo + CachedVal _ val -> bump stk >>= \stk -> poke stk val where k0 = maybe KE (CB . Hook) callback @@ -291,8 +291,8 @@ jump0 !callback !env !activeThreads !clo = do unitValue :: Closure unitValue = Enum Rf.unitRef TT.unitTag -lookupDenv :: Word64 -> DEnv -> Closure -lookupDenv p denv = fromMaybe BlackHole $ EC.lookup p denv +lookupDenv :: Word64 -> DEnv -> Val +lookupDenv p denv = fromMaybe (BoxedVal BlackHole) $ EC.lookup p denv buildLit :: Reference -> PackedTag -> MLit -> Closure buildLit _ _ (MI i) = IntClosure i @@ -338,12 +338,12 @@ exec !env !denv !_activeThreads !stk !k _ (Name r args) = do stk <- name stk args v pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (SetDyn p i) = do - clo <- bpeekOff stk i - pure (EC.mapInsert p clo denv, stk, k) + val <- peekOff stk i + pure (EC.mapInsert p val denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (Capture p) = do (cap, denv, stk, k) <- splitCont denv stk k p stk <- bump stk - bpoke stk cap + poke stk cap pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (UPrim1 op i) = do stk <- uprim1 stk op i @@ -787,10 +787,10 @@ enter !env !denv !activeThreads !stk !k !ck !args = \case -- TODO: start putting references in `Call` if we ever start -- detecting saturated calls. eval env denv activeThreads stk k dummyRef entry - (RComb (CachedClosure _cix clos)) -> do + (RComb (CachedVal _cix val)) -> do stk <- discardFrame stk stk <- bump stk - bpoke stk clos + poke stk val yield env denv activeThreads stk k {-# INLINE enter #-} @@ -1848,10 +1848,10 @@ yield !env !denv !activeThreads !stk !k = leap denv k where leap !denv0 (Mark a ps cs k) = do let denv = cs <> EC.withoutKeys denv0 ps - clo = denv0 EC.! EC.findMin ps + val = denv0 EC.! EC.findMin ps bpoke stk . DataB1 Rf.effectRef (PackedTag 0) =<< bpeek stk stk <- adjustArgs stk a - apply env denv activeThreads stk k False (VArg1 0) (BoxedVal clo) + apply env denv activeThreads stk k False (VArg1 0) val leap !denv (Push fsz asz (CIx ref _ _) f nx k) = do stk <- restoreFrame stk fsz asz stk <- ensure stk f @@ -1894,12 +1894,12 @@ splitCont :: Stack -> K -> Word64 -> - IO (Closure, DEnv, Stack, K) + IO (Val, DEnv, Stack, K) splitCont !denv !stk !k !p = walk denv asz KE k where asz = asize stk - walk :: EnumMap Word64 Closure -> SZ -> K -> K -> IO (Closure, EnumMap Word64 Closure, Stack, K) + walk :: EnumMap Word64 Val -> SZ -> K -> K -> IO (Val, EnumMap Word64 Val, Stack, K) walk !denv !sz !ck KE = die "fell off stack" >> finish denv sz 0 ck KE walk !denv !sz !ck (CB _) = @@ -1917,11 +1917,11 @@ splitCont !denv !stk !k !p = (Push n a br p brSect ck) k - finish :: EnumMap Word64 Closure -> SZ -> SZ -> K -> K -> (IO (Closure, EnumMap Word64 Closure, Stack, K)) + finish :: EnumMap Word64 Val -> SZ -> SZ -> K -> K -> (IO (Val, EnumMap Word64 Val, Stack, K)) finish !denv !sz !a !ck !k = do (seg, stk) <- grab stk sz stk <- adjustArgs stk a - return (Captured ck asz seg, denv, stk, k) + return (BoxedVal $ Captured ck asz seg, denv, stk, k) {-# INLINE splitCont #-} discardCont :: @@ -1936,10 +1936,10 @@ discardCont denv stk k p = {-# INLINE discardCont #-} resolve :: CCache -> DEnv -> Stack -> MRef -> IO Val -resolve _ _ _ (Env cix mcomb) = pure . boxedVal $ mCombClosure cix mcomb +resolve _ _ _ (Env cix mcomb) = pure $ mCombVal cix mcomb resolve _ _ stk (Stk i) = peekOff stk i resolve env denv _ (Dyn i) = case EC.lookup i denv of - Just clo -> pure . boxedVal $ clo + Just val -> pure val Nothing -> unhandledErr "resolve" env i unhandledErr :: String -> CCache -> Word64 -> IO a @@ -2161,15 +2161,15 @@ cacheAdd0 ntys0 termSuperGroups sands cc = do pure $ int `seq` rtm `seq` newCombRefs `seq` updatedCombs `seq` nsn `seq` ncc `seq` nsc `seq` (unresolvedCacheableCombs, unresolvedNonCacheableCombs) preEvalTopLevelConstants unresolvedCacheableCombs unresolvedNonCacheableCombs cc -preEvalTopLevelConstants :: (EnumMap Word64 (GCombs Closure CombIx)) -> (EnumMap Word64 (GCombs Closure CombIx)) -> CCache -> IO () +preEvalTopLevelConstants :: (EnumMap Word64 (GCombs Val CombIx)) -> (EnumMap Word64 (GCombs Val CombIx)) -> CCache -> IO () preEvalTopLevelConstants cacheableCombs newCombs cc = do activeThreads <- Just <$> UnliftIO.newIORef mempty evaluatedCacheableCombsVar <- newTVarIO mempty for_ (EC.mapToList cacheableCombs) \(w, _) -> do let hook stk = do - clos <- bpeek stk + val <- peek stk atomically $ do - modifyTVar evaluatedCacheableCombsVar $ EC.mapInsert w (EC.mapSingleton 0 $ CachedClosure w clos) + modifyTVar evaluatedCacheableCombsVar $ EC.mapInsert w (EC.mapSingleton 0 $ CachedVal w val) apply0 (Just hook) cc activeThreads w evaluatedCacheableCombs <- readTVarIO evaluatedCacheableCombsVar @@ -2250,7 +2250,7 @@ reflectValue rty = goV goK KE = pure ANF.KE goK (Mark a ps de k) = do ps <- traverse refTy (EC.setToList ps) - de <- traverse (\(k, v) -> (,) <$> refTy k <*> goV (boxedVal v {- TODO: Double check this -})) (mapToList de) + de <- traverse (\(k, v) -> (,) <$> refTy k <*> goV v) (mapToList de) ANF.Mark (fromIntegral a) ps (M.fromList de) <$> goK k goK (Push f a cix _ _rsect k) = ANF.Push @@ -2333,8 +2333,8 @@ reifyValue0 (combs, rty, rtm) = goV goV (ANF.Partial gr vs) = goIx gr >>= \case (cix, RComb (Comb rcomb)) -> boxedVal . PApV cix rcomb <$> traverse goV vs - (_, RComb (CachedClosure _ clo)) - | [] <- vs -> pure $ boxedVal clo + (_, RComb (CachedVal _ val)) + | [] <- vs -> pure val | otherwise -> die . err $ msg where msg = "reifyValue0: non-trivial partial application to cached value" @@ -2356,7 +2356,7 @@ reifyValue0 (combs, rty, rtm) = goV goK (ANF.Mark a ps de k) = mrk <$> traverse refTy ps - <*> traverse (\(k, v) -> (,) <$> refTy k <*> (expectClosure <$> goV v)) (M.toList de) + <*> traverse (\(k, v) -> (,) <$> refTy k <*> (goV v)) (M.toList de) <*> goK k where mrk ps de k = @@ -2375,9 +2375,6 @@ reifyValue0 (combs, rty, rtm) = goV die . err $ "tried to reify a continuation with a cached value resumption" ++ show r - expectClosure :: Val -> Closure - expectClosure v@(UnboxedVal {}) = error $ "expectClosure: Expected a closure val, but got:" <> show v - expectClosure (BoxedVal c) = c goL :: ANF.BLit -> IO Val goL (ANF.Text t) = pure . boxedVal . Foreign $ Wrap Rf.textRef t diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index c0ae916c2e..21e0ba925e 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -176,7 +176,7 @@ data K Mark !Int -- pending args !(EnumSet Word64) - !(EnumMap Word64 Closure) + !(EnumMap Word64 Val) !K | -- save information about a frame for later resumption Push @@ -184,7 +184,7 @@ data K !Int -- pending args !CombIx -- resumption section reference !Int -- stack guard - !(RSection Closure) -- resumption section + !(RSection Val) -- resumption section !K instance Eq K where @@ -210,7 +210,7 @@ instance Ord K where compare (Mark {}) _ = LT compare _ (Mark {}) = GT -newtype Closure = Closure {unClosure :: (GClosure (RComb Closure))} +newtype Closure = Closure {unClosure :: (GClosure (RComb Val))} deriving stock (Show, Eq, Ord) -- | Implementation for Unison sequences. @@ -476,7 +476,7 @@ pattern UnboxedDouble d <- TypedUnboxed (intToDouble -> d) ((== TT.floatTag) -> type SegList = [Val] -pattern PApV :: CombIx -> RCombInfo Closure -> SegList -> Closure +pattern PApV :: CombIx -> RCombInfo Val -> SegList -> Closure pattern PApV cix rcomb segs <- PAp cix rcomb (segToList -> segs) where @@ -667,6 +667,22 @@ data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} -- See universalEq. deriving (Show) +instance Eq Val where + (==) = \cases + (Val u (ut@UnboxedTypeTag {})) (Val v (vt@UnboxedTypeTag {})) -> u == v && ut == vt + (Val _ (UnboxedTypeTag {})) (Val _ _) -> False + (Val _ _) (Val _ (UnboxedTypeTag {})) -> False + (Val _ x) (Val _ y) -> x == y + +instance Ord Val where + compare = \cases + (UnboxedVal tu1) (UnboxedVal tu2) -> + (compare (getTUTag tu1) (getTUTag tu2)) + <> compare (getTUInt tu1) (getTUInt tu2) + (BoxedVal c1) (BoxedVal c2) -> compare c1 c2 + (UnboxedVal _) (BoxedVal _) -> LT + (BoxedVal _) (UnboxedVal _) -> GT + valToTypedUnboxed :: Val -> Maybe TypedUnboxed valToTypedUnboxed (Val u (UnboxedTypeTag t)) = Just $ TypedUnboxed u t valToTypedUnboxed _ = Nothing @@ -1170,7 +1186,11 @@ closureTermRefs f = \case contTermRefs :: (Monoid m) => (Reference -> m) -> K -> m contTermRefs f (Mark _ _ m k) = - foldMap (closureTermRefs f) m <> contTermRefs f k + ( m & foldMap \case + BoxedVal clo -> closureTermRefs f clo + _ -> mempty + ) + <> contTermRefs f k contTermRefs f (Push _ _ (CIx r _ _) _ _ k) = f r <> contTermRefs f k contTermRefs _ _ = mempty From ab66f8ec752121d93e007552adebb0b97af73678 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 10:22:21 -0700 Subject: [PATCH 039/113] Clean up closure patterns --- unison-runtime/src/Unison/Runtime/Machine.hs | 10 ++++---- unison-runtime/src/Unison/Runtime/Stack.hs | 26 ++++++-------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 4798a4433b..35e9291371 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1,9 +1,5 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DataKinds #-} -{-# LANGUAGE PatternGuards #-} -{-# LANGUAGE PatternSynonyms #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ViewPatterns #-} module Unison.Runtime.Machine where @@ -2245,6 +2241,7 @@ reflectValue rty = goV ANF.Cont <$> traverse goV segs <*> goK k (Foreign f) -> ANF.BLit <$> goF f BlackHole -> die $ err "black hole" + UnboxedTypeTag {} -> die $ err "impossible unboxed type tag" goK (CB _) = die $ err "callback continuation" goK KE = pure ANF.KE @@ -2400,7 +2397,8 @@ closureNum PAp {} = 0 closureNum DataC {} = 1 closureNum Captured {} = 2 closureNum Foreign {} = 3 -closureNum BlackHole {} = error "BlackHole" +closureNum UnboxedTypeTag {} = 4 +closureNum BlackHole {} = 5 universalEq :: (Foreign -> Foreign -> Bool) -> @@ -2537,6 +2535,8 @@ universalCompare frn = cmpVal False Just ar <- maybeUnwrapForeign Rf.iarrayRef fr -> arrayCmp (cmpc tyEq) al ar | otherwise -> frn fl fr + (UnboxedTypeTag t1) (UnboxedTypeTag t2) -> compare t1 t2 + (BlackHole) (BlackHole) -> EQ c d -> comparing closureNum c d cmpValList :: Bool -> [Val] -> [Val] -> Ordering cmpValList tyEq vs1 vs2 = diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 21e0ba925e..b42cc514fe 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -1,11 +1,3 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE PatternGuards #-} -{-# LANGUAGE PatternSynonyms #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE ViewPatterns #-} - module Unison.Runtime.Stack ( K (..), GClosure (..), @@ -282,6 +274,14 @@ pattern BlackHole = Closure GBlackHole pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) +{-# COMPLETE PAp, Enum, DataU1, DataU2, DataB1, DataB2, DataUB, DataBU, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} + +{-# COMPLETE DataC, PAp, Captured, Foreign, BlackHole, UnboxedTypeTag #-} + +{-# COMPLETE DataC, PApV, Captured, Foreign, BlackHole, UnboxedTypeTag #-} + +{-# COMPLETE DataC, PApV, CapV, Foreign, BlackHole, UnboxedTypeTag #-} + -- We can avoid allocating a closure for common type tags on each poke by having shared top-level closures for them. natTypeTag :: Closure natTypeTag = UnboxedTypeTag TT.natTag @@ -299,10 +299,6 @@ floatTypeTag :: Closure floatTypeTag = UnboxedTypeTag TT.floatTag {-# NOINLINE floatTypeTag #-} -{-# COMPLETE PAp, Enum, DataU1, DataU2, DataB1, DataB2, DataUB, DataBU, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} - -{-# COMPLETE DataC, Captured, Foreign, UnboxedTypeTag, BlackHole #-} - traceK :: Reference -> K -> [(Reference, Int)] traceK begin = dedup (begin, 1) where @@ -511,12 +507,6 @@ segFromList xs = ) & \(us, bs) -> (useg us, bseg bs) -{-# COMPLETE DataC, PAp, Captured, Foreign, BlackHole #-} - -{-# COMPLETE DataC, PApV, Captured, Foreign, BlackHole #-} - -{-# COMPLETE DataC, PApV, CapV, Foreign, BlackHole #-} - marshalToForeign :: (HasCallStack) => Closure -> Foreign marshalToForeign (Foreign x) = x marshalToForeign c = From 86c6234394ea5c7d93af19724a065b720bb71e92 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 10:38:17 -0700 Subject: [PATCH 040/113] Remove TypedUnboxed and the convention of storing unboxed values in DataU1 closures --- unison-runtime/src/Unison/Runtime/Stack.hs | 121 +++------------------ 1 file changed, 18 insertions(+), 103 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index b42cc514fe..86b5091a98 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -18,11 +18,7 @@ module Unison.Runtime.Stack Captured, Foreign, BlackHole, - UnboxedTypeTag, - CharClosure, - NatClosure, - DoubleClosure, - IntClosure + UnboxedTypeTag ), IxClosure, Callback (..), @@ -47,15 +43,6 @@ module Unison.Runtime.Stack ), boxedVal, USeq, - TypedUnboxed - ( TypedUnboxed, - getTUInt, - getTUTag, - UnboxedChar, - UnboxedNat, - UnboxedInt, - UnboxedDouble - ), traceK, frameDataSize, marshalToForeign, @@ -109,8 +96,6 @@ module Unison.Runtime.Stack upokeT, upokeOffT, unsafePokeIasN, - pokeTU, - pokeOffTU, bump, bumpn, grab, @@ -216,12 +201,12 @@ data GClosure comb {-# UNPACK #-} !(GCombInfo comb) {-# UNPACK #-} !Seg -- args | GEnum !Reference !PackedTag - | GDataU1 !Reference !PackedTag !TypedUnboxed - | GDataU2 !Reference !PackedTag !TypedUnboxed !TypedUnboxed + | GDataU1 !Reference !PackedTag !Val + | GDataU2 !Reference !PackedTag !Val !Val | GDataB1 !Reference !PackedTag !(GClosure comb) | GDataB2 !Reference !PackedTag !(GClosure comb) !(GClosure comb) - | GDataUB !Reference !PackedTag !TypedUnboxed !(GClosure comb) - | GDataBU !Reference !PackedTag !(GClosure comb) !TypedUnboxed + | GDataUB !Reference !PackedTag !Val !(GClosure comb) + | GDataBU !Reference !PackedTag !(GClosure comb) !Val | GDataG !Reference !PackedTag {-# UNPACK #-} !Seg | -- code cont, arg size, u/b data stacks GCaptured !K !Int {-# UNPACK #-} !Seg @@ -311,18 +296,15 @@ traceK begin = dedup (begin, 1) splitData :: Closure -> Maybe (Reference, PackedTag, SegList) splitData = \case (Enum r t) -> Just (r, t, []) - (DataU1 r t u) -> Just (r, t, [typedUnboxedToVal u]) - (DataU2 r t i j) -> Just (r, t, [typedUnboxedToVal i, typedUnboxedToVal j]) + (DataU1 r t u) -> Just (r, t, [u]) + (DataU2 r t i j) -> Just (r, t, [i, j]) (DataB1 r t x) -> Just (r, t, [boxedVal x]) (DataB2 r t x y) -> Just (r, t, [boxedVal x, boxedVal y]) - (DataUB r t u b) -> Just (r, t, [typedUnboxedToVal u, boxedVal b]) - (DataBU r t b u) -> Just (r, t, [boxedVal b, typedUnboxedToVal u]) + (DataUB r t u b) -> Just (r, t, [u, boxedVal b]) + (DataBU r t b u) -> Just (r, t, [boxedVal b, u]) (DataG r t seg) -> Just (r, t, segToList seg) _ -> Nothing -typedUnboxedToVal :: TypedUnboxed -> Val -typedUnboxedToVal (TypedUnboxed i t) = Val i (UnboxedTypeTag t) - -- | Converts a list of integers representing an unboxed segment back into the -- appropriate segment. Segments are stored backwards in the runtime, so this -- reverses the list. @@ -365,38 +347,9 @@ pattern DataC rf ct segs <- where DataC rf ct segs = formData rf ct segs --- | An unboxed value with an accompanying tag indicating its type. -data TypedUnboxed = TypedUnboxed {getTUInt :: !Int, getTUTag :: !PackedTag} - deriving (Show, Eq) - -instance Ord TypedUnboxed where - -- Compare type tags first. - compare (TypedUnboxed i t) (TypedUnboxed i' t') = compare t t' <> compare i i' - -pattern CharClosure :: Char -> Closure -pattern CharClosure c <- (unpackUnboxedClosure TT.charTag -> Just (Char.chr -> c)) - where - CharClosure c = DataU1 Ty.charRef TT.charTag (TypedUnboxed (Char.ord c) TT.charTag) - -pattern NatClosure :: Word64 -> Closure -pattern NatClosure n <- (unpackUnboxedClosure TT.natTag -> Just (toEnum -> n)) - where - NatClosure n = DataU1 Ty.natRef TT.natTag (TypedUnboxed (fromEnum n) TT.natTag) - -pattern DoubleClosure :: Double -> Closure -pattern DoubleClosure d <- (unpackUnboxedClosure TT.floatTag -> Just (intToDouble -> d)) - where - DoubleClosure d = DataU1 Ty.floatRef TT.floatTag (TypedUnboxed (doubleToInt d) TT.floatTag) - -pattern IntClosure :: Int -> Closure -pattern IntClosure i <- (unpackUnboxedClosure TT.intTag -> Just i) - where - IntClosure i = DataU1 Ty.intRef TT.intTag (TypedUnboxed i TT.intTag) - matchCharVal :: Val -> Maybe Char matchCharVal = \case (Val u (UnboxedTypeTag tt)) | tt == TT.charTag -> Just (Char.chr u) - (Val _ (CharClosure c)) -> Just c _ -> Nothing pattern CharVal :: Char -> Val @@ -407,7 +360,6 @@ pattern CharVal c <- (matchCharVal -> Just c) matchNatVal :: Val -> Maybe Word64 matchNatVal = \case (Val u (UnboxedTypeTag tt)) | tt == TT.natTag -> Just (toEnum u) - (Val _ (NatClosure n)) -> Just n _ -> Nothing pattern NatVal :: Word64 -> Val @@ -418,7 +370,6 @@ pattern NatVal n <- (matchNatVal -> Just n) matchDoubleVal :: Val -> Maybe Double matchDoubleVal = \case (Val u (UnboxedTypeTag tt)) | tt == TT.floatTag -> Just (intToDouble u) - (Val _ (DoubleClosure d)) -> Just d _ -> Nothing pattern DoubleVal :: Double -> Val @@ -429,7 +380,6 @@ pattern DoubleVal d <- (matchDoubleVal -> Just d) matchIntVal :: Val -> Maybe Int matchIntVal = \case (Val u (UnboxedTypeTag tt)) | tt == TT.intTag -> Just u - (Val _ (IntClosure i)) -> Just i _ -> Nothing pattern IntVal :: Int -> Val @@ -439,36 +389,11 @@ pattern IntVal i <- (matchIntVal -> Just i) doubleToInt :: Double -> Int doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 +{-# INLINE doubleToInt #-} intToDouble :: Int -> Double intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 - -unpackUnboxedClosure :: PackedTag -> Closure -> Maybe Int -unpackUnboxedClosure expectedTag = \case - DataU1 _ref tag (TypedUnboxed i _) - | tag == expectedTag -> Just i - _ -> Nothing -{-# INLINE unpackUnboxedClosure #-} - -pattern UnboxedChar :: Char -> TypedUnboxed -pattern UnboxedChar c <- TypedUnboxed (Char.chr -> c) ((== TT.charTag) -> True) - where - UnboxedChar c = TypedUnboxed (Char.ord c) TT.charTag - -pattern UnboxedNat :: Word64 -> TypedUnboxed -pattern UnboxedNat n <- TypedUnboxed (toEnum -> n) ((== TT.natTag) -> True) - where - UnboxedNat n = TypedUnboxed (fromEnum n) TT.natTag - -pattern UnboxedInt :: Int -> TypedUnboxed -pattern UnboxedInt i <- TypedUnboxed i ((== TT.intTag) -> True) - where - UnboxedInt i = TypedUnboxed i TT.intTag - -pattern UnboxedDouble :: Double -> TypedUnboxed -pattern UnboxedDouble d <- TypedUnboxed (intToDouble -> d) ((== TT.floatTag) -> True) - where - UnboxedDouble d = TypedUnboxed (doubleToInt d) TT.floatTag +{-# INLINE intToDouble #-} type SegList = [Val] @@ -666,28 +591,26 @@ instance Eq Val where instance Ord Val where compare = \cases - (UnboxedVal tu1) (UnboxedVal tu2) -> - (compare (getTUTag tu1) (getTUTag tu2)) - <> compare (getTUInt tu1) (getTUInt tu2) (BoxedVal c1) (BoxedVal c2) -> compare c1 c2 + (UnboxedVal (Val i1 t1)) (UnboxedVal (Val i2 t2)) -> compare t1 t2 <> compare i1 i2 (UnboxedVal _) (BoxedVal _) -> LT (BoxedVal _) (UnboxedVal _) -> GT -valToTypedUnboxed :: Val -> Maybe TypedUnboxed -valToTypedUnboxed (Val u (UnboxedTypeTag t)) = Just $ TypedUnboxed u t +-- | Matches a Val which is known to be unboxed, and returns the entire original value. +valToTypedUnboxed :: Val -> Maybe Val +valToTypedUnboxed v@(Val _ (UnboxedTypeTag {})) = Just v valToTypedUnboxed _ = Nothing --- | TODO: We need to either adjust this to catch `DataU1` closures as well, or stop creating DataU1 closures for --- unboxed values in the first place. -pattern UnboxedVal :: TypedUnboxed -> Val +pattern UnboxedVal :: Val -> Val pattern UnboxedVal t <- (valToTypedUnboxed -> Just t) where - UnboxedVal (TypedUnboxed i t) = Val i (UnboxedTypeTag t) + UnboxedVal v = v valToBoxed :: Val -> Maybe Closure valToBoxed UnboxedVal {} = Nothing valToBoxed (Val _ b) = Just b +-- | Matches a Val which is known to be boxed, and returns the closure portion. pattern BoxedVal :: Closure -> Val pattern BoxedVal b <- (valToBoxed -> Just b) where @@ -772,10 +695,6 @@ unsafePokeIasN stk n = do upokeT stk n TT.natTag {-# INLINE unsafePokeIasN #-} -pokeTU :: Stack -> TypedUnboxed -> IO () -pokeTU stk !(TypedUnboxed u t) = poke stk (Val u (UnboxedTypeTag t)) -{-# INLINE pokeTU #-} - -- | Store an unboxed tag to later match on. -- Often used to indicate the constructor of a data type that's been unpacked onto the stack, -- or some tag we're about to branch on. @@ -819,10 +738,6 @@ upokeOffT stk i u t = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOffT #-} -pokeOffTU :: Stack -> Off -> TypedUnboxed -> IO () -pokeOffTU stk i (TypedUnboxed u t) = pokeOff stk i (Val u (UnboxedTypeTag t)) -{-# INLINE pokeOffTU #-} - bpokeOff :: Stack -> Off -> BVal -> IO () bpokeOff (Stack _ _ sp _ bstk) i b = writeArray bstk (sp - i) b {-# INLINE bpokeOff #-} From 8cc3f5c60fd04c80b559bd95a64d478d573add10 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 10:41:07 -0700 Subject: [PATCH 041/113] Change builtins/foreigns to use Val rather than Closures --- .../src/Unison/Runtime/Foreign/Function.hs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 230f350503..c96052dce1 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -125,12 +125,12 @@ instance ForeignConvention Char where -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. -instance ForeignConvention Closure where - readForeign (i : args) stk = (args,) <$> bpeekOff stk i - readForeign [] _ = foreignCCError "Closure" - writeForeign stk c = do +instance ForeignConvention Val where + readForeign (i : args) stk = (args,) <$> peekOff stk i + readForeign [] _ = foreignCCError "Val" + writeForeign stk v = do stk <- bump stk - stk <$ (bpoke stk =<< evaluate c) + stk <$ (poke stk =<< evaluate v) instance ForeignConvention Text where readForeign = readForeignBuiltin @@ -431,35 +431,35 @@ instance ForeignConvention BufferMode where -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. -instance ForeignConvention [Closure] where +instance ForeignConvention [Val] where readForeign (i : args) stk = - (args,) . fmap getBoxedVal . toList <$> peekOffS stk i - readForeign _ _ = foreignCCError "[Closure]" + (args,) . toList <$> peekOffS stk i + readForeign _ _ = foreignCCError "[Val]" writeForeign stk l = do stk <- bump stk - stk <$ pokeS stk (Sq.fromList $ fmap boxedVal l) + stk <$ pokeS stk (Sq.fromList l) instance ForeignConvention [Foreign] where readForeign = readForeignAs (fmap marshalToForeign) writeForeign = writeForeignAs (fmap Foreign) -instance ForeignConvention (MVar Closure) where +instance ForeignConvention (MVar Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mvarRef) -instance ForeignConvention (TVar Closure) where +instance ForeignConvention (TVar Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap tvarRef) -instance ForeignConvention (IORef Closure) where +instance ForeignConvention (IORef Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap refRef) -instance ForeignConvention (Ticket Closure) where +instance ForeignConvention (Ticket Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap ticketRef) -instance ForeignConvention (Promise Closure) where +instance ForeignConvention (Promise Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap promiseRef) @@ -475,7 +475,7 @@ instance ForeignConvention Foreign where readForeign = readForeignAs marshalToForeign writeForeign = writeForeignAs Foreign -instance ForeignConvention (PA.MutableArray s Closure) where +instance ForeignConvention (PA.MutableArray s Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap marrayRef) @@ -483,7 +483,7 @@ instance ForeignConvention (PA.MutableByteArray s) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mbytearrayRef) -instance ForeignConvention (PA.Array Closure) where +instance ForeignConvention (PA.Array Val) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) From 79df6833e7c5a28b248310f24318470216c38628 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 13:27:28 -0700 Subject: [PATCH 042/113] Fix bad uargOnto --- unison-runtime/src/Unison/Runtime/Stack.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 86b5091a98..e77c07a4f6 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -492,7 +492,7 @@ uargOnto stk sp cop cp0 (ArgN v) = do loop $ i - 1 loop $ sz - 1 when overwrite $ - copyMutableByteArray cop (bytes $ cp + 1) buf 0 (bytes sz) + copyMutableByteArray cop (bytes $ cp0 + 1) buf 0 (bytes sz) pure cp where cp = cp0 + sz From f5dabea33d23ca8b3e45b705aa8d819d253a5e17 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 14:07:52 -0700 Subject: [PATCH 043/113] Replace Closures with Val in most builtins --- unison-runtime/src/Unison/Runtime/Builtin.hs | 102 +++++++++--------- .../src/Unison/Runtime/Foreign/Function.hs | 23 +++- unison-runtime/src/Unison/Runtime/Machine.hs | 47 ++++---- unison-runtime/src/Unison/Runtime/Stack.hs | 5 + 4 files changed, 95 insertions(+), 82 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index d0f2f515d0..8b0431342d 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -172,7 +172,7 @@ import Unison.Runtime.Foreign ) import Unison.Runtime.Foreign qualified as F import Unison.Runtime.Foreign.Function -import Unison.Runtime.Stack (Closure) +import Unison.Runtime.Stack (Val (..), emptyVal) import Unison.Runtime.Stack qualified as Closure import Unison.Symbol import Unison.Type (charRef) @@ -195,7 +195,7 @@ import Unison.Util.Text qualified as Util.Text import Unison.Util.Text.Pattern qualified as TPat import Unison.Var -type Failure = F.Failure Closure +type Failure = F.Failure Val freshes :: (Var v) => Int -> [v] freshes = freshes' mempty @@ -2223,11 +2223,11 @@ mkForeignIOF f = mkForeign $ \a -> tryIOE (f a) handleIOE (Left e) = Left $ Failure Ty.ioFailureRef (Util.Text.pack (show e)) unitValue handleIOE (Right a) = Right a -unitValue :: Closure -unitValue = Closure.Enum Ty.unitRef (PackedTag 0) +unitValue :: Val +unitValue = BoxedVal $ Closure.Enum Ty.unitRef (PackedTag 0) -natValue :: Word64 -> Closure -natValue w = Closure.NatClosure w +natValue :: Word64 -> Val +natValue w = NatVal w mkForeignTls :: forall a r. @@ -2564,43 +2564,43 @@ declareForeigns = do declareForeign Tracked "MVar.new" boxDirect . mkForeign - $ \(c :: Closure) -> newMVar c + $ \(c :: Val) -> newMVar c declareForeign Tracked "MVar.newEmpty.v2" unitDirect . mkForeign - $ \() -> newEmptyMVar @Closure + $ \() -> newEmptyMVar @Val declareForeign Tracked "MVar.take.impl.v3" boxToEFBox . mkForeignIOF - $ \(mv :: MVar Closure) -> takeMVar mv + $ \(mv :: MVar Val) -> takeMVar mv declareForeign Tracked "MVar.tryTake" boxToMaybeBox . mkForeign - $ \(mv :: MVar Closure) -> tryTakeMVar mv + $ \(mv :: MVar Val) -> tryTakeMVar mv declareForeign Tracked "MVar.put.impl.v3" boxBoxToEF0 . mkForeignIOF - $ \(mv :: MVar Closure, x) -> putMVar mv x + $ \(mv :: MVar Val, x) -> putMVar mv x declareForeign Tracked "MVar.tryPut.impl.v3" boxBoxToEFBool . mkForeignIOF - $ \(mv :: MVar Closure, x) -> tryPutMVar mv x + $ \(mv :: MVar Val, x) -> tryPutMVar mv x declareForeign Tracked "MVar.swap.impl.v3" boxBoxToEFBox . mkForeignIOF - $ \(mv :: MVar Closure, x) -> swapMVar mv x + $ \(mv :: MVar Val, x) -> swapMVar mv x declareForeign Tracked "MVar.isEmpty" boxToBool . mkForeign - $ \(mv :: MVar Closure) -> isEmptyMVar mv + $ \(mv :: MVar Val) -> isEmptyMVar mv declareForeign Tracked "MVar.read.impl.v3" boxToEFBox . mkForeignIOF - $ \(mv :: MVar Closure) -> readMVar mv + $ \(mv :: MVar Val) -> readMVar mv declareForeign Tracked "MVar.tryRead.impl.v3" boxToEFMBox . mkForeignIOF - $ \(mv :: MVar Closure) -> tryReadMVar mv + $ \(mv :: MVar Val) -> tryReadMVar mv declareForeign Untracked "Char.toText" (wordDirect Ty.charRef) . mkForeign $ \(ch :: Char) -> pure (Util.Text.singleton ch) @@ -2654,35 +2654,35 @@ declareForeigns = do \(certs :: [X.SignedCertificate], params :: ServerParams) -> pure $ updateServer (X.makeCertificateStore certs) params declareForeign Tracked "TVar.new" boxDirect . mkForeign $ - \(c :: Closure) -> unsafeSTMToIO $ STM.newTVar c + \(c :: Val) -> unsafeSTMToIO $ STM.newTVar c declareForeign Tracked "TVar.read" boxDirect . mkForeign $ - \(v :: STM.TVar Closure) -> unsafeSTMToIO $ STM.readTVar v + \(v :: STM.TVar Val) -> unsafeSTMToIO $ STM.readTVar v declareForeign Tracked "TVar.write" boxBoxTo0 . mkForeign $ - \(v :: STM.TVar Closure, c :: Closure) -> + \(v :: STM.TVar Val, c :: Val) -> unsafeSTMToIO $ STM.writeTVar v c declareForeign Tracked "TVar.newIO" boxDirect . mkForeign $ - \(c :: Closure) -> STM.newTVarIO c + \(c :: Val) -> STM.newTVarIO c declareForeign Tracked "TVar.readIO" boxDirect . mkForeign $ - \(v :: STM.TVar Closure) -> STM.readTVarIO v + \(v :: STM.TVar Val) -> STM.readTVarIO v declareForeign Tracked "TVar.swap" boxBoxDirect . mkForeign $ - \(v, c :: Closure) -> unsafeSTMToIO $ STM.swapTVar v c + \(v, c :: Val) -> unsafeSTMToIO $ STM.swapTVar v c declareForeign Tracked "STM.retry" unitDirect . mkForeign $ - \() -> unsafeSTMToIO STM.retry :: IO Closure + \() -> unsafeSTMToIO STM.retry :: IO Val -- Scope and Ref stuff declareForeign Untracked "Scope.ref" boxDirect . mkForeign - $ \(c :: Closure) -> newIORef c + $ \(c :: Val) -> newIORef c declareForeign Tracked "IO.ref" boxDirect . mkForeign - $ \(c :: Closure) -> evaluate c >>= newIORef + $ \(c :: Val) -> evaluate c >>= newIORef -- The docs for IORef state that IORef operations can be observed -- out of order ([1]) but actually GHC does emit the appropriate @@ -2692,16 +2692,16 @@ declareForeigns = do -- [2] https://github.com/ghc/ghc/blob/master/compiler/GHC/StgToCmm/Prim.hs#L286 -- [3] https://github.com/ghc/ghc/blob/master/compiler/GHC/StgToCmm/Prim.hs#L298 declareForeign Untracked "Ref.read" boxDirect . mkForeign $ - \(r :: IORef Closure) -> readIORef r + \(r :: IORef Val) -> readIORef r declareForeign Untracked "Ref.write" boxBoxTo0 . mkForeign $ - \(r :: IORef Closure, c :: Closure) -> evaluate c >>= writeIORef r + \(r :: IORef Val, c :: Val) -> evaluate c >>= writeIORef r declareForeign Tracked "Ref.readForCas" boxDirect . mkForeign $ - \(r :: IORef Closure) -> readForCAS r + \(r :: IORef Val) -> readForCAS r declareForeign Tracked "Ref.Ticket.read" boxDirect . mkForeign $ - \(t :: Ticket Closure) -> pure $ peekTicket t + \(t :: Ticket Val) -> pure $ peekTicket t -- In GHC, CAS returns both a Boolean and the current value of the -- IORef, which can be used to retry a failed CAS. @@ -2717,23 +2717,23 @@ declareForeigns = do -- [1]: https://github.com/ghc/ghc/blob/master/rts/PrimOps.cmm#L697 -- [2]: https://github.com/ghc/ghc/blob/master/compiler/GHC/StgToCmm/Prim.hs#L285 declareForeign Tracked "Ref.cas" boxBoxBoxToBool . mkForeign $ - \(r :: IORef Closure, t :: Ticket Closure, v :: Closure) -> fmap fst $ + \(r :: IORef Val, t :: Ticket Val, v :: Val) -> fmap fst $ do t <- evaluate t casIORef r t v declareForeign Tracked "Promise.new" unitDirect . mkForeign $ - \() -> newPromise @Closure + \() -> newPromise @Val -- the only exceptions from Promise.read are async and shouldn't be caught declareForeign Tracked "Promise.read" boxDirect . mkForeign $ - \(p :: Promise Closure) -> readPromise p + \(p :: Promise Val) -> readPromise p declareForeign Tracked "Promise.tryRead" boxToMaybeBox . mkForeign $ - \(p :: Promise Closure) -> tryReadPromise p + \(p :: Promise Val) -> tryReadPromise p declareForeign Tracked "Promise.write" boxBoxToBool . mkForeign $ - \(p :: Promise Closure, a :: Closure) -> writePromise p a + \(p :: Promise Val, a :: Val) -> writePromise p a declareForeign Tracked "Tls.newClient.impl.v3" boxBoxToEFBox . mkForeignTls $ \( config :: TLS.ClientParams, @@ -2935,7 +2935,7 @@ declareForeigns = do checkBounds name (PA.sizeofMutableArray dst) (doff + l - 1) $ checkBounds name (PA.sizeofMutableArray src) (soff + l - 1) $ Right - <$> PA.copyMutableArray @IO @Closure + <$> PA.copyMutableArray @IO @Val dst (fromIntegral doff) src @@ -2969,7 +2969,7 @@ declareForeigns = do checkBounds name (PA.sizeofMutableArray dst) (doff + l - 1) $ checkBounds name (PA.sizeofArray src) (soff + l - 1) $ Right - <$> PA.copyArray @IO @Closure + <$> PA.copyArray @IO @Val dst (fromIntegral doff) src @@ -2977,9 +2977,9 @@ declareForeigns = do (fromIntegral l) declareForeign Untracked "ImmutableArray.size" boxToNat . mkForeign $ - pure . fromIntegral @Int @Word64 . PA.sizeofArray @Closure + pure . fromIntegral @Int @Word64 . PA.sizeofArray @Val declareForeign Untracked "MutableArray.size" boxToNat . mkForeign $ - pure . fromIntegral @Int @Word64 . PA.sizeofMutableArray @PA.RealWorld @Closure + pure . fromIntegral @Int @Word64 . PA.sizeofMutableArray @PA.RealWorld @Val declareForeign Untracked "ImmutableByteArray.size" boxToNat . mkForeign $ pure . fromIntegral @Int @Word64 . PA.sizeofByteArray declareForeign Untracked "MutableByteArray.size" boxToNat . mkForeign $ @@ -3065,7 +3065,7 @@ declareForeigns = do declareForeign Untracked "MutableByteArray.freeze!" boxDirect . mkForeign $ PA.unsafeFreezeByteArray declareForeign Untracked "MutableArray.freeze!" boxDirect . mkForeign $ - PA.unsafeFreezeArray @IO @Closure + PA.unsafeFreezeArray @IO @Val declareForeign Untracked "MutableByteArray.freeze" boxNatNatToExnBox . mkForeign $ \(src, off, len) -> @@ -3080,9 +3080,9 @@ declareForeigns = do $ Right <$> PA.freezeByteArray src (fromIntegral off) (fromIntegral len) declareForeign Untracked "MutableArray.freeze" boxNatNatToExnBox . mkForeign $ - \(src :: PA.MutableArray PA.RealWorld Closure, off, len) -> + \(src :: PA.MutableArray PA.RealWorld Val, off, len) -> if len == 0 - then fmap Right . PA.unsafeFreezeArray =<< PA.newArray 0 ( Closure.BlackHole) + then fmap Right . PA.unsafeFreezeArray =<< PA.newArray 0 emptyVal else checkBounds "MutableArray.freeze" @@ -3097,9 +3097,9 @@ declareForeigns = do pure . PA.sizeofByteArray declareForeign Tracked "IO.array" natToBox . mkForeign $ - \n -> PA.newArray n (Closure.BlackHole :: Closure) + \n -> PA.newArray n emptyVal declareForeign Tracked "IO.arrayOf" boxNatToBox . mkForeign $ - \(v :: Closure, n) -> PA.newArray n v + \(v :: Val, n) -> PA.newArray n v declareForeign Tracked "IO.bytearray" natToBox . mkForeign $ PA.newByteArray declareForeign Tracked "IO.bytearrayOf" natNatToBox . mkForeign @@ -3109,9 +3109,9 @@ declareForeigns = do pure arr declareForeign Untracked "Scope.array" natToBox . mkForeign $ - \n -> PA.newArray n (Closure.BlackHole :: Closure) + \n -> PA.newArray n emptyVal declareForeign Untracked "Scope.arrayOf" boxNatToBox . mkForeign $ - \(v :: Closure, n) -> PA.newArray n v + \(v :: Val, n) -> PA.newArray n v declareForeign Untracked "Scope.bytearray" natToBox . mkForeign $ PA.newByteArray declareForeign Untracked "Scope.bytearrayOf" natNatToBox . mkForeign @@ -3141,12 +3141,12 @@ declareForeigns = do \(beg, end) -> evaluate . TPat.cpattern . TPat.Char . TPat.Not $ TPat.CharRange beg end declareForeign Untracked "Text.patterns.charIn" boxDirect . mkForeign $ \ccs -> do cs <- for ccs $ \case - Closure.CharClosure c -> pure c + CharVal c -> pure c _ -> die "Text.patterns.charIn: non-character closure" evaluate . TPat.cpattern . TPat.Char $ TPat.CharSet cs declareForeign Untracked "Text.patterns.notCharIn" boxDirect . mkForeign $ \ccs -> do cs <- for ccs $ \case - Closure.CharClosure c -> pure c + CharVal c -> pure c _ -> die "Text.patterns.notCharIn: non-character closure" evaluate . TPat.cpattern . TPat.Char . TPat.Not $ TPat.CharSet cs declareForeign Untracked "Pattern.many" boxDirect . mkForeign $ @@ -3179,7 +3179,7 @@ declareForeigns = do declareForeign Untracked "Char.Class.range" (wordWordDirect charRef charRef) . mkForeign $ \(a, b) -> pure $ TPat.CharRange a b declareForeign Untracked "Char.Class.anyOf" boxDirect . mkForeign $ \ccs -> do cs <- for ccs $ \case - Closure.CharClosure c -> pure c + CharVal c -> pure c _ -> die "Text.patterns.charIn: non-character closure" evaluate $ TPat.CharSet cs declareForeign Untracked "Char.Class.alphanumeric" direct . mkForeign $ \() -> pure (TPat.CharClass TPat.AlphaNum) @@ -3201,7 +3201,7 @@ declareForeigns = do type RW = PA.PrimState IO checkedRead :: - Text -> (PA.MutableArray RW Closure, Word64) -> IO (Either Failure Closure) + Text -> (PA.MutableArray RW Val, Word64) -> IO (Either Failure Val) checkedRead name (arr, w) = checkBounds name @@ -3210,7 +3210,7 @@ checkedRead name (arr, w) = (Right <$> PA.readArray arr (fromIntegral w)) checkedWrite :: - Text -> (PA.MutableArray RW Closure, Word64, Closure) -> IO (Either Failure ()) + Text -> (PA.MutableArray RW Val, Word64, Val) -> IO (Either Failure ()) checkedWrite name (arr, w, v) = checkBounds name @@ -3219,7 +3219,7 @@ checkedWrite name (arr, w, v) = (Right <$> PA.writeArray arr (fromIntegral w) v) checkedIndex :: - Text -> (PA.Array Closure, Word64) -> IO (Either Failure Closure) + Text -> (PA.Array Val, Word64) -> IO (Either Failure Val) checkedIndex name (arr, w) = checkBounds name diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index c96052dce1..8399c7ee13 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -123,8 +123,6 @@ instance ForeignConvention Char where stk <- bump stk stk <$ pokeC stk ch --- In reality this fixes the type to be 'RClosure', but allows us to defer --- the typechecker a bit and avoid a bunch of annoying type annotations. instance ForeignConvention Val where readForeign (i : args) stk = (args,) <$> peekOff stk i readForeign [] _ = foreignCCError "Val" @@ -132,6 +130,15 @@ instance ForeignConvention Val where stk <- bump stk stk <$ (poke stk =<< evaluate v) +-- In reality this fixes the type to be 'RClosure', but allows us to defer +-- the typechecker a bit and avoid a bunch of annoying type annotations. +instance ForeignConvention Closure where + readForeign (i : args) stk = (args,) <$> bpeekOff stk i + readForeign [] _ = foreignCCError "Closure" + writeForeign stk c = do + stk <- bump stk + stk <$ (bpoke stk =<< evaluate c) + instance ForeignConvention Text where readForeign = readForeignBuiltin writeForeign = writeForeignBuiltin @@ -431,7 +438,7 @@ instance ForeignConvention BufferMode where -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. -instance ForeignConvention [Val] where +instance {-# OVERLAPPING #-} ForeignConvention [Val] where readForeign (i : args) stk = (args,) . toList <$> peekOffS stk i readForeign _ _ = foreignCCError "[Val]" @@ -439,6 +446,16 @@ instance ForeignConvention [Val] where stk <- bump stk stk <$ pokeS stk (Sq.fromList l) +-- In reality this fixes the type to be 'RClosure', but allows us to defer +-- the typechecker a bit and avoid a bunch of annoying type annotations. +instance {-# OVERLAPPING #-} ForeignConvention [Closure] where + readForeign (i : args) stk = + (args,) . fmap getBoxedVal . toList <$> peekOffS stk i + readForeign _ _ = foreignCCError "[Closure]" + writeForeign stk l = do + stk <- bump stk + stk <$ pokeS stk (Sq.fromList . fmap BoxedVal $ l) + instance ForeignConvention [Foreign] where readForeign = readForeignAs (fmap marshalToForeign) writeForeign = writeForeignAs (fmap Foreign) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 35e9291371..207250c2c7 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -8,10 +8,8 @@ import Control.Concurrent.STM as STM import Control.Exception import Control.Lens import Data.Bits -import Data.Char qualified as Char import Data.Map.Strict qualified as M import Data.Ord (comparing) -import Data.Primitive.ByteArray qualified as BA import Data.Sequence qualified as Sq import Data.Set qualified as S import Data.Set qualified as Set @@ -1571,13 +1569,12 @@ bprim1 !stk VWRS i = bprim1 !stk PAKT i = do s <- peekOffS stk i stk <- bump stk - pokeBi stk . Util.Text.pack . toList $ clo2char <$> s + pokeBi stk . Util.Text.pack . toList $ val2char <$> s pure stk where - clo2char :: Val -> Char - clo2char (Val _ (CharClosure c)) = c - clo2char (Val c tt) | tt == charTypeTag = Char.chr $ c - clo2char c = error $ "pack text: non-character closure: " ++ show c + val2char :: Val -> Char + val2char (CharVal c) = c + val2char c = error $ "pack text: non-character closure: " ++ show c bprim1 !stk UPKT i = do t <- peekOffBi stk i stk <- bump stk @@ -1596,8 +1593,7 @@ bprim1 !stk PAKB i = do where -- TODO: Should we have a tag for bytes specifically? clo2w8 :: Val -> Word8 - clo2w8 (Val _ (NatClosure n)) = toEnum . fromEnum $ n - clo2w8 (Val n tt) | tt == natTypeTag = toEnum $ n + clo2w8 (NatVal n) = toEnum . fromEnum $ n clo2w8 c = error $ "pack bytes: non-natural closure: " ++ show c bprim1 !stk UPKB i = do b <- peekOffBi stk i @@ -2230,8 +2226,14 @@ reflectValue rty = goV goV = \case -- For back-compatibility we reflect all Unboxed values into boxed literals, we could change this in the future, -- but there's not much of a big reason to. - UnboxedVal tu -> ANF.BLit <$> reflectUData tu - BoxedVal clos -> + + NatVal n -> pure . ANF.BLit $ ANF.Pos n + IntVal n + | n >= 0 -> pure . ANF.BLit $ ANF.Pos (fromIntegral n) + | otherwise -> pure . ANF.BLit $ ANF.Neg (fromIntegral (abs n)) + DoubleVal f -> pure . ANF.BLit $ ANF.Float f + CharVal c -> pure . ANF.BLit $ ANF.Char c + val@(Val _ clos) -> case clos of (PApV cix _rComb args) -> ANF.Partial (goIx cix) <$> traverse goV args @@ -2241,7 +2243,7 @@ reflectValue rty = goV ANF.Cont <$> traverse goV segs <*> goK k (Foreign f) -> ANF.BLit <$> goF f BlackHole -> die $ err "black hole" - UnboxedTypeTag {} -> die $ err "impossible unboxed type tag" + UnboxedTypeTag {} -> die $ err $ "unknown unboxed value" <> show val goK (CB _) = die $ err "callback continuation" goK KE = pure ANF.KE @@ -2277,19 +2279,6 @@ reflectValue rty = goV ANF.Arr <$> traverse goV a | otherwise = die $ err $ "foreign value: " <> (show f) - -- For back-compatibility reasons all unboxed values are uplifted to boxed when serializing to ANF. - reflectUData :: TypedUnboxed -> IO ANF.BLit - reflectUData (TypedUnboxed v t) - | t == TT.natTag = pure $ ANF.Pos (fromIntegral v) - | t == TT.charTag = pure $ ANF.Char (toEnum v) - | t == TT.intTag, v >= 0 = pure $ ANF.Pos (fromIntegral v) - | t == TT.intTag, v < 0 = pure $ ANF.Neg (fromIntegral (-v)) - | t == TT.floatTag = pure $ ANF.Float (intToDouble v) - | otherwise = die . err $ "unboxed data: " <> show (t, v) - - intToDouble :: Int -> Double - intToDouble w = indexByteArray (BA.byteArrayFromList [w]) 0 - reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Val) reifyValue cc val = do erc <- @@ -2502,12 +2491,14 @@ universalCompare frn = cmpVal False where cmpVal :: Bool -> Val -> Val -> Ordering cmpVal tyEq = \cases - (UnboxedVal tu1) (UnboxedVal tu2) -> - Monoid.whenM tyEq (compare (maskTags $ getTUTag tu1) (maskTags $ getTUTag tu2)) - <> compare (getTUInt tu1) (getTUInt tu2) (BoxedVal c1) (BoxedVal c2) -> cmpc tyEq c1 c2 (UnboxedVal _) (BoxedVal _) -> LT (BoxedVal _) (UnboxedVal _) -> GT + (UnboxedVal (Val v1 t1)) (UnboxedVal (Val v2 t2)) -> + -- We don't need to mask the tags since unboxed types are + -- always treated like nullary constructors and have an empty ctag. + Monoid.whenM tyEq (compare t1 t2) + <> compare v1 v2 cmpl :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index e77c07a4f6..2c15d9f06f 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -41,6 +41,7 @@ module Unison.Runtime.Stack UnboxedVal, BoxedVal ), + emptyVal, boxedVal, USeq, traceK, @@ -596,6 +597,10 @@ instance Ord Val where (UnboxedVal _) (BoxedVal _) -> LT (BoxedVal _) (UnboxedVal _) -> GT +-- | A nulled out value you can use when filling empty arrays, etc. +emptyVal :: Val +emptyVal = Val (-1) BlackHole + -- | Matches a Val which is known to be unboxed, and returns the entire original value. valToTypedUnboxed :: Val -> Maybe Val valToTypedUnboxed v@(Val _ (UnboxedTypeTag {})) = Just v From 3918cdf25d6af56dc010194af639fa5d83868564 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 14:34:21 -0700 Subject: [PATCH 044/113] Add a few runtime transcript tests --- unison-src/transcripts/runtime-tests.md | 38 ++++++++ .../transcripts/runtime-tests.output.md | 88 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 unison-src/transcripts/runtime-tests.md create mode 100644 unison-src/transcripts/runtime-tests.output.md diff --git a/unison-src/transcripts/runtime-tests.md b/unison-src/transcripts/runtime-tests.md new file mode 100644 index 0000000000..fe83465195 --- /dev/null +++ b/unison-src/transcripts/runtime-tests.md @@ -0,0 +1,38 @@ +# An assortment of regression tests that exercise various interesting cases within the runtime. + +```ucm:hide +scratch/main> builtins.merge lib.builtins +``` + + +```unison +negativeCaseMatch = match -10 with + +1 -> "bad" + -10 -> "good" + +3 -> "bad" + _ -> "bad" +> negativeCaseMatch + +funcWithMoreThanTwoUnboxedArgs : Nat -> Nat -> Nat -> Nat +funcWithMoreThanTwoUnboxedArgs x y z = + x + y + z + +> funcWithMoreThanTwoUnboxedArgs 1 2 3 + +funcWithMixedArgTypes : Nat -> Text -> Nat -> Text +funcWithMixedArgTypes x y z = + Nat.toText x ++ y ++ Nat.toText z + +> funcWithMixedArgTypes 1 "hello" 2 + +unboxedAndBoxedArgsInSequences = ([1, 2, 3], ["x", "y", "z"]) +> unboxedAndBoxedArgsInSequences + +casting = (Nat.toInt 100, + Float.toRepresentation 3.14, + Float.fromRepresentation 4614253070214989087, + Int.fromRepresentation 100, + Int.toRepresentation +10, + Int.toRepresentation -10) +> casting +``` diff --git a/unison-src/transcripts/runtime-tests.output.md b/unison-src/transcripts/runtime-tests.output.md new file mode 100644 index 0000000000..29ddf11d07 --- /dev/null +++ b/unison-src/transcripts/runtime-tests.output.md @@ -0,0 +1,88 @@ +# An assortment of regression tests that exercise various interesting cases within the runtime. + +``` unison +negativeCaseMatch = match -10 with + +1 -> "bad" + -10 -> "good" + +3 -> "bad" + _ -> "bad" +> negativeCaseMatch + +funcWithMoreThanTwoUnboxedArgs : Nat -> Nat -> Nat -> Nat +funcWithMoreThanTwoUnboxedArgs x y z = + x + y + z + +> funcWithMoreThanTwoUnboxedArgs 1 2 3 + +funcWithMixedArgTypes : Nat -> Text -> Nat -> Text +funcWithMixedArgTypes x y z = + Nat.toText x ++ y ++ Nat.toText z + +> funcWithMixedArgTypes 1 "hello" 2 + +unboxedAndBoxedArgsInSequences = ([1, 2, 3], ["x", "y", "z"]) +> unboxedAndBoxedArgsInSequences + +casting = (Nat.toInt 100, + Float.toRepresentation 3.14, + Float.fromRepresentation 4614253070214989087, + Int.fromRepresentation 100, + Int.toRepresentation +10, + Int.toRepresentation -10) +> casting +``` + +``` 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`: + + casting : ( Int, + Nat, + Float, + Int, + Nat, + Nat) + funcWithMixedArgTypes : Nat + -> Text + -> Nat + -> Text + funcWithMoreThanTwoUnboxedArgs : Nat -> Nat -> Nat -> Nat + negativeCaseMatch : Text + unboxedAndBoxedArgsInSequences : ([Nat], [Text]) + + Now evaluating any watch expressions (lines starting with + `>`)... Ctrl+C cancels. + + 6 | > negativeCaseMatch + ⧩ + "good" + + 12 | > funcWithMoreThanTwoUnboxedArgs 1 2 3 + ⧩ + 6 + + 18 | > funcWithMixedArgTypes 1 "hello" 2 + ⧩ + "1hello2" + + 21 | > unboxedAndBoxedArgsInSequences + ⧩ + ([1, 2, 3], ["x", "y", "z"]) + + 29 | > casting + ⧩ + ( 100 + , +4614253070214989087 + , 4614253070214989087 + , 100 + , +10 + , -10 + ) + +``` From 9349c7a1953a4e846309bc192d9d2ebc0eedf0a7 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 14:34:21 -0700 Subject: [PATCH 045/113] Simplify BLits by removing superfluous refs and tags --- unison-runtime/src/Unison/Runtime/MCode.hs | 22 ++--------------- .../src/Unison/Runtime/MCode/Serialize.hs | 4 ++-- unison-runtime/src/Unison/Runtime/Machine.hs | 24 +++++++++++-------- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index d700478329..d35b5f7e6e 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -57,7 +57,6 @@ import Data.Bits (shiftL, shiftR, (.|.)) import Data.Coerce import Data.Functor ((<&>)) import Data.Map.Strict qualified as M -import Data.Primitive.ByteArray import Data.Primitive.PrimArray import Data.Primitive.PrimArray qualified as PA import Data.Void (Void, absurd) @@ -92,7 +91,6 @@ import Unison.Runtime.ANF pattern TVar, ) import Unison.Runtime.ANF qualified as ANF -import Unison.Runtime.Builtin.Types (builtinTypeNumbering) import Unison.Util.EnumContainers as EC import Unison.Util.Text (Text) import Unison.Var (Var) @@ -497,9 +495,7 @@ data GInstr comb | -- Push a particular value onto the appropriate stack Lit !MLit -- value to push onto the stack | -- Push a particular value directly onto the boxed stack - -- TODO: We don't actually need the ref/packed tag here, - -- we can always infer them from the constructor of MLit. - BLit !Reference !PackedTag !MLit + BLit !MLit | -- Print a value on the unboxed stack Print !Int -- index of the primitive value to print | -- Put a delimiter on the continuation @@ -1472,22 +1468,8 @@ litToMLit (ANF.LY r) = MY r emitLit :: ANF.Lit -> Instr emitLit = Lit . litToMLit -doubleToInt :: Double -> Int -doubleToInt d = indexByteArray (byteArrayFromList [d]) 0 - emitBLit :: ANF.Lit -> Instr -emitBLit l = case l of - (ANF.F d) -> BLit lRef builtinTypeTag (MI $ doubleToInt d) - _ -> BLit lRef builtinTypeTag (litToMLit l) - where - lRef = ANF.litRef l - builtinTypeTag :: PackedTag - builtinTypeTag = - case M.lookup (ANF.litRef l) builtinTypeNumbering of - Nothing -> error "emitBLit: unknown builtin type reference" - Just n -> - let rt = toEnum (fromIntegral n) - in (packTags rt 0) +emitBLit l = BLit (litToMLit l) -- Emits some fix-up code for calling functions. Some of the -- variables in scope come from the top-level let rec, but these diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index f915a4d035..0907b3a911 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -215,7 +215,7 @@ putInstr = \case (Info s) -> putTag InfoT *> serialize s (Pack r w a) -> putTag PackT *> putReference r *> putPackedTag w *> putArgs a (Lit l) -> putTag LitT *> putLit l - (BLit r tt l) -> putTag BLitT *> putReference r *> putPackedTag tt *> putLit l + (BLit l) -> putTag BLitT *> putLit l (Print i) -> putTag PrintT *> pInt i (Reset s) -> putTag ResetT *> putEnumSet pWord s (Fork i) -> putTag ForkT *> pInt i @@ -237,7 +237,7 @@ getInstr = InfoT -> Info <$> deserialize PackT -> Pack <$> getReference <*> getPackedTag <*> getArgs LitT -> Lit <$> getLit - BLitT -> BLit <$> getReference <*> getPackedTag <*> getLit + BLitT -> BLit <$> getLit PrintT -> Print <$> gInt ResetT -> Reset <$> getEnumSet gWord ForkT -> Fork <$> gInt diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 207250c2c7..5dd8936a41 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -288,14 +288,18 @@ unitValue = Enum Rf.unitRef TT.unitTag lookupDenv :: Word64 -> DEnv -> Val lookupDenv p denv = fromMaybe (BoxedVal BlackHole) $ EC.lookup p denv -buildLit :: Reference -> PackedTag -> MLit -> Closure -buildLit _ _ (MI i) = IntClosure i -buildLit _ _ (MN n) = NatClosure n -buildLit _ _ (MC c) = CharClosure c -buildLit _ _ (MT t) = Foreign (Wrap Rf.textRef t) -buildLit _ _ (MM r) = Foreign (Wrap Rf.termLinkRef r) -buildLit _ _ (MY r) = Foreign (Wrap Rf.typeLinkRef r) -buildLit _ _ (MD _) = error "buildLit: double" +buildBoxedLit :: MLit -> Closure +buildBoxedLit = \case + MT t -> Foreign (Wrap Rf.textRef t) + MM r -> Foreign (Wrap Rf.termLinkRef r) + MY r -> Foreign (Wrap Rf.typeLinkRef r) + MI {} -> errUnboxed + MN {} -> errUnboxed + MC {} -> errUnboxed + MD {} -> errUnboxed + where + errUnboxed = error "buildBoxedList: unboxed type used with BLit" +{-# INLINE buildBoxedLit #-} debugger :: (Show a) => Stack -> String -> a -> Bool debugger stk msg a = unsafePerformIO $ do @@ -566,9 +570,9 @@ exec !_ !denv !_activeThreads !stk !k _ (Lit (MY r)) = do stk <- bump stk bpoke stk (Foreign (Wrap Rf.typeLinkRef r)) pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (BLit rf tt l) = do +exec !_ !denv !_activeThreads !stk !k _ (BLit l) = do stk <- bump stk - bpoke stk $ buildLit rf tt l + bpoke stk $ buildBoxedLit l pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (Reset ps) = do (stk, a) <- saveArgs stk From 5f97c6e73bed02f9311e24ba8b3f764758cb8d68 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 14:56:38 -0700 Subject: [PATCH 046/113] Collapse DataU1 DataU2 DataB1 DataB2... into just Data1 Data2 --- unison-runtime/src/Unison/Runtime/Machine.hs | 102 ++++++------------- unison-runtime/src/Unison/Runtime/Stack.hs | 65 ++++-------- 2 files changed, 46 insertions(+), 121 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 5dd8936a41..388078c0e4 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -655,8 +655,7 @@ encodeExn stk exc = do | otherwise = (Rf.miscFailureRef, disp exn, boxedVal unitValue) numValue :: Maybe Reference -> Val -> IO Word64 -numValue _ (UnboxedVal tu) = pure (fromIntegral $ getTUInt tu) -numValue _ (BoxedVal (DataU1 _ _ i)) = pure (fromIntegral $ getTUInt i) +numValue _ (Val v (UnboxedTypeTag {})) = pure (fromIntegral @Int @Word64 v) numValue mr clo = die $ "numValue: bad closure: " @@ -947,39 +946,17 @@ closureArgs !_ _ = error "closure arguments can only be boxed." {-# INLINE closureArgs #-} --- | TODO: Experiment: --- In cases where we need to check the boxed stack to see where the argument lives --- we can either fetch from both unboxed and boxed stacks, then check the boxed result; --- OR we can just fetch from the boxed stack and check the result, then conditionally --- fetch from the unboxed stack. --- --- The former puts more work before the branch, which _may_ be better for cpu pipelining, --- but the latter avoids an unnecessary fetch from the unboxed stack in cases where all args are boxed. +-- | Pack some number of args into a data type of the provided ref/tag type. buildData :: Stack -> Reference -> PackedTag -> Args -> IO Closure buildData !_ !r !t ZArgs = pure $ Enum r t buildData !stk !r !t (VArg1 i) = do - bv <- bpeekOff stk i - case bv of - UnboxedTypeTag ut -> do - uv <- upeekOff stk i - pure $ DataU1 r t (TypedUnboxed uv ut) - _ -> pure $ DataB1 r t bv + v <- peekOff stk i + pure $ Data1 r t v buildData !stk !r !t (VArg2 i j) = do - b1 <- bpeekOff stk i - b2 <- bpeekOff stk j - case (b1, b2) of - (UnboxedTypeTag t1, UnboxedTypeTag t2) -> do - u1 <- upeekOff stk i - u2 <- upeekOff stk j - pure $ DataU2 r t (TypedUnboxed u1 t1) (TypedUnboxed u2 t2) - (UnboxedTypeTag t1, _) -> do - u1 <- upeekOff stk i - pure $ DataUB r t (TypedUnboxed u1 t1) b2 - (_, UnboxedTypeTag t2) -> do - u2 <- upeekOff stk j - pure $ DataBU r t b1 (TypedUnboxed u2 t2) - _ -> pure $ DataB2 r t b1 b2 + v1 <- peekOff stk i + v2 <- peekOff stk j + pure $ Data2 r t v1 v2 buildData !stk !r !t (VArgR i l) = do seg <- augSeg I stk nullSeg (Just $ ArgR i l) pure $ DataG r t seg @@ -1006,39 +983,20 @@ dumpDataNoTag :: dumpDataNoTag !mr !stk = \case -- Normally we want to avoid dumping unboxed values since it's unnecessary, but sometimes we don't know the type of -- the incoming value and end up dumping unboxed values, so we just push them back to the stack as-is. e.g. in type-casts/coercions - val@(UnboxedVal tu) -> do + val@(Val _ (UnboxedTypeTag t)) -> do stk <- bump stk poke stk val - pure (getTUTag tu, stk) - (BoxedVal clos) -> case clos of + pure (t, stk) + Val _ clos -> case clos of (Enum _ t) -> pure (t, stk) - (DataU1 _ t x) -> do - stk <- bump stk - pokeTU stk x - pure (t, stk) - (DataU2 _ t x y) -> do - stk <- bumpn stk 2 - pokeOffTU stk 1 y - pokeTU stk x - pure (t, stk) - (DataB1 _ t x) -> do + (Data1 _ t x) -> do stk <- bump stk - bpoke stk x - pure (t, stk) - (DataB2 _ t x y) -> do - stk <- bumpn stk 2 - bpokeOff stk 1 y - bpoke stk x - pure (t, stk) - (DataUB _ t x y) -> do - stk <- bumpn stk 2 - pokeTU stk x - bpokeOff stk 1 y + poke stk x pure (t, stk) - (DataBU _ t x y) -> do + (Data2 _ t x y) -> do stk <- bumpn stk 2 - bpoke stk x - pokeOffTU stk 1 y + pokeOff stk 1 y + poke stk x pure (t, stk) (DataG _ t seg) -> do stk <- dumpSeg stk seg S @@ -1584,26 +1542,24 @@ bprim1 !stk UPKT i = do stk <- bump stk pokeS stk . Sq.fromList - -- TODO: Should this be unboxed chars? - . fmap (boxedVal . CharClosure) + . fmap CharVal . Util.Text.unpack $ t pure stk bprim1 !stk PAKB i = do s <- peekOffS stk i stk <- bump stk - pokeBi stk . By.fromWord8s . fmap clo2w8 $ toList s + pokeBi stk . By.fromWord8s . fmap val2w8 $ toList s pure stk where -- TODO: Should we have a tag for bytes specifically? - clo2w8 :: Val -> Word8 - clo2w8 (NatVal n) = toEnum . fromEnum $ n - clo2w8 c = error $ "pack bytes: non-natural closure: " ++ show c + val2w8 :: Val -> Word8 + val2w8 (NatVal n) = toEnum . fromEnum $ n + val2w8 c = error $ "pack bytes: non-natural closure: " ++ show c bprim1 !stk UPKB i = do b <- peekOffBi stk i stk <- bump stk - -- TODO: Should this be unboxed nats/bytes? - pokeS stk . Sq.fromList . fmap (boxedVal . NatClosure . toEnum @Word64 . fromEnum @Word8) $ + pokeS stk . Sq.fromList . fmap (NatVal . toEnum @Word64 . fromEnum @Word8) $ By.toWord8s b pure stk bprim1 !stk SIZB i = do @@ -1845,7 +1801,7 @@ yield !env !denv !activeThreads !stk !k = leap denv k leap !denv0 (Mark a ps cs k) = do let denv = cs <> EC.withoutKeys denv0 ps val = denv0 EC.! EC.findMin ps - bpoke stk . DataB1 Rf.effectRef (PackedTag 0) =<< bpeek stk + bpoke stk . Data1 Rf.effectRef (PackedTag 0) =<< peek stk stk <- adjustArgs stk a apply env denv activeThreads stk k False (VArg1 0) val leap !denv (Push fsz asz (CIx ref _ _) f nx k) = do @@ -1980,7 +1936,7 @@ refLookup s m r decodeCacheArgument :: USeq -> IO [(Reference, Code)] decodeCacheArgument s = for (toList s) $ \case - (Val _unboxed (DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _))) -> + (Val _unboxed (Data2 _ _ (BoxedVal (Foreign x)) (BoxedVal (Data2 _ _ (BoxedVal (Foreign y)) _)))) -> case unwrapForeign x of Ref r -> pure (r, unwrapForeign y) _ -> die "decodeCacheArgument: Con reference" @@ -1999,15 +1955,15 @@ encodeSandboxListResult = encodeSandboxResult :: Either [Reference] [Reference] -> Closure encodeSandboxResult (Left rfs) = - encodeLeft . Foreign . Wrap Rf.listRef $ encodeSandboxListResult rfs + encodeLeft . boxedVal . Foreign . Wrap Rf.listRef $ encodeSandboxListResult rfs encodeSandboxResult (Right rfs) = - encodeRight . Foreign . Wrap Rf.listRef $ encodeSandboxListResult rfs + encodeRight . boxedVal . Foreign . Wrap Rf.listRef $ encodeSandboxListResult rfs -encodeLeft :: Closure -> Closure -encodeLeft = DataB1 Rf.eitherRef TT.leftTag +encodeLeft :: Val -> Closure +encodeLeft = Data1 Rf.eitherRef TT.leftTag -encodeRight :: Closure -> Closure -encodeRight = DataB1 Rf.eitherRef TT.rightTag +encodeRight :: Val -> Closure +encodeRight = Data1 Rf.eitherRef TT.rightTag addRefs :: TVar Word64 -> diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 2c15d9f06f..2972b00699 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -8,12 +8,8 @@ module Unison.Runtime.Stack CapV, PAp, Enum, - DataU1, - DataU2, - DataB1, - DataB2, - DataUB, - DataBU, + Data1, + Data2, DataG, Captured, Foreign, @@ -202,12 +198,8 @@ data GClosure comb {-# UNPACK #-} !(GCombInfo comb) {-# UNPACK #-} !Seg -- args | GEnum !Reference !PackedTag - | GDataU1 !Reference !PackedTag !Val - | GDataU2 !Reference !PackedTag !Val !Val - | GDataB1 !Reference !PackedTag !(GClosure comb) - | GDataB2 !Reference !PackedTag !(GClosure comb) !(GClosure comb) - | GDataUB !Reference !PackedTag !Val !(GClosure comb) - | GDataBU !Reference !PackedTag !(GClosure comb) !Val + | GData1 !Reference !PackedTag !Val + | GData2 !Reference !PackedTag !Val !Val | GDataG !Reference !PackedTag {-# UNPACK #-} !Seg | -- code cont, arg size, u/b data stacks GCaptured !K !Int {-# UNPACK #-} !Seg @@ -226,29 +218,15 @@ instance Eq (GClosure comb) where instance Ord (GClosure comb) where compare a b = compare (a $> ()) (b $> ()) +pattern PAp :: CombIx -> GCombInfo (RComb Val) -> Seg -> Closure pattern PAp cix comb seg = Closure (GPAp cix comb seg) +pattern Enum :: Reference -> PackedTag -> Closure pattern Enum r t = Closure (GEnum r t) -pattern DataU1 r t i = Closure (GDataU1 r t i) +pattern Data1 r t i = Closure (GData1 r t i) -pattern DataU2 r t i j = Closure (GDataU2 r t i j) - -pattern DataB1 r t x <- Closure (GDataB1 r t (Closure -> x)) - where - DataB1 r t x = Closure (GDataB1 r t (unClosure x)) - -pattern DataB2 r t x y <- Closure (GDataB2 r t (Closure -> x) (Closure -> y)) - where - DataB2 r t x y = Closure (GDataB2 r t (unClosure x) (unClosure y)) - -pattern DataUB r t i y <- Closure (GDataUB r t i (Closure -> y)) - where - DataUB r t i y = Closure (GDataUB r t i (unClosure y)) - -pattern DataBU r t y i <- Closure (GDataBU r t (Closure -> y) i) - where - DataBU r t y i = Closure (GDataBU r t (unClosure y) i) +pattern Data2 r t i j = Closure (GData2 r t i j) pattern DataG r t seg = Closure (GDataG r t seg) @@ -260,7 +238,7 @@ pattern BlackHole = Closure GBlackHole pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) -{-# COMPLETE PAp, Enum, DataU1, DataU2, DataB1, DataB2, DataUB, DataBU, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} +{-# COMPLETE PAp, Enum, Data1, Data2, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} {-# COMPLETE DataC, PAp, Captured, Foreign, BlackHole, UnboxedTypeTag #-} @@ -297,12 +275,8 @@ traceK begin = dedup (begin, 1) splitData :: Closure -> Maybe (Reference, PackedTag, SegList) splitData = \case (Enum r t) -> Just (r, t, []) - (DataU1 r t u) -> Just (r, t, [u]) - (DataU2 r t i j) -> Just (r, t, [i, j]) - (DataB1 r t x) -> Just (r, t, [boxedVal x]) - (DataB2 r t x y) -> Just (r, t, [boxedVal x, boxedVal y]) - (DataUB r t u b) -> Just (r, t, [u, boxedVal b]) - (DataBU r t b u) -> Just (r, t, [boxedVal b, u]) + (Data1 r t u) -> Just (r, t, [u]) + (Data2 r t i j) -> Just (r, t, [i, j]) (DataG r t seg) -> Just (r, t, segToList seg) _ -> Nothing @@ -325,12 +299,8 @@ bseg = L.fromList . reverse formData :: Reference -> PackedTag -> SegList -> Closure formData r t [] = Enum r t -formData r t [UnboxedVal tu] = DataU1 r t tu -formData r t [UnboxedVal i, UnboxedVal j] = DataU2 r t i j -formData r t [UnboxedVal u, Val _ b] = DataUB r t u b -formData r t [Val _ b, UnboxedVal u] = DataBU r t b u -formData r t [Val _ x] = DataB1 r t x -formData r t [Val _ x, Val _ y] = DataB2 r t x y +formData r t [v1] = Data1 r t v1 +formData r t [v1, v2] = Data2 r t v1 v2 formData r t segList = DataG r t (segFromList segList) frameDataSize :: K -> Int @@ -1082,11 +1052,10 @@ closureTermRefs :: (Monoid m) => (Reference -> m) -> (Closure -> m) closureTermRefs f = \case PAp (CIx r _ _) _ (_useg, bseg) -> f r <> foldMap (closureTermRefs f) bseg - (DataB1 _ _ c) -> closureTermRefs f c - (DataB2 _ _ c1 c2) -> - closureTermRefs f c1 <> closureTermRefs f c2 - (DataUB _ _ _ c) -> - closureTermRefs f c + (DataC _ _ vs) -> + vs & foldMap \case + BoxedVal c -> closureTermRefs f c + UnboxedVal {} -> mempty (Captured k _ (_useg, bseg)) -> contTermRefs f k <> foldMap (closureTermRefs f) bseg (Foreign fo) From 35119f18b2e37c95367d4d2e18878f56eaf1a47c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 15:34:41 -0700 Subject: [PATCH 047/113] Unify MCode Lits to simplify boxing/unboxing of lits --- unison-runtime/src/Unison/Runtime/ANF.hs | 2 - unison-runtime/src/Unison/Runtime/MCode.hs | 10 ++-- .../src/Unison/Runtime/MCode/Serialize.hs | 5 -- unison-runtime/src/Unison/Runtime/Machine.hs | 54 +++++-------------- .../transcripts/runtime-tests.output.md | 8 +-- 5 files changed, 16 insertions(+), 63 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index db76277817..e7d6d955d5 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -1835,8 +1835,6 @@ anfBlock (Boolean' b) = pure (mempty, pure $ TCon Ty.booleanRef (if b then 1 else 0) []) anfBlock (Lit' l@(T _)) = pure (mempty, pure $ TLit l) -anfBlock (Lit' l@(N _)) = - pure (mempty, pure $ TLit l) anfBlock (Lit' l) = pure (mempty, pure $ TBLit l) anfBlock (Ref' r) = pure (mempty, (Indirect (), TCom r [])) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index d35b5f7e6e..e13447d39e 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -494,8 +494,6 @@ data GInstr comb !Args -- arguments to pack | -- Push a particular value onto the appropriate stack Lit !MLit -- value to push onto the stack - | -- Push a particular value directly onto the boxed stack - BLit !MLit | -- Print a value on the unboxed stack Print !Int -- index of the primitive value to print | -- Put a delimiter on the continuation @@ -960,7 +958,7 @@ emitSection _ _ _ _ ctx (TLit l) = | ANF.LY {} <- l = addCount 1 | otherwise = addCount 1 emitSection _ _ _ _ ctx (TBLit l) = - addCount 1 . countCtx ctx . Ins (emitBLit l) . Yield $ VArg1 0 + addCount 1 . countCtx ctx . Ins (emitLit l) . Yield $ VArg1 0 emitSection rns grpr grpn rec ctx (TMatch v bs) | Just (i, BX) <- ctxResolve ctx v, MatchData r cs df <- bs = @@ -1136,7 +1134,7 @@ emitLet :: emitLet _ _ _ _ _ _ _ (TLit l) = fmap (Ins $ emitLit l) emitLet _ _ _ _ _ _ _ (TBLit l) = - fmap (Ins $ emitBLit l) + fmap (Ins $ emitLit l) -- emitLet rns grp _ _ _ ctx (TApp (FComb r) args) -- -- We should be able to tell if we are making a saturated call -- -- or not here. We aren't carrying the information here yet, though. @@ -1465,12 +1463,10 @@ litToMLit (ANF.T t) = MT t litToMLit (ANF.LM r) = MM r litToMLit (ANF.LY r) = MY r +-- | Emit a literal as a machine literal of the correct boxed/unboxed format. emitLit :: ANF.Lit -> Instr emitLit = Lit . litToMLit -emitBLit :: ANF.Lit -> Instr -emitBLit l = BLit (litToMLit l) - -- Emits some fix-up code for calling functions. Some of the -- variables in scope come from the top-level let rec, but these -- are definitions, not values on the stack. These definitions cannot diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 0907b3a911..1633f1c10f 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -160,7 +160,6 @@ data InstrT | AtomicallyT | SeqT | TryForceT - | BLitT instance Tag InstrT where tag2word UPrim1T = 0 @@ -180,7 +179,6 @@ instance Tag InstrT where tag2word AtomicallyT = 14 tag2word SeqT = 15 tag2word TryForceT = 16 - tag2word BLitT = 17 word2tag 0 = pure UPrim1T word2tag 1 = pure UPrim2T @@ -199,7 +197,6 @@ instance Tag InstrT where word2tag 14 = pure AtomicallyT word2tag 15 = pure SeqT word2tag 16 = pure TryForceT - word2tag 17 = pure BLitT word2tag n = unknownTag "InstrT" n putInstr :: (MonadPut m) => GInstr cix -> m () @@ -215,7 +212,6 @@ putInstr = \case (Info s) -> putTag InfoT *> serialize s (Pack r w a) -> putTag PackT *> putReference r *> putPackedTag w *> putArgs a (Lit l) -> putTag LitT *> putLit l - (BLit l) -> putTag BLitT *> putLit l (Print i) -> putTag PrintT *> pInt i (Reset s) -> putTag ResetT *> putEnumSet pWord s (Fork i) -> putTag ForkT *> pInt i @@ -237,7 +233,6 @@ getInstr = InfoT -> Info <$> deserialize PackT -> Pack <$> getReference <*> getPackedTag <*> getArgs LitT -> Lit <$> getLit - BLitT -> BLit <$> getLit PrintT -> Print <$> gInt ResetT -> Reset <$> getEnumSet gWord ForkT -> Fork <$> gInt diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 388078c0e4..ebec65c590 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -288,18 +288,16 @@ unitValue = Enum Rf.unitRef TT.unitTag lookupDenv :: Word64 -> DEnv -> Val lookupDenv p denv = fromMaybe (BoxedVal BlackHole) $ EC.lookup p denv -buildBoxedLit :: MLit -> Closure -buildBoxedLit = \case - MT t -> Foreign (Wrap Rf.textRef t) - MM r -> Foreign (Wrap Rf.termLinkRef r) - MY r -> Foreign (Wrap Rf.typeLinkRef r) - MI {} -> errUnboxed - MN {} -> errUnboxed - MC {} -> errUnboxed - MD {} -> errUnboxed - where - errUnboxed = error "buildBoxedList: unboxed type used with BLit" -{-# INLINE buildBoxedLit #-} +litToVal :: MLit -> Val +litToVal = \case + MT t -> BoxedVal $ Foreign (Wrap Rf.textRef t) + MM r -> BoxedVal $ Foreign (Wrap Rf.termLinkRef r) + MY r -> BoxedVal $ Foreign (Wrap Rf.typeLinkRef r) + MI i -> IntVal i + MN n -> NatVal n + MC c -> CharVal c + MD d -> DoubleVal d +{-# INLINE litToVal #-} debugger :: (Show a) => Stack -> String -> a -> Bool debugger stk msg a = unsafePerformIO $ do @@ -542,37 +540,9 @@ exec !_ !denv !_activeThreads !stk !k _ (Print i) = do t <- peekOffBi stk i Tx.putStrLn (Util.Text.toText t) pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MI n)) = do - stk <- bump stk - pokeI stk n - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MC c)) = do - stk <- bump stk - pokeC stk c - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MN n)) = do - stk <- bump stk - pokeN stk n - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MD d)) = do - stk <- bump stk - pokeD stk d - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MT t)) = do - stk <- bump stk - bpoke stk (Foreign (Wrap Rf.textRef t)) - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MM r)) = do - stk <- bump stk - bpoke stk (Foreign (Wrap Rf.termLinkRef r)) - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (Lit (MY r)) = do - stk <- bump stk - bpoke stk (Foreign (Wrap Rf.typeLinkRef r)) - pure (denv, stk, k) -exec !_ !denv !_activeThreads !stk !k _ (BLit l) = do +exec !_ !denv !_activeThreads !stk !k _ (Lit ml) = do stk <- bump stk - bpoke stk $ buildBoxedLit l + poke stk $ litToVal ml pure (denv, stk, k) exec !_ !denv !_activeThreads !stk !k _ (Reset ps) = do (stk, a) <- saveArgs stk diff --git a/unison-src/transcripts/runtime-tests.output.md b/unison-src/transcripts/runtime-tests.output.md index 29ddf11d07..a8d9795aa1 100644 --- a/unison-src/transcripts/runtime-tests.output.md +++ b/unison-src/transcripts/runtime-tests.output.md @@ -77,12 +77,6 @@ casting = (Nat.toInt 100, 29 | > casting ⧩ - ( 100 - , +4614253070214989087 - , 4614253070214989087 - , 100 - , +10 - , -10 - ) + (100, 3.14, 4614253070214989087, 100, +10, -10) ``` From 963d8238945820bcd3649582a15f3140a12907b7 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 21:30:39 -0700 Subject: [PATCH 048/113] Fix up UnboxedVal patterns --- unison-runtime/src/Unison/Runtime/Machine.hs | 23 +++++------ unison-runtime/src/Unison/Runtime/Stack.hs | 43 ++++++++------------ 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index ebec65c590..57b37f4137 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -625,7 +625,7 @@ encodeExn stk exc = do | otherwise = (Rf.miscFailureRef, disp exn, boxedVal unitValue) numValue :: Maybe Reference -> Val -> IO Word64 -numValue _ (Val v (UnboxedTypeTag {})) = pure (fromIntegral @Int @Word64 v) +numValue _ (UnboxedVal v _) = pure (fromIntegral @Int @Word64 v) numValue mr clo = die $ "numValue: bad closure: " @@ -953,11 +953,11 @@ dumpDataNoTag :: dumpDataNoTag !mr !stk = \case -- Normally we want to avoid dumping unboxed values since it's unnecessary, but sometimes we don't know the type of -- the incoming value and end up dumping unboxed values, so we just push them back to the stack as-is. e.g. in type-casts/coercions - val@(Val _ (UnboxedTypeTag t)) -> do + val@(UnboxedVal _ t) -> do stk <- bump stk poke stk val pure (t, stk) - Val _ clos -> case clos of + BoxedVal clos -> case clos of (Enum _ t) -> pure (t, stk) (Data1 _ t x) -> do stk <- bump stk @@ -2329,10 +2329,9 @@ universalEq frn = eqVal eql :: (a -> b -> Bool) -> [a] -> [b] -> Bool eql cm l r = length l == length r && and (zipWith cm l r) eqVal :: Val -> Val -> Bool - eqVal (Val u (ut@UnboxedTypeTag {})) (Val v (vt@UnboxedTypeTag {})) = u == v && ut == vt - eqVal (Val _ (UnboxedTypeTag {})) (Val _ _) = False - eqVal (Val _ _) (Val _ (UnboxedTypeTag {})) = False - eqVal (Val _ x) (Val _ y) = eqc x y + eqVal (UnboxedVal v1 t1) (UnboxedVal v2 t2) = t1 == t2 && v1 == v2 + eqVal (BoxedVal x) (BoxedVal y) = eqc x y + eqVal _ _ = False eqc :: Closure -> Closure -> Bool eqc (DataC _ ct1 [w1]) (DataC _ ct2 [w2]) = matchTags ct1 ct2 && eqVal w1 w2 @@ -2422,9 +2421,9 @@ universalCompare frn = cmpVal False cmpVal :: Bool -> Val -> Val -> Ordering cmpVal tyEq = \cases (BoxedVal c1) (BoxedVal c2) -> cmpc tyEq c1 c2 - (UnboxedVal _) (BoxedVal _) -> LT - (BoxedVal _) (UnboxedVal _) -> GT - (UnboxedVal (Val v1 t1)) (UnboxedVal (Val v2 t2)) -> + (UnboxedVal {}) (BoxedVal {}) -> LT + (BoxedVal {}) (UnboxedVal {}) -> GT + (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> -- We don't need to mask the tags since unboxed types are -- always treated like nullary constructors and have an empty ctag. Monoid.whenM tyEq (compare t1 t2) @@ -2464,8 +2463,8 @@ universalCompare frn = cmpVal False -- Written in a strange way way to maintain back-compat with the -- old val lists which had boxed/unboxed separated let partitionVals = foldMap \case - UnboxedVal tu -> ([tu], mempty) - BoxedVal b -> (mempty, [b]) + UnboxedVal v tt -> ([(tt, v)], mempty) + BoxedVal clos -> (mempty, [clos]) (us1, bs1) = partitionVals vs1 (us2, bs2) = partitionVals vs2 in cmpl compare us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 2972b00699..a1a0d0fbc1 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -320,43 +320,43 @@ pattern DataC rf ct segs <- matchCharVal :: Val -> Maybe Char matchCharVal = \case - (Val u (UnboxedTypeTag tt)) | tt == TT.charTag -> Just (Char.chr u) + (UnboxedVal u tt) | tt == TT.charTag -> Just (Char.chr u) _ -> Nothing pattern CharVal :: Char -> Val pattern CharVal c <- (matchCharVal -> Just c) where - CharVal c = Val (Char.ord c) (UnboxedTypeTag TT.charTag) + CharVal c = UnboxedVal (Char.ord c) TT.charTag matchNatVal :: Val -> Maybe Word64 matchNatVal = \case - (Val u (UnboxedTypeTag tt)) | tt == TT.natTag -> Just (toEnum u) + (UnboxedVal u tt) | tt == TT.natTag -> Just (toEnum u) _ -> Nothing pattern NatVal :: Word64 -> Val pattern NatVal n <- (matchNatVal -> Just n) where - NatVal n = Val (fromEnum n) (UnboxedTypeTag TT.natTag) + NatVal n = UnboxedVal (fromEnum n) TT.natTag matchDoubleVal :: Val -> Maybe Double matchDoubleVal = \case - (Val u (UnboxedTypeTag tt)) | tt == TT.floatTag -> Just (intToDouble u) + (UnboxedVal u tt) | tt == TT.floatTag -> Just (intToDouble u) _ -> Nothing pattern DoubleVal :: Double -> Val pattern DoubleVal d <- (matchDoubleVal -> Just d) where - DoubleVal d = Val (doubleToInt d) (UnboxedTypeTag TT.floatTag) + DoubleVal d = UnboxedVal (doubleToInt d) TT.floatTag matchIntVal :: Val -> Maybe Int matchIntVal = \case - (Val u (UnboxedTypeTag tt)) | tt == TT.intTag -> Just u + (UnboxedVal u tt) | tt == TT.intTag -> Just u _ -> Nothing pattern IntVal :: Int -> Val pattern IntVal i <- (matchIntVal -> Just i) where - IntVal i = Val i (UnboxedTypeTag TT.intTag) + IntVal i = UnboxedVal i TT.intTag doubleToInt :: Double -> Int doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 @@ -555,31 +555,24 @@ data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} instance Eq Val where (==) = \cases - (Val u (ut@UnboxedTypeTag {})) (Val v (vt@UnboxedTypeTag {})) -> u == v && ut == vt - (Val _ (UnboxedTypeTag {})) (Val _ _) -> False - (Val _ _) (Val _ (UnboxedTypeTag {})) -> False - (Val _ x) (Val _ y) -> x == y + (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> t1 == t2 && v1 == v2 + (BoxedVal x) (BoxedVal y) -> x == y + (UnboxedVal {}) (BoxedVal {}) -> False + (BoxedVal {}) (UnboxedVal {}) -> False instance Ord Val where compare = \cases (BoxedVal c1) (BoxedVal c2) -> compare c1 c2 - (UnboxedVal (Val i1 t1)) (UnboxedVal (Val i2 t2)) -> compare t1 t2 <> compare i1 i2 - (UnboxedVal _) (BoxedVal _) -> LT - (BoxedVal _) (UnboxedVal _) -> GT + (UnboxedVal i1 t1) (UnboxedVal i2 t2) -> compare t1 t2 <> compare i1 i2 + (UnboxedVal {}) (BoxedVal _) -> LT + (BoxedVal _) (UnboxedVal {}) -> GT -- | A nulled out value you can use when filling empty arrays, etc. emptyVal :: Val emptyVal = Val (-1) BlackHole --- | Matches a Val which is known to be unboxed, and returns the entire original value. -valToTypedUnboxed :: Val -> Maybe Val -valToTypedUnboxed v@(Val _ (UnboxedTypeTag {})) = Just v -valToTypedUnboxed _ = Nothing - -pattern UnboxedVal :: Val -> Val -pattern UnboxedVal t <- (valToTypedUnboxed -> Just t) - where - UnboxedVal v = v +pattern UnboxedVal :: Int -> PackedTag -> Val +pattern UnboxedVal v t = (Val v (UnboxedTypeTag t)) valToBoxed :: Val -> Maybe Closure valToBoxed UnboxedVal {} = Nothing @@ -589,7 +582,7 @@ valToBoxed (Val _ b) = Just b pattern BoxedVal :: Closure -> Val pattern BoxedVal b <- (valToBoxed -> Just b) where - BoxedVal b = Val 0 b + BoxedVal b = Val (-1) b {-# COMPLETE UnboxedVal, BoxedVal #-} From e254c11030d701c0c1245f2d82ce94812d66c6f7 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 22:18:05 -0700 Subject: [PATCH 049/113] Simplify ForeignOp helpers --- unison-runtime/src/Unison/Runtime/Builtin.hs | 1067 +++++++----------- 1 file changed, 390 insertions(+), 677 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 8b0431342d..aac6b369ee 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -42,7 +42,6 @@ import Crypto.PubKey.Ed25519 qualified as Ed25519 import Crypto.PubKey.RSA.PKCS15 qualified as RSA import Crypto.Random (getRandomBytes) import Data.Bits (shiftL, shiftR, (.|.)) -import Unison.Runtime.Builtin.Types import Data.ByteArray qualified as BA import Data.ByteString (hGet, hGetSome, hPut) import Data.ByteString.Lazy qualified as L @@ -163,6 +162,7 @@ import Unison.Runtime.ANF as ANF import Unison.Runtime.ANF.Rehash (checkGroupHashes) import Unison.Runtime.ANF.Serialize as ANF import Unison.Runtime.Array qualified as PA +import Unison.Runtime.Builtin.Types import Unison.Runtime.Crypto.Rsa as Rsa import Unison.Runtime.Exception (die) import Unison.Runtime.Foreign @@ -175,7 +175,6 @@ import Unison.Runtime.Foreign.Function import Unison.Runtime.Stack (Val (..), emptyVal) import Unison.Runtime.Stack qualified as Closure import Unison.Symbol -import Unison.Type (charRef) import Unison.Type qualified as Ty import Unison.Util.Bytes qualified as Bytes import Unison.Util.EnumContainers as EC @@ -299,11 +298,6 @@ notlift :: (Var v) => v -> ANormal v notlift v = TMatch v $ MatchIntegral (mapFromList [(1, fls), (0, tru)]) Nothing --- unbox :: (Var v) => v -> Reference -> v -> ANormal v -> ANormal v --- unbox v0 r v b = --- TMatch v0 $ --- MatchData r (mapSingleton 0 $ ([UN], TAbs v b)) Nothing - unenum :: (Var v) => Int -> v -> Reference -> v -> ANormal v -> ANormal v unenum n v0 r v nx = TMatch v0 $ MatchData r cases Nothing @@ -333,7 +327,7 @@ unop pop rf = unop' pop rf rf unop' :: (Var v) => POp -> Reference -> Reference -> SuperNormal v unop' pop _rfi _rfo = unop0 0 $ \[x] -> - (TPrm pop [x]) + (TPrm pop [x]) binop :: (Var v) => POp -> Reference -> SuperNormal v binop pop rf = binop' pop rf rf rf @@ -346,35 +340,35 @@ binop' :: Reference -> SuperNormal v binop' pop _rfx _rfy _rfr = - binop0 0 $ \[ x, y] -> TPrm pop [x, y] + binop0 0 $ \[x, y] -> TPrm pop [x, y] -- | Lift a comparison op. cmpop :: (Var v) => POp -> Reference -> SuperNormal v cmpop pop _rf = binop0 1 $ \[x, y, b] -> - TLetD b UN (TPrm pop [x, y]) - $ boolift b + TLetD b UN (TPrm pop [x, y]) $ + boolift b -- | Like `cmpop`, but swaps the arguments. cmpopb :: (Var v) => POp -> Reference -> SuperNormal v cmpopb pop _rf = - binop0 1 $ \[ x, y, b] -> - TLetD b UN (TPrm pop [y, x]) - $ boolift b + binop0 1 $ \[x, y, b] -> + TLetD b UN (TPrm pop [y, x]) $ + boolift b -- | Like `cmpop`, but negates the result. cmpopn :: (Var v) => POp -> Reference -> SuperNormal v cmpopn pop _rf = - binop0 1 $ \[ x, y, b] -> - TLetD b UN (TPrm pop [x, y]) - $ notlift b + binop0 1 $ \[x, y, b] -> + TLetD b UN (TPrm pop [x, y]) $ + notlift b -- | Like `cmpop`, but swaps arguments then negates the result. cmpopbn :: (Var v) => POp -> Reference -> SuperNormal v cmpopbn pop _rf = binop0 1 $ \[x, y, b] -> - TLetD b UN (TPrm pop [y, x]) - $ notlift b + TLetD b UN (TPrm pop [y, x]) $ + notlift b addi, subi, muli, divi, modi, shli, shri, powi :: (Var v) => SuperNormal v addi = binop ADDI Ty.intRef @@ -504,7 +498,7 @@ n2f = unop' NTOF Ty.natRef Ty.floatRef trni :: (Var v) => SuperNormal v trni = unop0 2 $ \[x, z, b] -> - TLetD z UN (TLit $ I 0) + TLetD z UN (TLit $ I 0) . TLetD b UN (TPrm LEQI [x, z]) . TMatch b $ MatchIntegral @@ -514,7 +508,7 @@ trni = unop0 2 $ \[x, z, b] -> modular :: (Var v) => POp -> (Bool -> ANormal v) -> SuperNormal v modular pop ret = unop0 2 $ \[x, m, t] -> - TLetD t UN (TLit $ I 2) + TLetD t UN (TLit $ I 2) . TLetD m UN (TPrm pop [x, t]) . TMatch m $ MatchIntegral @@ -529,22 +523,22 @@ oddn = modular MODN (\b -> if b then tru else fls) dropn :: (Var v) => SuperNormal v dropn = binop0 1 $ \[x, y, b] -> - TLetD b UN (TPrm LEQN [x, y]) - $ ( TMatch b $ - MatchIntegral - (mapSingleton 1 $ TLit $ N 0) - (Just $ TPrm SUBN [x, y]) - ) + TLetD b UN (TPrm LEQN [x, y]) $ + ( TMatch b $ + MatchIntegral + (mapSingleton 1 $ TLit $ N 0) + (Just $ TPrm SUBN [x, y]) + ) appendt, taket, dropt, indext, indexb, sizet, unconst, unsnoct :: (Var v) => SuperNormal v appendt = binop0 0 $ \[x, y] -> TPrm CATT [x, y] taket = binop0 0 $ \[x, y] -> - TPrm TAKT [x, y] + TPrm TAKT [x, y] dropt = binop0 0 $ \[x, y] -> - TPrm DRPT [x, y] + TPrm DRPT [x, y] -atb = binop0 2 $ \[n, b, t, r] -> - TLetD t UN (TPrm IDXB [n, b]) +atb = binop0 2 $ \[n, b, t, r] -> + TLetD t UN (TPrm IDXB [n, b]) . TMatch t . MatchSum $ mapFromList @@ -601,7 +595,7 @@ unconst = unop0 6 $ \[x, t, c, y, p, u, yp] -> ) ] -unsnoct = unop0 6 $ \[x, t, c, y, p, u, cp] -> +unsnoct = unop0 6 $ \[x, t, c, y, p, u, cp] -> TLetD t UN (TPrm USNC [x]) . TMatch t . MatchSum @@ -627,8 +621,8 @@ takes, drops, sizes, ats, emptys :: (Var v) => SuperNormal v takes = binop0 0 $ \[x, y] -> TPrm TAKS [x, y] drops = binop0 0 $ \[x, y] -> TPrm DRPS [x, y] sizes = unop0 0 $ \[x] -> (TPrm SIZS [x]) -ats = binop0 2 $ \[x, y, t, r] -> - TLetD t UN (TPrm IDXS [x, y]) +ats = binop0 2 $ \[x, y, t, r] -> + TLetD t UN (TPrm IDXS [x, y]) . TMatch t . MatchSum $ mapFromList @@ -657,7 +651,7 @@ viewrs = unop0 3 $ \[s, u, i, l] -> splitls, splitrs :: (Var v) => SuperNormal v splitls = binop0 3 $ \[n, s, t, l, r] -> - TLetD t UN (TPrm SPLL [n, s]) + TLetD t UN (TPrm SPLL [n, s]) . TMatch t . MatchSum $ mapFromList @@ -665,7 +659,7 @@ splitls = binop0 3 $ \[n, s, t, l, r] -> (1, ([BX, BX], TAbss [l, r] $ seqViewElem l r)) ] splitrs = binop0 3 $ \[n, s, t, l, r] -> - TLetD t UN (TPrm SPLR [n, s]) + TLetD t UN (TPrm SPLR [n, s]) . TMatch t . MatchSum $ mapFromList @@ -720,7 +714,7 @@ n2t = unop0 0 $ \[n] -> TPrm NTOT [n] f2t = unop0 0 $ \[f] -> TPrm FTOT [f] t2i, t2n, t2f :: SuperNormal Symbol -t2i = unop0 2 $ \[x, t, n] -> +t2i = unop0 2 $ \[x, t, n] -> TLetD t UN (TPrm TTOI [x]) . TMatch t . MatchSum @@ -764,8 +758,8 @@ equ = binop0 1 $ \[x, y, b] -> cmpu :: SuperNormal Symbol cmpu = binop0 1 $ \[x, y, c] -> - TLetD c UN (TPrm CMPU [x, y]) - $ (TPrm DECI [c]) + TLetD c UN (TPrm CMPU [x, y]) $ + (TPrm DECI [c]) ltu :: SuperNormal Symbol ltu = binop0 1 $ \[x, y, c] -> @@ -821,8 +815,9 @@ coerceType :: Reference -> Reference -> SuperNormal Symbol coerceType _ri _ro = -- TODO: Fix this with a proper type-coercion unop0 0 $ \[x] -> TVar x - -- unbox x0 ri x $ - -- TCon ro 0 [x] + +-- unbox x0 ri x $ +-- TCon ro 0 [x] -- This version of unsafeCoerce is the identity function. It works -- only if the two types being coerced between are actually the same, @@ -1033,7 +1028,7 @@ seek'handle instr = . TLetD result UN (TFOp instr [arg1, seek, arg3]) $ outIoFailUnit stack1 stack2 stack3 unit fail result where - (arg1, arg2, arg3, seek, stack1, stack2, stack3, unit, fail, result) = fresh + (arg1, arg2, arg3, seek, stack1, stack2, stack3, unit, fail, result) = fresh no'buf, line'buf, block'buf, sblock'buf :: (Enum e) => e no'buf = toEnum $ fromIntegral Ty.bufferModeNoBufferingId @@ -1046,24 +1041,17 @@ infixr 0 --> (-->) :: a -> b -> (a, b) x --> y = (x, y) --- Box an unboxed value --- Takes the boxed variable, the unboxed variable, and the type of the value -box :: (Var v) => v -> v -> Reference -> Term ANormalF v -> Term ANormalF v -box b u ty = TLetD b BX (TCon ty 0 [u]) - time'zone :: ForeignOp time'zone instr = ([BX],) . TAbss [secs] . TLets Direct [offset, summer, name] [UN, UN, BX] (TFOp instr [secs]) - . box bsummer summer Ty.natRef - . box boffset offset Ty.intRef . TLetD un BX (TCon Ty.unitRef 0 []) . TLetD p2 BX (TCon Ty.pairRef 0 [name, un]) - . TLetD p1 BX (TCon Ty.pairRef 0 [bsummer, p2]) - $ TCon Ty.pairRef 0 [boffset, p1] + . TLetD p1 BX (TCon Ty.pairRef 0 [summer, p2]) + $ TCon Ty.pairRef 0 [offset, p1] where - (secs, offset, boffset, summer, bsummer, name, un, p2, p1) = fresh + (secs, offset, summer, name, un, p2, p1) = fresh start'process :: ForeignOp start'process instr = @@ -1144,7 +1132,7 @@ get'buffering'output eitherResult stack1 stack2 stack3 resultTag anyVar failVar get'buffering :: ForeignOp get'buffering = - inBx arg1 eitherResult $ + in1 arg1 eitherResult $ get'buffering'output eitherResult n n2 n3 resultTag anyVar failVar successVar where (arg1, eitherResult, n, n2, n3, resultTag, anyVar, failVar, successVar) = fresh @@ -1176,13 +1164,12 @@ crypto'hmac instr = where (alg, by, x, vl) = fresh --- Input Shape -- these will represent different argument lists a +-- Input Shape -- these represent different argument lists a -- foreign might expect -- --- They will be named according to their shape: --- inBx : one boxed input arg --- inNat : one Nat input arg --- inBxBx : two boxed input args +-- They are named according to their shape: +-- inUnit : one input arg, unit output +-- in1 : one input arg -- -- All of these functions will have take (at least) the same three arguments -- @@ -1196,19 +1183,23 @@ inUnit :: forall v. (Var v) => v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) inUnit unit result cont instr = ([BX], TAbs unit $ TLetD result UN (TFOp instr []) cont) +inN :: forall v. (Var v) => [v] -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +inN args result cont instr = + (args $> BX,) + . TAbss args + $ TLetD result UN (TFOp instr args) cont + -- a -> ... -inBx :: forall v. (Var v) => v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBx arg result cont instr = - ([BX],) - . TAbs arg - $ TLetD result UN (TFOp instr [arg]) cont +in1 :: forall v. (Var v) => v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +in1 arg result cont instr = inN [arg] result cont instr --- Nat -> ... -inNat :: forall v. (Var v) => v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inNat nat result cont instr = - ([BX],) - . TAbs nat - $ TLetD result UN (TFOp instr [nat]) cont +-- a -> b -> ... +in2 :: forall v. (Var v) => v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +in2 arg1 arg2 result cont instr = inN [arg1, arg2] result cont instr + +-- a -> b -> c -> ... +in3 :: forall v. (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +in3 arg1 arg2 arg3 result cont instr = inN [arg1, arg2, arg3] result cont instr -- Maybe a -> b -> ... inMaybeBx :: forall v. (Var v) => v -> v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) @@ -1227,20 +1218,6 @@ inMaybeBx arg1 arg2 arg3 mb result cont instr = (fromIntegral Ty.someId, ([BX], TAbs arg3 . TLetD mb UN (TLit $ I 1) $ TLetD result UN (TFOp instr [mb, arg3, arg2]) cont)) ] --- a -> b -> ... -inBxBx :: forall v. (Var v) => v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxBx arg1 arg2 result cont instr = - ([BX, BX],) - . TAbss [arg1, arg2] - $ TLetD result UN (TFOp instr [arg1, arg2]) cont - --- a -> b -> c -> ... -inBxBxBx :: forall v. (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxBxBx arg1 arg2 arg3 result cont instr = - ([BX, BX, BX],) - . TAbss [arg1, arg2, arg3] - $ TLetD result UN (TFOp instr [arg1, arg2, arg3]) cont - set'echo :: ForeignOp set'echo instr = ([BX, BX],) @@ -1251,29 +1228,9 @@ set'echo instr = where (arg1, arg2, bol, stack1, stack2, stack3, unit, fail, result) = fresh --- a -> Nat -> ... -inBxNat :: forall v. (Var v) => v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxNat arg1 arg2 result cont instr = - ([BX, BX],) - . TAbss [arg1, arg2] - $ TLetD result UN (TFOp instr [arg1, arg2]) cont - -inBxNatNat :: - (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxNatNat arg1 arg2 arg3 result cont instr = - ([BX, BX, BX],) - . TAbss [arg1, arg2, arg3] - $ TLetD result UN (TFOp instr [arg1, arg2, arg3]) cont - -inBxNatBx :: (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxNatBx arg1 arg2 arg3 result cont instr = - ([BX, BX, BX],) - . TAbss [arg1, arg2, arg3] - $ TLetD result UN (TFOp instr [arg1, arg2, arg3]) cont - -- a -> IOMode -> ... -inBxIomr :: forall v. (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) -inBxIomr arg1 arg2 fm result cont instr = +inIomr :: forall v. (Var v) => v -> v -> v -> v -> ANormal v -> FOp -> ([Mem], ANormal v) +inIomr arg1 arg2 fm result cont instr = ([BX, BX],) . TAbss [arg1, arg2] . unenum 4 arg2 Ty.fileModeRef fm @@ -1292,24 +1249,11 @@ inBxIomr arg1 arg2 fm result cont instr = -- outMaybe :: forall v. (Var v) => v -> v -> ANormal v -outMaybe maybe result = - TMatch result . MatchSum $ - mapFromList - [ (0, ([], none)), - (1, ([BX], TAbs maybe $ some maybe)) - ] - -outMaybeNat :: (Var v) => v -> v -> ANormal v -outMaybeNat tag result = +outMaybe tag result = TMatch tag . MatchSum $ mapFromList [ (0, ([], none)), - ( 1, - ( [UN], - -- TODO: Fix this? - TAbs result $ some result - ) - ) + (1, ([BX], TAbs result $ some result)) ] outMaybeNTup :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v @@ -1354,18 +1298,6 @@ outIoFail stack1 stack2 stack3 any fail result = (1, ([BX], TAbs stack1 $ right stack1)) ] -outIoFailNat :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v -outIoFailNat stack1 stack2 stack3 fail extra result = - TMatch result . MatchSum $ - mapFromList - [ failureCase stack1 stack2 stack3 extra fail, - ( 1, - ([UN],) - . TAbs stack3 - $ right stack3 - ) - ] - outIoFailChar :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v outIoFailChar stack1 stack2 stack3 fail extra result = TMatch result . MatchSum $ @@ -1398,20 +1330,6 @@ exnCase stack1 stack2 stack3 any fail = . TLetD fail BX (TCon Ty.failureRef 0 [stack1, stack2, any]) $ TReq Ty.exceptionRef 0 [fail] -outIoExnNat :: - forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v -outIoExnNat stack1 stack2 stack3 any fail result = - TMatch result . MatchSum $ - mapFromList - [ exnCase stack1 stack2 stack3 any fail, - ( 1, - -- TODO: Can I simplify this? - ([UN],) - . TAbs stack1 - $ TVar stack1 - ) - ] - outIoExnUnit :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v outIoExnUnit stack1 stack2 stack3 any fail result = @@ -1421,18 +1339,18 @@ outIoExnUnit stack1 stack2 stack3 any fail result = (1, ([], TCon Ty.unitRef 0 [])) ] -outIoExnBox :: +outIoExn :: (Var v) => v -> v -> v -> v -> v -> v -> ANormal v -outIoExnBox stack1 stack2 stack3 any fail result = +outIoExn stack1 stack2 stack3 any fail result = TMatch result . MatchSum $ mapFromList [ exnCase stack1 stack2 stack3 any fail, (1, ([BX], TAbs stack1 $ TVar stack1)) ] -outIoExnEBoxBox :: +outIoExnEither :: (Var v) => v -> v -> v -> v -> v -> v -> v -> v -> ANormal v -outIoExnEBoxBox stack1 stack2 stack3 any fail t0 t1 res = +outIoExnEither stack1 stack2 stack3 any fail t0 t1 res = TMatch t0 . MatchSum $ mapFromList [ exnCase stack1 stack2 stack3 any fail, @@ -1448,18 +1366,6 @@ outIoExnEBoxBox stack1 stack2 stack3 any fail t0 t1 res = ) ] -outIoFailBox :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v -outIoFailBox stack1 stack2 stack3 any fail result = - TMatch result . MatchSum $ - mapFromList - [ failureCase stack1 stack2 stack3 any fail, - ( 1, - ([BX],) - . TAbs stack1 - $ right stack1 - ) - ] - outIoFailUnit :: forall v. (Var v) => v -> v -> v -> v -> v -> v -> ANormal v outIoFailUnit stack1 stack2 stack3 extra fail result = TMatch result . MatchSum $ @@ -1526,7 +1432,7 @@ outIoFailG stack1 stack2 stack3 fail result output k = -- -- These are pairings of input and output functions to handle a -- foreign call. The input function represents the numbers and types --- of the inputs to a forein call. The output function takes the +-- of the inputs to a foreign call. The output function takes the -- result of the foreign call and turns it into a Unison type. -- @@ -1534,72 +1440,37 @@ outIoFailG stack1 stack2 stack3 fail result output k = direct :: ForeignOp direct instr = ([], TFOp instr []) --- () -> a -unitDirect :: ForeignOp -unitDirect instr = ([BX],) . TAbs arg $ TFOp instr [] where arg = fresh1 - --- a -> b -boxDirect :: ForeignOp -boxDirect instr = - ([BX],) - . TAbs arg - $ TFOp instr [arg] - where - arg = fresh1 - --- () -> Either Failure Nat -unitToEFNat :: ForeignOp -unitToEFNat = - inUnit unit result $ - outIoFailNat stack1 stack2 stack3 fail nat result - where - (unit, stack1, stack2, stack3, fail, nat, result) = fresh - --- () -> Int -unitToInt :: ForeignOp -unitToInt = +-- () -> r +unitToR :: ForeignOp +unitToR = inUnit unit result $ TVar result where (unit, result) = fresh -- () -> Either Failure a -unitToEFBox :: ForeignOp -unitToEFBox = +unitToEF :: ForeignOp +unitToEF = inUnit unit result $ - outIoFailBox stack1 stack2 stack3 any fail result + outIoFail stack1 stack2 stack3 any fail result where (unit, stack1, stack2, stack3, fail, any, result) = fresh --- a -> Int --- --- TODO: Probably don't need all these boxing type wrapper things now. -boxToInt :: ForeignOp -boxToInt = inBx arg result (TVar result) - where - (arg, result) = fresh - --- a -> Nat -boxToNat :: ForeignOp -boxToNat = inBx arg result (TVar result) - where - (arg, result) = fresh - -boxIomrToEFBox :: ForeignOp -boxIomrToEFBox = - inBxIomr arg1 arg2 enum result $ - outIoFailBox stack1 stack2 stack3 any fail result +argIomrToEF :: ForeignOp +argIomrToEF = + inIomr arg1 arg2 enum result $ + outIoFail stack1 stack2 stack3 any fail result where (arg1, arg2, enum, stack1, stack2, stack3, any, fail, result) = fresh -- a -> () -boxTo0 :: ForeignOp -boxTo0 = inBx arg result (TCon Ty.unitRef 0 []) +argToUnit :: ForeignOp +argToUnit = in1 arg result (TCon Ty.unitRef 0 []) where (arg, result) = fresh -- a -> b ->{E} () -boxBoxTo0 :: ForeignOp -boxBoxTo0 instr = +arg2To0 :: ForeignOp +arg2To0 instr = ([BX, BX],) . TAbss [arg1, arg2] . TLets Direct [] [] (TFOp instr [arg1, arg2]) @@ -1607,139 +1478,43 @@ boxBoxTo0 instr = where (arg1, arg2) = fresh --- a -> b ->{E} Nat -boxBoxToNat :: ForeignOp -boxBoxToNat instr = - ([BX, BX],) - . TAbss [arg1, arg2] - $ (TFOp instr [arg1, arg2]) +-- ... -> Bool +argNToBool :: Int -> ForeignOp +argNToBool n instr = + (replicate n BX,) + . TAbss args + $ TLetD result UN (TFOp instr args) (boolift result) where - (arg1, arg2) = fresh - --- a -> b -> Option c + (result : args) = freshes (n + 1) --- a -> Bool -boxToBool :: ForeignOp -boxToBool = - inBx arg result $ - boolift result - where - (arg, result) = fresh - --- a -> b -> Bool -boxBoxToBool :: ForeignOp -boxBoxToBool = - inBxBx arg1 arg2 result $ boolift result - where - (arg1, arg2, result) = fresh - --- a -> b -> c -> Bool -boxBoxBoxToBool :: ForeignOp -boxBoxBoxToBool = - inBxBxBx arg1 arg2 arg3 result $ boolift result - where - (arg1, arg2, arg3, result) = fresh - --- Nat -> c --- Works for an type that's packed into a word, just --- pass `wordDirect Ty.natRef`, `wordDirect Ty.floatRef` --- etc --- --- TODO: Do we still need this? -wordDirect :: Reference -> ForeignOp -wordDirect _wordType instr = - ([BX],) - . TAbss [ub1] - $ TFOp instr [ub1] - where - ub1 = fresh1 - --- Nat -> Bool --- --- TODO: Do we still need this? -boxWordToBool :: Reference -> ForeignOp -boxWordToBool _wordType instr = - ([BX, BX],) - . TAbss [b1, uw1] - $ TLetD result UN (TFOp instr [b1, uw1]) (boolift result) - where - (b1, uw1, result) = fresh - --- Nat -> Nat -> c --- --- TODO: Do we still need this? -wordWordDirect :: Reference -> Reference -> ForeignOp -wordWordDirect _word1 _word2 instr = - ([BX, BX],) - . TAbss [ub1, ub2] - $ TFOp instr [ub1, ub2] +argNDirect :: Int -> ForeignOp +argNDirect n instr = + (replicate n BX,) + . TAbss args + $ TFOp instr args where - (ub1, ub2) = fresh - --- Nat -> a -> c --- Works for an type that's packed into a word, just --- pass `wordBoxDirect Ty.natRef`, `wordBoxDirect Ty.floatRef` --- etc --- --- TODO: Do we still need this? -wordBoxDirect :: Reference -> ForeignOp -wordBoxDirect _wordType instr = - ([BX, BX],) - . TAbss [ub1, b2] - $ TFOp instr [ub1, b2] - where - (b2, ub1) = fresh - --- a -> Nat -> c --- works for any second argument type that is packed into a word --- --- TODO: Do we still need this? -boxWordDirect :: Reference -> ForeignOp -boxWordDirect _wordType instr = - ([BX, BX],) - . TAbss [b1, ub2] - $ TFOp instr [b1, ub2] - where - (b1, ub2) = fresh - --- a -> b -> c -boxBoxDirect :: ForeignOp -boxBoxDirect instr = - ([BX, BX],) - . TAbss [b1, b2] - $ TFOp instr [b1, b2] - where - (b1, b2) = fresh - --- a -> b -> c -> d -boxBoxBoxDirect :: ForeignOp -boxBoxBoxDirect instr = - ([BX, BX, BX],) - . TAbss [b1, b2, b3] - $ TFOp instr [b1, b2, b3] - where - (b1, b2, b3) = fresh + args = freshes n -- a -> Either Failure b -boxToEFBox :: ForeignOp -boxToEFBox = - inBx arg result $ - outIoFailBox stack1 stack2 stack3 any fail result +argToEF :: ForeignOp +argToEF = + in1 arg result $ + outIoFail stack1 stack2 stack3 any fail result where (arg, result, stack1, stack2, stack3, any, fail) = fresh -- a -> Either Failure (b, c) -boxToEFTup :: ForeignOp -boxToEFTup = - inBx arg result $ +argToEFTup :: ForeignOp +argToEFTup = + in1 arg result $ outIoFailTup stack1 stack2 stack3 stack4 stack5 extra fail result where (arg, result, stack1, stack2, stack3, stack4, stack5, extra, fail) = fresh -- a -> Either Failure (Maybe b) -boxToEFMBox :: ForeignOp -boxToEFMBox = - inBx arg result +argToEFM :: ForeignOp +argToEFM = + in1 arg result . outIoFailG stack1 stack2 stack3 fail result output $ \k -> ( [UN], @@ -1753,222 +1528,161 @@ boxToEFMBox = (arg, result, stack1, stack2, stack3, stack4, fail, output) = fresh -- a -> Maybe b -boxToMaybeBox :: ForeignOp -boxToMaybeBox = - inBx arg result $ outMaybe maybe result - where - (arg, maybe, result) = fresh - --- a -> Maybe Nat -boxToMaybeNat :: ForeignOp -boxToMaybeNat = inBx arg tag $ outMaybeNat tag result +argToMaybe :: ForeignOp +argToMaybe = in1 arg tag $ outMaybe tag result where (arg, tag, result) = fresh -- a -> Maybe (Nat, b) -boxToMaybeNTup :: ForeignOp -boxToMaybeNTup = - inBx arg result $ outMaybeNTup a b u bp p result +argToMaybeNTup :: ForeignOp +argToMaybeNTup = + in1 arg result $ outMaybeNTup a b u bp p result where (arg, a, b, u, bp, p, result) = fresh -- a -> b -> Maybe (c, d) -boxBoxToMaybeTup :: ForeignOp -boxBoxToMaybeTup = - inBxBx arg1 arg2 result $ outMaybeTup a b u bp ap result +arg2ToMaybeTup :: ForeignOp +arg2ToMaybeTup = + in2 arg1 arg2 result $ outMaybeTup a b u bp ap result where (arg1, arg2, a, b, u, bp, ap, result) = fresh -- a -> Either Failure Bool -boxToEFBool :: ForeignOp -boxToEFBool = - inBx arg result $ +argToEFBool :: ForeignOp +argToEFBool = + in1 arg result $ outIoFailBool stack1 stack2 stack3 bool fail result where (arg, stack1, stack2, stack3, bool, fail, result) = fresh -- a -> Either Failure Char -boxToEFChar :: ForeignOp -boxToEFChar = - inBx arg result $ +argToEFChar :: ForeignOp +argToEFChar = + in1 arg result $ outIoFailChar stack1 stack2 stack3 bool fail result where (arg, stack1, stack2, stack3, bool, fail, result) = fresh -- a -> b -> Either Failure Bool -boxBoxToEFBool :: ForeignOp -boxBoxToEFBool = - inBxBx arg1 arg2 result $ +arg2ToEFBool :: ForeignOp +arg2ToEFBool = + in2 arg1 arg2 result $ outIoFailBool stack1 stack2 stack3 bool fail result where (arg1, arg2, stack1, stack2, stack3, bool, fail, result) = fresh -- a -> b -> c -> Either Failure Bool -boxBoxBoxToEFBool :: ForeignOp -boxBoxBoxToEFBool = - inBxBxBx arg1 arg2 arg3 result $ +arg3ToEFBool :: ForeignOp +arg3ToEFBool = + in3 arg1 arg2 arg3 result $ outIoFailBool stack1 stack2 stack3 bool fail result where (arg1, arg2, arg3, stack1, stack2, stack3, bool, fail, result) = fresh -- a -> Either Failure () -boxToEF0 :: ForeignOp -boxToEF0 = - inBx arg result $ +argToEF0 :: ForeignOp +argToEF0 = + in1 arg result $ outIoFailUnit stack1 stack2 stack3 unit fail result where (arg, result, stack1, stack2, stack3, unit, fail) = fresh -- a -> b -> Either Failure () -boxBoxToEF0 :: ForeignOp -boxBoxToEF0 = - inBxBx arg1 arg2 result $ +arg2ToEF0 :: ForeignOp +arg2ToEF0 = + in2 arg1 arg2 result $ outIoFailUnit stack1 stack2 stack3 fail unit result where (arg1, arg2, result, stack1, stack2, stack3, fail, unit) = fresh -- a -> b -> c -> Either Failure () -boxBoxBoxToEF0 :: ForeignOp -boxBoxBoxToEF0 = - inBxBxBx arg1 arg2 arg3 result $ +arg3ToEF0 :: ForeignOp +arg3ToEF0 = + in3 arg1 arg2 arg3 result $ outIoFailUnit stack1 stack2 stack3 fail unit result where (arg1, arg2, arg3, result, stack1, stack2, stack3, fail, unit) = fresh --- a -> Either Failure Nat -boxToEFNat :: ForeignOp -boxToEFNat = - inBx arg result $ - outIoFailNat stack1 stack2 stack3 nat fail result +-- a -> Either Failure b +argToEFNat :: ForeignOp +argToEFNat = + in1 arg result $ + outIoFail stack1 stack2 stack3 nat fail result where (arg, result, stack1, stack2, stack3, nat, fail) = fresh -- Maybe a -> b -> Either Failure c -maybeBoxToEFBox :: ForeignOp -maybeBoxToEFBox = +maybeToEF :: ForeignOp +maybeToEF = inMaybeBx arg1 arg2 arg3 mb result $ outIoFail stack1 stack2 stack3 any fail result where (arg1, arg2, arg3, mb, result, stack1, stack2, stack3, any, fail) = fresh -- a -> b -> Either Failure c -boxBoxToEFBox :: ForeignOp -boxBoxToEFBox = - inBxBx arg1 arg2 result $ +arg2ToEF :: ForeignOp +arg2ToEF = + in2 arg1 arg2 result $ outIoFail stack1 stack2 stack3 any fail result where (arg1, arg2, result, stack1, stack2, stack3, any, fail) = fresh -- a -> b -> c -> Either Failure d -boxBoxBoxToEFBox :: ForeignOp -boxBoxBoxToEFBox = - inBxBxBx arg1 arg2 arg3 result $ +arg3ToEF :: ForeignOp +arg3ToEF = + in3 arg1 arg2 arg3 result $ outIoFail stack1 stack2 stack3 any fail result where (arg1, arg2, arg3, result, stack1, stack2, stack3, any, fail) = fresh --- Nat -> a --- Nat only -natToBox :: ForeignOp -natToBox = wordDirect Ty.natRef - --- Nat -> Nat -> a --- Nat only -natNatToBox :: ForeignOp -natNatToBox = wordWordDirect Ty.natRef Ty.natRef - --- Nat -> Nat -> a -> b -natNatBoxToBox :: ForeignOp -natNatBoxToBox instr = - ([BX, BX, BX],) - . TAbss [ua1, ua2, a3] - $ TFOp instr [ua1, ua2, a3] - where - (a3, ua1, ua2) = fresh - --- a -> Nat -> c --- Nat only -boxNatToBox :: ForeignOp -boxNatToBox = boxWordDirect Ty.natRef - --- a -> Nat -> Either Failure b -boxNatToEFBox :: ForeignOp -boxNatToEFBox = - inBxNat arg1 arg2 result $ - outIoFail stack1 stack2 stack3 any fail result +-- a -> b ->{Exception} c +arg2ToExn :: ForeignOp +arg2ToExn = + in2 arg1 arg2 result $ + outIoExn stack1 stack2 stack3 any fail result where (arg1, arg2, stack1, stack2, stack3, any, fail, result) = fresh --- a -> Nat ->{Exception} b -boxNatToExnBox :: ForeignOp -boxNatToExnBox = - inBxNat arg1 arg2 result $ - outIoExnBox stack1 stack2 stack3 fail any result - where - (arg1, arg2, stack1, stack2, stack3, any, fail, result) = fresh - --- a -> Nat -> b ->{Exception} () -boxNatBoxToExnUnit :: ForeignOp -boxNatBoxToExnUnit = - inBxNatBx arg1 arg2 arg3 result $ - outIoExnUnit stack1 stack2 stack3 any fail result - where - (arg1, arg2, arg3, stack1, stack2, stack3, any, fail, result) = fresh - --- a -> Nat ->{Exception} Nat -boxNatToExnNat :: ForeignOp -boxNatToExnNat = - inBxNat arg1 arg2 result $ - outIoExnNat stack1 stack2 stack3 any fail result - where - (arg1, arg2, stack1, stack2, stack3, any, fail, result) = fresh - --- a -> Nat -> Nat ->{Exception} () -boxNatNatToExnUnit :: ForeignOp -boxNatNatToExnUnit = - inBxNatNat arg1 arg2 arg3 result $ +-- a -> b -> c ->{Exception} () +arg3ToExnUnit :: ForeignOp +arg3ToExnUnit = + in3 arg1 arg2 arg3 result $ outIoExnUnit stack1 stack2 stack3 any fail result where - (arg1, arg2, arg3, result, stack1, stack2, stack3, any, fail) = fresh + (arg1, arg2, arg3, stack1, stack2, stack3, any, fail, result) = fresh -- a -> Nat -> Nat ->{Exception} b -boxNatNatToExnBox :: ForeignOp -boxNatNatToExnBox = - inBxNatNat arg1 arg2 arg3 result $ - outIoExnBox stack1 stack2 stack3 any fail result +arg3ToExn :: ForeignOp +arg3ToExn = + in3 arg1 arg2 arg3 result $ + outIoExn stack1 stack2 stack3 any fail result where (arg1, arg2, arg3, result, stack1, stack2, stack3, any, fail) = fresh -- a -> Nat -> b -> Nat -> Nat ->{Exception} () -boxNatBoxNatNatToExnUnit :: ForeignOp -boxNatBoxNatNatToExnUnit instr = +arg5ToExnUnit :: ForeignOp +arg5ToExnUnit instr = ([BX, BX, BX, BX, BX],) . TAbss [a0, ua1, a2, ua3, ua4] . TLetD result UN (TFOp instr [a0, ua1, a2, ua3, ua4]) $ outIoExnUnit stack1 stack2 stack3 any fail result where - (a0, a2, ua1, ua3, ua4, result, stack1, stack2, stack3, any, fail) = fresh + (a0, a2, ua1, ua3, ua4, result, stack1, stack2, stack3, any, fail) = fresh -- a ->{Exception} Either b c -boxToExnEBoxBox :: ForeignOp -boxToExnEBoxBox instr = +argToExnE :: ForeignOp +argToExnE instr = ([BX],) . TAbs a . TLetD t0 UN (TFOp instr [a]) - $ outIoExnEBoxBox stack1 stack2 stack3 any fail t0 t1 result + $ outIoExnEither stack1 stack2 stack3 any fail t0 t1 result where (a, stack1, stack2, stack3, any, fail, t0, t1, result) = fresh --- Nat -> Either Failure b --- natToEFBox :: ForeignOp --- natToEFBox = inNat arg nat result $ outIoFail stack1 stack2 fail result --- where --- (arg, nat, stack1, stack2, fail, result) = fresh - -- Nat -> Either Failure () -natToEFUnit :: ForeignOp -natToEFUnit = - inNat nat result +argToEFUnit :: ForeignOp +argToEFUnit = + in1 nat result . TMatch result . MatchSum $ mapFromList @@ -1983,8 +1697,8 @@ natToEFUnit = (nat, result, fail, stack1, stack2, stack3, unit) = fresh -- a -> Either b c -boxToEBoxBox :: ForeignOp -boxToEBoxBox instr = +argToEither :: ForeignOp +argToEither instr = ([BX],) . TAbss [b] . TLetD e UN (TFOp instr [b]) @@ -2264,35 +1978,35 @@ mkForeignTlsE f = mkForeign $ \a -> fmap flatten (tryIO2 (tryIO1 (f a))) declareUdpForeigns :: FDecl Symbol () declareUdpForeigns = do - declareForeign Tracked "IO.UDP.clientSocket.impl.v1" boxBoxToEFBox + declareForeign Tracked "IO.UDP.clientSocket.impl.v1" arg2ToEF . mkForeignIOF $ \(host :: Util.Text.Text, port :: Util.Text.Text) -> let hostStr = Util.Text.toString host portStr = Util.Text.toString port in UDP.clientSocket hostStr portStr True - declareForeign Tracked "IO.UDP.UDPSocket.recv.impl.v1" boxToEFBox + declareForeign Tracked "IO.UDP.UDPSocket.recv.impl.v1" argToEF . mkForeignIOF $ \(sock :: UDPSocket) -> Bytes.fromArray <$> UDP.recv sock - declareForeign Tracked "IO.UDP.UDPSocket.send.impl.v1" boxBoxToEF0 + declareForeign Tracked "IO.UDP.UDPSocket.send.impl.v1" arg2ToEF0 . mkForeignIOF $ \(sock :: UDPSocket, bytes :: Bytes.Bytes) -> UDP.send sock (Bytes.toArray bytes) - declareForeign Tracked "IO.UDP.UDPSocket.close.impl.v1" boxToEF0 + declareForeign Tracked "IO.UDP.UDPSocket.close.impl.v1" argToEF0 . mkForeignIOF $ \(sock :: UDPSocket) -> UDP.close sock - declareForeign Tracked "IO.UDP.ListenSocket.close.impl.v1" boxToEF0 + declareForeign Tracked "IO.UDP.ListenSocket.close.impl.v1" argToEF0 . mkForeignIOF $ \(sock :: ListenSocket) -> UDP.stop sock - declareForeign Tracked "IO.UDP.UDPSocket.toText.impl.v1" boxDirect + declareForeign Tracked "IO.UDP.UDPSocket.toText.impl.v1" (argNDirect 1) . mkForeign $ \(sock :: UDPSocket) -> pure $ show sock - declareForeign Tracked "IO.UDP.serverSocket.impl.v1" boxBoxToEFBox + declareForeign Tracked "IO.UDP.serverSocket.impl.v1" arg2ToEF . mkForeignIOF $ \(ip :: Util.Text.Text, port :: Util.Text.Text) -> let maybeIp = readMaybe $ Util.Text.toString ip :: Maybe IP @@ -2302,19 +2016,19 @@ declareUdpForeigns = do (_, Nothing) -> fail "Invalid Port Number" (Just ip, Just pt) -> UDP.serverSocket (ip, pt) - declareForeign Tracked "IO.UDP.ListenSocket.toText.impl.v1" boxDirect + declareForeign Tracked "IO.UDP.ListenSocket.toText.impl.v1" (argNDirect 1) . mkForeign $ \(sock :: ListenSocket) -> pure $ show sock - declareForeign Tracked "IO.UDP.ListenSocket.recvFrom.impl.v1" boxToEFTup + declareForeign Tracked "IO.UDP.ListenSocket.recvFrom.impl.v1" argToEFTup . mkForeignIOF $ fmap (first Bytes.fromArray) <$> UDP.recvFrom - declareForeign Tracked "IO.UDP.ClientSockAddr.toText.v1" boxDirect + declareForeign Tracked "IO.UDP.ClientSockAddr.toText.v1" (argNDirect 1) . mkForeign $ \(sock :: ClientSockAddr) -> pure $ show sock - declareForeign Tracked "IO.UDP.ListenSocket.sendTo.impl.v1" boxBoxBoxToEF0 + declareForeign Tracked "IO.UDP.ListenSocket.sendTo.impl.v1" arg3ToEF0 . mkForeignIOF $ \(socket :: ListenSocket, bytes :: Bytes.Bytes, addr :: ClientSockAddr) -> UDP.sendTo socket (Bytes.toArray bytes) addr @@ -2322,7 +2036,7 @@ declareUdpForeigns = do declareForeigns :: FDecl Symbol () declareForeigns = do declareUdpForeigns - declareForeign Tracked "IO.openFile.impl.v3" boxIomrToEFBox $ + declareForeign Tracked "IO.openFile.impl.v3" argIomrToEF $ mkForeignIOF $ \(fnameText :: Util.Text.Text, n :: Int) -> let fname = Util.Text.toString fnameText mode = case n of @@ -2332,19 +2046,19 @@ declareForeigns = do _ -> ReadWriteMode in openFile fname mode - declareForeign Tracked "IO.closeFile.impl.v3" boxToEF0 $ mkForeignIOF hClose - declareForeign Tracked "IO.isFileEOF.impl.v3" boxToEFBool $ mkForeignIOF hIsEOF - declareForeign Tracked "IO.isFileOpen.impl.v3" boxToEFBool $ mkForeignIOF hIsOpen - declareForeign Tracked "IO.getEcho.impl.v1" boxToEFBool $ mkForeignIOF hGetEcho - declareForeign Tracked "IO.ready.impl.v1" boxToEFBool $ mkForeignIOF hReady - declareForeign Tracked "IO.getChar.impl.v1" boxToEFChar $ mkForeignIOF hGetChar - declareForeign Tracked "IO.isSeekable.impl.v3" boxToEFBool $ mkForeignIOF hIsSeekable + declareForeign Tracked "IO.closeFile.impl.v3" argToEF0 $ mkForeignIOF hClose + declareForeign Tracked "IO.isFileEOF.impl.v3" argToEFBool $ mkForeignIOF hIsEOF + declareForeign Tracked "IO.isFileOpen.impl.v3" argToEFBool $ mkForeignIOF hIsOpen + declareForeign Tracked "IO.getEcho.impl.v1" argToEFBool $ mkForeignIOF hGetEcho + declareForeign Tracked "IO.ready.impl.v1" argToEFBool $ mkForeignIOF hReady + declareForeign Tracked "IO.getChar.impl.v1" argToEFChar $ mkForeignIOF hGetChar + declareForeign Tracked "IO.isSeekable.impl.v3" argToEFBool $ mkForeignIOF hIsSeekable declareForeign Tracked "IO.seekHandle.impl.v3" seek'handle . mkForeignIOF $ \(h, sm, n) -> hSeek h sm (fromIntegral (n :: Int)) - declareForeign Tracked "IO.handlePosition.impl.v3" boxToEFNat + declareForeign Tracked "IO.handlePosition.impl.v3" argToEFNat -- TODO: truncating integer . mkForeignIOF $ \h -> fromInteger @Word64 <$> hTell h @@ -2358,48 +2072,48 @@ declareForeigns = do declareForeign Tracked "IO.setEcho.impl.v1" set'echo . mkForeignIOF $ uncurry hSetEcho - declareForeign Tracked "IO.getLine.impl.v1" boxToEFBox $ + declareForeign Tracked "IO.getLine.impl.v1" argToEF $ mkForeignIOF $ fmap Util.Text.fromText . Text.IO.hGetLine - declareForeign Tracked "IO.getBytes.impl.v3" boxNatToEFBox . mkForeignIOF $ + declareForeign Tracked "IO.getBytes.impl.v3" arg2ToEF . mkForeignIOF $ \(h, n) -> Bytes.fromArray <$> hGet h n - declareForeign Tracked "IO.getSomeBytes.impl.v1" boxNatToEFBox . mkForeignIOF $ + declareForeign Tracked "IO.getSomeBytes.impl.v1" arg2ToEF . mkForeignIOF $ \(h, n) -> Bytes.fromArray <$> hGetSome h n - declareForeign Tracked "IO.putBytes.impl.v3" boxBoxToEF0 . mkForeignIOF $ \(h, bs) -> hPut h (Bytes.toArray bs) + declareForeign Tracked "IO.putBytes.impl.v3" arg2ToEF0 . mkForeignIOF $ \(h, bs) -> hPut h (Bytes.toArray bs) - declareForeign Tracked "IO.systemTime.impl.v3" unitToEFNat $ + declareForeign Tracked "IO.systemTime.impl.v3" unitToEF $ mkForeignIOF $ \() -> getPOSIXTime - declareForeign Tracked "IO.systemTimeMicroseconds.v1" unitToInt $ + declareForeign Tracked "IO.systemTimeMicroseconds.v1" unitToR $ mkForeign $ \() -> fmap (1e6 *) getPOSIXTime - declareForeign Tracked "Clock.internals.monotonic.v1" unitToEFBox $ + declareForeign Tracked "Clock.internals.monotonic.v1" unitToEF $ mkForeignIOF $ \() -> getTime Monotonic - declareForeign Tracked "Clock.internals.realtime.v1" unitToEFBox $ + declareForeign Tracked "Clock.internals.realtime.v1" unitToEF $ mkForeignIOF $ \() -> getTime Realtime - declareForeign Tracked "Clock.internals.processCPUTime.v1" unitToEFBox $ + declareForeign Tracked "Clock.internals.processCPUTime.v1" unitToEF $ mkForeignIOF $ \() -> getTime ProcessCPUTime - declareForeign Tracked "Clock.internals.threadCPUTime.v1" unitToEFBox $ + declareForeign Tracked "Clock.internals.threadCPUTime.v1" unitToEF $ mkForeignIOF $ \() -> getTime ThreadCPUTime - declareForeign Tracked "Clock.internals.sec.v1" boxToInt $ + declareForeign Tracked "Clock.internals.sec.v1" (argNDirect 1) $ mkForeign (\n -> pure (fromIntegral $ sec n :: Word64)) -- A TimeSpec that comes from getTime never has negative nanos, -- so we can safely cast to Nat - declareForeign Tracked "Clock.internals.nsec.v1" boxToNat $ + declareForeign Tracked "Clock.internals.nsec.v1" (argNDirect 1) $ mkForeign (\n -> pure (fromIntegral $ nsec n :: Word64)) declareForeign Tracked "Clock.internals.systemTimeZone.v1" time'zone $ @@ -2411,116 +2125,116 @@ declareForeigns = do let chop = reverse . dropWhile isPathSeparator . reverse - declareForeign Tracked "IO.getTempDirectory.impl.v3" unitToEFBox $ + declareForeign Tracked "IO.getTempDirectory.impl.v3" unitToEF $ mkForeignIOF $ \() -> chop <$> getTemporaryDirectory - declareForeign Tracked "IO.createTempDirectory.impl.v3" boxToEFBox $ + declareForeign Tracked "IO.createTempDirectory.impl.v3" argToEF $ mkForeignIOF $ \prefix -> do temp <- getTemporaryDirectory chop <$> createTempDirectory temp prefix - declareForeign Tracked "IO.getCurrentDirectory.impl.v3" unitToEFBox + declareForeign Tracked "IO.getCurrentDirectory.impl.v3" unitToEF . mkForeignIOF $ \() -> getCurrentDirectory - declareForeign Tracked "IO.setCurrentDirectory.impl.v3" boxToEF0 $ + declareForeign Tracked "IO.setCurrentDirectory.impl.v3" argToEF0 $ mkForeignIOF setCurrentDirectory - declareForeign Tracked "IO.fileExists.impl.v3" boxToEFBool $ + declareForeign Tracked "IO.fileExists.impl.v3" argToEFBool $ mkForeignIOF doesPathExist - declareForeign Tracked "IO.getEnv.impl.v1" boxToEFBox $ + declareForeign Tracked "IO.getEnv.impl.v1" argToEF $ mkForeignIOF getEnv - declareForeign Tracked "IO.getArgs.impl.v1" unitToEFBox $ + declareForeign Tracked "IO.getArgs.impl.v1" unitToEF $ mkForeignIOF $ \() -> fmap Util.Text.pack <$> SYS.getArgs - declareForeign Tracked "IO.isDirectory.impl.v3" boxToEFBool $ + declareForeign Tracked "IO.isDirectory.impl.v3" argToEFBool $ mkForeignIOF doesDirectoryExist - declareForeign Tracked "IO.createDirectory.impl.v3" boxToEF0 $ + declareForeign Tracked "IO.createDirectory.impl.v3" argToEF0 $ mkForeignIOF $ createDirectoryIfMissing True - declareForeign Tracked "IO.removeDirectory.impl.v3" boxToEF0 $ + declareForeign Tracked "IO.removeDirectory.impl.v3" argToEF0 $ mkForeignIOF removeDirectoryRecursive - declareForeign Tracked "IO.renameDirectory.impl.v3" boxBoxToEF0 $ + declareForeign Tracked "IO.renameDirectory.impl.v3" arg2ToEF0 $ mkForeignIOF $ uncurry renameDirectory - declareForeign Tracked "IO.directoryContents.impl.v3" boxToEFBox $ + declareForeign Tracked "IO.directoryContents.impl.v3" argToEF $ mkForeignIOF $ (fmap Util.Text.pack <$>) . getDirectoryContents - declareForeign Tracked "IO.removeFile.impl.v3" boxToEF0 $ + declareForeign Tracked "IO.removeFile.impl.v3" argToEF0 $ mkForeignIOF removeFile - declareForeign Tracked "IO.renameFile.impl.v3" boxBoxToEF0 $ + declareForeign Tracked "IO.renameFile.impl.v3" arg2ToEF0 $ mkForeignIOF $ uncurry renameFile - declareForeign Tracked "IO.getFileTimestamp.impl.v3" boxToEFNat + declareForeign Tracked "IO.getFileTimestamp.impl.v3" argToEFNat . mkForeignIOF $ fmap utcTimeToPOSIXSeconds . getModificationTime - declareForeign Tracked "IO.getFileSize.impl.v3" boxToEFNat + declareForeign Tracked "IO.getFileSize.impl.v3" argToEFNat -- TODO: truncating integer . mkForeignIOF $ \fp -> fromInteger @Word64 <$> getFileSize fp - declareForeign Tracked "IO.serverSocket.impl.v3" maybeBoxToEFBox + declareForeign Tracked "IO.serverSocket.impl.v3" maybeToEF . mkForeignIOF $ \( mhst :: Maybe Util.Text.Text, port ) -> fst <$> SYS.bindSock (hostPreference mhst) port - declareForeign Tracked "Socket.toText" boxDirect + declareForeign Tracked "Socket.toText" (argNDirect 1) . mkForeign $ \(sock :: Socket) -> pure $ show sock - declareForeign Tracked "Handle.toText" boxDirect + declareForeign Tracked "Handle.toText" (argNDirect 1) . mkForeign $ \(hand :: Handle) -> pure $ show hand - declareForeign Tracked "ThreadId.toText" boxDirect + declareForeign Tracked "ThreadId.toText" (argNDirect 1) . mkForeign $ \(threadId :: ThreadId) -> pure $ show threadId - declareForeign Tracked "IO.socketPort.impl.v3" boxToEFNat + declareForeign Tracked "IO.socketPort.impl.v3" argToEFNat . mkForeignIOF $ \(handle :: Socket) -> do n <- SYS.socketPort handle return (fromIntegral n :: Word64) - declareForeign Tracked "IO.listen.impl.v3" boxToEF0 + declareForeign Tracked "IO.listen.impl.v3" argToEF0 . mkForeignIOF $ \sk -> SYS.listenSock sk 2048 - declareForeign Tracked "IO.clientSocket.impl.v3" boxBoxToEFBox + declareForeign Tracked "IO.clientSocket.impl.v3" arg2ToEF . mkForeignIOF $ fmap fst . uncurry SYS.connectSock - declareForeign Tracked "IO.closeSocket.impl.v3" boxToEF0 $ + declareForeign Tracked "IO.closeSocket.impl.v3" argToEF0 $ mkForeignIOF SYS.closeSock - declareForeign Tracked "IO.socketAccept.impl.v3" boxToEFBox + declareForeign Tracked "IO.socketAccept.impl.v3" argToEF . mkForeignIOF $ fmap fst . SYS.accept - declareForeign Tracked "IO.socketSend.impl.v3" boxBoxToEF0 + declareForeign Tracked "IO.socketSend.impl.v3" arg2ToEF0 . mkForeignIOF $ \(sk, bs) -> SYS.send sk (Bytes.toArray bs) - declareForeign Tracked "IO.socketReceive.impl.v3" boxNatToEFBox + declareForeign Tracked "IO.socketReceive.impl.v3" arg2ToEF . mkForeignIOF $ \(hs, n) -> maybe mempty Bytes.fromArray <$> SYS.recv hs n - declareForeign Tracked "IO.kill.impl.v3" boxToEF0 $ mkForeignIOF killThread + declareForeign Tracked "IO.kill.impl.v3" argToEF0 $ mkForeignIOF killThread let mx :: Word64 mx = fromIntegral (maxBound :: Int) @@ -2530,7 +2244,7 @@ declareForeigns = do | n < mx = threadDelay (fromIntegral n) | otherwise = threadDelay maxBound >> customDelay (n - mx) - declareForeign Tracked "IO.delay.impl.v3" natToEFUnit $ + declareForeign Tracked "IO.delay.impl.v3" argToEFUnit $ mkForeignIOF customDelay declareForeign Tracked "IO.stdHandle" standard'handle @@ -2544,7 +2258,7 @@ declareForeigns = do let exitDecode ExitSuccess = 0 exitDecode (ExitFailure n) = n - declareForeign Tracked "IO.process.call" boxBoxToNat . mkForeign $ + declareForeign Tracked "IO.process.call" (argNDirect 2) . mkForeign $ \(exe, map Util.Text.unpack -> args) -> withCreateProcess (proc exe args) $ \_ _ _ p -> exitDecode <$> waitForProcess p @@ -2553,77 +2267,77 @@ declareForeigns = do \(exe, map Util.Text.unpack -> args) -> runInteractiveProcess exe args Nothing Nothing - declareForeign Tracked "IO.process.kill" boxTo0 . mkForeign $ + declareForeign Tracked "IO.process.kill" argToUnit . mkForeign $ terminateProcess - declareForeign Tracked "IO.process.wait" boxToNat . mkForeign $ + declareForeign Tracked "IO.process.wait" (argNDirect 1) . mkForeign $ \ph -> exitDecode <$> waitForProcess ph - declareForeign Tracked "IO.process.exitCode" boxToMaybeNat . mkForeign $ + declareForeign Tracked "IO.process.exitCode" argToMaybe . mkForeign $ fmap (fmap exitDecode) . getProcessExitCode - declareForeign Tracked "MVar.new" boxDirect + declareForeign Tracked "MVar.new" (argNDirect 1) . mkForeign $ \(c :: Val) -> newMVar c - declareForeign Tracked "MVar.newEmpty.v2" unitDirect + declareForeign Tracked "MVar.newEmpty.v2" (argNDirect 1) . mkForeign $ \() -> newEmptyMVar @Val - declareForeign Tracked "MVar.take.impl.v3" boxToEFBox + declareForeign Tracked "MVar.take.impl.v3" argToEF . mkForeignIOF $ \(mv :: MVar Val) -> takeMVar mv - declareForeign Tracked "MVar.tryTake" boxToMaybeBox + declareForeign Tracked "MVar.tryTake" argToMaybe . mkForeign $ \(mv :: MVar Val) -> tryTakeMVar mv - declareForeign Tracked "MVar.put.impl.v3" boxBoxToEF0 + declareForeign Tracked "MVar.put.impl.v3" arg2ToEF0 . mkForeignIOF $ \(mv :: MVar Val, x) -> putMVar mv x - declareForeign Tracked "MVar.tryPut.impl.v3" boxBoxToEFBool + declareForeign Tracked "MVar.tryPut.impl.v3" arg2ToEFBool . mkForeignIOF $ \(mv :: MVar Val, x) -> tryPutMVar mv x - declareForeign Tracked "MVar.swap.impl.v3" boxBoxToEFBox + declareForeign Tracked "MVar.swap.impl.v3" arg2ToEF . mkForeignIOF $ \(mv :: MVar Val, x) -> swapMVar mv x - declareForeign Tracked "MVar.isEmpty" boxToBool + declareForeign Tracked "MVar.isEmpty" (argNToBool 1) . mkForeign $ \(mv :: MVar Val) -> isEmptyMVar mv - declareForeign Tracked "MVar.read.impl.v3" boxToEFBox + declareForeign Tracked "MVar.read.impl.v3" argToEF . mkForeignIOF $ \(mv :: MVar Val) -> readMVar mv - declareForeign Tracked "MVar.tryRead.impl.v3" boxToEFMBox + declareForeign Tracked "MVar.tryRead.impl.v3" argToEFM . mkForeignIOF $ \(mv :: MVar Val) -> tryReadMVar mv - declareForeign Untracked "Char.toText" (wordDirect Ty.charRef) . mkForeign $ + declareForeign Untracked "Char.toText" (argNDirect 1) . mkForeign $ \(ch :: Char) -> pure (Util.Text.singleton ch) - declareForeign Untracked "Text.repeat" (wordBoxDirect Ty.natRef) . mkForeign $ + declareForeign Untracked "Text.repeat" (argNDirect 2) . mkForeign $ \(n :: Word64, txt :: Util.Text.Text) -> pure (Util.Text.replicate (fromIntegral n) txt) - declareForeign Untracked "Text.reverse" boxDirect . mkForeign $ + declareForeign Untracked "Text.reverse" (argNDirect 1) . mkForeign $ pure . Util.Text.reverse - declareForeign Untracked "Text.toUppercase" boxDirect . mkForeign $ + declareForeign Untracked "Text.toUppercase" (argNDirect 1) . mkForeign $ pure . Util.Text.toUppercase - declareForeign Untracked "Text.toLowercase" boxDirect . mkForeign $ + declareForeign Untracked "Text.toLowercase" (argNDirect 1) . mkForeign $ pure . Util.Text.toLowercase - declareForeign Untracked "Text.toUtf8" boxDirect . mkForeign $ + declareForeign Untracked "Text.toUtf8" (argNDirect 1) . mkForeign $ pure . Util.Text.toUtf8 - declareForeign Untracked "Text.fromUtf8.impl.v3" boxToEFBox . mkForeign $ + declareForeign Untracked "Text.fromUtf8.impl.v3" argToEF . mkForeign $ pure . mapLeft (\t -> Failure Ty.ioFailureRef (Util.Text.pack t) unitValue) . Util.Text.fromUtf8 - declareForeign Tracked "Tls.ClientConfig.default" boxBoxDirect . mkForeign $ + declareForeign Tracked "Tls.ClientConfig.default" (argNDirect 2) . mkForeign $ \(hostName :: Util.Text.Text, serverId :: Bytes.Bytes) -> fmap ( \store -> @@ -2634,7 +2348,7 @@ declareForeigns = do ) X.getSystemCertificateStore - declareForeign Tracked "Tls.ServerConfig.default" boxBoxDirect $ + declareForeign Tracked "Tls.ServerConfig.default" (argNDirect 2) $ mkForeign $ \(certs :: [X.SignedCertificate], key :: X.PrivKey) -> pure $ @@ -2645,42 +2359,42 @@ declareForeigns = do let updateClient :: X.CertificateStore -> TLS.ClientParams -> TLS.ClientParams updateClient certs client = client {TLS.clientShared = ((clientShared client) {TLS.sharedCAStore = certs})} - in declareForeign Tracked "Tls.ClientConfig.certificates.set" boxBoxDirect . mkForeign $ + in declareForeign Tracked "Tls.ClientConfig.certificates.set" (argNDirect 2) . mkForeign $ \(certs :: [X.SignedCertificate], params :: ClientParams) -> pure $ updateClient (X.makeCertificateStore certs) params let updateServer :: X.CertificateStore -> TLS.ServerParams -> TLS.ServerParams updateServer certs client = client {TLS.serverShared = ((serverShared client) {TLS.sharedCAStore = certs})} - in declareForeign Tracked "Tls.ServerConfig.certificates.set" boxBoxDirect . mkForeign $ + in declareForeign Tracked "Tls.ServerConfig.certificates.set" (argNDirect 2) . mkForeign $ \(certs :: [X.SignedCertificate], params :: ServerParams) -> pure $ updateServer (X.makeCertificateStore certs) params - declareForeign Tracked "TVar.new" boxDirect . mkForeign $ + declareForeign Tracked "TVar.new" (argNDirect 1) . mkForeign $ \(c :: Val) -> unsafeSTMToIO $ STM.newTVar c - declareForeign Tracked "TVar.read" boxDirect . mkForeign $ + declareForeign Tracked "TVar.read" (argNDirect 1) . mkForeign $ \(v :: STM.TVar Val) -> unsafeSTMToIO $ STM.readTVar v - declareForeign Tracked "TVar.write" boxBoxTo0 . mkForeign $ + declareForeign Tracked "TVar.write" arg2To0 . mkForeign $ \(v :: STM.TVar Val, c :: Val) -> unsafeSTMToIO $ STM.writeTVar v c - declareForeign Tracked "TVar.newIO" boxDirect . mkForeign $ + declareForeign Tracked "TVar.newIO" (argNDirect 1) . mkForeign $ \(c :: Val) -> STM.newTVarIO c - declareForeign Tracked "TVar.readIO" boxDirect . mkForeign $ + declareForeign Tracked "TVar.readIO" (argNDirect 1) . mkForeign $ \(v :: STM.TVar Val) -> STM.readTVarIO v - declareForeign Tracked "TVar.swap" boxBoxDirect . mkForeign $ + declareForeign Tracked "TVar.swap" (argNDirect 2) . mkForeign $ \(v, c :: Val) -> unsafeSTMToIO $ STM.swapTVar v c - declareForeign Tracked "STM.retry" unitDirect . mkForeign $ + declareForeign Tracked "STM.retry" (argNDirect 1) . mkForeign $ \() -> unsafeSTMToIO STM.retry :: IO Val -- Scope and Ref stuff - declareForeign Untracked "Scope.ref" boxDirect + declareForeign Untracked "Scope.ref" (argNDirect 1) . mkForeign $ \(c :: Val) -> newIORef c - declareForeign Tracked "IO.ref" boxDirect + declareForeign Tracked "IO.ref" (argNDirect 1) . mkForeign $ \(c :: Val) -> evaluate c >>= newIORef @@ -2691,16 +2405,16 @@ declareForeigns = do -- [1] https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-IORef.html#g:2 -- [2] https://github.com/ghc/ghc/blob/master/compiler/GHC/StgToCmm/Prim.hs#L286 -- [3] https://github.com/ghc/ghc/blob/master/compiler/GHC/StgToCmm/Prim.hs#L298 - declareForeign Untracked "Ref.read" boxDirect . mkForeign $ + declareForeign Untracked "Ref.read" (argNDirect 1) . mkForeign $ \(r :: IORef Val) -> readIORef r - declareForeign Untracked "Ref.write" boxBoxTo0 . mkForeign $ + declareForeign Untracked "Ref.write" arg2To0 . mkForeign $ \(r :: IORef Val, c :: Val) -> evaluate c >>= writeIORef r - declareForeign Tracked "Ref.readForCas" boxDirect . mkForeign $ + declareForeign Tracked "Ref.readForCas" (argNDirect 1) . mkForeign $ \(r :: IORef Val) -> readForCAS r - declareForeign Tracked "Ref.Ticket.read" boxDirect . mkForeign $ + declareForeign Tracked "Ref.Ticket.read" (argNDirect 1) . mkForeign $ \(t :: Ticket Val) -> pure $ peekTicket t -- In GHC, CAS returns both a Boolean and the current value of the @@ -2716,39 +2430,39 @@ declareForeigns = do -- -- [1]: https://github.com/ghc/ghc/blob/master/rts/PrimOps.cmm#L697 -- [2]: https://github.com/ghc/ghc/blob/master/compiler/GHC/StgToCmm/Prim.hs#L285 - declareForeign Tracked "Ref.cas" boxBoxBoxToBool . mkForeign $ + declareForeign Tracked "Ref.cas" (argNToBool 3) . mkForeign $ \(r :: IORef Val, t :: Ticket Val, v :: Val) -> fmap fst $ do t <- evaluate t casIORef r t v - declareForeign Tracked "Promise.new" unitDirect . mkForeign $ + declareForeign Tracked "Promise.new" (argNDirect 1) . mkForeign $ \() -> newPromise @Val -- the only exceptions from Promise.read are async and shouldn't be caught - declareForeign Tracked "Promise.read" boxDirect . mkForeign $ + declareForeign Tracked "Promise.read" (argNDirect 1) . mkForeign $ \(p :: Promise Val) -> readPromise p - declareForeign Tracked "Promise.tryRead" boxToMaybeBox . mkForeign $ + declareForeign Tracked "Promise.tryRead" argToMaybe . mkForeign $ \(p :: Promise Val) -> tryReadPromise p - declareForeign Tracked "Promise.write" boxBoxToBool . mkForeign $ + declareForeign Tracked "Promise.write" (argNToBool 2) . mkForeign $ \(p :: Promise Val, a :: Val) -> writePromise p a - declareForeign Tracked "Tls.newClient.impl.v3" boxBoxToEFBox . mkForeignTls $ + declareForeign Tracked "Tls.newClient.impl.v3" arg2ToEF . mkForeignTls $ \( config :: TLS.ClientParams, socket :: SYS.Socket ) -> TLS.contextNew socket config - declareForeign Tracked "Tls.newServer.impl.v3" boxBoxToEFBox . mkForeignTls $ + declareForeign Tracked "Tls.newServer.impl.v3" arg2ToEF . mkForeignTls $ \( config :: TLS.ServerParams, socket :: SYS.Socket ) -> TLS.contextNew socket config - declareForeign Tracked "Tls.handshake.impl.v3" boxToEF0 . mkForeignTls $ + declareForeign Tracked "Tls.handshake.impl.v3" argToEF0 . mkForeignTls $ \(tls :: TLS.Context) -> TLS.handshake tls - declareForeign Tracked "Tls.send.impl.v3" boxBoxToEF0 . mkForeignTls $ + declareForeign Tracked "Tls.send.impl.v3" arg2ToEF0 . mkForeignTls $ \( tls :: TLS.Context, bytes :: Bytes.Bytes ) -> TLS.sendData tls (Bytes.toLazyByteString bytes) @@ -2761,53 +2475,53 @@ declareForeigns = do Left l -> Left l asCert :: PEM -> Either String X.SignedCertificate asCert pem = X.decodeSignedCertificate $ pemContent pem - in declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeignTlsE $ + in declareForeign Tracked "Tls.decodeCert.impl.v3" argToEF . mkForeignTlsE $ \(bytes :: Bytes.Bytes) -> pure $ mapLeft wrapFailure $ (decoded >=> asCert) bytes - declareForeign Tracked "Tls.encodeCert" boxDirect . mkForeign $ + declareForeign Tracked "Tls.encodeCert" (argNDirect 1) . mkForeign $ \(cert :: X.SignedCertificate) -> pure $ Bytes.fromArray $ X.encodeSignedObject cert - declareForeign Tracked "Tls.decodePrivateKey" boxDirect . mkForeign $ + declareForeign Tracked "Tls.decodePrivateKey" (argNDirect 1) . mkForeign $ \(bytes :: Bytes.Bytes) -> pure $ X.readKeyFileFromMemory $ L.toStrict $ Bytes.toLazyByteString bytes - declareForeign Tracked "Tls.encodePrivateKey" boxDirect . mkForeign $ + declareForeign Tracked "Tls.encodePrivateKey" (argNDirect 1) . mkForeign $ \(privateKey :: X.PrivKey) -> pure $ Util.Text.toUtf8 $ Util.Text.pack $ show privateKey - declareForeign Tracked "Tls.receive.impl.v3" boxToEFBox . mkForeignTls $ + declareForeign Tracked "Tls.receive.impl.v3" argToEF . mkForeignTls $ \(tls :: TLS.Context) -> do bs <- TLS.recvData tls pure $ Bytes.fromArray bs - declareForeign Tracked "Tls.terminate.impl.v3" boxToEF0 . mkForeignTls $ + declareForeign Tracked "Tls.terminate.impl.v3" argToEF0 . mkForeignTls $ \(tls :: TLS.Context) -> TLS.bye tls - declareForeign Untracked "Code.validateLinks" boxToExnEBoxBox + declareForeign Untracked "Code.validateLinks" argToExnE . mkForeign $ \(lsgs0 :: [(Referent, Code)]) -> do let f (msg, rs) = Failure Ty.miscFailureRef (Util.Text.fromText msg) rs pure . first f $ checkGroupHashes lsgs0 - declareForeign Untracked "Code.dependencies" boxDirect + declareForeign Untracked "Code.dependencies" (argNDirect 1) . mkForeign $ \(CodeRep sg _) -> pure $ Wrap Ty.termLinkRef . Ref <$> groupTermLinks sg - declareForeign Untracked "Code.serialize" boxDirect + declareForeign Untracked "Code.serialize" (argNDirect 1) . mkForeign $ \(co :: Code) -> pure . Bytes.fromArray $ serializeCode builtinForeignNames co - declareForeign Untracked "Code.deserialize" boxToEBoxBox + declareForeign Untracked "Code.deserialize" argToEither . mkForeign $ pure . deserializeCode . Bytes.toArray - declareForeign Untracked "Code.display" boxBoxDirect . mkForeign $ + declareForeign Untracked "Code.display" (argNDirect 2) . mkForeign $ \(nm, (CodeRep sg _)) -> pure $ prettyGroup @Symbol (Util.Text.unpack nm) sg "" - declareForeign Untracked "Value.dependencies" boxDirect + declareForeign Untracked "Value.dependencies" (argNDirect 1) . mkForeign $ pure . fmap (Wrap Ty.termLinkRef . Ref) . valueTermLinks - declareForeign Untracked "Value.serialize" boxDirect + declareForeign Untracked "Value.serialize" (argNDirect 1) . mkForeign $ pure . Bytes.fromArray . serializeValue - declareForeign Untracked "Value.deserialize" boxToEBoxBox + declareForeign Untracked "Value.deserialize" argToEither . mkForeign $ pure . deserializeValue . Bytes.toArray -- Hashing functions @@ -2827,12 +2541,12 @@ declareForeigns = do declareHashAlgorithm "Blake2s_256" Hash.Blake2s_256 declareHashAlgorithm "Md5" Hash.MD5 - declareForeign Untracked "crypto.hashBytes" boxBoxDirect . mkForeign $ + declareForeign Untracked "crypto.hashBytes" (argNDirect 2) . mkForeign $ \(HashAlgorithm _ alg, b :: Bytes.Bytes) -> let ctx = Hash.hashInitWith alg in pure . Bytes.fromArray . Hash.hashFinalize $ Hash.hashUpdates ctx (Bytes.byteStringChunks b) - declareForeign Untracked "crypto.hmacBytes" boxBoxBoxDirect + declareForeign Untracked "crypto.hmacBytes" (argNDirect 3) . mkForeign $ \(HashAlgorithm _ alg, key :: Bytes.Bytes, msg :: Bytes.Bytes) -> let out = u alg $ HMAC.hmac (Bytes.toArray @BA.Bytes key) (Bytes.toArray @BA.Bytes msg) @@ -2861,19 +2575,19 @@ declareForeigns = do $ L.toChunks s in pure . Bytes.fromArray . hmac alg $ serializeValueForHash x - declareForeign Untracked "crypto.Ed25519.sign.impl" boxBoxBoxToEFBox + declareForeign Untracked "crypto.Ed25519.sign.impl" arg3ToEF . mkForeign $ pure . signEd25519Wrapper - declareForeign Untracked "crypto.Ed25519.verify.impl" boxBoxBoxToEFBool + declareForeign Untracked "crypto.Ed25519.verify.impl" arg3ToEFBool . mkForeign $ pure . verifyEd25519Wrapper - declareForeign Untracked "crypto.Rsa.sign.impl" boxBoxToEFBox + declareForeign Untracked "crypto.Rsa.sign.impl" arg2ToEF . mkForeign $ pure . signRsaWrapper - declareForeign Untracked "crypto.Rsa.verify.impl" boxBoxBoxToEFBool + declareForeign Untracked "crypto.Rsa.verify.impl" arg3ToEFBool . mkForeign $ pure . verifyRsaWrapper @@ -2887,45 +2601,45 @@ declareForeigns = do declareForeign Untracked "Universal.murmurHash" murmur'hash . mkForeign $ pure . asWord64 . hash64 . serializeValueForHash - declareForeign Tracked "IO.randomBytes" natToBox . mkForeign $ + declareForeign Tracked "IO.randomBytes" (argNDirect 1) . mkForeign $ \n -> Bytes.fromArray <$> getRandomBytes @IO @ByteString n - declareForeign Untracked "Bytes.zlib.compress" boxDirect . mkForeign $ pure . Bytes.zlibCompress - declareForeign Untracked "Bytes.gzip.compress" boxDirect . mkForeign $ pure . Bytes.gzipCompress - declareForeign Untracked "Bytes.zlib.decompress" boxToEBoxBox . mkForeign $ \bs -> + declareForeign Untracked "Bytes.zlib.compress" (argNDirect 1) . mkForeign $ pure . Bytes.zlibCompress + declareForeign Untracked "Bytes.gzip.compress" (argNDirect 1) . mkForeign $ pure . Bytes.gzipCompress + declareForeign Untracked "Bytes.zlib.decompress" argToEither . mkForeign $ \bs -> catchAll (pure (Bytes.zlibDecompress bs)) - declareForeign Untracked "Bytes.gzip.decompress" boxToEBoxBox . mkForeign $ \bs -> + declareForeign Untracked "Bytes.gzip.decompress" argToEither . mkForeign $ \bs -> catchAll (pure (Bytes.gzipDecompress bs)) - declareForeign Untracked "Bytes.toBase16" boxDirect . mkForeign $ pure . Bytes.toBase16 - declareForeign Untracked "Bytes.toBase32" boxDirect . mkForeign $ pure . Bytes.toBase32 - declareForeign Untracked "Bytes.toBase64" boxDirect . mkForeign $ pure . Bytes.toBase64 - declareForeign Untracked "Bytes.toBase64UrlUnpadded" boxDirect . mkForeign $ pure . Bytes.toBase64UrlUnpadded + declareForeign Untracked "Bytes.toBase16" (argNDirect 1) . mkForeign $ pure . Bytes.toBase16 + declareForeign Untracked "Bytes.toBase32" (argNDirect 1) . mkForeign $ pure . Bytes.toBase32 + declareForeign Untracked "Bytes.toBase64" (argNDirect 1) . mkForeign $ pure . Bytes.toBase64 + declareForeign Untracked "Bytes.toBase64UrlUnpadded" (argNDirect 1) . mkForeign $ pure . Bytes.toBase64UrlUnpadded - declareForeign Untracked "Bytes.fromBase16" boxToEBoxBox . mkForeign $ + declareForeign Untracked "Bytes.fromBase16" argToEither . mkForeign $ pure . mapLeft Util.Text.fromText . Bytes.fromBase16 - declareForeign Untracked "Bytes.fromBase32" boxToEBoxBox . mkForeign $ + declareForeign Untracked "Bytes.fromBase32" argToEither . mkForeign $ pure . mapLeft Util.Text.fromText . Bytes.fromBase32 - declareForeign Untracked "Bytes.fromBase64" boxToEBoxBox . mkForeign $ + declareForeign Untracked "Bytes.fromBase64" argToEither . mkForeign $ pure . mapLeft Util.Text.fromText . Bytes.fromBase64 - declareForeign Untracked "Bytes.fromBase64UrlUnpadded" boxToEBoxBox . mkForeign $ + declareForeign Untracked "Bytes.fromBase64UrlUnpadded" argToEither . mkForeign $ pure . mapLeft Util.Text.fromText . Bytes.fromBase64UrlUnpadded - declareForeign Untracked "Bytes.decodeNat64be" boxToMaybeNTup . mkForeign $ pure . Bytes.decodeNat64be - declareForeign Untracked "Bytes.decodeNat64le" boxToMaybeNTup . mkForeign $ pure . Bytes.decodeNat64le - declareForeign Untracked "Bytes.decodeNat32be" boxToMaybeNTup . mkForeign $ pure . Bytes.decodeNat32be - declareForeign Untracked "Bytes.decodeNat32le" boxToMaybeNTup . mkForeign $ pure . Bytes.decodeNat32le - declareForeign Untracked "Bytes.decodeNat16be" boxToMaybeNTup . mkForeign $ pure . Bytes.decodeNat16be - declareForeign Untracked "Bytes.decodeNat16le" boxToMaybeNTup . mkForeign $ pure . Bytes.decodeNat16le - - declareForeign Untracked "Bytes.encodeNat64be" (wordDirect Ty.natRef) . mkForeign $ pure . Bytes.encodeNat64be - declareForeign Untracked "Bytes.encodeNat64le" (wordDirect Ty.natRef) . mkForeign $ pure . Bytes.encodeNat64le - declareForeign Untracked "Bytes.encodeNat32be" (wordDirect Ty.natRef) . mkForeign $ pure . Bytes.encodeNat32be - declareForeign Untracked "Bytes.encodeNat32le" (wordDirect Ty.natRef) . mkForeign $ pure . Bytes.encodeNat32le - declareForeign Untracked "Bytes.encodeNat16be" (wordDirect Ty.natRef) . mkForeign $ pure . Bytes.encodeNat16be - declareForeign Untracked "Bytes.encodeNat16le" (wordDirect Ty.natRef) . mkForeign $ pure . Bytes.encodeNat16le - - declareForeign Untracked "MutableArray.copyTo!" boxNatBoxNatNatToExnUnit + declareForeign Untracked "Bytes.decodeNat64be" argToMaybeNTup . mkForeign $ pure . Bytes.decodeNat64be + declareForeign Untracked "Bytes.decodeNat64le" argToMaybeNTup . mkForeign $ pure . Bytes.decodeNat64le + declareForeign Untracked "Bytes.decodeNat32be" argToMaybeNTup . mkForeign $ pure . Bytes.decodeNat32be + declareForeign Untracked "Bytes.decodeNat32le" argToMaybeNTup . mkForeign $ pure . Bytes.decodeNat32le + declareForeign Untracked "Bytes.decodeNat16be" argToMaybeNTup . mkForeign $ pure . Bytes.decodeNat16be + declareForeign Untracked "Bytes.decodeNat16le" argToMaybeNTup . mkForeign $ pure . Bytes.decodeNat16le + + declareForeign Untracked "Bytes.encodeNat64be" (argNDirect 1) . mkForeign $ pure . Bytes.encodeNat64be + declareForeign Untracked "Bytes.encodeNat64le" (argNDirect 1) . mkForeign $ pure . Bytes.encodeNat64le + declareForeign Untracked "Bytes.encodeNat32be" (argNDirect 1) . mkForeign $ pure . Bytes.encodeNat32be + declareForeign Untracked "Bytes.encodeNat32le" (argNDirect 1) . mkForeign $ pure . Bytes.encodeNat32le + declareForeign Untracked "Bytes.encodeNat16be" (argNDirect 1) . mkForeign $ pure . Bytes.encodeNat16be + declareForeign Untracked "Bytes.encodeNat16le" (argNDirect 1) . mkForeign $ pure . Bytes.encodeNat16le + + declareForeign Untracked "MutableArray.copyTo!" arg5ToExnUnit . mkForeign $ \(dst, doff, src, soff, l) -> let name = "MutableArray.copyTo!" @@ -2942,7 +2656,7 @@ declareForeigns = do (fromIntegral soff) (fromIntegral l) - declareForeign Untracked "MutableByteArray.copyTo!" boxNatBoxNatNatToExnUnit + declareForeign Untracked "MutableByteArray.copyTo!" arg5ToExnUnit . mkForeign $ \(dst, doff, src, soff, l) -> let name = "MutableByteArray.copyTo!" @@ -2959,7 +2673,7 @@ declareForeigns = do (fromIntegral soff) (fromIntegral l) - declareForeign Untracked "ImmutableArray.copyTo!" boxNatBoxNatNatToExnUnit + declareForeign Untracked "ImmutableArray.copyTo!" arg5ToExnUnit . mkForeign $ \(dst, doff, src, soff, l) -> let name = "ImmutableArray.copyTo!" @@ -2976,16 +2690,16 @@ declareForeigns = do (fromIntegral soff) (fromIntegral l) - declareForeign Untracked "ImmutableArray.size" boxToNat . mkForeign $ + declareForeign Untracked "ImmutableArray.size" (argNDirect 1) . mkForeign $ pure . fromIntegral @Int @Word64 . PA.sizeofArray @Val - declareForeign Untracked "MutableArray.size" boxToNat . mkForeign $ + declareForeign Untracked "MutableArray.size" (argNDirect 1) . mkForeign $ pure . fromIntegral @Int @Word64 . PA.sizeofMutableArray @PA.RealWorld @Val - declareForeign Untracked "ImmutableByteArray.size" boxToNat . mkForeign $ + declareForeign Untracked "ImmutableByteArray.size" (argNDirect 1) . mkForeign $ pure . fromIntegral @Int @Word64 . PA.sizeofByteArray - declareForeign Untracked "MutableByteArray.size" boxToNat . mkForeign $ + declareForeign Untracked "MutableByteArray.size" (argNDirect 1) . mkForeign $ pure . fromIntegral @Int @Word64 . PA.sizeofMutableByteArray @PA.RealWorld - declareForeign Untracked "ImmutableByteArray.copyTo!" boxNatBoxNatNatToExnUnit + declareForeign Untracked "ImmutableByteArray.copyTo!" arg5ToExnUnit . mkForeign $ \(dst, doff, src, soff, l) -> let name = "ImmutableByteArray.copyTo!" @@ -3002,72 +2716,72 @@ declareForeigns = do (fromIntegral soff) (fromIntegral l) - declareForeign Untracked "MutableArray.read" boxNatToExnBox + declareForeign Untracked "MutableArray.read" arg2ToExn . mkForeign $ checkedRead "MutableArray.read" - declareForeign Untracked "MutableByteArray.read8" boxNatToExnNat + declareForeign Untracked "MutableByteArray.read8" arg2ToExn . mkForeign $ checkedRead8 "MutableByteArray.read8" - declareForeign Untracked "MutableByteArray.read16be" boxNatToExnNat + declareForeign Untracked "MutableByteArray.read16be" arg2ToExn . mkForeign $ checkedRead16 "MutableByteArray.read16be" - declareForeign Untracked "MutableByteArray.read24be" boxNatToExnNat + declareForeign Untracked "MutableByteArray.read24be" arg2ToExn . mkForeign $ checkedRead24 "MutableByteArray.read24be" - declareForeign Untracked "MutableByteArray.read32be" boxNatToExnNat + declareForeign Untracked "MutableByteArray.read32be" arg2ToExn . mkForeign $ checkedRead32 "MutableByteArray.read32be" - declareForeign Untracked "MutableByteArray.read40be" boxNatToExnNat + declareForeign Untracked "MutableByteArray.read40be" arg2ToExn . mkForeign $ checkedRead40 "MutableByteArray.read40be" - declareForeign Untracked "MutableByteArray.read64be" boxNatToExnNat + declareForeign Untracked "MutableByteArray.read64be" arg2ToExn . mkForeign $ checkedRead64 "MutableByteArray.read64be" - declareForeign Untracked "MutableArray.write" boxNatBoxToExnUnit + declareForeign Untracked "MutableArray.write" arg3ToExnUnit . mkForeign $ checkedWrite "MutableArray.write" - declareForeign Untracked "MutableByteArray.write8" boxNatNatToExnUnit + declareForeign Untracked "MutableByteArray.write8" arg3ToExnUnit . mkForeign $ checkedWrite8 "MutableByteArray.write8" - declareForeign Untracked "MutableByteArray.write16be" boxNatNatToExnUnit + declareForeign Untracked "MutableByteArray.write16be" arg3ToExnUnit . mkForeign $ checkedWrite16 "MutableByteArray.write16be" - declareForeign Untracked "MutableByteArray.write32be" boxNatNatToExnUnit + declareForeign Untracked "MutableByteArray.write32be" arg3ToExnUnit . mkForeign $ checkedWrite32 "MutableByteArray.write32be" - declareForeign Untracked "MutableByteArray.write64be" boxNatNatToExnUnit + declareForeign Untracked "MutableByteArray.write64be" arg3ToExnUnit . mkForeign $ checkedWrite64 "MutableByteArray.write64be" - declareForeign Untracked "ImmutableArray.read" boxNatToExnBox + declareForeign Untracked "ImmutableArray.read" arg2ToExn . mkForeign $ checkedIndex "ImmutableArray.read" - declareForeign Untracked "ImmutableByteArray.read8" boxNatToExnNat + declareForeign Untracked "ImmutableByteArray.read8" arg2ToExn . mkForeign $ checkedIndex8 "ImmutableByteArray.read8" - declareForeign Untracked "ImmutableByteArray.read16be" boxNatToExnNat + declareForeign Untracked "ImmutableByteArray.read16be" arg2ToExn . mkForeign $ checkedIndex16 "ImmutableByteArray.read16be" - declareForeign Untracked "ImmutableByteArray.read24be" boxNatToExnNat + declareForeign Untracked "ImmutableByteArray.read24be" arg2ToExn . mkForeign $ checkedIndex24 "ImmutableByteArray.read24be" - declareForeign Untracked "ImmutableByteArray.read32be" boxNatToExnNat + declareForeign Untracked "ImmutableByteArray.read32be" arg2ToExn . mkForeign $ checkedIndex32 "ImmutableByteArray.read32be" - declareForeign Untracked "ImmutableByteArray.read40be" boxNatToExnNat + declareForeign Untracked "ImmutableByteArray.read40be" arg2ToExn . mkForeign $ checkedIndex40 "ImmutableByteArray.read40be" - declareForeign Untracked "ImmutableByteArray.read64be" boxNatToExnNat + declareForeign Untracked "ImmutableByteArray.read64be" arg2ToExn . mkForeign $ checkedIndex64 "ImmutableByteArray.read64be" - declareForeign Untracked "MutableByteArray.freeze!" boxDirect . mkForeign $ + declareForeign Untracked "MutableByteArray.freeze!" (argNDirect 1) . mkForeign $ PA.unsafeFreezeByteArray - declareForeign Untracked "MutableArray.freeze!" boxDirect . mkForeign $ + declareForeign Untracked "MutableArray.freeze!" (argNDirect 1) . mkForeign $ PA.unsafeFreezeArray @IO @Val - declareForeign Untracked "MutableByteArray.freeze" boxNatNatToExnBox . mkForeign $ + declareForeign Untracked "MutableByteArray.freeze" arg3ToExn . mkForeign $ \(src, off, len) -> if len == 0 then fmap Right . PA.unsafeFreezeByteArray =<< PA.newByteArray 0 @@ -3079,7 +2793,7 @@ declareForeigns = do 0 $ Right <$> PA.freezeByteArray src (fromIntegral off) (fromIntegral len) - declareForeign Untracked "MutableArray.freeze" boxNatNatToExnBox . mkForeign $ + declareForeign Untracked "MutableArray.freeze" arg3ToExn . mkForeign $ \(src :: PA.MutableArray PA.RealWorld Val, off, len) -> if len == 0 then fmap Right . PA.unsafeFreezeArray =<< PA.newArray 0 emptyVal @@ -3090,37 +2804,37 @@ declareForeigns = do (off + len - 1) $ Right <$> PA.freezeArray src (fromIntegral off) (fromIntegral len) - declareForeign Untracked "MutableByteArray.length" boxToNat . mkForeign $ + declareForeign Untracked "MutableByteArray.length" (argNDirect 1) . mkForeign $ pure . PA.sizeofMutableByteArray @PA.RealWorld - declareForeign Untracked "ImmutableByteArray.length" boxToNat . mkForeign $ + declareForeign Untracked "ImmutableByteArray.length" (argNDirect 1) . mkForeign $ pure . PA.sizeofByteArray - declareForeign Tracked "IO.array" natToBox . mkForeign $ + declareForeign Tracked "IO.array" (argNDirect 1) . mkForeign $ \n -> PA.newArray n emptyVal - declareForeign Tracked "IO.arrayOf" boxNatToBox . mkForeign $ + declareForeign Tracked "IO.arrayOf" (argNDirect 2) . mkForeign $ \(v :: Val, n) -> PA.newArray n v - declareForeign Tracked "IO.bytearray" natToBox . mkForeign $ PA.newByteArray - declareForeign Tracked "IO.bytearrayOf" natNatToBox + declareForeign Tracked "IO.bytearray" (argNDirect 1) . mkForeign $ PA.newByteArray + declareForeign Tracked "IO.bytearrayOf" (argNDirect 2) . mkForeign $ \(init, sz) -> do arr <- PA.newByteArray sz PA.fillByteArray arr 0 sz init pure arr - declareForeign Untracked "Scope.array" natToBox . mkForeign $ + declareForeign Untracked "Scope.array" (argNDirect 1) . mkForeign $ \n -> PA.newArray n emptyVal - declareForeign Untracked "Scope.arrayOf" boxNatToBox . mkForeign $ + declareForeign Untracked "Scope.arrayOf" (argNDirect 2) . mkForeign $ \(v :: Val, n) -> PA.newArray n v - declareForeign Untracked "Scope.bytearray" natToBox . mkForeign $ PA.newByteArray - declareForeign Untracked "Scope.bytearrayOf" natNatToBox + declareForeign Untracked "Scope.bytearray" (argNDirect 1) . mkForeign $ PA.newByteArray + declareForeign Untracked "Scope.bytearrayOf" (argNDirect 2) . mkForeign $ \(init, sz) -> do arr <- PA.newByteArray sz PA.fillByteArray arr 0 sz init pure arr - declareForeign Untracked "Text.patterns.literal" boxDirect . mkForeign $ + declareForeign Untracked "Text.patterns.literal" (argNDirect 1) . mkForeign $ \txt -> evaluate . TPat.cpattern $ TPat.Literal txt declareForeign Untracked "Text.patterns.digit" direct . mkForeign $ let v = TPat.cpattern (TPat.Char (TPat.CharRange '0' '9')) in \() -> pure v @@ -3134,50 +2848,49 @@ declareForeigns = do let v = TPat.cpattern (TPat.Char TPat.Any) in \() -> pure v declareForeign Untracked "Text.patterns.eof" direct . mkForeign $ let v = TPat.cpattern TPat.Eof in \() -> pure v - let ccd = wordWordDirect Ty.charRef Ty.charRef - declareForeign Untracked "Text.patterns.charRange" ccd . mkForeign $ + declareForeign Untracked "Text.patterns.charRange" (argNDirect 2) . mkForeign $ \(beg, end) -> evaluate . TPat.cpattern . TPat.Char $ TPat.CharRange beg end - declareForeign Untracked "Text.patterns.notCharRange" ccd . mkForeign $ + declareForeign Untracked "Text.patterns.notCharRange" (argNDirect 2) . mkForeign $ \(beg, end) -> evaluate . TPat.cpattern . TPat.Char . TPat.Not $ TPat.CharRange beg end - declareForeign Untracked "Text.patterns.charIn" boxDirect . mkForeign $ \ccs -> do + declareForeign Untracked "Text.patterns.charIn" (argNDirect 1) . mkForeign $ \ccs -> do cs <- for ccs $ \case CharVal c -> pure c _ -> die "Text.patterns.charIn: non-character closure" evaluate . TPat.cpattern . TPat.Char $ TPat.CharSet cs - declareForeign Untracked "Text.patterns.notCharIn" boxDirect . mkForeign $ \ccs -> do + declareForeign Untracked "Text.patterns.notCharIn" (argNDirect 1) . mkForeign $ \ccs -> do cs <- for ccs $ \case CharVal c -> pure c _ -> die "Text.patterns.notCharIn: non-character closure" evaluate . TPat.cpattern . TPat.Char . TPat.Not $ TPat.CharSet cs - declareForeign Untracked "Pattern.many" boxDirect . mkForeign $ + declareForeign Untracked "Pattern.many" (argNDirect 1) . mkForeign $ \(TPat.CP p _) -> evaluate . TPat.cpattern $ TPat.Many False p - declareForeign Untracked "Pattern.many.corrected" boxDirect . mkForeign $ + declareForeign Untracked "Pattern.many.corrected" (argNDirect 1) . mkForeign $ \(TPat.CP p _) -> evaluate . TPat.cpattern $ TPat.Many True p - declareForeign Untracked "Pattern.capture" boxDirect . mkForeign $ + declareForeign Untracked "Pattern.capture" (argNDirect 1) . mkForeign $ \(TPat.CP p _) -> evaluate . TPat.cpattern $ TPat.Capture p - declareForeign Untracked "Pattern.captureAs" boxBoxDirect . mkForeign $ + declareForeign Untracked "Pattern.captureAs" (argNDirect 2) . mkForeign $ \(t, (TPat.CP p _)) -> evaluate . TPat.cpattern $ TPat.CaptureAs t p - declareForeign Untracked "Pattern.join" boxDirect . mkForeign $ \ps -> + declareForeign Untracked "Pattern.join" (argNDirect 1) . mkForeign $ \ps -> evaluate . TPat.cpattern . TPat.Join $ map (\(TPat.CP p _) -> p) ps - declareForeign Untracked "Pattern.or" boxBoxDirect . mkForeign $ + declareForeign Untracked "Pattern.or" (argNDirect 2) . mkForeign $ \(TPat.CP l _, TPat.CP r _) -> evaluate . TPat.cpattern $ TPat.Or l r - declareForeign Untracked "Pattern.replicate" natNatBoxToBox . mkForeign $ + declareForeign Untracked "Pattern.replicate" (argNDirect 3) . mkForeign $ \(m0 :: Word64, n0 :: Word64, TPat.CP p _) -> let m = fromIntegral m0; n = fromIntegral n0 in evaluate . TPat.cpattern $ TPat.Replicate m n p - declareForeign Untracked "Pattern.run" boxBoxToMaybeTup . mkForeign $ + declareForeign Untracked "Pattern.run" arg2ToMaybeTup . mkForeign $ \(TPat.CP _ matcher, input :: Text) -> pure $ matcher input - declareForeign Untracked "Pattern.isMatch" boxBoxToBool . mkForeign $ + declareForeign Untracked "Pattern.isMatch" (argNToBool 2) . mkForeign $ \(TPat.CP _ matcher, input :: Text) -> pure . isJust $ matcher input declareForeign Untracked "Char.Class.any" direct . mkForeign $ \() -> pure TPat.Any - declareForeign Untracked "Char.Class.not" boxDirect . mkForeign $ pure . TPat.Not - declareForeign Untracked "Char.Class.and" boxBoxDirect . mkForeign $ \(a, b) -> pure $ TPat.Intersect a b - declareForeign Untracked "Char.Class.or" boxBoxDirect . mkForeign $ \(a, b) -> pure $ TPat.Union a b - declareForeign Untracked "Char.Class.range" (wordWordDirect charRef charRef) . mkForeign $ \(a, b) -> pure $ TPat.CharRange a b - declareForeign Untracked "Char.Class.anyOf" boxDirect . mkForeign $ \ccs -> do + declareForeign Untracked "Char.Class.not" (argNDirect 1) . mkForeign $ pure . TPat.Not + declareForeign Untracked "Char.Class.and" (argNDirect 2) . mkForeign $ \(a, b) -> pure $ TPat.Intersect a b + declareForeign Untracked "Char.Class.or" (argNDirect 2) . mkForeign $ \(a, b) -> pure $ TPat.Union a b + declareForeign Untracked "Char.Class.range" (argNDirect 2) . mkForeign $ \(a, b) -> pure $ TPat.CharRange a b + declareForeign Untracked "Char.Class.anyOf" (argNDirect 1) . mkForeign $ \ccs -> do cs <- for ccs $ \case CharVal c -> pure c _ -> die "Text.patterns.charIn: non-character closure" @@ -3194,8 +2907,8 @@ declareForeigns = do declareForeign Untracked "Char.Class.symbol" direct . mkForeign $ \() -> pure (TPat.CharClass TPat.Symbol) declareForeign Untracked "Char.Class.separator" direct . mkForeign $ \() -> pure (TPat.CharClass TPat.Separator) declareForeign Untracked "Char.Class.letter" direct . mkForeign $ \() -> pure (TPat.CharClass TPat.Letter) - declareForeign Untracked "Char.Class.is" (boxWordToBool charRef) . mkForeign $ \(cl, c) -> evaluate $ TPat.charPatternPred cl c - declareForeign Untracked "Text.patterns.char" boxDirect . mkForeign $ \c -> + declareForeign Untracked "Char.Class.is" (argNToBool 2) . mkForeign $ \(cl, c) -> evaluate $ TPat.charPatternPred cl c + declareForeign Untracked "Text.patterns.char" (argNDirect 1) . mkForeign $ \c -> let v = TPat.cpattern (TPat.Char c) in pure v type RW = PA.PrimState IO From 2ed0ec62b4bd3cb3937cdbb9816be869f9fb031e Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 22:18:05 -0700 Subject: [PATCH 050/113] Remove unnecessary type references on primops --- unison-runtime/src/Unison/Runtime/Builtin.hs | 195 +++++++++---------- 1 file changed, 93 insertions(+), 102 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index aac6b369ee..030111c76d 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -321,114 +321,105 @@ binop0 n f = where xs@(x0 : y0 : _) = freshes (2 + n) -unop :: (Var v) => POp -> Reference -> SuperNormal v -unop pop rf = unop' pop rf rf - -unop' :: (Var v) => POp -> Reference -> Reference -> SuperNormal v -unop' pop _rfi _rfo = +unop :: (Var v) => POp -> SuperNormal v +unop pop = unop0 0 $ \[x] -> (TPrm pop [x]) -binop :: (Var v) => POp -> Reference -> SuperNormal v -binop pop rf = binop' pop rf rf rf - -binop' :: +binop :: (Var v) => POp -> - Reference -> - Reference -> - Reference -> SuperNormal v -binop' pop _rfx _rfy _rfr = +binop pop = binop0 0 $ \[x, y] -> TPrm pop [x, y] -- | Lift a comparison op. -cmpop :: (Var v) => POp -> Reference -> SuperNormal v -cmpop pop _rf = +cmpop :: (Var v) => POp -> SuperNormal v +cmpop pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [x, y]) $ boolift b -- | Like `cmpop`, but swaps the arguments. -cmpopb :: (Var v) => POp -> Reference -> SuperNormal v -cmpopb pop _rf = +cmpopb :: (Var v) => POp -> SuperNormal v +cmpopb pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [y, x]) $ boolift b -- | Like `cmpop`, but negates the result. -cmpopn :: (Var v) => POp -> Reference -> SuperNormal v -cmpopn pop _rf = +cmpopn :: (Var v) => POp -> SuperNormal v +cmpopn pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [x, y]) $ notlift b -- | Like `cmpop`, but swaps arguments then negates the result. -cmpopbn :: (Var v) => POp -> Reference -> SuperNormal v -cmpopbn pop _rf = +cmpopbn :: (Var v) => POp -> SuperNormal v +cmpopbn pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [y, x]) $ notlift b addi, subi, muli, divi, modi, shli, shri, powi :: (Var v) => SuperNormal v -addi = binop ADDI Ty.intRef -subi = binop SUBI Ty.intRef -muli = binop MULI Ty.intRef -divi = binop DIVI Ty.intRef -modi = binop MODI Ty.intRef -shli = binop' SHLI Ty.intRef Ty.natRef Ty.intRef -shri = binop' SHRI Ty.intRef Ty.natRef Ty.intRef -powi = binop' POWI Ty.intRef Ty.natRef Ty.intRef +addi = binop ADDI +subi = binop SUBI +muli = binop MULI +divi = binop DIVI +modi = binop MODI +shli = binop SHLI +shri = binop SHRI +powi = binop POWI addn, subn, muln, divn, modn, shln, shrn, pown :: (Var v) => SuperNormal v -addn = binop ADDN Ty.natRef -subn = binop' SUBN Ty.natRef Ty.natRef Ty.intRef -muln = binop MULN Ty.natRef -divn = binop DIVN Ty.natRef -modn = binop MODN Ty.natRef -shln = binop SHLN Ty.natRef -shrn = binop SHRN Ty.natRef -pown = binop POWN Ty.natRef +addn = binop ADDN +subn = binop SUBN +muln = binop MULN +divn = binop DIVN +modn = binop MODN +shln = binop SHLN +shrn = binop SHRN +pown = binop POWN eqi, eqn, lti, ltn, lei, len :: (Var v) => SuperNormal v -eqi = cmpop EQLI Ty.intRef -lti = cmpopbn LEQI Ty.intRef -lei = cmpop LEQI Ty.intRef -eqn = cmpop EQLN Ty.natRef -ltn = cmpopbn LEQN Ty.natRef -len = cmpop LEQN Ty.natRef +eqi = cmpop EQLI +lti = cmpopbn LEQI +lei = cmpop LEQI +eqn = cmpop EQLN +ltn = cmpopbn LEQN +len = cmpop LEQN gti, gtn, gei, gen :: (Var v) => SuperNormal v -gti = cmpopn LEQI Ty.intRef -gei = cmpopb LEQI Ty.intRef -gtn = cmpopn LEQN Ty.intRef -gen = cmpopb LEQN Ty.intRef +gti = cmpopn LEQI +gei = cmpopb LEQI +gtn = cmpopn LEQN +gen = cmpopb LEQN inci, incn :: (Var v) => SuperNormal v -inci = unop INCI Ty.intRef -incn = unop INCN Ty.natRef +inci = unop INCI +incn = unop INCN sgni, negi :: (Var v) => SuperNormal v -sgni = unop SGNI Ty.intRef -negi = unop NEGI Ty.intRef +sgni = unop SGNI +negi = unop NEGI lzeron, tzeron, lzeroi, tzeroi, popn, popi :: (Var v) => SuperNormal v -lzeron = unop LZRO Ty.natRef -tzeron = unop TZRO Ty.natRef -popn = unop POPC Ty.natRef -popi = unop' POPC Ty.intRef Ty.natRef -lzeroi = unop' LZRO Ty.intRef Ty.natRef -tzeroi = unop' TZRO Ty.intRef Ty.natRef +lzeron = unop LZRO +tzeron = unop TZRO +popn = unop POPC +popi = unop POPC +lzeroi = unop LZRO +tzeroi = unop TZRO andn, orn, xorn, compln, andi, ori, xori, compli :: (Var v) => SuperNormal v -andn = binop ANDN Ty.natRef -orn = binop IORN Ty.natRef -xorn = binop XORN Ty.natRef -compln = unop COMN Ty.natRef -andi = binop ANDN Ty.intRef -ori = binop IORN Ty.intRef -xori = binop XORN Ty.intRef -compli = unop COMN Ty.intRef +andn = binop ANDN +orn = binop IORN +xorn = binop XORN +compln = unop COMN +andi = binop ANDN +ori = binop IORN +xori = binop XORN +compli = unop COMN addf, subf, @@ -439,26 +430,26 @@ addf, logf, logbf :: (Var v) => SuperNormal v -addf = binop ADDF Ty.floatRef -subf = binop SUBF Ty.floatRef -mulf = binop MULF Ty.floatRef -divf = binop DIVF Ty.floatRef -powf = binop POWF Ty.floatRef -sqrtf = unop SQRT Ty.floatRef -logf = unop LOGF Ty.floatRef -logbf = binop LOGB Ty.floatRef +addf = binop ADDF +subf = binop SUBF +mulf = binop MULF +divf = binop DIVF +powf = binop POWF +sqrtf = unop SQRT +logf = unop LOGF +logbf = binop LOGB expf, absf :: (Var v) => SuperNormal v -expf = unop EXPF Ty.floatRef -absf = unop ABSF Ty.floatRef +expf = unop EXPF +absf = unop ABSF cosf, sinf, tanf, acosf, asinf, atanf :: (Var v) => SuperNormal v -cosf = unop COSF Ty.floatRef -sinf = unop SINF Ty.floatRef -tanf = unop TANF Ty.floatRef -acosf = unop ACOS Ty.floatRef -asinf = unop ASIN Ty.floatRef -atanf = unop ATAN Ty.floatRef +cosf = unop COSF +sinf = unop SINF +tanf = unop TANF +acosf = unop ACOS +asinf = unop ASIN +atanf = unop ATAN coshf, sinhf, @@ -468,33 +459,33 @@ coshf, atanhf, atan2f :: (Var v) => SuperNormal v -coshf = unop COSH Ty.floatRef -sinhf = unop SINH Ty.floatRef -tanhf = unop TANH Ty.floatRef -acoshf = unop ACSH Ty.floatRef -asinhf = unop ASNH Ty.floatRef -atanhf = unop ATNH Ty.floatRef -atan2f = binop ATN2 Ty.floatRef +coshf = unop COSH +sinhf = unop SINH +tanhf = unop TANH +acoshf = unop ACSH +asinhf = unop ASNH +atanhf = unop ATNH +atan2f = binop ATN2 ltf, gtf, lef, gef, eqf, neqf :: (Var v) => SuperNormal v -ltf = cmpopbn LEQF Ty.floatRef -gtf = cmpopn LEQF Ty.floatRef -lef = cmpop LEQF Ty.floatRef -gef = cmpopb LEQF Ty.floatRef -eqf = cmpop EQLF Ty.floatRef -neqf = cmpopn EQLF Ty.floatRef +ltf = cmpopbn LEQF +gtf = cmpopn LEQF +lef = cmpop LEQF +gef = cmpopb LEQF +eqf = cmpop EQLF +neqf = cmpopn EQLF minf, maxf :: (Var v) => SuperNormal v -minf = binop MINF Ty.floatRef -maxf = binop MAXF Ty.floatRef +minf = binop MINF +maxf = binop MAXF ceilf, floorf, truncf, roundf, i2f, n2f :: (Var v) => SuperNormal v -ceilf = unop' CEIL Ty.floatRef Ty.intRef -floorf = unop' FLOR Ty.floatRef Ty.intRef -truncf = unop' TRNF Ty.floatRef Ty.intRef -roundf = unop' RNDF Ty.floatRef Ty.intRef -i2f = unop' ITOF Ty.intRef Ty.floatRef -n2f = unop' NTOF Ty.natRef Ty.floatRef +ceilf = unop CEIL +floorf = unop FLOR +truncf = unop TRNF +roundf = unop RNDF +i2f = unop ITOF +n2f = unop NTOF trni :: (Var v) => SuperNormal v trni = unop0 2 $ \[x, z, b] -> From 25a67b72f636c5ac049a36a37fbce122387c3a7e Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 21:43:05 -0700 Subject: [PATCH 051/113] Rerun transcripts --- unison-src/transcripts/fix2693.output.md | 7996 +++++++++++----------- unison-src/transcripts/io.output.md | 549 +- 2 files changed, 4009 insertions(+), 4536 deletions(-) diff --git a/unison-src/transcripts/fix2693.output.md b/unison-src/transcripts/fix2693.output.md index e5414c32a8..454a449fe7 100644 --- a/unison-src/transcripts/fix2693.output.md +++ b/unison-src/transcripts/fix2693.output.md @@ -48,2005 +48,2005 @@ scratch/main> add 1 | > range 2000 ⧩ - [ 1 - , 2 - , 3 - , 4 - , 5 - , 6 - , 7 - , 8 - , 9 - , 10 - , 11 - , 12 - , 13 - , 14 - , 15 - , 16 - , 17 - , 18 - , 19 - , 20 - , 21 - , 22 - , 23 - , 24 - , 25 - , 26 - , 27 - , 28 - , 29 - , 30 - , 31 - , 32 - , 33 - , 34 - , 35 - , 36 - , 37 - , 38 - , 39 - , 40 - , 41 - , 42 - , 43 - , 44 - , 45 - , 46 - , 47 - , 48 - , 49 - , 50 - , 51 - , 52 - , 53 - , 54 - , 55 - , 56 - , 57 - , 58 - , 59 - , 60 - , 61 - , 62 - , 63 - , 64 - , 65 - , 66 - , 67 - , 68 - , 69 - , 70 - , 71 - , 72 - , 73 - , 74 - , 75 - , 76 - , 77 - , 78 - , 79 - , 80 - , 81 - , 82 - , 83 - , 84 - , 85 - , 86 - , 87 - , 88 - , 89 - , 90 - , 91 - , 92 - , 93 - , 94 - , 95 - , 96 - , 97 - , 98 - , 99 - , 100 - , 101 - , 102 - , 103 - , 104 - , 105 - , 106 - , 107 - , 108 - , 109 - , 110 - , 111 - , 112 - , 113 - , 114 - , 115 - , 116 - , 117 - , 118 - , 119 - , 120 - , 121 - , 122 - , 123 - , 124 - , 125 - , 126 - , 127 - , 128 - , 129 - , 130 - , 131 - , 132 - , 133 - , 134 - , 135 - , 136 - , 137 - , 138 - , 139 - , 140 - , 141 - , 142 - , 143 - , 144 - , 145 - , 146 - , 147 - , 148 - , 149 - , 150 - , 151 - , 152 - , 153 - , 154 - , 155 - , 156 - , 157 - , 158 - , 159 - , 160 - , 161 - , 162 - , 163 - , 164 - , 165 - , 166 - , 167 - , 168 - , 169 - , 170 - , 171 - , 172 - , 173 - , 174 - , 175 - , 176 - , 177 - , 178 - , 179 - , 180 - , 181 - , 182 - , 183 - , 184 - , 185 - , 186 - , 187 - , 188 - , 189 - , 190 - , 191 - , 192 - , 193 - , 194 - , 195 - , 196 - , 197 - , 198 - , 199 - , 200 - , 201 - , 202 - , 203 - , 204 - , 205 - , 206 - , 207 - , 208 - , 209 - , 210 - , 211 - , 212 - , 213 - , 214 - , 215 - , 216 - , 217 - , 218 - , 219 - , 220 - , 221 - , 222 - , 223 - , 224 - , 225 - , 226 - , 227 - , 228 - , 229 - , 230 - , 231 - , 232 - , 233 - , 234 - , 235 - , 236 - , 237 - , 238 - , 239 - , 240 - , 241 - , 242 - , 243 - , 244 - , 245 - , 246 - , 247 - , 248 - , 249 - , 250 - , 251 - , 252 - , 253 - , 254 - , 255 - , 256 - , 257 - , 258 - , 259 - , 260 - , 261 - , 262 - , 263 - , 264 - , 265 - , 266 - , 267 - , 268 - , 269 - , 270 - , 271 - , 272 - , 273 - , 274 - , 275 - , 276 - , 277 - , 278 - , 279 - , 280 - , 281 - , 282 - , 283 - , 284 - , 285 - , 286 - , 287 - , 288 - , 289 - , 290 - , 291 - , 292 - , 293 - , 294 - , 295 - , 296 - , 297 - , 298 - , 299 - , 300 - , 301 - , 302 - , 303 - , 304 - , 305 - , 306 - , 307 - , 308 - , 309 - , 310 - , 311 - , 312 - , 313 - , 314 - , 315 - , 316 - , 317 - , 318 - , 319 - , 320 - , 321 - , 322 - , 323 - , 324 - , 325 - , 326 - , 327 - , 328 - , 329 - , 330 - , 331 - , 332 - , 333 - , 334 - , 335 - , 336 - , 337 - , 338 - , 339 - , 340 - , 341 - , 342 - , 343 - , 344 - , 345 - , 346 - , 347 - , 348 - , 349 - , 350 - , 351 - , 352 - , 353 - , 354 - , 355 - , 356 - , 357 - , 358 - , 359 - , 360 - , 361 - , 362 - , 363 - , 364 - , 365 - , 366 - , 367 - , 368 - , 369 - , 370 - , 371 - , 372 - , 373 - , 374 - , 375 - , 376 - , 377 - , 378 - , 379 - , 380 - , 381 - , 382 - , 383 - , 384 - , 385 - , 386 - , 387 - , 388 - , 389 - , 390 - , 391 - , 392 - , 393 - , 394 - , 395 - , 396 - , 397 - , 398 - , 399 - , 400 - , 401 - , 402 - , 403 - , 404 - , 405 - , 406 - , 407 - , 408 - , 409 - , 410 - , 411 - , 412 - , 413 - , 414 - , 415 - , 416 - , 417 - , 418 - , 419 - , 420 - , 421 - , 422 - , 423 - , 424 - , 425 - , 426 - , 427 - , 428 - , 429 - , 430 - , 431 - , 432 - , 433 - , 434 - , 435 - , 436 - , 437 - , 438 - , 439 - , 440 - , 441 - , 442 - , 443 - , 444 - , 445 - , 446 - , 447 - , 448 - , 449 - , 450 - , 451 - , 452 - , 453 - , 454 - , 455 - , 456 - , 457 - , 458 - , 459 - , 460 - , 461 - , 462 - , 463 - , 464 - , 465 - , 466 - , 467 - , 468 - , 469 - , 470 - , 471 - , 472 - , 473 - , 474 - , 475 - , 476 - , 477 - , 478 - , 479 - , 480 - , 481 - , 482 - , 483 - , 484 - , 485 - , 486 - , 487 - , 488 - , 489 - , 490 - , 491 - , 492 - , 493 - , 494 - , 495 - , 496 - , 497 - , 498 - , 499 - , 500 - , 501 - , 502 - , 503 - , 504 - , 505 - , 506 - , 507 - , 508 - , 509 - , 510 - , 511 - , 512 - , 513 - , 514 - , 515 - , 516 - , 517 - , 518 - , 519 - , 520 - , 521 - , 522 - , 523 - , 524 - , 525 - , 526 - , 527 - , 528 - , 529 - , 530 - , 531 - , 532 - , 533 - , 534 - , 535 - , 536 - , 537 - , 538 - , 539 - , 540 - , 541 - , 542 - , 543 - , 544 - , 545 - , 546 - , 547 - , 548 - , 549 - , 550 - , 551 - , 552 - , 553 - , 554 - , 555 - , 556 - , 557 - , 558 - , 559 - , 560 - , 561 - , 562 - , 563 - , 564 - , 565 - , 566 - , 567 - , 568 - , 569 - , 570 - , 571 - , 572 - , 573 - , 574 - , 575 - , 576 - , 577 - , 578 - , 579 - , 580 - , 581 - , 582 - , 583 - , 584 - , 585 - , 586 - , 587 - , 588 - , 589 - , 590 - , 591 - , 592 - , 593 - , 594 - , 595 - , 596 - , 597 - , 598 - , 599 - , 600 - , 601 - , 602 - , 603 - , 604 - , 605 - , 606 - , 607 - , 608 - , 609 - , 610 - , 611 - , 612 - , 613 - , 614 - , 615 - , 616 - , 617 - , 618 - , 619 - , 620 - , 621 - , 622 - , 623 - , 624 - , 625 - , 626 - , 627 - , 628 - , 629 - , 630 - , 631 - , 632 - , 633 - , 634 - , 635 - , 636 - , 637 - , 638 - , 639 - , 640 - , 641 - , 642 - , 643 - , 644 - , 645 - , 646 - , 647 - , 648 - , 649 - , 650 - , 651 - , 652 - , 653 - , 654 - , 655 - , 656 - , 657 - , 658 - , 659 - , 660 - , 661 - , 662 - , 663 - , 664 - , 665 - , 666 - , 667 - , 668 - , 669 - , 670 - , 671 - , 672 - , 673 - , 674 - , 675 - , 676 - , 677 - , 678 - , 679 - , 680 - , 681 - , 682 - , 683 - , 684 - , 685 - , 686 - , 687 - , 688 - , 689 - , 690 - , 691 - , 692 - , 693 - , 694 - , 695 - , 696 - , 697 - , 698 - , 699 - , 700 - , 701 - , 702 - , 703 - , 704 - , 705 - , 706 - , 707 - , 708 - , 709 - , 710 - , 711 - , 712 - , 713 - , 714 - , 715 - , 716 - , 717 - , 718 - , 719 - , 720 - , 721 - , 722 - , 723 - , 724 - , 725 - , 726 - , 727 - , 728 - , 729 - , 730 - , 731 - , 732 - , 733 - , 734 - , 735 - , 736 - , 737 - , 738 - , 739 - , 740 - , 741 - , 742 - , 743 - , 744 - , 745 - , 746 - , 747 - , 748 - , 749 - , 750 - , 751 - , 752 - , 753 - , 754 - , 755 - , 756 - , 757 - , 758 - , 759 - , 760 - , 761 - , 762 - , 763 - , 764 - , 765 - , 766 - , 767 - , 768 - , 769 - , 770 - , 771 - , 772 - , 773 - , 774 - , 775 - , 776 - , 777 - , 778 - , 779 - , 780 - , 781 - , 782 - , 783 - , 784 - , 785 - , 786 - , 787 - , 788 - , 789 - , 790 - , 791 - , 792 - , 793 - , 794 - , 795 - , 796 - , 797 - , 798 - , 799 - , 800 - , 801 - , 802 - , 803 - , 804 - , 805 - , 806 - , 807 - , 808 - , 809 - , 810 - , 811 - , 812 - , 813 - , 814 - , 815 - , 816 - , 817 - , 818 - , 819 - , 820 - , 821 - , 822 - , 823 - , 824 - , 825 - , 826 - , 827 - , 828 - , 829 - , 830 - , 831 - , 832 - , 833 - , 834 - , 835 - , 836 - , 837 - , 838 - , 839 - , 840 - , 841 - , 842 - , 843 - , 844 - , 845 - , 846 - , 847 - , 848 - , 849 - , 850 - , 851 - , 852 - , 853 - , 854 - , 855 - , 856 - , 857 - , 858 - , 859 - , 860 - , 861 - , 862 - , 863 - , 864 - , 865 - , 866 - , 867 - , 868 - , 869 - , 870 - , 871 - , 872 - , 873 - , 874 - , 875 - , 876 - , 877 - , 878 - , 879 - , 880 - , 881 - , 882 - , 883 - , 884 - , 885 - , 886 - , 887 - , 888 - , 889 - , 890 - , 891 - , 892 - , 893 - , 894 - , 895 - , 896 - , 897 - , 898 - , 899 - , 900 - , 901 - , 902 - , 903 - , 904 - , 905 - , 906 - , 907 - , 908 - , 909 - , 910 - , 911 - , 912 - , 913 - , 914 - , 915 - , 916 - , 917 - , 918 - , 919 - , 920 - , 921 - , 922 - , 923 - , 924 - , 925 - , 926 - , 927 - , 928 - , 929 - , 930 - , 931 - , 932 - , 933 - , 934 - , 935 - , 936 - , 937 - , 938 - , 939 - , 940 - , 941 - , 942 - , 943 - , 944 - , 945 - , 946 - , 947 - , 948 - , 949 - , 950 - , 951 - , 952 - , 953 - , 954 - , 955 - , 956 - , 957 - , 958 - , 959 - , 960 - , 961 - , 962 - , 963 - , 964 - , 965 - , 966 - , 967 - , 968 - , 969 - , 970 - , 971 - , 972 - , 973 - , 974 - , 975 - , 976 - , 977 - , 978 - , 979 - , 980 - , 981 - , 982 - , 983 - , 984 - , 985 - , 986 - , 987 - , 988 - , 989 - , 990 - , 991 - , 992 - , 993 - , 994 - , 995 - , 996 - , 997 - , 998 - , 999 - , 1000 - , 1001 - , 1002 - , 1003 - , 1004 - , 1005 - , 1006 - , 1007 - , 1008 - , 1009 - , 1010 - , 1011 - , 1012 - , 1013 - , 1014 - , 1015 - , 1016 - , 1017 - , 1018 - , 1019 - , 1020 - , 1021 - , 1022 - , 1023 - , 1024 - , 1025 - , 1026 - , 1027 - , 1028 - , 1029 - , 1030 - , 1031 - , 1032 - , 1033 - , 1034 - , 1035 - , 1036 - , 1037 - , 1038 - , 1039 - , 1040 - , 1041 - , 1042 - , 1043 - , 1044 - , 1045 - , 1046 - , 1047 - , 1048 - , 1049 - , 1050 - , 1051 - , 1052 - , 1053 - , 1054 - , 1055 - , 1056 - , 1057 - , 1058 - , 1059 - , 1060 - , 1061 - , 1062 - , 1063 - , 1064 - , 1065 - , 1066 - , 1067 - , 1068 - , 1069 - , 1070 - , 1071 - , 1072 - , 1073 - , 1074 - , 1075 - , 1076 - , 1077 - , 1078 - , 1079 - , 1080 - , 1081 - , 1082 - , 1083 - , 1084 - , 1085 - , 1086 - , 1087 - , 1088 - , 1089 - , 1090 - , 1091 - , 1092 - , 1093 - , 1094 - , 1095 - , 1096 - , 1097 - , 1098 - , 1099 - , 1100 - , 1101 - , 1102 - , 1103 - , 1104 - , 1105 - , 1106 - , 1107 - , 1108 - , 1109 - , 1110 - , 1111 - , 1112 - , 1113 - , 1114 - , 1115 - , 1116 - , 1117 - , 1118 - , 1119 - , 1120 - , 1121 - , 1122 - , 1123 - , 1124 - , 1125 - , 1126 - , 1127 - , 1128 - , 1129 - , 1130 - , 1131 - , 1132 - , 1133 - , 1134 - , 1135 - , 1136 - , 1137 - , 1138 - , 1139 - , 1140 - , 1141 - , 1142 - , 1143 - , 1144 - , 1145 - , 1146 - , 1147 - , 1148 - , 1149 - , 1150 - , 1151 - , 1152 - , 1153 - , 1154 - , 1155 - , 1156 - , 1157 - , 1158 - , 1159 - , 1160 - , 1161 - , 1162 - , 1163 - , 1164 - , 1165 - , 1166 - , 1167 - , 1168 - , 1169 - , 1170 - , 1171 - , 1172 - , 1173 - , 1174 - , 1175 - , 1176 - , 1177 - , 1178 - , 1179 - , 1180 - , 1181 - , 1182 - , 1183 - , 1184 - , 1185 - , 1186 - , 1187 - , 1188 - , 1189 - , 1190 - , 1191 - , 1192 - , 1193 - , 1194 - , 1195 - , 1196 - , 1197 - , 1198 - , 1199 - , 1200 - , 1201 - , 1202 - , 1203 - , 1204 - , 1205 - , 1206 - , 1207 - , 1208 - , 1209 - , 1210 - , 1211 - , 1212 - , 1213 - , 1214 - , 1215 - , 1216 - , 1217 - , 1218 - , 1219 - , 1220 - , 1221 - , 1222 - , 1223 - , 1224 - , 1225 - , 1226 - , 1227 - , 1228 - , 1229 - , 1230 - , 1231 - , 1232 - , 1233 - , 1234 - , 1235 - , 1236 - , 1237 - , 1238 - , 1239 - , 1240 - , 1241 - , 1242 - , 1243 - , 1244 - , 1245 - , 1246 - , 1247 - , 1248 - , 1249 - , 1250 - , 1251 - , 1252 - , 1253 - , 1254 - , 1255 - , 1256 - , 1257 - , 1258 - , 1259 - , 1260 - , 1261 - , 1262 - , 1263 - , 1264 - , 1265 - , 1266 - , 1267 - , 1268 - , 1269 - , 1270 - , 1271 - , 1272 - , 1273 - , 1274 - , 1275 - , 1276 - , 1277 - , 1278 - , 1279 - , 1280 - , 1281 - , 1282 - , 1283 - , 1284 - , 1285 - , 1286 - , 1287 - , 1288 - , 1289 - , 1290 - , 1291 - , 1292 - , 1293 - , 1294 - , 1295 - , 1296 - , 1297 - , 1298 - , 1299 - , 1300 - , 1301 - , 1302 - , 1303 - , 1304 - , 1305 - , 1306 - , 1307 - , 1308 - , 1309 - , 1310 - , 1311 - , 1312 - , 1313 - , 1314 - , 1315 - , 1316 - , 1317 - , 1318 - , 1319 - , 1320 - , 1321 - , 1322 - , 1323 - , 1324 - , 1325 - , 1326 - , 1327 - , 1328 - , 1329 - , 1330 - , 1331 - , 1332 - , 1333 - , 1334 - , 1335 - , 1336 - , 1337 - , 1338 - , 1339 - , 1340 - , 1341 - , 1342 - , 1343 - , 1344 - , 1345 - , 1346 - , 1347 - , 1348 - , 1349 - , 1350 - , 1351 - , 1352 - , 1353 - , 1354 - , 1355 - , 1356 - , 1357 - , 1358 - , 1359 - , 1360 - , 1361 - , 1362 - , 1363 - , 1364 - , 1365 - , 1366 - , 1367 - , 1368 - , 1369 - , 1370 - , 1371 - , 1372 - , 1373 - , 1374 - , 1375 - , 1376 - , 1377 - , 1378 - , 1379 - , 1380 - , 1381 - , 1382 - , 1383 - , 1384 - , 1385 - , 1386 - , 1387 - , 1388 - , 1389 - , 1390 - , 1391 - , 1392 - , 1393 - , 1394 - , 1395 - , 1396 - , 1397 - , 1398 - , 1399 - , 1400 - , 1401 - , 1402 - , 1403 - , 1404 - , 1405 - , 1406 - , 1407 - , 1408 - , 1409 - , 1410 - , 1411 - , 1412 - , 1413 - , 1414 - , 1415 - , 1416 - , 1417 - , 1418 - , 1419 - , 1420 - , 1421 - , 1422 - , 1423 - , 1424 - , 1425 - , 1426 - , 1427 - , 1428 - , 1429 - , 1430 - , 1431 - , 1432 - , 1433 - , 1434 - , 1435 - , 1436 - , 1437 - , 1438 - , 1439 - , 1440 - , 1441 - , 1442 - , 1443 - , 1444 - , 1445 - , 1446 - , 1447 - , 1448 - , 1449 - , 1450 - , 1451 - , 1452 - , 1453 - , 1454 - , 1455 - , 1456 - , 1457 - , 1458 - , 1459 - , 1460 - , 1461 - , 1462 - , 1463 - , 1464 - , 1465 - , 1466 - , 1467 - , 1468 - , 1469 - , 1470 - , 1471 - , 1472 - , 1473 - , 1474 - , 1475 - , 1476 - , 1477 - , 1478 - , 1479 - , 1480 - , 1481 - , 1482 - , 1483 - , 1484 - , 1485 - , 1486 - , 1487 - , 1488 - , 1489 - , 1490 - , 1491 - , 1492 - , 1493 - , 1494 - , 1495 - , 1496 - , 1497 - , 1498 - , 1499 - , 1500 - , 1501 - , 1502 - , 1503 - , 1504 - , 1505 - , 1506 - , 1507 - , 1508 - , 1509 - , 1510 - , 1511 - , 1512 - , 1513 - , 1514 - , 1515 - , 1516 - , 1517 - , 1518 - , 1519 - , 1520 - , 1521 - , 1522 - , 1523 - , 1524 - , 1525 - , 1526 - , 1527 - , 1528 - , 1529 - , 1530 - , 1531 - , 1532 - , 1533 - , 1534 - , 1535 - , 1536 - , 1537 - , 1538 - , 1539 - , 1540 - , 1541 - , 1542 - , 1543 - , 1544 - , 1545 - , 1546 - , 1547 - , 1548 - , 1549 - , 1550 - , 1551 - , 1552 - , 1553 - , 1554 - , 1555 - , 1556 - , 1557 - , 1558 - , 1559 - , 1560 - , 1561 - , 1562 - , 1563 - , 1564 - , 1565 - , 1566 - , 1567 - , 1568 - , 1569 - , 1570 - , 1571 - , 1572 - , 1573 - , 1574 - , 1575 - , 1576 - , 1577 - , 1578 - , 1579 - , 1580 - , 1581 - , 1582 - , 1583 - , 1584 - , 1585 - , 1586 - , 1587 - , 1588 - , 1589 - , 1590 - , 1591 - , 1592 - , 1593 - , 1594 - , 1595 - , 1596 - , 1597 - , 1598 - , 1599 - , 1600 - , 1601 - , 1602 - , 1603 - , 1604 - , 1605 - , 1606 - , 1607 - , 1608 - , 1609 - , 1610 - , 1611 - , 1612 - , 1613 - , 1614 - , 1615 - , 1616 - , 1617 - , 1618 - , 1619 - , 1620 - , 1621 - , 1622 - , 1623 - , 1624 - , 1625 - , 1626 - , 1627 - , 1628 - , 1629 - , 1630 - , 1631 - , 1632 - , 1633 - , 1634 - , 1635 - , 1636 - , 1637 - , 1638 - , 1639 - , 1640 - , 1641 - , 1642 - , 1643 - , 1644 - , 1645 - , 1646 - , 1647 - , 1648 - , 1649 - , 1650 - , 1651 - , 1652 - , 1653 - , 1654 - , 1655 - , 1656 - , 1657 - , 1658 - , 1659 - , 1660 - , 1661 - , 1662 - , 1663 - , 1664 - , 1665 - , 1666 - , 1667 - , 1668 - , 1669 - , 1670 - , 1671 - , 1672 - , 1673 - , 1674 - , 1675 - , 1676 - , 1677 - , 1678 - , 1679 - , 1680 - , 1681 - , 1682 - , 1683 - , 1684 - , 1685 - , 1686 - , 1687 - , 1688 - , 1689 - , 1690 - , 1691 - , 1692 - , 1693 - , 1694 - , 1695 - , 1696 - , 1697 - , 1698 - , 1699 - , 1700 - , 1701 - , 1702 - , 1703 - , 1704 - , 1705 - , 1706 - , 1707 - , 1708 - , 1709 - , 1710 - , 1711 - , 1712 - , 1713 - , 1714 - , 1715 - , 1716 - , 1717 - , 1718 - , 1719 - , 1720 - , 1721 - , 1722 - , 1723 - , 1724 - , 1725 - , 1726 - , 1727 - , 1728 - , 1729 - , 1730 - , 1731 - , 1732 - , 1733 - , 1734 - , 1735 - , 1736 - , 1737 - , 1738 - , 1739 - , 1740 - , 1741 - , 1742 - , 1743 - , 1744 - , 1745 - , 1746 - , 1747 - , 1748 - , 1749 - , 1750 - , 1751 - , 1752 - , 1753 - , 1754 - , 1755 - , 1756 - , 1757 - , 1758 - , 1759 - , 1760 - , 1761 - , 1762 - , 1763 - , 1764 - , 1765 - , 1766 - , 1767 - , 1768 - , 1769 - , 1770 - , 1771 - , 1772 - , 1773 - , 1774 - , 1775 - , 1776 - , 1777 - , 1778 - , 1779 - , 1780 - , 1781 - , 1782 - , 1783 - , 1784 - , 1785 - , 1786 - , 1787 - , 1788 - , 1789 - , 1790 - , 1791 - , 1792 - , 1793 - , 1794 - , 1795 - , 1796 - , 1797 - , 1798 - , 1799 - , 1800 - , 1801 - , 1802 - , 1803 - , 1804 - , 1805 - , 1806 - , 1807 - , 1808 - , 1809 - , 1810 - , 1811 - , 1812 - , 1813 - , 1814 - , 1815 - , 1816 - , 1817 - , 1818 - , 1819 - , 1820 - , 1821 - , 1822 - , 1823 - , 1824 - , 1825 - , 1826 - , 1827 - , 1828 - , 1829 - , 1830 - , 1831 - , 1832 - , 1833 - , 1834 - , 1835 - , 1836 - , 1837 - , 1838 - , 1839 - , 1840 - , 1841 - , 1842 - , 1843 - , 1844 - , 1845 - , 1846 - , 1847 - , 1848 - , 1849 - , 1850 - , 1851 - , 1852 - , 1853 - , 1854 - , 1855 - , 1856 - , 1857 - , 1858 - , 1859 - , 1860 - , 1861 - , 1862 - , 1863 - , 1864 - , 1865 - , 1866 - , 1867 - , 1868 - , 1869 - , 1870 - , 1871 - , 1872 - , 1873 - , 1874 - , 1875 - , 1876 - , 1877 - , 1878 - , 1879 - , 1880 - , 1881 - , 1882 - , 1883 - , 1884 - , 1885 - , 1886 - , 1887 - , 1888 - , 1889 - , 1890 - , 1891 - , 1892 - , 1893 - , 1894 - , 1895 - , 1896 - , 1897 - , 1898 - , 1899 - , 1900 - , 1901 - , 1902 - , 1903 - , 1904 - , 1905 - , 1906 - , 1907 - , 1908 - , 1909 - , 1910 - , 1911 - , 1912 - , 1913 - , 1914 - , 1915 - , 1916 - , 1917 - , 1918 - , 1919 - , 1920 - , 1921 - , 1922 - , 1923 - , 1924 - , 1925 - , 1926 - , 1927 - , 1928 - , 1929 - , 1930 - , 1931 - , 1932 - , 1933 - , 1934 - , 1935 - , 1936 - , 1937 - , 1938 - , 1939 - , 1940 - , 1941 - , 1942 - , 1943 - , 1944 - , 1945 - , 1946 - , 1947 - , 1948 - , 1949 - , 1950 - , 1951 - , 1952 - , 1953 - , 1954 - , 1955 - , 1956 - , 1957 - , 1958 - , 1959 - , 1960 - , 1961 - , 1962 - , 1963 - , 1964 - , 1965 - , 1966 - , 1967 - , 1968 - , 1969 - , 1970 - , 1971 - , 1972 - , 1973 - , 1974 - , 1975 - , 1976 - , 1977 - , 1978 - , 1979 - , 1980 - , 1981 - , 1982 - , 1983 - , 1984 - , 1985 - , 1986 - , 1987 - , 1988 - , 1989 - , 1990 - , 1991 - , 1992 - , 1993 - , 1994 - , 1995 - , 1996 - , 1997 - , 1998 - , 1999 + [ +1 + , +2 + , +3 + , +4 + , +5 + , +6 + , +7 + , +8 + , +9 + , +10 + , +11 + , +12 + , +13 + , +14 + , +15 + , +16 + , +17 + , +18 + , +19 + , +20 + , +21 + , +22 + , +23 + , +24 + , +25 + , +26 + , +27 + , +28 + , +29 + , +30 + , +31 + , +32 + , +33 + , +34 + , +35 + , +36 + , +37 + , +38 + , +39 + , +40 + , +41 + , +42 + , +43 + , +44 + , +45 + , +46 + , +47 + , +48 + , +49 + , +50 + , +51 + , +52 + , +53 + , +54 + , +55 + , +56 + , +57 + , +58 + , +59 + , +60 + , +61 + , +62 + , +63 + , +64 + , +65 + , +66 + , +67 + , +68 + , +69 + , +70 + , +71 + , +72 + , +73 + , +74 + , +75 + , +76 + , +77 + , +78 + , +79 + , +80 + , +81 + , +82 + , +83 + , +84 + , +85 + , +86 + , +87 + , +88 + , +89 + , +90 + , +91 + , +92 + , +93 + , +94 + , +95 + , +96 + , +97 + , +98 + , +99 + , +100 + , +101 + , +102 + , +103 + , +104 + , +105 + , +106 + , +107 + , +108 + , +109 + , +110 + , +111 + , +112 + , +113 + , +114 + , +115 + , +116 + , +117 + , +118 + , +119 + , +120 + , +121 + , +122 + , +123 + , +124 + , +125 + , +126 + , +127 + , +128 + , +129 + , +130 + , +131 + , +132 + , +133 + , +134 + , +135 + , +136 + , +137 + , +138 + , +139 + , +140 + , +141 + , +142 + , +143 + , +144 + , +145 + , +146 + , +147 + , +148 + , +149 + , +150 + , +151 + , +152 + , +153 + , +154 + , +155 + , +156 + , +157 + , +158 + , +159 + , +160 + , +161 + , +162 + , +163 + , +164 + , +165 + , +166 + , +167 + , +168 + , +169 + , +170 + , +171 + , +172 + , +173 + , +174 + , +175 + , +176 + , +177 + , +178 + , +179 + , +180 + , +181 + , +182 + , +183 + , +184 + , +185 + , +186 + , +187 + , +188 + , +189 + , +190 + , +191 + , +192 + , +193 + , +194 + , +195 + , +196 + , +197 + , +198 + , +199 + , +200 + , +201 + , +202 + , +203 + , +204 + , +205 + , +206 + , +207 + , +208 + , +209 + , +210 + , +211 + , +212 + , +213 + , +214 + , +215 + , +216 + , +217 + , +218 + , +219 + , +220 + , +221 + , +222 + , +223 + , +224 + , +225 + , +226 + , +227 + , +228 + , +229 + , +230 + , +231 + , +232 + , +233 + , +234 + , +235 + , +236 + , +237 + , +238 + , +239 + , +240 + , +241 + , +242 + , +243 + , +244 + , +245 + , +246 + , +247 + , +248 + , +249 + , +250 + , +251 + , +252 + , +253 + , +254 + , +255 + , +256 + , +257 + , +258 + , +259 + , +260 + , +261 + , +262 + , +263 + , +264 + , +265 + , +266 + , +267 + , +268 + , +269 + , +270 + , +271 + , +272 + , +273 + , +274 + , +275 + , +276 + , +277 + , +278 + , +279 + , +280 + , +281 + , +282 + , +283 + , +284 + , +285 + , +286 + , +287 + , +288 + , +289 + , +290 + , +291 + , +292 + , +293 + , +294 + , +295 + , +296 + , +297 + , +298 + , +299 + , +300 + , +301 + , +302 + , +303 + , +304 + , +305 + , +306 + , +307 + , +308 + , +309 + , +310 + , +311 + , +312 + , +313 + , +314 + , +315 + , +316 + , +317 + , +318 + , +319 + , +320 + , +321 + , +322 + , +323 + , +324 + , +325 + , +326 + , +327 + , +328 + , +329 + , +330 + , +331 + , +332 + , +333 + , +334 + , +335 + , +336 + , +337 + , +338 + , +339 + , +340 + , +341 + , +342 + , +343 + , +344 + , +345 + , +346 + , +347 + , +348 + , +349 + , +350 + , +351 + , +352 + , +353 + , +354 + , +355 + , +356 + , +357 + , +358 + , +359 + , +360 + , +361 + , +362 + , +363 + , +364 + , +365 + , +366 + , +367 + , +368 + , +369 + , +370 + , +371 + , +372 + , +373 + , +374 + , +375 + , +376 + , +377 + , +378 + , +379 + , +380 + , +381 + , +382 + , +383 + , +384 + , +385 + , +386 + , +387 + , +388 + , +389 + , +390 + , +391 + , +392 + , +393 + , +394 + , +395 + , +396 + , +397 + , +398 + , +399 + , +400 + , +401 + , +402 + , +403 + , +404 + , +405 + , +406 + , +407 + , +408 + , +409 + , +410 + , +411 + , +412 + , +413 + , +414 + , +415 + , +416 + , +417 + , +418 + , +419 + , +420 + , +421 + , +422 + , +423 + , +424 + , +425 + , +426 + , +427 + , +428 + , +429 + , +430 + , +431 + , +432 + , +433 + , +434 + , +435 + , +436 + , +437 + , +438 + , +439 + , +440 + , +441 + , +442 + , +443 + , +444 + , +445 + , +446 + , +447 + , +448 + , +449 + , +450 + , +451 + , +452 + , +453 + , +454 + , +455 + , +456 + , +457 + , +458 + , +459 + , +460 + , +461 + , +462 + , +463 + , +464 + , +465 + , +466 + , +467 + , +468 + , +469 + , +470 + , +471 + , +472 + , +473 + , +474 + , +475 + , +476 + , +477 + , +478 + , +479 + , +480 + , +481 + , +482 + , +483 + , +484 + , +485 + , +486 + , +487 + , +488 + , +489 + , +490 + , +491 + , +492 + , +493 + , +494 + , +495 + , +496 + , +497 + , +498 + , +499 + , +500 + , +501 + , +502 + , +503 + , +504 + , +505 + , +506 + , +507 + , +508 + , +509 + , +510 + , +511 + , +512 + , +513 + , +514 + , +515 + , +516 + , +517 + , +518 + , +519 + , +520 + , +521 + , +522 + , +523 + , +524 + , +525 + , +526 + , +527 + , +528 + , +529 + , +530 + , +531 + , +532 + , +533 + , +534 + , +535 + , +536 + , +537 + , +538 + , +539 + , +540 + , +541 + , +542 + , +543 + , +544 + , +545 + , +546 + , +547 + , +548 + , +549 + , +550 + , +551 + , +552 + , +553 + , +554 + , +555 + , +556 + , +557 + , +558 + , +559 + , +560 + , +561 + , +562 + , +563 + , +564 + , +565 + , +566 + , +567 + , +568 + , +569 + , +570 + , +571 + , +572 + , +573 + , +574 + , +575 + , +576 + , +577 + , +578 + , +579 + , +580 + , +581 + , +582 + , +583 + , +584 + , +585 + , +586 + , +587 + , +588 + , +589 + , +590 + , +591 + , +592 + , +593 + , +594 + , +595 + , +596 + , +597 + , +598 + , +599 + , +600 + , +601 + , +602 + , +603 + , +604 + , +605 + , +606 + , +607 + , +608 + , +609 + , +610 + , +611 + , +612 + , +613 + , +614 + , +615 + , +616 + , +617 + , +618 + , +619 + , +620 + , +621 + , +622 + , +623 + , +624 + , +625 + , +626 + , +627 + , +628 + , +629 + , +630 + , +631 + , +632 + , +633 + , +634 + , +635 + , +636 + , +637 + , +638 + , +639 + , +640 + , +641 + , +642 + , +643 + , +644 + , +645 + , +646 + , +647 + , +648 + , +649 + , +650 + , +651 + , +652 + , +653 + , +654 + , +655 + , +656 + , +657 + , +658 + , +659 + , +660 + , +661 + , +662 + , +663 + , +664 + , +665 + , +666 + , +667 + , +668 + , +669 + , +670 + , +671 + , +672 + , +673 + , +674 + , +675 + , +676 + , +677 + , +678 + , +679 + , +680 + , +681 + , +682 + , +683 + , +684 + , +685 + , +686 + , +687 + , +688 + , +689 + , +690 + , +691 + , +692 + , +693 + , +694 + , +695 + , +696 + , +697 + , +698 + , +699 + , +700 + , +701 + , +702 + , +703 + , +704 + , +705 + , +706 + , +707 + , +708 + , +709 + , +710 + , +711 + , +712 + , +713 + , +714 + , +715 + , +716 + , +717 + , +718 + , +719 + , +720 + , +721 + , +722 + , +723 + , +724 + , +725 + , +726 + , +727 + , +728 + , +729 + , +730 + , +731 + , +732 + , +733 + , +734 + , +735 + , +736 + , +737 + , +738 + , +739 + , +740 + , +741 + , +742 + , +743 + , +744 + , +745 + , +746 + , +747 + , +748 + , +749 + , +750 + , +751 + , +752 + , +753 + , +754 + , +755 + , +756 + , +757 + , +758 + , +759 + , +760 + , +761 + , +762 + , +763 + , +764 + , +765 + , +766 + , +767 + , +768 + , +769 + , +770 + , +771 + , +772 + , +773 + , +774 + , +775 + , +776 + , +777 + , +778 + , +779 + , +780 + , +781 + , +782 + , +783 + , +784 + , +785 + , +786 + , +787 + , +788 + , +789 + , +790 + , +791 + , +792 + , +793 + , +794 + , +795 + , +796 + , +797 + , +798 + , +799 + , +800 + , +801 + , +802 + , +803 + , +804 + , +805 + , +806 + , +807 + , +808 + , +809 + , +810 + , +811 + , +812 + , +813 + , +814 + , +815 + , +816 + , +817 + , +818 + , +819 + , +820 + , +821 + , +822 + , +823 + , +824 + , +825 + , +826 + , +827 + , +828 + , +829 + , +830 + , +831 + , +832 + , +833 + , +834 + , +835 + , +836 + , +837 + , +838 + , +839 + , +840 + , +841 + , +842 + , +843 + , +844 + , +845 + , +846 + , +847 + , +848 + , +849 + , +850 + , +851 + , +852 + , +853 + , +854 + , +855 + , +856 + , +857 + , +858 + , +859 + , +860 + , +861 + , +862 + , +863 + , +864 + , +865 + , +866 + , +867 + , +868 + , +869 + , +870 + , +871 + , +872 + , +873 + , +874 + , +875 + , +876 + , +877 + , +878 + , +879 + , +880 + , +881 + , +882 + , +883 + , +884 + , +885 + , +886 + , +887 + , +888 + , +889 + , +890 + , +891 + , +892 + , +893 + , +894 + , +895 + , +896 + , +897 + , +898 + , +899 + , +900 + , +901 + , +902 + , +903 + , +904 + , +905 + , +906 + , +907 + , +908 + , +909 + , +910 + , +911 + , +912 + , +913 + , +914 + , +915 + , +916 + , +917 + , +918 + , +919 + , +920 + , +921 + , +922 + , +923 + , +924 + , +925 + , +926 + , +927 + , +928 + , +929 + , +930 + , +931 + , +932 + , +933 + , +934 + , +935 + , +936 + , +937 + , +938 + , +939 + , +940 + , +941 + , +942 + , +943 + , +944 + , +945 + , +946 + , +947 + , +948 + , +949 + , +950 + , +951 + , +952 + , +953 + , +954 + , +955 + , +956 + , +957 + , +958 + , +959 + , +960 + , +961 + , +962 + , +963 + , +964 + , +965 + , +966 + , +967 + , +968 + , +969 + , +970 + , +971 + , +972 + , +973 + , +974 + , +975 + , +976 + , +977 + , +978 + , +979 + , +980 + , +981 + , +982 + , +983 + , +984 + , +985 + , +986 + , +987 + , +988 + , +989 + , +990 + , +991 + , +992 + , +993 + , +994 + , +995 + , +996 + , +997 + , +998 + , +999 + , +1000 + , +1001 + , +1002 + , +1003 + , +1004 + , +1005 + , +1006 + , +1007 + , +1008 + , +1009 + , +1010 + , +1011 + , +1012 + , +1013 + , +1014 + , +1015 + , +1016 + , +1017 + , +1018 + , +1019 + , +1020 + , +1021 + , +1022 + , +1023 + , +1024 + , +1025 + , +1026 + , +1027 + , +1028 + , +1029 + , +1030 + , +1031 + , +1032 + , +1033 + , +1034 + , +1035 + , +1036 + , +1037 + , +1038 + , +1039 + , +1040 + , +1041 + , +1042 + , +1043 + , +1044 + , +1045 + , +1046 + , +1047 + , +1048 + , +1049 + , +1050 + , +1051 + , +1052 + , +1053 + , +1054 + , +1055 + , +1056 + , +1057 + , +1058 + , +1059 + , +1060 + , +1061 + , +1062 + , +1063 + , +1064 + , +1065 + , +1066 + , +1067 + , +1068 + , +1069 + , +1070 + , +1071 + , +1072 + , +1073 + , +1074 + , +1075 + , +1076 + , +1077 + , +1078 + , +1079 + , +1080 + , +1081 + , +1082 + , +1083 + , +1084 + , +1085 + , +1086 + , +1087 + , +1088 + , +1089 + , +1090 + , +1091 + , +1092 + , +1093 + , +1094 + , +1095 + , +1096 + , +1097 + , +1098 + , +1099 + , +1100 + , +1101 + , +1102 + , +1103 + , +1104 + , +1105 + , +1106 + , +1107 + , +1108 + , +1109 + , +1110 + , +1111 + , +1112 + , +1113 + , +1114 + , +1115 + , +1116 + , +1117 + , +1118 + , +1119 + , +1120 + , +1121 + , +1122 + , +1123 + , +1124 + , +1125 + , +1126 + , +1127 + , +1128 + , +1129 + , +1130 + , +1131 + , +1132 + , +1133 + , +1134 + , +1135 + , +1136 + , +1137 + , +1138 + , +1139 + , +1140 + , +1141 + , +1142 + , +1143 + , +1144 + , +1145 + , +1146 + , +1147 + , +1148 + , +1149 + , +1150 + , +1151 + , +1152 + , +1153 + , +1154 + , +1155 + , +1156 + , +1157 + , +1158 + , +1159 + , +1160 + , +1161 + , +1162 + , +1163 + , +1164 + , +1165 + , +1166 + , +1167 + , +1168 + , +1169 + , +1170 + , +1171 + , +1172 + , +1173 + , +1174 + , +1175 + , +1176 + , +1177 + , +1178 + , +1179 + , +1180 + , +1181 + , +1182 + , +1183 + , +1184 + , +1185 + , +1186 + , +1187 + , +1188 + , +1189 + , +1190 + , +1191 + , +1192 + , +1193 + , +1194 + , +1195 + , +1196 + , +1197 + , +1198 + , +1199 + , +1200 + , +1201 + , +1202 + , +1203 + , +1204 + , +1205 + , +1206 + , +1207 + , +1208 + , +1209 + , +1210 + , +1211 + , +1212 + , +1213 + , +1214 + , +1215 + , +1216 + , +1217 + , +1218 + , +1219 + , +1220 + , +1221 + , +1222 + , +1223 + , +1224 + , +1225 + , +1226 + , +1227 + , +1228 + , +1229 + , +1230 + , +1231 + , +1232 + , +1233 + , +1234 + , +1235 + , +1236 + , +1237 + , +1238 + , +1239 + , +1240 + , +1241 + , +1242 + , +1243 + , +1244 + , +1245 + , +1246 + , +1247 + , +1248 + , +1249 + , +1250 + , +1251 + , +1252 + , +1253 + , +1254 + , +1255 + , +1256 + , +1257 + , +1258 + , +1259 + , +1260 + , +1261 + , +1262 + , +1263 + , +1264 + , +1265 + , +1266 + , +1267 + , +1268 + , +1269 + , +1270 + , +1271 + , +1272 + , +1273 + , +1274 + , +1275 + , +1276 + , +1277 + , +1278 + , +1279 + , +1280 + , +1281 + , +1282 + , +1283 + , +1284 + , +1285 + , +1286 + , +1287 + , +1288 + , +1289 + , +1290 + , +1291 + , +1292 + , +1293 + , +1294 + , +1295 + , +1296 + , +1297 + , +1298 + , +1299 + , +1300 + , +1301 + , +1302 + , +1303 + , +1304 + , +1305 + , +1306 + , +1307 + , +1308 + , +1309 + , +1310 + , +1311 + , +1312 + , +1313 + , +1314 + , +1315 + , +1316 + , +1317 + , +1318 + , +1319 + , +1320 + , +1321 + , +1322 + , +1323 + , +1324 + , +1325 + , +1326 + , +1327 + , +1328 + , +1329 + , +1330 + , +1331 + , +1332 + , +1333 + , +1334 + , +1335 + , +1336 + , +1337 + , +1338 + , +1339 + , +1340 + , +1341 + , +1342 + , +1343 + , +1344 + , +1345 + , +1346 + , +1347 + , +1348 + , +1349 + , +1350 + , +1351 + , +1352 + , +1353 + , +1354 + , +1355 + , +1356 + , +1357 + , +1358 + , +1359 + , +1360 + , +1361 + , +1362 + , +1363 + , +1364 + , +1365 + , +1366 + , +1367 + , +1368 + , +1369 + , +1370 + , +1371 + , +1372 + , +1373 + , +1374 + , +1375 + , +1376 + , +1377 + , +1378 + , +1379 + , +1380 + , +1381 + , +1382 + , +1383 + , +1384 + , +1385 + , +1386 + , +1387 + , +1388 + , +1389 + , +1390 + , +1391 + , +1392 + , +1393 + , +1394 + , +1395 + , +1396 + , +1397 + , +1398 + , +1399 + , +1400 + , +1401 + , +1402 + , +1403 + , +1404 + , +1405 + , +1406 + , +1407 + , +1408 + , +1409 + , +1410 + , +1411 + , +1412 + , +1413 + , +1414 + , +1415 + , +1416 + , +1417 + , +1418 + , +1419 + , +1420 + , +1421 + , +1422 + , +1423 + , +1424 + , +1425 + , +1426 + , +1427 + , +1428 + , +1429 + , +1430 + , +1431 + , +1432 + , +1433 + , +1434 + , +1435 + , +1436 + , +1437 + , +1438 + , +1439 + , +1440 + , +1441 + , +1442 + , +1443 + , +1444 + , +1445 + , +1446 + , +1447 + , +1448 + , +1449 + , +1450 + , +1451 + , +1452 + , +1453 + , +1454 + , +1455 + , +1456 + , +1457 + , +1458 + , +1459 + , +1460 + , +1461 + , +1462 + , +1463 + , +1464 + , +1465 + , +1466 + , +1467 + , +1468 + , +1469 + , +1470 + , +1471 + , +1472 + , +1473 + , +1474 + , +1475 + , +1476 + , +1477 + , +1478 + , +1479 + , +1480 + , +1481 + , +1482 + , +1483 + , +1484 + , +1485 + , +1486 + , +1487 + , +1488 + , +1489 + , +1490 + , +1491 + , +1492 + , +1493 + , +1494 + , +1495 + , +1496 + , +1497 + , +1498 + , +1499 + , +1500 + , +1501 + , +1502 + , +1503 + , +1504 + , +1505 + , +1506 + , +1507 + , +1508 + , +1509 + , +1510 + , +1511 + , +1512 + , +1513 + , +1514 + , +1515 + , +1516 + , +1517 + , +1518 + , +1519 + , +1520 + , +1521 + , +1522 + , +1523 + , +1524 + , +1525 + , +1526 + , +1527 + , +1528 + , +1529 + , +1530 + , +1531 + , +1532 + , +1533 + , +1534 + , +1535 + , +1536 + , +1537 + , +1538 + , +1539 + , +1540 + , +1541 + , +1542 + , +1543 + , +1544 + , +1545 + , +1546 + , +1547 + , +1548 + , +1549 + , +1550 + , +1551 + , +1552 + , +1553 + , +1554 + , +1555 + , +1556 + , +1557 + , +1558 + , +1559 + , +1560 + , +1561 + , +1562 + , +1563 + , +1564 + , +1565 + , +1566 + , +1567 + , +1568 + , +1569 + , +1570 + , +1571 + , +1572 + , +1573 + , +1574 + , +1575 + , +1576 + , +1577 + , +1578 + , +1579 + , +1580 + , +1581 + , +1582 + , +1583 + , +1584 + , +1585 + , +1586 + , +1587 + , +1588 + , +1589 + , +1590 + , +1591 + , +1592 + , +1593 + , +1594 + , +1595 + , +1596 + , +1597 + , +1598 + , +1599 + , +1600 + , +1601 + , +1602 + , +1603 + , +1604 + , +1605 + , +1606 + , +1607 + , +1608 + , +1609 + , +1610 + , +1611 + , +1612 + , +1613 + , +1614 + , +1615 + , +1616 + , +1617 + , +1618 + , +1619 + , +1620 + , +1621 + , +1622 + , +1623 + , +1624 + , +1625 + , +1626 + , +1627 + , +1628 + , +1629 + , +1630 + , +1631 + , +1632 + , +1633 + , +1634 + , +1635 + , +1636 + , +1637 + , +1638 + , +1639 + , +1640 + , +1641 + , +1642 + , +1643 + , +1644 + , +1645 + , +1646 + , +1647 + , +1648 + , +1649 + , +1650 + , +1651 + , +1652 + , +1653 + , +1654 + , +1655 + , +1656 + , +1657 + , +1658 + , +1659 + , +1660 + , +1661 + , +1662 + , +1663 + , +1664 + , +1665 + , +1666 + , +1667 + , +1668 + , +1669 + , +1670 + , +1671 + , +1672 + , +1673 + , +1674 + , +1675 + , +1676 + , +1677 + , +1678 + , +1679 + , +1680 + , +1681 + , +1682 + , +1683 + , +1684 + , +1685 + , +1686 + , +1687 + , +1688 + , +1689 + , +1690 + , +1691 + , +1692 + , +1693 + , +1694 + , +1695 + , +1696 + , +1697 + , +1698 + , +1699 + , +1700 + , +1701 + , +1702 + , +1703 + , +1704 + , +1705 + , +1706 + , +1707 + , +1708 + , +1709 + , +1710 + , +1711 + , +1712 + , +1713 + , +1714 + , +1715 + , +1716 + , +1717 + , +1718 + , +1719 + , +1720 + , +1721 + , +1722 + , +1723 + , +1724 + , +1725 + , +1726 + , +1727 + , +1728 + , +1729 + , +1730 + , +1731 + , +1732 + , +1733 + , +1734 + , +1735 + , +1736 + , +1737 + , +1738 + , +1739 + , +1740 + , +1741 + , +1742 + , +1743 + , +1744 + , +1745 + , +1746 + , +1747 + , +1748 + , +1749 + , +1750 + , +1751 + , +1752 + , +1753 + , +1754 + , +1755 + , +1756 + , +1757 + , +1758 + , +1759 + , +1760 + , +1761 + , +1762 + , +1763 + , +1764 + , +1765 + , +1766 + , +1767 + , +1768 + , +1769 + , +1770 + , +1771 + , +1772 + , +1773 + , +1774 + , +1775 + , +1776 + , +1777 + , +1778 + , +1779 + , +1780 + , +1781 + , +1782 + , +1783 + , +1784 + , +1785 + , +1786 + , +1787 + , +1788 + , +1789 + , +1790 + , +1791 + , +1792 + , +1793 + , +1794 + , +1795 + , +1796 + , +1797 + , +1798 + , +1799 + , +1800 + , +1801 + , +1802 + , +1803 + , +1804 + , +1805 + , +1806 + , +1807 + , +1808 + , +1809 + , +1810 + , +1811 + , +1812 + , +1813 + , +1814 + , +1815 + , +1816 + , +1817 + , +1818 + , +1819 + , +1820 + , +1821 + , +1822 + , +1823 + , +1824 + , +1825 + , +1826 + , +1827 + , +1828 + , +1829 + , +1830 + , +1831 + , +1832 + , +1833 + , +1834 + , +1835 + , +1836 + , +1837 + , +1838 + , +1839 + , +1840 + , +1841 + , +1842 + , +1843 + , +1844 + , +1845 + , +1846 + , +1847 + , +1848 + , +1849 + , +1850 + , +1851 + , +1852 + , +1853 + , +1854 + , +1855 + , +1856 + , +1857 + , +1858 + , +1859 + , +1860 + , +1861 + , +1862 + , +1863 + , +1864 + , +1865 + , +1866 + , +1867 + , +1868 + , +1869 + , +1870 + , +1871 + , +1872 + , +1873 + , +1874 + , +1875 + , +1876 + , +1877 + , +1878 + , +1879 + , +1880 + , +1881 + , +1882 + , +1883 + , +1884 + , +1885 + , +1886 + , +1887 + , +1888 + , +1889 + , +1890 + , +1891 + , +1892 + , +1893 + , +1894 + , +1895 + , +1896 + , +1897 + , +1898 + , +1899 + , +1900 + , +1901 + , +1902 + , +1903 + , +1904 + , +1905 + , +1906 + , +1907 + , +1908 + , +1909 + , +1910 + , +1911 + , +1912 + , +1913 + , +1914 + , +1915 + , +1916 + , +1917 + , +1918 + , +1919 + , +1920 + , +1921 + , +1922 + , +1923 + , +1924 + , +1925 + , +1926 + , +1927 + , +1928 + , +1929 + , +1930 + , +1931 + , +1932 + , +1933 + , +1934 + , +1935 + , +1936 + , +1937 + , +1938 + , +1939 + , +1940 + , +1941 + , +1942 + , +1943 + , +1944 + , +1945 + , +1946 + , +1947 + , +1948 + , +1949 + , +1950 + , +1951 + , +1952 + , +1953 + , +1954 + , +1955 + , +1956 + , +1957 + , +1958 + , +1959 + , +1960 + , +1961 + , +1962 + , +1963 + , +1964 + , +1965 + , +1966 + , +1967 + , +1968 + , +1969 + , +1970 + , +1971 + , +1972 + , +1973 + , +1974 + , +1975 + , +1976 + , +1977 + , +1978 + , +1979 + , +1980 + , +1981 + , +1982 + , +1983 + , +1984 + , +1985 + , +1986 + , +1987 + , +1988 + , +1989 + , +1990 + , +1991 + , +1992 + , +1993 + , +1994 + , +1995 + , +1996 + , +1997 + , +1998 + , +1999 , 2000 ] @@ -2070,2005 +2070,2005 @@ Should be cached: 1 | > range 2000 ⧩ - [ 1 - , 2 - , 3 - , 4 - , 5 - , 6 - , 7 - , 8 - , 9 - , 10 - , 11 - , 12 - , 13 - , 14 - , 15 - , 16 - , 17 - , 18 - , 19 - , 20 - , 21 - , 22 - , 23 - , 24 - , 25 - , 26 - , 27 - , 28 - , 29 - , 30 - , 31 - , 32 - , 33 - , 34 - , 35 - , 36 - , 37 - , 38 - , 39 - , 40 - , 41 - , 42 - , 43 - , 44 - , 45 - , 46 - , 47 - , 48 - , 49 - , 50 - , 51 - , 52 - , 53 - , 54 - , 55 - , 56 - , 57 - , 58 - , 59 - , 60 - , 61 - , 62 - , 63 - , 64 - , 65 - , 66 - , 67 - , 68 - , 69 - , 70 - , 71 - , 72 - , 73 - , 74 - , 75 - , 76 - , 77 - , 78 - , 79 - , 80 - , 81 - , 82 - , 83 - , 84 - , 85 - , 86 - , 87 - , 88 - , 89 - , 90 - , 91 - , 92 - , 93 - , 94 - , 95 - , 96 - , 97 - , 98 - , 99 - , 100 - , 101 - , 102 - , 103 - , 104 - , 105 - , 106 - , 107 - , 108 - , 109 - , 110 - , 111 - , 112 - , 113 - , 114 - , 115 - , 116 - , 117 - , 118 - , 119 - , 120 - , 121 - , 122 - , 123 - , 124 - , 125 - , 126 - , 127 - , 128 - , 129 - , 130 - , 131 - , 132 - , 133 - , 134 - , 135 - , 136 - , 137 - , 138 - , 139 - , 140 - , 141 - , 142 - , 143 - , 144 - , 145 - , 146 - , 147 - , 148 - , 149 - , 150 - , 151 - , 152 - , 153 - , 154 - , 155 - , 156 - , 157 - , 158 - , 159 - , 160 - , 161 - , 162 - , 163 - , 164 - , 165 - , 166 - , 167 - , 168 - , 169 - , 170 - , 171 - , 172 - , 173 - , 174 - , 175 - , 176 - , 177 - , 178 - , 179 - , 180 - , 181 - , 182 - , 183 - , 184 - , 185 - , 186 - , 187 - , 188 - , 189 - , 190 - , 191 - , 192 - , 193 - , 194 - , 195 - , 196 - , 197 - , 198 - , 199 - , 200 - , 201 - , 202 - , 203 - , 204 - , 205 - , 206 - , 207 - , 208 - , 209 - , 210 - , 211 - , 212 - , 213 - , 214 - , 215 - , 216 - , 217 - , 218 - , 219 - , 220 - , 221 - , 222 - , 223 - , 224 - , 225 - , 226 - , 227 - , 228 - , 229 - , 230 - , 231 - , 232 - , 233 - , 234 - , 235 - , 236 - , 237 - , 238 - , 239 - , 240 - , 241 - , 242 - , 243 - , 244 - , 245 - , 246 - , 247 - , 248 - , 249 - , 250 - , 251 - , 252 - , 253 - , 254 - , 255 - , 256 - , 257 - , 258 - , 259 - , 260 - , 261 - , 262 - , 263 - , 264 - , 265 - , 266 - , 267 - , 268 - , 269 - , 270 - , 271 - , 272 - , 273 - , 274 - , 275 - , 276 - , 277 - , 278 - , 279 - , 280 - , 281 - , 282 - , 283 - , 284 - , 285 - , 286 - , 287 - , 288 - , 289 - , 290 - , 291 - , 292 - , 293 - , 294 - , 295 - , 296 - , 297 - , 298 - , 299 - , 300 - , 301 - , 302 - , 303 - , 304 - , 305 - , 306 - , 307 - , 308 - , 309 - , 310 - , 311 - , 312 - , 313 - , 314 - , 315 - , 316 - , 317 - , 318 - , 319 - , 320 - , 321 - , 322 - , 323 - , 324 - , 325 - , 326 - , 327 - , 328 - , 329 - , 330 - , 331 - , 332 - , 333 - , 334 - , 335 - , 336 - , 337 - , 338 - , 339 - , 340 - , 341 - , 342 - , 343 - , 344 - , 345 - , 346 - , 347 - , 348 - , 349 - , 350 - , 351 - , 352 - , 353 - , 354 - , 355 - , 356 - , 357 - , 358 - , 359 - , 360 - , 361 - , 362 - , 363 - , 364 - , 365 - , 366 - , 367 - , 368 - , 369 - , 370 - , 371 - , 372 - , 373 - , 374 - , 375 - , 376 - , 377 - , 378 - , 379 - , 380 - , 381 - , 382 - , 383 - , 384 - , 385 - , 386 - , 387 - , 388 - , 389 - , 390 - , 391 - , 392 - , 393 - , 394 - , 395 - , 396 - , 397 - , 398 - , 399 - , 400 - , 401 - , 402 - , 403 - , 404 - , 405 - , 406 - , 407 - , 408 - , 409 - , 410 - , 411 - , 412 - , 413 - , 414 - , 415 - , 416 - , 417 - , 418 - , 419 - , 420 - , 421 - , 422 - , 423 - , 424 - , 425 - , 426 - , 427 - , 428 - , 429 - , 430 - , 431 - , 432 - , 433 - , 434 - , 435 - , 436 - , 437 - , 438 - , 439 - , 440 - , 441 - , 442 - , 443 - , 444 - , 445 - , 446 - , 447 - , 448 - , 449 - , 450 - , 451 - , 452 - , 453 - , 454 - , 455 - , 456 - , 457 - , 458 - , 459 - , 460 - , 461 - , 462 - , 463 - , 464 - , 465 - , 466 - , 467 - , 468 - , 469 - , 470 - , 471 - , 472 - , 473 - , 474 - , 475 - , 476 - , 477 - , 478 - , 479 - , 480 - , 481 - , 482 - , 483 - , 484 - , 485 - , 486 - , 487 - , 488 - , 489 - , 490 - , 491 - , 492 - , 493 - , 494 - , 495 - , 496 - , 497 - , 498 - , 499 - , 500 - , 501 - , 502 - , 503 - , 504 - , 505 - , 506 - , 507 - , 508 - , 509 - , 510 - , 511 - , 512 - , 513 - , 514 - , 515 - , 516 - , 517 - , 518 - , 519 - , 520 - , 521 - , 522 - , 523 - , 524 - , 525 - , 526 - , 527 - , 528 - , 529 - , 530 - , 531 - , 532 - , 533 - , 534 - , 535 - , 536 - , 537 - , 538 - , 539 - , 540 - , 541 - , 542 - , 543 - , 544 - , 545 - , 546 - , 547 - , 548 - , 549 - , 550 - , 551 - , 552 - , 553 - , 554 - , 555 - , 556 - , 557 - , 558 - , 559 - , 560 - , 561 - , 562 - , 563 - , 564 - , 565 - , 566 - , 567 - , 568 - , 569 - , 570 - , 571 - , 572 - , 573 - , 574 - , 575 - , 576 - , 577 - , 578 - , 579 - , 580 - , 581 - , 582 - , 583 - , 584 - , 585 - , 586 - , 587 - , 588 - , 589 - , 590 - , 591 - , 592 - , 593 - , 594 - , 595 - , 596 - , 597 - , 598 - , 599 - , 600 - , 601 - , 602 - , 603 - , 604 - , 605 - , 606 - , 607 - , 608 - , 609 - , 610 - , 611 - , 612 - , 613 - , 614 - , 615 - , 616 - , 617 - , 618 - , 619 - , 620 - , 621 - , 622 - , 623 - , 624 - , 625 - , 626 - , 627 - , 628 - , 629 - , 630 - , 631 - , 632 - , 633 - , 634 - , 635 - , 636 - , 637 - , 638 - , 639 - , 640 - , 641 - , 642 - , 643 - , 644 - , 645 - , 646 - , 647 - , 648 - , 649 - , 650 - , 651 - , 652 - , 653 - , 654 - , 655 - , 656 - , 657 - , 658 - , 659 - , 660 - , 661 - , 662 - , 663 - , 664 - , 665 - , 666 - , 667 - , 668 - , 669 - , 670 - , 671 - , 672 - , 673 - , 674 - , 675 - , 676 - , 677 - , 678 - , 679 - , 680 - , 681 - , 682 - , 683 - , 684 - , 685 - , 686 - , 687 - , 688 - , 689 - , 690 - , 691 - , 692 - , 693 - , 694 - , 695 - , 696 - , 697 - , 698 - , 699 - , 700 - , 701 - , 702 - , 703 - , 704 - , 705 - , 706 - , 707 - , 708 - , 709 - , 710 - , 711 - , 712 - , 713 - , 714 - , 715 - , 716 - , 717 - , 718 - , 719 - , 720 - , 721 - , 722 - , 723 - , 724 - , 725 - , 726 - , 727 - , 728 - , 729 - , 730 - , 731 - , 732 - , 733 - , 734 - , 735 - , 736 - , 737 - , 738 - , 739 - , 740 - , 741 - , 742 - , 743 - , 744 - , 745 - , 746 - , 747 - , 748 - , 749 - , 750 - , 751 - , 752 - , 753 - , 754 - , 755 - , 756 - , 757 - , 758 - , 759 - , 760 - , 761 - , 762 - , 763 - , 764 - , 765 - , 766 - , 767 - , 768 - , 769 - , 770 - , 771 - , 772 - , 773 - , 774 - , 775 - , 776 - , 777 - , 778 - , 779 - , 780 - , 781 - , 782 - , 783 - , 784 - , 785 - , 786 - , 787 - , 788 - , 789 - , 790 - , 791 - , 792 - , 793 - , 794 - , 795 - , 796 - , 797 - , 798 - , 799 - , 800 - , 801 - , 802 - , 803 - , 804 - , 805 - , 806 - , 807 - , 808 - , 809 - , 810 - , 811 - , 812 - , 813 - , 814 - , 815 - , 816 - , 817 - , 818 - , 819 - , 820 - , 821 - , 822 - , 823 - , 824 - , 825 - , 826 - , 827 - , 828 - , 829 - , 830 - , 831 - , 832 - , 833 - , 834 - , 835 - , 836 - , 837 - , 838 - , 839 - , 840 - , 841 - , 842 - , 843 - , 844 - , 845 - , 846 - , 847 - , 848 - , 849 - , 850 - , 851 - , 852 - , 853 - , 854 - , 855 - , 856 - , 857 - , 858 - , 859 - , 860 - , 861 - , 862 - , 863 - , 864 - , 865 - , 866 - , 867 - , 868 - , 869 - , 870 - , 871 - , 872 - , 873 - , 874 - , 875 - , 876 - , 877 - , 878 - , 879 - , 880 - , 881 - , 882 - , 883 - , 884 - , 885 - , 886 - , 887 - , 888 - , 889 - , 890 - , 891 - , 892 - , 893 - , 894 - , 895 - , 896 - , 897 - , 898 - , 899 - , 900 - , 901 - , 902 - , 903 - , 904 - , 905 - , 906 - , 907 - , 908 - , 909 - , 910 - , 911 - , 912 - , 913 - , 914 - , 915 - , 916 - , 917 - , 918 - , 919 - , 920 - , 921 - , 922 - , 923 - , 924 - , 925 - , 926 - , 927 - , 928 - , 929 - , 930 - , 931 - , 932 - , 933 - , 934 - , 935 - , 936 - , 937 - , 938 - , 939 - , 940 - , 941 - , 942 - , 943 - , 944 - , 945 - , 946 - , 947 - , 948 - , 949 - , 950 - , 951 - , 952 - , 953 - , 954 - , 955 - , 956 - , 957 - , 958 - , 959 - , 960 - , 961 - , 962 - , 963 - , 964 - , 965 - , 966 - , 967 - , 968 - , 969 - , 970 - , 971 - , 972 - , 973 - , 974 - , 975 - , 976 - , 977 - , 978 - , 979 - , 980 - , 981 - , 982 - , 983 - , 984 - , 985 - , 986 - , 987 - , 988 - , 989 - , 990 - , 991 - , 992 - , 993 - , 994 - , 995 - , 996 - , 997 - , 998 - , 999 - , 1000 - , 1001 - , 1002 - , 1003 - , 1004 - , 1005 - , 1006 - , 1007 - , 1008 - , 1009 - , 1010 - , 1011 - , 1012 - , 1013 - , 1014 - , 1015 - , 1016 - , 1017 - , 1018 - , 1019 - , 1020 - , 1021 - , 1022 - , 1023 - , 1024 - , 1025 - , 1026 - , 1027 - , 1028 - , 1029 - , 1030 - , 1031 - , 1032 - , 1033 - , 1034 - , 1035 - , 1036 - , 1037 - , 1038 - , 1039 - , 1040 - , 1041 - , 1042 - , 1043 - , 1044 - , 1045 - , 1046 - , 1047 - , 1048 - , 1049 - , 1050 - , 1051 - , 1052 - , 1053 - , 1054 - , 1055 - , 1056 - , 1057 - , 1058 - , 1059 - , 1060 - , 1061 - , 1062 - , 1063 - , 1064 - , 1065 - , 1066 - , 1067 - , 1068 - , 1069 - , 1070 - , 1071 - , 1072 - , 1073 - , 1074 - , 1075 - , 1076 - , 1077 - , 1078 - , 1079 - , 1080 - , 1081 - , 1082 - , 1083 - , 1084 - , 1085 - , 1086 - , 1087 - , 1088 - , 1089 - , 1090 - , 1091 - , 1092 - , 1093 - , 1094 - , 1095 - , 1096 - , 1097 - , 1098 - , 1099 - , 1100 - , 1101 - , 1102 - , 1103 - , 1104 - , 1105 - , 1106 - , 1107 - , 1108 - , 1109 - , 1110 - , 1111 - , 1112 - , 1113 - , 1114 - , 1115 - , 1116 - , 1117 - , 1118 - , 1119 - , 1120 - , 1121 - , 1122 - , 1123 - , 1124 - , 1125 - , 1126 - , 1127 - , 1128 - , 1129 - , 1130 - , 1131 - , 1132 - , 1133 - , 1134 - , 1135 - , 1136 - , 1137 - , 1138 - , 1139 - , 1140 - , 1141 - , 1142 - , 1143 - , 1144 - , 1145 - , 1146 - , 1147 - , 1148 - , 1149 - , 1150 - , 1151 - , 1152 - , 1153 - , 1154 - , 1155 - , 1156 - , 1157 - , 1158 - , 1159 - , 1160 - , 1161 - , 1162 - , 1163 - , 1164 - , 1165 - , 1166 - , 1167 - , 1168 - , 1169 - , 1170 - , 1171 - , 1172 - , 1173 - , 1174 - , 1175 - , 1176 - , 1177 - , 1178 - , 1179 - , 1180 - , 1181 - , 1182 - , 1183 - , 1184 - , 1185 - , 1186 - , 1187 - , 1188 - , 1189 - , 1190 - , 1191 - , 1192 - , 1193 - , 1194 - , 1195 - , 1196 - , 1197 - , 1198 - , 1199 - , 1200 - , 1201 - , 1202 - , 1203 - , 1204 - , 1205 - , 1206 - , 1207 - , 1208 - , 1209 - , 1210 - , 1211 - , 1212 - , 1213 - , 1214 - , 1215 - , 1216 - , 1217 - , 1218 - , 1219 - , 1220 - , 1221 - , 1222 - , 1223 - , 1224 - , 1225 - , 1226 - , 1227 - , 1228 - , 1229 - , 1230 - , 1231 - , 1232 - , 1233 - , 1234 - , 1235 - , 1236 - , 1237 - , 1238 - , 1239 - , 1240 - , 1241 - , 1242 - , 1243 - , 1244 - , 1245 - , 1246 - , 1247 - , 1248 - , 1249 - , 1250 - , 1251 - , 1252 - , 1253 - , 1254 - , 1255 - , 1256 - , 1257 - , 1258 - , 1259 - , 1260 - , 1261 - , 1262 - , 1263 - , 1264 - , 1265 - , 1266 - , 1267 - , 1268 - , 1269 - , 1270 - , 1271 - , 1272 - , 1273 - , 1274 - , 1275 - , 1276 - , 1277 - , 1278 - , 1279 - , 1280 - , 1281 - , 1282 - , 1283 - , 1284 - , 1285 - , 1286 - , 1287 - , 1288 - , 1289 - , 1290 - , 1291 - , 1292 - , 1293 - , 1294 - , 1295 - , 1296 - , 1297 - , 1298 - , 1299 - , 1300 - , 1301 - , 1302 - , 1303 - , 1304 - , 1305 - , 1306 - , 1307 - , 1308 - , 1309 - , 1310 - , 1311 - , 1312 - , 1313 - , 1314 - , 1315 - , 1316 - , 1317 - , 1318 - , 1319 - , 1320 - , 1321 - , 1322 - , 1323 - , 1324 - , 1325 - , 1326 - , 1327 - , 1328 - , 1329 - , 1330 - , 1331 - , 1332 - , 1333 - , 1334 - , 1335 - , 1336 - , 1337 - , 1338 - , 1339 - , 1340 - , 1341 - , 1342 - , 1343 - , 1344 - , 1345 - , 1346 - , 1347 - , 1348 - , 1349 - , 1350 - , 1351 - , 1352 - , 1353 - , 1354 - , 1355 - , 1356 - , 1357 - , 1358 - , 1359 - , 1360 - , 1361 - , 1362 - , 1363 - , 1364 - , 1365 - , 1366 - , 1367 - , 1368 - , 1369 - , 1370 - , 1371 - , 1372 - , 1373 - , 1374 - , 1375 - , 1376 - , 1377 - , 1378 - , 1379 - , 1380 - , 1381 - , 1382 - , 1383 - , 1384 - , 1385 - , 1386 - , 1387 - , 1388 - , 1389 - , 1390 - , 1391 - , 1392 - , 1393 - , 1394 - , 1395 - , 1396 - , 1397 - , 1398 - , 1399 - , 1400 - , 1401 - , 1402 - , 1403 - , 1404 - , 1405 - , 1406 - , 1407 - , 1408 - , 1409 - , 1410 - , 1411 - , 1412 - , 1413 - , 1414 - , 1415 - , 1416 - , 1417 - , 1418 - , 1419 - , 1420 - , 1421 - , 1422 - , 1423 - , 1424 - , 1425 - , 1426 - , 1427 - , 1428 - , 1429 - , 1430 - , 1431 - , 1432 - , 1433 - , 1434 - , 1435 - , 1436 - , 1437 - , 1438 - , 1439 - , 1440 - , 1441 - , 1442 - , 1443 - , 1444 - , 1445 - , 1446 - , 1447 - , 1448 - , 1449 - , 1450 - , 1451 - , 1452 - , 1453 - , 1454 - , 1455 - , 1456 - , 1457 - , 1458 - , 1459 - , 1460 - , 1461 - , 1462 - , 1463 - , 1464 - , 1465 - , 1466 - , 1467 - , 1468 - , 1469 - , 1470 - , 1471 - , 1472 - , 1473 - , 1474 - , 1475 - , 1476 - , 1477 - , 1478 - , 1479 - , 1480 - , 1481 - , 1482 - , 1483 - , 1484 - , 1485 - , 1486 - , 1487 - , 1488 - , 1489 - , 1490 - , 1491 - , 1492 - , 1493 - , 1494 - , 1495 - , 1496 - , 1497 - , 1498 - , 1499 - , 1500 - , 1501 - , 1502 - , 1503 - , 1504 - , 1505 - , 1506 - , 1507 - , 1508 - , 1509 - , 1510 - , 1511 - , 1512 - , 1513 - , 1514 - , 1515 - , 1516 - , 1517 - , 1518 - , 1519 - , 1520 - , 1521 - , 1522 - , 1523 - , 1524 - , 1525 - , 1526 - , 1527 - , 1528 - , 1529 - , 1530 - , 1531 - , 1532 - , 1533 - , 1534 - , 1535 - , 1536 - , 1537 - , 1538 - , 1539 - , 1540 - , 1541 - , 1542 - , 1543 - , 1544 - , 1545 - , 1546 - , 1547 - , 1548 - , 1549 - , 1550 - , 1551 - , 1552 - , 1553 - , 1554 - , 1555 - , 1556 - , 1557 - , 1558 - , 1559 - , 1560 - , 1561 - , 1562 - , 1563 - , 1564 - , 1565 - , 1566 - , 1567 - , 1568 - , 1569 - , 1570 - , 1571 - , 1572 - , 1573 - , 1574 - , 1575 - , 1576 - , 1577 - , 1578 - , 1579 - , 1580 - , 1581 - , 1582 - , 1583 - , 1584 - , 1585 - , 1586 - , 1587 - , 1588 - , 1589 - , 1590 - , 1591 - , 1592 - , 1593 - , 1594 - , 1595 - , 1596 - , 1597 - , 1598 - , 1599 - , 1600 - , 1601 - , 1602 - , 1603 - , 1604 - , 1605 - , 1606 - , 1607 - , 1608 - , 1609 - , 1610 - , 1611 - , 1612 - , 1613 - , 1614 - , 1615 - , 1616 - , 1617 - , 1618 - , 1619 - , 1620 - , 1621 - , 1622 - , 1623 - , 1624 - , 1625 - , 1626 - , 1627 - , 1628 - , 1629 - , 1630 - , 1631 - , 1632 - , 1633 - , 1634 - , 1635 - , 1636 - , 1637 - , 1638 - , 1639 - , 1640 - , 1641 - , 1642 - , 1643 - , 1644 - , 1645 - , 1646 - , 1647 - , 1648 - , 1649 - , 1650 - , 1651 - , 1652 - , 1653 - , 1654 - , 1655 - , 1656 - , 1657 - , 1658 - , 1659 - , 1660 - , 1661 - , 1662 - , 1663 - , 1664 - , 1665 - , 1666 - , 1667 - , 1668 - , 1669 - , 1670 - , 1671 - , 1672 - , 1673 - , 1674 - , 1675 - , 1676 - , 1677 - , 1678 - , 1679 - , 1680 - , 1681 - , 1682 - , 1683 - , 1684 - , 1685 - , 1686 - , 1687 - , 1688 - , 1689 - , 1690 - , 1691 - , 1692 - , 1693 - , 1694 - , 1695 - , 1696 - , 1697 - , 1698 - , 1699 - , 1700 - , 1701 - , 1702 - , 1703 - , 1704 - , 1705 - , 1706 - , 1707 - , 1708 - , 1709 - , 1710 - , 1711 - , 1712 - , 1713 - , 1714 - , 1715 - , 1716 - , 1717 - , 1718 - , 1719 - , 1720 - , 1721 - , 1722 - , 1723 - , 1724 - , 1725 - , 1726 - , 1727 - , 1728 - , 1729 - , 1730 - , 1731 - , 1732 - , 1733 - , 1734 - , 1735 - , 1736 - , 1737 - , 1738 - , 1739 - , 1740 - , 1741 - , 1742 - , 1743 - , 1744 - , 1745 - , 1746 - , 1747 - , 1748 - , 1749 - , 1750 - , 1751 - , 1752 - , 1753 - , 1754 - , 1755 - , 1756 - , 1757 - , 1758 - , 1759 - , 1760 - , 1761 - , 1762 - , 1763 - , 1764 - , 1765 - , 1766 - , 1767 - , 1768 - , 1769 - , 1770 - , 1771 - , 1772 - , 1773 - , 1774 - , 1775 - , 1776 - , 1777 - , 1778 - , 1779 - , 1780 - , 1781 - , 1782 - , 1783 - , 1784 - , 1785 - , 1786 - , 1787 - , 1788 - , 1789 - , 1790 - , 1791 - , 1792 - , 1793 - , 1794 - , 1795 - , 1796 - , 1797 - , 1798 - , 1799 - , 1800 - , 1801 - , 1802 - , 1803 - , 1804 - , 1805 - , 1806 - , 1807 - , 1808 - , 1809 - , 1810 - , 1811 - , 1812 - , 1813 - , 1814 - , 1815 - , 1816 - , 1817 - , 1818 - , 1819 - , 1820 - , 1821 - , 1822 - , 1823 - , 1824 - , 1825 - , 1826 - , 1827 - , 1828 - , 1829 - , 1830 - , 1831 - , 1832 - , 1833 - , 1834 - , 1835 - , 1836 - , 1837 - , 1838 - , 1839 - , 1840 - , 1841 - , 1842 - , 1843 - , 1844 - , 1845 - , 1846 - , 1847 - , 1848 - , 1849 - , 1850 - , 1851 - , 1852 - , 1853 - , 1854 - , 1855 - , 1856 - , 1857 - , 1858 - , 1859 - , 1860 - , 1861 - , 1862 - , 1863 - , 1864 - , 1865 - , 1866 - , 1867 - , 1868 - , 1869 - , 1870 - , 1871 - , 1872 - , 1873 - , 1874 - , 1875 - , 1876 - , 1877 - , 1878 - , 1879 - , 1880 - , 1881 - , 1882 - , 1883 - , 1884 - , 1885 - , 1886 - , 1887 - , 1888 - , 1889 - , 1890 - , 1891 - , 1892 - , 1893 - , 1894 - , 1895 - , 1896 - , 1897 - , 1898 - , 1899 - , 1900 - , 1901 - , 1902 - , 1903 - , 1904 - , 1905 - , 1906 - , 1907 - , 1908 - , 1909 - , 1910 - , 1911 - , 1912 - , 1913 - , 1914 - , 1915 - , 1916 - , 1917 - , 1918 - , 1919 - , 1920 - , 1921 - , 1922 - , 1923 - , 1924 - , 1925 - , 1926 - , 1927 - , 1928 - , 1929 - , 1930 - , 1931 - , 1932 - , 1933 - , 1934 - , 1935 - , 1936 - , 1937 - , 1938 - , 1939 - , 1940 - , 1941 - , 1942 - , 1943 - , 1944 - , 1945 - , 1946 - , 1947 - , 1948 - , 1949 - , 1950 - , 1951 - , 1952 - , 1953 - , 1954 - , 1955 - , 1956 - , 1957 - , 1958 - , 1959 - , 1960 - , 1961 - , 1962 - , 1963 - , 1964 - , 1965 - , 1966 - , 1967 - , 1968 - , 1969 - , 1970 - , 1971 - , 1972 - , 1973 - , 1974 - , 1975 - , 1976 - , 1977 - , 1978 - , 1979 - , 1980 - , 1981 - , 1982 - , 1983 - , 1984 - , 1985 - , 1986 - , 1987 - , 1988 - , 1989 - , 1990 - , 1991 - , 1992 - , 1993 - , 1994 - , 1995 - , 1996 - , 1997 - , 1998 - , 1999 + [ +1 + , +2 + , +3 + , +4 + , +5 + , +6 + , +7 + , +8 + , +9 + , +10 + , +11 + , +12 + , +13 + , +14 + , +15 + , +16 + , +17 + , +18 + , +19 + , +20 + , +21 + , +22 + , +23 + , +24 + , +25 + , +26 + , +27 + , +28 + , +29 + , +30 + , +31 + , +32 + , +33 + , +34 + , +35 + , +36 + , +37 + , +38 + , +39 + , +40 + , +41 + , +42 + , +43 + , +44 + , +45 + , +46 + , +47 + , +48 + , +49 + , +50 + , +51 + , +52 + , +53 + , +54 + , +55 + , +56 + , +57 + , +58 + , +59 + , +60 + , +61 + , +62 + , +63 + , +64 + , +65 + , +66 + , +67 + , +68 + , +69 + , +70 + , +71 + , +72 + , +73 + , +74 + , +75 + , +76 + , +77 + , +78 + , +79 + , +80 + , +81 + , +82 + , +83 + , +84 + , +85 + , +86 + , +87 + , +88 + , +89 + , +90 + , +91 + , +92 + , +93 + , +94 + , +95 + , +96 + , +97 + , +98 + , +99 + , +100 + , +101 + , +102 + , +103 + , +104 + , +105 + , +106 + , +107 + , +108 + , +109 + , +110 + , +111 + , +112 + , +113 + , +114 + , +115 + , +116 + , +117 + , +118 + , +119 + , +120 + , +121 + , +122 + , +123 + , +124 + , +125 + , +126 + , +127 + , +128 + , +129 + , +130 + , +131 + , +132 + , +133 + , +134 + , +135 + , +136 + , +137 + , +138 + , +139 + , +140 + , +141 + , +142 + , +143 + , +144 + , +145 + , +146 + , +147 + , +148 + , +149 + , +150 + , +151 + , +152 + , +153 + , +154 + , +155 + , +156 + , +157 + , +158 + , +159 + , +160 + , +161 + , +162 + , +163 + , +164 + , +165 + , +166 + , +167 + , +168 + , +169 + , +170 + , +171 + , +172 + , +173 + , +174 + , +175 + , +176 + , +177 + , +178 + , +179 + , +180 + , +181 + , +182 + , +183 + , +184 + , +185 + , +186 + , +187 + , +188 + , +189 + , +190 + , +191 + , +192 + , +193 + , +194 + , +195 + , +196 + , +197 + , +198 + , +199 + , +200 + , +201 + , +202 + , +203 + , +204 + , +205 + , +206 + , +207 + , +208 + , +209 + , +210 + , +211 + , +212 + , +213 + , +214 + , +215 + , +216 + , +217 + , +218 + , +219 + , +220 + , +221 + , +222 + , +223 + , +224 + , +225 + , +226 + , +227 + , +228 + , +229 + , +230 + , +231 + , +232 + , +233 + , +234 + , +235 + , +236 + , +237 + , +238 + , +239 + , +240 + , +241 + , +242 + , +243 + , +244 + , +245 + , +246 + , +247 + , +248 + , +249 + , +250 + , +251 + , +252 + , +253 + , +254 + , +255 + , +256 + , +257 + , +258 + , +259 + , +260 + , +261 + , +262 + , +263 + , +264 + , +265 + , +266 + , +267 + , +268 + , +269 + , +270 + , +271 + , +272 + , +273 + , +274 + , +275 + , +276 + , +277 + , +278 + , +279 + , +280 + , +281 + , +282 + , +283 + , +284 + , +285 + , +286 + , +287 + , +288 + , +289 + , +290 + , +291 + , +292 + , +293 + , +294 + , +295 + , +296 + , +297 + , +298 + , +299 + , +300 + , +301 + , +302 + , +303 + , +304 + , +305 + , +306 + , +307 + , +308 + , +309 + , +310 + , +311 + , +312 + , +313 + , +314 + , +315 + , +316 + , +317 + , +318 + , +319 + , +320 + , +321 + , +322 + , +323 + , +324 + , +325 + , +326 + , +327 + , +328 + , +329 + , +330 + , +331 + , +332 + , +333 + , +334 + , +335 + , +336 + , +337 + , +338 + , +339 + , +340 + , +341 + , +342 + , +343 + , +344 + , +345 + , +346 + , +347 + , +348 + , +349 + , +350 + , +351 + , +352 + , +353 + , +354 + , +355 + , +356 + , +357 + , +358 + , +359 + , +360 + , +361 + , +362 + , +363 + , +364 + , +365 + , +366 + , +367 + , +368 + , +369 + , +370 + , +371 + , +372 + , +373 + , +374 + , +375 + , +376 + , +377 + , +378 + , +379 + , +380 + , +381 + , +382 + , +383 + , +384 + , +385 + , +386 + , +387 + , +388 + , +389 + , +390 + , +391 + , +392 + , +393 + , +394 + , +395 + , +396 + , +397 + , +398 + , +399 + , +400 + , +401 + , +402 + , +403 + , +404 + , +405 + , +406 + , +407 + , +408 + , +409 + , +410 + , +411 + , +412 + , +413 + , +414 + , +415 + , +416 + , +417 + , +418 + , +419 + , +420 + , +421 + , +422 + , +423 + , +424 + , +425 + , +426 + , +427 + , +428 + , +429 + , +430 + , +431 + , +432 + , +433 + , +434 + , +435 + , +436 + , +437 + , +438 + , +439 + , +440 + , +441 + , +442 + , +443 + , +444 + , +445 + , +446 + , +447 + , +448 + , +449 + , +450 + , +451 + , +452 + , +453 + , +454 + , +455 + , +456 + , +457 + , +458 + , +459 + , +460 + , +461 + , +462 + , +463 + , +464 + , +465 + , +466 + , +467 + , +468 + , +469 + , +470 + , +471 + , +472 + , +473 + , +474 + , +475 + , +476 + , +477 + , +478 + , +479 + , +480 + , +481 + , +482 + , +483 + , +484 + , +485 + , +486 + , +487 + , +488 + , +489 + , +490 + , +491 + , +492 + , +493 + , +494 + , +495 + , +496 + , +497 + , +498 + , +499 + , +500 + , +501 + , +502 + , +503 + , +504 + , +505 + , +506 + , +507 + , +508 + , +509 + , +510 + , +511 + , +512 + , +513 + , +514 + , +515 + , +516 + , +517 + , +518 + , +519 + , +520 + , +521 + , +522 + , +523 + , +524 + , +525 + , +526 + , +527 + , +528 + , +529 + , +530 + , +531 + , +532 + , +533 + , +534 + , +535 + , +536 + , +537 + , +538 + , +539 + , +540 + , +541 + , +542 + , +543 + , +544 + , +545 + , +546 + , +547 + , +548 + , +549 + , +550 + , +551 + , +552 + , +553 + , +554 + , +555 + , +556 + , +557 + , +558 + , +559 + , +560 + , +561 + , +562 + , +563 + , +564 + , +565 + , +566 + , +567 + , +568 + , +569 + , +570 + , +571 + , +572 + , +573 + , +574 + , +575 + , +576 + , +577 + , +578 + , +579 + , +580 + , +581 + , +582 + , +583 + , +584 + , +585 + , +586 + , +587 + , +588 + , +589 + , +590 + , +591 + , +592 + , +593 + , +594 + , +595 + , +596 + , +597 + , +598 + , +599 + , +600 + , +601 + , +602 + , +603 + , +604 + , +605 + , +606 + , +607 + , +608 + , +609 + , +610 + , +611 + , +612 + , +613 + , +614 + , +615 + , +616 + , +617 + , +618 + , +619 + , +620 + , +621 + , +622 + , +623 + , +624 + , +625 + , +626 + , +627 + , +628 + , +629 + , +630 + , +631 + , +632 + , +633 + , +634 + , +635 + , +636 + , +637 + , +638 + , +639 + , +640 + , +641 + , +642 + , +643 + , +644 + , +645 + , +646 + , +647 + , +648 + , +649 + , +650 + , +651 + , +652 + , +653 + , +654 + , +655 + , +656 + , +657 + , +658 + , +659 + , +660 + , +661 + , +662 + , +663 + , +664 + , +665 + , +666 + , +667 + , +668 + , +669 + , +670 + , +671 + , +672 + , +673 + , +674 + , +675 + , +676 + , +677 + , +678 + , +679 + , +680 + , +681 + , +682 + , +683 + , +684 + , +685 + , +686 + , +687 + , +688 + , +689 + , +690 + , +691 + , +692 + , +693 + , +694 + , +695 + , +696 + , +697 + , +698 + , +699 + , +700 + , +701 + , +702 + , +703 + , +704 + , +705 + , +706 + , +707 + , +708 + , +709 + , +710 + , +711 + , +712 + , +713 + , +714 + , +715 + , +716 + , +717 + , +718 + , +719 + , +720 + , +721 + , +722 + , +723 + , +724 + , +725 + , +726 + , +727 + , +728 + , +729 + , +730 + , +731 + , +732 + , +733 + , +734 + , +735 + , +736 + , +737 + , +738 + , +739 + , +740 + , +741 + , +742 + , +743 + , +744 + , +745 + , +746 + , +747 + , +748 + , +749 + , +750 + , +751 + , +752 + , +753 + , +754 + , +755 + , +756 + , +757 + , +758 + , +759 + , +760 + , +761 + , +762 + , +763 + , +764 + , +765 + , +766 + , +767 + , +768 + , +769 + , +770 + , +771 + , +772 + , +773 + , +774 + , +775 + , +776 + , +777 + , +778 + , +779 + , +780 + , +781 + , +782 + , +783 + , +784 + , +785 + , +786 + , +787 + , +788 + , +789 + , +790 + , +791 + , +792 + , +793 + , +794 + , +795 + , +796 + , +797 + , +798 + , +799 + , +800 + , +801 + , +802 + , +803 + , +804 + , +805 + , +806 + , +807 + , +808 + , +809 + , +810 + , +811 + , +812 + , +813 + , +814 + , +815 + , +816 + , +817 + , +818 + , +819 + , +820 + , +821 + , +822 + , +823 + , +824 + , +825 + , +826 + , +827 + , +828 + , +829 + , +830 + , +831 + , +832 + , +833 + , +834 + , +835 + , +836 + , +837 + , +838 + , +839 + , +840 + , +841 + , +842 + , +843 + , +844 + , +845 + , +846 + , +847 + , +848 + , +849 + , +850 + , +851 + , +852 + , +853 + , +854 + , +855 + , +856 + , +857 + , +858 + , +859 + , +860 + , +861 + , +862 + , +863 + , +864 + , +865 + , +866 + , +867 + , +868 + , +869 + , +870 + , +871 + , +872 + , +873 + , +874 + , +875 + , +876 + , +877 + , +878 + , +879 + , +880 + , +881 + , +882 + , +883 + , +884 + , +885 + , +886 + , +887 + , +888 + , +889 + , +890 + , +891 + , +892 + , +893 + , +894 + , +895 + , +896 + , +897 + , +898 + , +899 + , +900 + , +901 + , +902 + , +903 + , +904 + , +905 + , +906 + , +907 + , +908 + , +909 + , +910 + , +911 + , +912 + , +913 + , +914 + , +915 + , +916 + , +917 + , +918 + , +919 + , +920 + , +921 + , +922 + , +923 + , +924 + , +925 + , +926 + , +927 + , +928 + , +929 + , +930 + , +931 + , +932 + , +933 + , +934 + , +935 + , +936 + , +937 + , +938 + , +939 + , +940 + , +941 + , +942 + , +943 + , +944 + , +945 + , +946 + , +947 + , +948 + , +949 + , +950 + , +951 + , +952 + , +953 + , +954 + , +955 + , +956 + , +957 + , +958 + , +959 + , +960 + , +961 + , +962 + , +963 + , +964 + , +965 + , +966 + , +967 + , +968 + , +969 + , +970 + , +971 + , +972 + , +973 + , +974 + , +975 + , +976 + , +977 + , +978 + , +979 + , +980 + , +981 + , +982 + , +983 + , +984 + , +985 + , +986 + , +987 + , +988 + , +989 + , +990 + , +991 + , +992 + , +993 + , +994 + , +995 + , +996 + , +997 + , +998 + , +999 + , +1000 + , +1001 + , +1002 + , +1003 + , +1004 + , +1005 + , +1006 + , +1007 + , +1008 + , +1009 + , +1010 + , +1011 + , +1012 + , +1013 + , +1014 + , +1015 + , +1016 + , +1017 + , +1018 + , +1019 + , +1020 + , +1021 + , +1022 + , +1023 + , +1024 + , +1025 + , +1026 + , +1027 + , +1028 + , +1029 + , +1030 + , +1031 + , +1032 + , +1033 + , +1034 + , +1035 + , +1036 + , +1037 + , +1038 + , +1039 + , +1040 + , +1041 + , +1042 + , +1043 + , +1044 + , +1045 + , +1046 + , +1047 + , +1048 + , +1049 + , +1050 + , +1051 + , +1052 + , +1053 + , +1054 + , +1055 + , +1056 + , +1057 + , +1058 + , +1059 + , +1060 + , +1061 + , +1062 + , +1063 + , +1064 + , +1065 + , +1066 + , +1067 + , +1068 + , +1069 + , +1070 + , +1071 + , +1072 + , +1073 + , +1074 + , +1075 + , +1076 + , +1077 + , +1078 + , +1079 + , +1080 + , +1081 + , +1082 + , +1083 + , +1084 + , +1085 + , +1086 + , +1087 + , +1088 + , +1089 + , +1090 + , +1091 + , +1092 + , +1093 + , +1094 + , +1095 + , +1096 + , +1097 + , +1098 + , +1099 + , +1100 + , +1101 + , +1102 + , +1103 + , +1104 + , +1105 + , +1106 + , +1107 + , +1108 + , +1109 + , +1110 + , +1111 + , +1112 + , +1113 + , +1114 + , +1115 + , +1116 + , +1117 + , +1118 + , +1119 + , +1120 + , +1121 + , +1122 + , +1123 + , +1124 + , +1125 + , +1126 + , +1127 + , +1128 + , +1129 + , +1130 + , +1131 + , +1132 + , +1133 + , +1134 + , +1135 + , +1136 + , +1137 + , +1138 + , +1139 + , +1140 + , +1141 + , +1142 + , +1143 + , +1144 + , +1145 + , +1146 + , +1147 + , +1148 + , +1149 + , +1150 + , +1151 + , +1152 + , +1153 + , +1154 + , +1155 + , +1156 + , +1157 + , +1158 + , +1159 + , +1160 + , +1161 + , +1162 + , +1163 + , +1164 + , +1165 + , +1166 + , +1167 + , +1168 + , +1169 + , +1170 + , +1171 + , +1172 + , +1173 + , +1174 + , +1175 + , +1176 + , +1177 + , +1178 + , +1179 + , +1180 + , +1181 + , +1182 + , +1183 + , +1184 + , +1185 + , +1186 + , +1187 + , +1188 + , +1189 + , +1190 + , +1191 + , +1192 + , +1193 + , +1194 + , +1195 + , +1196 + , +1197 + , +1198 + , +1199 + , +1200 + , +1201 + , +1202 + , +1203 + , +1204 + , +1205 + , +1206 + , +1207 + , +1208 + , +1209 + , +1210 + , +1211 + , +1212 + , +1213 + , +1214 + , +1215 + , +1216 + , +1217 + , +1218 + , +1219 + , +1220 + , +1221 + , +1222 + , +1223 + , +1224 + , +1225 + , +1226 + , +1227 + , +1228 + , +1229 + , +1230 + , +1231 + , +1232 + , +1233 + , +1234 + , +1235 + , +1236 + , +1237 + , +1238 + , +1239 + , +1240 + , +1241 + , +1242 + , +1243 + , +1244 + , +1245 + , +1246 + , +1247 + , +1248 + , +1249 + , +1250 + , +1251 + , +1252 + , +1253 + , +1254 + , +1255 + , +1256 + , +1257 + , +1258 + , +1259 + , +1260 + , +1261 + , +1262 + , +1263 + , +1264 + , +1265 + , +1266 + , +1267 + , +1268 + , +1269 + , +1270 + , +1271 + , +1272 + , +1273 + , +1274 + , +1275 + , +1276 + , +1277 + , +1278 + , +1279 + , +1280 + , +1281 + , +1282 + , +1283 + , +1284 + , +1285 + , +1286 + , +1287 + , +1288 + , +1289 + , +1290 + , +1291 + , +1292 + , +1293 + , +1294 + , +1295 + , +1296 + , +1297 + , +1298 + , +1299 + , +1300 + , +1301 + , +1302 + , +1303 + , +1304 + , +1305 + , +1306 + , +1307 + , +1308 + , +1309 + , +1310 + , +1311 + , +1312 + , +1313 + , +1314 + , +1315 + , +1316 + , +1317 + , +1318 + , +1319 + , +1320 + , +1321 + , +1322 + , +1323 + , +1324 + , +1325 + , +1326 + , +1327 + , +1328 + , +1329 + , +1330 + , +1331 + , +1332 + , +1333 + , +1334 + , +1335 + , +1336 + , +1337 + , +1338 + , +1339 + , +1340 + , +1341 + , +1342 + , +1343 + , +1344 + , +1345 + , +1346 + , +1347 + , +1348 + , +1349 + , +1350 + , +1351 + , +1352 + , +1353 + , +1354 + , +1355 + , +1356 + , +1357 + , +1358 + , +1359 + , +1360 + , +1361 + , +1362 + , +1363 + , +1364 + , +1365 + , +1366 + , +1367 + , +1368 + , +1369 + , +1370 + , +1371 + , +1372 + , +1373 + , +1374 + , +1375 + , +1376 + , +1377 + , +1378 + , +1379 + , +1380 + , +1381 + , +1382 + , +1383 + , +1384 + , +1385 + , +1386 + , +1387 + , +1388 + , +1389 + , +1390 + , +1391 + , +1392 + , +1393 + , +1394 + , +1395 + , +1396 + , +1397 + , +1398 + , +1399 + , +1400 + , +1401 + , +1402 + , +1403 + , +1404 + , +1405 + , +1406 + , +1407 + , +1408 + , +1409 + , +1410 + , +1411 + , +1412 + , +1413 + , +1414 + , +1415 + , +1416 + , +1417 + , +1418 + , +1419 + , +1420 + , +1421 + , +1422 + , +1423 + , +1424 + , +1425 + , +1426 + , +1427 + , +1428 + , +1429 + , +1430 + , +1431 + , +1432 + , +1433 + , +1434 + , +1435 + , +1436 + , +1437 + , +1438 + , +1439 + , +1440 + , +1441 + , +1442 + , +1443 + , +1444 + , +1445 + , +1446 + , +1447 + , +1448 + , +1449 + , +1450 + , +1451 + , +1452 + , +1453 + , +1454 + , +1455 + , +1456 + , +1457 + , +1458 + , +1459 + , +1460 + , +1461 + , +1462 + , +1463 + , +1464 + , +1465 + , +1466 + , +1467 + , +1468 + , +1469 + , +1470 + , +1471 + , +1472 + , +1473 + , +1474 + , +1475 + , +1476 + , +1477 + , +1478 + , +1479 + , +1480 + , +1481 + , +1482 + , +1483 + , +1484 + , +1485 + , +1486 + , +1487 + , +1488 + , +1489 + , +1490 + , +1491 + , +1492 + , +1493 + , +1494 + , +1495 + , +1496 + , +1497 + , +1498 + , +1499 + , +1500 + , +1501 + , +1502 + , +1503 + , +1504 + , +1505 + , +1506 + , +1507 + , +1508 + , +1509 + , +1510 + , +1511 + , +1512 + , +1513 + , +1514 + , +1515 + , +1516 + , +1517 + , +1518 + , +1519 + , +1520 + , +1521 + , +1522 + , +1523 + , +1524 + , +1525 + , +1526 + , +1527 + , +1528 + , +1529 + , +1530 + , +1531 + , +1532 + , +1533 + , +1534 + , +1535 + , +1536 + , +1537 + , +1538 + , +1539 + , +1540 + , +1541 + , +1542 + , +1543 + , +1544 + , +1545 + , +1546 + , +1547 + , +1548 + , +1549 + , +1550 + , +1551 + , +1552 + , +1553 + , +1554 + , +1555 + , +1556 + , +1557 + , +1558 + , +1559 + , +1560 + , +1561 + , +1562 + , +1563 + , +1564 + , +1565 + , +1566 + , +1567 + , +1568 + , +1569 + , +1570 + , +1571 + , +1572 + , +1573 + , +1574 + , +1575 + , +1576 + , +1577 + , +1578 + , +1579 + , +1580 + , +1581 + , +1582 + , +1583 + , +1584 + , +1585 + , +1586 + , +1587 + , +1588 + , +1589 + , +1590 + , +1591 + , +1592 + , +1593 + , +1594 + , +1595 + , +1596 + , +1597 + , +1598 + , +1599 + , +1600 + , +1601 + , +1602 + , +1603 + , +1604 + , +1605 + , +1606 + , +1607 + , +1608 + , +1609 + , +1610 + , +1611 + , +1612 + , +1613 + , +1614 + , +1615 + , +1616 + , +1617 + , +1618 + , +1619 + , +1620 + , +1621 + , +1622 + , +1623 + , +1624 + , +1625 + , +1626 + , +1627 + , +1628 + , +1629 + , +1630 + , +1631 + , +1632 + , +1633 + , +1634 + , +1635 + , +1636 + , +1637 + , +1638 + , +1639 + , +1640 + , +1641 + , +1642 + , +1643 + , +1644 + , +1645 + , +1646 + , +1647 + , +1648 + , +1649 + , +1650 + , +1651 + , +1652 + , +1653 + , +1654 + , +1655 + , +1656 + , +1657 + , +1658 + , +1659 + , +1660 + , +1661 + , +1662 + , +1663 + , +1664 + , +1665 + , +1666 + , +1667 + , +1668 + , +1669 + , +1670 + , +1671 + , +1672 + , +1673 + , +1674 + , +1675 + , +1676 + , +1677 + , +1678 + , +1679 + , +1680 + , +1681 + , +1682 + , +1683 + , +1684 + , +1685 + , +1686 + , +1687 + , +1688 + , +1689 + , +1690 + , +1691 + , +1692 + , +1693 + , +1694 + , +1695 + , +1696 + , +1697 + , +1698 + , +1699 + , +1700 + , +1701 + , +1702 + , +1703 + , +1704 + , +1705 + , +1706 + , +1707 + , +1708 + , +1709 + , +1710 + , +1711 + , +1712 + , +1713 + , +1714 + , +1715 + , +1716 + , +1717 + , +1718 + , +1719 + , +1720 + , +1721 + , +1722 + , +1723 + , +1724 + , +1725 + , +1726 + , +1727 + , +1728 + , +1729 + , +1730 + , +1731 + , +1732 + , +1733 + , +1734 + , +1735 + , +1736 + , +1737 + , +1738 + , +1739 + , +1740 + , +1741 + , +1742 + , +1743 + , +1744 + , +1745 + , +1746 + , +1747 + , +1748 + , +1749 + , +1750 + , +1751 + , +1752 + , +1753 + , +1754 + , +1755 + , +1756 + , +1757 + , +1758 + , +1759 + , +1760 + , +1761 + , +1762 + , +1763 + , +1764 + , +1765 + , +1766 + , +1767 + , +1768 + , +1769 + , +1770 + , +1771 + , +1772 + , +1773 + , +1774 + , +1775 + , +1776 + , +1777 + , +1778 + , +1779 + , +1780 + , +1781 + , +1782 + , +1783 + , +1784 + , +1785 + , +1786 + , +1787 + , +1788 + , +1789 + , +1790 + , +1791 + , +1792 + , +1793 + , +1794 + , +1795 + , +1796 + , +1797 + , +1798 + , +1799 + , +1800 + , +1801 + , +1802 + , +1803 + , +1804 + , +1805 + , +1806 + , +1807 + , +1808 + , +1809 + , +1810 + , +1811 + , +1812 + , +1813 + , +1814 + , +1815 + , +1816 + , +1817 + , +1818 + , +1819 + , +1820 + , +1821 + , +1822 + , +1823 + , +1824 + , +1825 + , +1826 + , +1827 + , +1828 + , +1829 + , +1830 + , +1831 + , +1832 + , +1833 + , +1834 + , +1835 + , +1836 + , +1837 + , +1838 + , +1839 + , +1840 + , +1841 + , +1842 + , +1843 + , +1844 + , +1845 + , +1846 + , +1847 + , +1848 + , +1849 + , +1850 + , +1851 + , +1852 + , +1853 + , +1854 + , +1855 + , +1856 + , +1857 + , +1858 + , +1859 + , +1860 + , +1861 + , +1862 + , +1863 + , +1864 + , +1865 + , +1866 + , +1867 + , +1868 + , +1869 + , +1870 + , +1871 + , +1872 + , +1873 + , +1874 + , +1875 + , +1876 + , +1877 + , +1878 + , +1879 + , +1880 + , +1881 + , +1882 + , +1883 + , +1884 + , +1885 + , +1886 + , +1887 + , +1888 + , +1889 + , +1890 + , +1891 + , +1892 + , +1893 + , +1894 + , +1895 + , +1896 + , +1897 + , +1898 + , +1899 + , +1900 + , +1901 + , +1902 + , +1903 + , +1904 + , +1905 + , +1906 + , +1907 + , +1908 + , +1909 + , +1910 + , +1911 + , +1912 + , +1913 + , +1914 + , +1915 + , +1916 + , +1917 + , +1918 + , +1919 + , +1920 + , +1921 + , +1922 + , +1923 + , +1924 + , +1925 + , +1926 + , +1927 + , +1928 + , +1929 + , +1930 + , +1931 + , +1932 + , +1933 + , +1934 + , +1935 + , +1936 + , +1937 + , +1938 + , +1939 + , +1940 + , +1941 + , +1942 + , +1943 + , +1944 + , +1945 + , +1946 + , +1947 + , +1948 + , +1949 + , +1950 + , +1951 + , +1952 + , +1953 + , +1954 + , +1955 + , +1956 + , +1957 + , +1958 + , +1959 + , +1960 + , +1961 + , +1962 + , +1963 + , +1964 + , +1965 + , +1966 + , +1967 + , +1968 + , +1969 + , +1970 + , +1971 + , +1972 + , +1973 + , +1974 + , +1975 + , +1976 + , +1977 + , +1978 + , +1979 + , +1980 + , +1981 + , +1982 + , +1983 + , +1984 + , +1985 + , +1986 + , +1987 + , +1988 + , +1989 + , +1990 + , +1991 + , +1992 + , +1993 + , +1994 + , +1995 + , +1996 + , +1997 + , +1998 + , +1999 , 2000 ] diff --git a/unison-src/transcripts/io.output.md b/unison-src/transcripts/io.output.md index 77c84aea6b..7cf1e4f95b 100644 --- a/unison-src/transcripts/io.output.md +++ b/unison-src/transcripts/io.output.md @@ -156,564 +156,37 @@ scratch/main> io.test testOpenClose New test results: 1. testOpenClose ◉ file should be open - ◉ file handle buffering should match what we just set. ◉ file should be closed ◉ bytes have been written ◉ bytes have been written ◉ file should be closed - ✅ 6 test(s) passing + 2. testOpenClose ✗ file handle buffering should match what we just set. - Tip: Use view 1 to view the source of a test. - -``` -### Reading files with getSomeBytes - -Tests: - - - getSomeBytes - - putBytes - - isFileOpen - - seekHandle - -``` unison -testGetSomeBytes : '{io2.IO} [Result] -testGetSomeBytes _ = - test = 'let - tempDir = (newTempDir "getSomeBytes") - fooFile = tempDir ++ "/foo" - - testData = "0123456789" - testSize = size testData - - chunkSize = 7 - check "chunk size splits data into 2 uneven sides" ((chunkSize > (testSize / 2)) && (chunkSize < testSize)) - - - -- write testData to a temporary file - fooWrite = openFile fooFile Write - putBytes fooWrite (toUtf8 testData) - closeFile fooWrite - check "file should be closed" (not (isFileOpen fooWrite)) - - -- reopen for reading back the data in chunks - fooRead = openFile fooFile Read - - -- read first part of file - chunk1 = getSomeBytes fooRead chunkSize |> fromUtf8 - check "first chunk matches first part of testData" (chunk1 == take chunkSize testData) - - -- read rest of file - chunk2 = getSomeBytes fooRead chunkSize |> fromUtf8 - check "second chunk matches rest of testData" (chunk2 == drop chunkSize testData) - - check "should be at end of file" (isFileEOF fooRead) - - readAtEOF = getSomeBytes fooRead chunkSize - check "reading at end of file results in Bytes.empty" (readAtEOF == Bytes.empty) - - -- request many bytes from the start of the file - seekHandle fooRead AbsoluteSeek +0 - bigRead = getSomeBytes fooRead (testSize * 999) |> fromUtf8 - check "requesting many bytes results in what's available" (bigRead == testData) - - closeFile fooRead - check "file should be closed" (not (isFileOpen fooRead)) - - runTest test -``` - -``` 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`: - - testGetSomeBytes : '{IO} [Result] - -``` -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testGetSomeBytes : '{IO} [Result] - -scratch/main> io.test testGetSomeBytes - - New test results: - - 1. testGetSomeBytes ◉ chunk size splits data into 2 uneven sides - ◉ file should be closed - ◉ first chunk matches first part of testData - ◉ second chunk matches rest of testData - ◉ should be at end of file - ◉ reading at end of file results in Bytes.empty - ◉ requesting many bytes results in what's available - ◉ file should be closed - - ✅ 8 test(s) passing - - Tip: Use view 1 to view the source of a test. - -``` -### Seeking in open files - -Tests: - - - openFile - - putBytes - - closeFile - - isSeekable - - isFileEOF - - seekHandle - - getBytes - - getLine - -``` unison -testSeek : '{io2.IO} [Result] -testSeek _ = - test = 'let - tempDir = newTempDir "seek" - emit (Ok "seeked") - fooFile = tempDir ++ "/foo" - handle1 = openFile fooFile FileMode.Append - putBytes handle1 (toUtf8 "12345678") - closeFile handle1 - - handle3 = openFile fooFile FileMode.Read - check "readable file should be seekable" (isSeekable handle3) - check "shouldn't be the EOF" (not (isFileEOF handle3)) - expectU "we should be at position 0" 0 (handlePosition handle3) - - seekHandle handle3 AbsoluteSeek +1 - expectU "we should be at position 1" 1 (handlePosition handle3) - bytes3a = getBytes handle3 1000 - text3a = Text.fromUtf8 bytes3a - expectU "should be able to read our temporary file after seeking" "2345678" text3a - closeFile handle3 - - barFile = tempDir ++ "/bar" - handle4 = openFile barFile FileMode.Append - putBytes handle4 (toUtf8 "foobar\n") - closeFile handle4 - - handle5 = openFile barFile FileMode.Read - expectU "getLine should get a line" "foobar" (getLine handle5) - closeFile handle5 - - runTest test - -testAppend : '{io2.IO} [Result] -testAppend _ = - test = 'let - tempDir = newTempDir "openFile" - fooFile = tempDir ++ "/foo" - handle1 = openFile fooFile FileMode.Write - putBytes handle1 (toUtf8 "test1") - closeFile handle1 - - handle2 = openFile fooFile FileMode.Append - putBytes handle2 (toUtf8 "test2") - closeFile handle2 - - handle3 = openFile fooFile FileMode.Read - bytes3 = getBytes handle3 1000 - text3 = Text.fromUtf8 bytes3 - - expectU "should be able to read our temporary file" "test1test2" text3 - - closeFile handle3 - - runTest test -``` - -``` 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`: - - testAppend : '{IO} [Result] - testSeek : '{IO} [Result] - -``` -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testAppend : '{IO} [Result] - testSeek : '{IO} [Result] - -scratch/main> io.test testSeek - - New test results: - - 1. testSeek ◉ seeked - ◉ readable file should be seekable - ◉ shouldn't be the EOF - ◉ we should be at position 0 - ◉ we should be at position 1 - ◉ should be able to read our temporary file after seeking - ◉ getLine should get a line - - ✅ 7 test(s) passing - - Tip: Use view 1 to view the source of a test. - -scratch/main> io.test testAppend - - New test results: - - 1. testAppend ◉ should be able to read our temporary file - - ✅ 1 test(s) passing + 🚫 1 test(s) failing, ✅ 5 test(s) passing Tip: Use view 1 to view the source of a test. ``` -### SystemTime -``` unison -testSystemTime : '{io2.IO} [Result] -testSystemTime _ = - test = 'let - t = !systemTime - check "systemTime should be sane" ((t > 1600000000) && (t < 2000000000)) - runTest test -``` -``` ucm +🛑 - Loading changes detected in scratch.u. +The transcript failed due to an error in the stanza above. The error is: - 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`: - - testSystemTime : '{IO} [Result] - -``` -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testSystemTime : '{IO} [Result] - -scratch/main> io.test testSystemTime New test results: - 1. testSystemTime ◉ systemTime should be sane - - ✅ 1 test(s) passing - - Tip: Use view 1 to view the source of a test. - -``` -### Get temp directory - -``` unison -testGetTempDirectory : '{io2.IO} [Result] -testGetTempDirectory _ = - test = 'let - tempDir = reraise !getTempDirectory.impl - check "Temp directory is directory" (isDirectory tempDir) - check "Temp directory should exist" (fileExists tempDir) - runTest test -``` - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testGetTempDirectory : '{IO} [Result] - -scratch/main> io.test testGetTempDirectory - - New test results: - - 1. testGetTempDirectory ◉ Temp directory is directory - ◉ Temp directory should exist - - ✅ 2 test(s) passing - - Tip: Use view 1 to view the source of a test. - -``` -### Get current directory - -``` unison -testGetCurrentDirectory : '{io2.IO} [Result] -testGetCurrentDirectory _ = - test = 'let - currentDir = reraise !getCurrentDirectory.impl - check "Current directory is directory" (isDirectory currentDir) - check "Current directory should exist" (fileExists currentDir) - runTest test -``` - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testGetCurrentDirectory : '{IO} [Result] - -scratch/main> io.test testGetCurrentDirectory - - New test results: - - 1. testGetCurrentDirectory ◉ Current directory is directory - ◉ Current directory should exist - - ✅ 2 test(s) passing - - Tip: Use view 1 to view the source of a test. - -``` -### Get directory contents - -``` unison -testDirContents : '{io2.IO} [Result] -testDirContents _ = - test = 'let - tempDir = newTempDir "dircontents" - c = reraise (directoryContents.impl tempDir) - check "directory size should be" (size c == 2) - check "directory contents should have current directory and parent" let - (c == [".", ".."]) || (c == ["..", "."]) - runTest test -``` - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testDirContents : '{IO} [Result] - -scratch/main> io.test testDirContents - - New test results: - - 1. testDirContents ◉ directory size should be - ◉ directory contents should have current directory and parent - - ✅ 2 test(s) passing - - Tip: Use view 1 to view the source of a test. - -``` -### Read environment variables - -``` unison -testGetEnv : '{io2.IO} [Result] -testGetEnv _ = - test = 'let - path = reraise (getEnv.impl "PATH") -- PATH exists on windows, mac and linux. - check "PATH environent variable should be set" (size path > 0) - match getEnv.impl "DOESNTEXIST" with - Right _ -> emit (Fail "env var shouldn't exist") - Left _ -> emit (Ok "DOESNTEXIST didn't exist") - runTest test -``` - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testGetEnv : '{IO} [Result] - -scratch/main> io.test testGetEnv - - New test results: - - 1. testGetEnv ◉ PATH environent variable should be set - ◉ DOESNTEXIST didn't exist - - ✅ 2 test(s) passing - - Tip: Use view 1 to view the source of a test. - -``` -### Read command line args - -`runMeWithNoArgs`, `runMeWithOneArg`, and `runMeWithTwoArgs` raise exceptions -unless they called with the right number of arguments. - -``` unison -testGetArgs.fail : Text -> Failure -testGetArgs.fail descr = Failure (typeLink IOFailure) descr !Any - -testGetArgs.runMeWithNoArgs : '{io2.IO, Exception} () -testGetArgs.runMeWithNoArgs = 'let - args = reraise !getArgs.impl - match args with - [] -> printLine "called with no args" - _ -> raise (testGetArgs.fail "called with args") - -testGetArgs.runMeWithOneArg : '{io2.IO, Exception} () -testGetArgs.runMeWithOneArg = 'let - args = reraise !getArgs.impl - match args with - [] -> raise (testGetArgs.fail "called with no args") - [_] -> printLine "called with one arg" - _ -> raise (testGetArgs.fail "called with too many args") - -testGetArgs.runMeWithTwoArgs : '{io2.IO, Exception} () -testGetArgs.runMeWithTwoArgs = 'let - args = reraise !getArgs.impl - match args with - [] -> raise (testGetArgs.fail "called with no args") - [_] -> raise (testGetArgs.fail "called with one arg") - [_, _] -> printLine "called with two args" - _ -> raise (testGetArgs.fail "called with too many args") -``` - -Test that they can be run with the right number of args. - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testGetArgs.fail : Text -> Failure - testGetArgs.runMeWithNoArgs : '{IO, Exception} () - testGetArgs.runMeWithOneArg : '{IO, Exception} () - testGetArgs.runMeWithTwoArgs : '{IO, Exception} () - -scratch/main> run runMeWithNoArgs - - () - -scratch/main> run runMeWithOneArg foo - - () - -scratch/main> run runMeWithTwoArgs foo bar - - () - -``` -Calling our examples with the wrong number of args will error. - -``` ucm -scratch/main> run runMeWithNoArgs foo - - 💔💥 - - The program halted with an unhandled exception: - - Failure (typeLink IOFailure) "called with args" (Any ()) - - Stack trace: - ##raise - -``` -``` ucm -scratch/main> run runMeWithOneArg - - 💔💥 - - The program halted with an unhandled exception: - - Failure (typeLink IOFailure) "called with no args" (Any ()) - - Stack trace: - ##raise - -``` -``` ucm -scratch/main> run runMeWithOneArg foo bar - - 💔💥 - - The program halted with an unhandled exception: - - Failure - (typeLink IOFailure) "called with too many args" (Any ()) - - Stack trace: - ##raise - -``` -``` ucm -scratch/main> run runMeWithTwoArgs - - 💔💥 - - The program halted with an unhandled exception: - - Failure (typeLink IOFailure) "called with no args" (Any ()) - - Stack trace: - ##raise - -``` -### Get the time zone - -``` unison -testTimeZone = do - (offset, summer, name) = Clock.internals.systemTimeZone +0 - _ = (offset : Int, summer : Nat, name : Text) - () -``` - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testTimeZone : '{IO} () - -scratch/main> run testTimeZone - - () - -``` -### Get some random bytes - -``` unison -testRandom : '{io2.IO} [Result] -testRandom = do - test = do - bytes = IO.randomBytes 10 - check "randomBytes returns the right number of bytes" (size bytes == 10) - runTest test -``` - -``` ucm -scratch/main> add - - ⍟ I've added these definitions: - - testRandom : '{IO} [Result] - -scratch/main> io.test testGetEnv - - New test results: + 1. testOpenClose ◉ file should be open + ◉ file should be closed + ◉ bytes have been written + ◉ bytes have been written + ◉ file should be closed - 1. testGetEnv ◉ PATH environent variable should be set - ◉ DOESNTEXIST didn't exist + 2. testOpenClose ✗ file handle buffering should match what we just set. - ✅ 2 test(s) passing + 🚫 1 test(s) failing, ✅ 5 test(s) passing Tip: Use view 1 to view the source of a test. -``` From 3394a5e872fb4c205f9364277facb49e7491298a Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 11:04:37 -0700 Subject: [PATCH 052/113] Add CAST instruction for runtime type coercion --- unison-runtime/src/Unison/Runtime/ANF.hs | 1 + unison-runtime/src/Unison/Runtime/Builtin.hs | 37 ++++++++++---------- unison-runtime/src/Unison/Runtime/MCode.hs | 2 ++ unison-runtime/src/Unison/Runtime/Machine.hs | 6 ++++ 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index e7d6d955d5..7d4421e603 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -1353,6 +1353,7 @@ data POp | TTON -- textToNat | TTOF -- textToFloat | FTOT -- floatToText + | CAST -- runtime type cast for unboxed values. | -- Concurrency FORK -- fork | -- Universal operations diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 030111c76d..51ca1e5a8f 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -193,6 +193,7 @@ import Unison.Util.Text (Text) import Unison.Util.Text qualified as Util.Text import Unison.Util.Text.Pattern qualified as TPat import Unison.Var +import qualified Unison.Runtime.TypeTags as TT type Failure = F.Failure Val @@ -321,7 +322,7 @@ binop0 n f = where xs@(x0 : y0 : _) = freshes (2 + n) -unop :: (Var v) => POp -> SuperNormal v +unop :: (Var v) => POp -> SuperNormal v unop pop = unop0 0 $ \[x] -> (TPrm pop [x]) @@ -334,7 +335,7 @@ binop pop = binop0 0 $ \[x, y] -> TPrm pop [x, y] -- | Lift a comparison op. -cmpop :: (Var v) => POp -> SuperNormal v +cmpop :: (Var v) => POp -> SuperNormal v cmpop pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [x, y]) $ @@ -348,14 +349,14 @@ cmpopb pop = boolift b -- | Like `cmpop`, but negates the result. -cmpopn :: (Var v) => POp -> SuperNormal v +cmpopn :: (Var v) => POp -> SuperNormal v cmpopn pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [x, y]) $ notlift b -- | Like `cmpop`, but swaps arguments then negates the result. -cmpopbn :: (Var v) => POp -> SuperNormal v +cmpopbn :: (Var v) => POp -> SuperNormal v cmpopbn pop = binop0 1 $ \[x, y, b] -> TLetD b UN (TPrm pop [y, x]) $ @@ -799,13 +800,13 @@ andb = binop0 0 $ \[p, q] -> TMatch p . flip (MatchData Ty.booleanRef) Nothing $ mapFromList [(0, ([], fls)), (1, ([], TVar q))] --- unsafeCoerce, used for numeric types where conversion is a --- no-op on the representation. Ideally this will be inlined and --- eliminated so that no instruction is necessary. -coerceType :: Reference -> Reference -> SuperNormal Symbol -coerceType _ri _ro = - -- TODO: Fix this with a proper type-coercion - unop0 0 $ \[x] -> TVar x +-- A runtime type-cast. Used to unsafely coerce between unboxed +-- types at runtime without changing their representation. +coerceType :: PackedTag -> SuperNormal Symbol +coerceType (PackedTag destType) = + unop0 1 $ \[v, tag] -> + TLetD tag UN (TLit $ N destType) + $ TPrm CAST [v, tag] -- unbox x0 ri x $ -- TCon ro 0 [x] @@ -1716,8 +1717,8 @@ builtinLookup = ("Int.<=", (Untracked, lei)), ("Int.>", (Untracked, gti)), ("Int.>=", (Untracked, gei)), - ("Int.fromRepresentation", (Untracked, coerceType Ty.natRef Ty.intRef)), - ("Int.toRepresentation", (Untracked, coerceType Ty.intRef Ty.natRef)), + ("Int.fromRepresentation", (Untracked, coerceType TT.intTag)), + ("Int.toRepresentation", (Untracked, coerceType TT.natTag)), ("Int.increment", (Untracked, inci)), ("Int.signum", (Untracked, sgni)), ("Int.negate", (Untracked, negi)), @@ -1761,7 +1762,7 @@ builtinLookup = ("Nat.complement", (Untracked, compln)), ("Nat.pow", (Untracked, pown)), ("Nat.drop", (Untracked, dropn)), - ("Nat.toInt", (Untracked, coerceType Ty.natRef Ty.intRef)), + ("Nat.toInt", (Untracked, coerceType TT.intTag)), ("Nat.toFloat", (Untracked, n2f)), ("Nat.toText", (Untracked, n2t)), ("Nat.fromText", (Untracked, t2n)), @@ -1774,8 +1775,8 @@ builtinLookup = ("Float.log", (Untracked, logf)), ("Float.logBase", (Untracked, logbf)), ("Float.sqrt", (Untracked, sqrtf)), - ("Float.fromRepresentation", (Untracked, coerceType Ty.natRef Ty.floatRef)), - ("Float.toRepresentation", (Untracked, coerceType Ty.floatRef Ty.natRef)), + ("Float.fromRepresentation", (Untracked, coerceType TT.floatTag)), + ("Float.toRepresentation", (Untracked, coerceType TT.natTag)), ("Float.min", (Untracked, minf)), ("Float.max", (Untracked, maxf)), ("Float.<", (Untracked, ltf)), @@ -1831,8 +1832,8 @@ builtinLookup = ("Debug.trace", (Tracked, gen'trace)), ("Debug.toText", (Tracked, debug'text)), ("unsafe.coerceAbilities", (Untracked, poly'coerce)), - ("Char.toNat", (Untracked, coerceType Ty.charRef Ty.natRef)), - ("Char.fromNat", (Untracked, coerceType Ty.natRef Ty.charRef)), + ("Char.toNat", (Untracked, coerceType TT.natTag)), + ("Char.fromNat", (Untracked, coerceType TT.charTag)), ("Bytes.empty", (Untracked, emptyb)), ("Bytes.fromList", (Untracked, packb)), ("Bytes.toList", (Untracked, unpackb)), diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index e13447d39e..aa6377b0c3 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -360,6 +360,7 @@ data UPrim2 | LOGB -- logBase | MAXF -- max | MINF -- min + | CAST -- unboxed runtime type cast (int to nat, etc.) deriving (Show, Eq, Ord) data BPrim1 @@ -1240,6 +1241,7 @@ emitPOp ANF.FTOT = emitBP1 FTOT emitPOp ANF.TTON = emitBP1 TTON emitPOp ANF.TTOI = emitBP1 TTOI emitPOp ANF.TTOF = emitBP1 TTOF +emitPOp ANF.CAST = emitP2 CAST -- text emitPOp ANF.CATT = emitBP2 CATT emitPOp ANF.TAKT = emitBP2 TAKT diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 57b37f4137..c7e64ac796 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1378,6 +1378,12 @@ uprim2 !stk XORN !i !j = do stk <- bump stk pokeN stk (xor x y) pure stk +uprim2 !stk CAST !ti !vi = do + newTypeTag <- peekOffN stk ti + v <- upeekOff stk vi + stk <- bump stk + poke stk $ UnboxedVal v (PackedTag newTypeTag) + pure stk {-# INLINE uprim2 #-} bprim1 :: From c57e7a903dcd0d49b11d77e49b0c3286ae2b11a1 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 11:27:44 -0700 Subject: [PATCH 053/113] Fix cast --- unison-runtime/src/Unison/Runtime/ANF/Serialize.hs | 1 + unison-runtime/src/Unison/Runtime/Machine.hs | 2 +- unison-runtime/src/Unison/Runtime/Serialize.hs | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs index fb1c53b9e4..4d46a0cdb8 100644 --- a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs @@ -648,6 +648,7 @@ pOpCode op = case op of IXOB -> 121 SDBL -> 122 SDBV -> 123 + CAST -> 124 pOpAssoc :: [(POp, Word16)] pOpAssoc = map (\op -> (op, pOpCode op)) [minBound .. maxBound] diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index c7e64ac796..fce1050979 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1378,7 +1378,7 @@ uprim2 !stk XORN !i !j = do stk <- bump stk pokeN stk (xor x y) pure stk -uprim2 !stk CAST !ti !vi = do +uprim2 !stk CAST !vi !ti = do newTypeTag <- peekOffN stk ti v <- upeekOff stk vi stk <- bump stk diff --git a/unison-runtime/src/Unison/Runtime/Serialize.hs b/unison-runtime/src/Unison/Runtime/Serialize.hs index b93dfd3fef..5cd5732226 100644 --- a/unison-runtime/src/Unison/Runtime/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/Serialize.hs @@ -397,6 +397,7 @@ instance Tag UPrim2 where tag2word LOGB = 31 tag2word MAXF = 32 tag2word MINF = 33 + tag2word CAST = 34 word2tag 0 = pure ADDI word2tag 1 = pure ADDN @@ -432,6 +433,7 @@ instance Tag UPrim2 where word2tag 31 = pure LOGB word2tag 32 = pure MAXF word2tag 33 = pure MINF + word2tag 34 = pure CAST word2tag n = unknownTag "UPrim2" n instance Tag BPrim1 where From 848c40631ab9aa6198059203383bef9f483ab42a Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 11:27:44 -0700 Subject: [PATCH 054/113] Fix Nat -> Word conversions --- unison-runtime/src/Unison/Runtime/Builtin.hs | 2 +- unison-runtime/src/Unison/Runtime/Machine.hs | 1 + unison-runtime/src/Unison/Runtime/Stack.hs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 51ca1e5a8f..359b3ee712 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -805,7 +805,7 @@ andb = binop0 0 $ \[p, q] -> coerceType :: PackedTag -> SuperNormal Symbol coerceType (PackedTag destType) = unop0 1 $ \[v, tag] -> - TLetD tag UN (TLit $ N destType) + TLetD tag UN (TLit $ I $ fromIntegral destType) $ TPrm CAST [v, tag] -- unbox x0 ri x $ diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index fce1050979..bca9092fa9 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1382,6 +1382,7 @@ uprim2 !stk CAST !vi !ti = do newTypeTag <- peekOffN stk ti v <- upeekOff stk vi stk <- bump stk + Debug.debugM Debug.Temp "CASTING" (v, newTypeTag) poke stk $ UnboxedVal v (PackedTag newTypeTag) pure stk {-# INLINE uprim2 #-} diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index a1a0d0fbc1..e9274f8160 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -336,7 +336,7 @@ matchNatVal = \case pattern NatVal :: Word64 -> Val pattern NatVal n <- (matchNatVal -> Just n) where - NatVal n = UnboxedVal (fromEnum n) TT.natTag + NatVal n = UnboxedVal (fromIntegral n) TT.natTag matchDoubleVal :: Val -> Maybe Double matchDoubleVal = \case From 82d466dadbbe42fe11fdbbe8a4112a0d7773892f Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 17:38:45 -0700 Subject: [PATCH 055/113] Debugging stack-arg issues --- unison-runtime/src/Unison/Runtime/Machine.hs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index bca9092fa9..2d1e822eeb 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -791,14 +791,22 @@ apply !env !denv !activeThreads !stk !k !ck !args !val = case comb of LamI a f entry | ck || a <= ac -> do + !_ <- pure $ debugger stk "apply-LamI-beforeEnsure" () stk <- ensure stk f + !_ <- pure $ debugger stk "apply-LamI-beforeMove" () stk <- moveArgs stk args + !_ <- pure $ debugger stk "apply-LamI-afterMove" () stk <- dumpSeg stk seg A + !_ <- pure $ debugger stk "apply-LamI-afterdumpSeg" () stk <- acceptArgs stk a + !_ <- pure $ debugger stk "apply-LamI-afteracceptArgs" () eval env denv activeThreads stk k combRef entry | otherwise -> do + !_ <- pure $ debugger stk "apply-LamIotherwise-beforeCloseArgs" () seg <- closeArgs C stk seg args + !_ <- pure $ debugger stk "apply-LamIotherwise-afterCloseArgs" () stk <- discardFrame =<< frameArgs stk + !_ <- pure $ debugger stk "apply-LamIotherwise-afterDiscardFrame" () stk <- bump stk bpoke stk $ PAp cix comb seg yield env denv activeThreads stk k @@ -887,7 +895,9 @@ moveArgs !stk (VArgR i l) = do stk <- prepareArgs stk (ArgR i l) pure stk moveArgs !stk (VArgN as) = do + !_ <- pure $ debugger stk "before prepareArgs" as stk <- prepareArgs stk (ArgN as) + !_ <- pure $ debugger stk "after prepareArgs" as pure stk moveArgs !stk (VArgV i) = do stk <- From 1657260381cba0d22b1c7321cd91b4eb54f3bb76 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 29 Oct 2024 12:27:28 -0700 Subject: [PATCH 056/113] Stack debugging: Add stack_check macros --- unison-runtime/package.yaml | 5 + unison-runtime/src/Unison/Runtime/Stack.hs | 142 ++++++++++++++++++--- unison-runtime/unison-runtime.cabal | 8 ++ 3 files changed, 137 insertions(+), 18 deletions(-) diff --git a/unison-runtime/package.yaml b/unison-runtime/package.yaml index a7526e5b07..6635be308d 100644 --- a/unison-runtime/package.yaml +++ b/unison-runtime/package.yaml @@ -11,12 +11,17 @@ flags: arraychecks: manual: true default: false + stackchecks: + manual: true + default: false when: - condition: flag(optimized) ghc-options: -funbox-strict-fields -O2 - condition: flag(arraychecks) cpp-options: -DARRAY_CHECK + - condition: flag(stackchecks) + cpp-options: -DSTACK_CHECK library: diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index e9274f8160..57bcd00ba2 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -1,3 +1,6 @@ +{-# LANGUAGE CPP #-} +{-# LANGUAGE ConstraintKinds #-} + module Unison.Runtime.Stack ( K (..), GClosure (..), @@ -121,6 +124,7 @@ where import Control.Monad.Primitive import Data.Char qualified as Char +import Data.Kind (Constraint) import Data.Primitive.ByteArray qualified as BA import Data.Word import GHC.Exts as L (IsList (..)) @@ -135,6 +139,40 @@ import Unison.Type qualified as Ty import Unison.Util.EnumContainers as EC import Prelude hiding (words) +{- ORMOLU_DISABLE -} +#ifdef STACK_CHECK +type DebugCallStack = (HasCallStack :: Constraint) + +unboxedSentinel :: Int +unboxedSentinel = -99 + +boxedSentinel :: Closure +boxedSentinel = (Closure GUnboxedSentinel) + +assertBumped :: HasCallStack => Stack -> Off -> IO () +assertBumped (Stack _ _ sp ustk bstk) i = do + u <- readByteArray ustk (sp - i) + b <- readArray bstk (sp - i) + when (u /= unboxedSentinel || b /= boxedSentinel) $ error $ "Expected stack slot to have been bumped, but it was:" <> show (Val u b) + +assertUnboxed :: HasCallStack => Stack -> Off -> IO () +assertUnboxed (Stack _ _ sp ustk bstk) i = do + (u :: Int) <- readByteArray ustk (sp - i) + b <- readArray bstk (sp - i) + case b of + UnboxedTypeTag _ -> pure () + _ -> error $ "Expected stack val to be unboxed, but it was:" <> show (Val u b) + +pokeSentinelOff :: Stack -> Off -> IO () +pokeSentinelOff (Stack _ _ sp ustk bstk) off = do + writeByteArray ustk (sp - off) unboxedSentinel + writeArray bstk (sp - off) boxedSentinel +#else +-- Don't track callstacks in production, it's expensive +type DebugCallStack = (() :: Constraint) +#endif +{- ORMOLU_ENABLE -} + newtype Callback = Hook (Stack -> IO ()) instance Eq Callback where _ == _ = True @@ -192,6 +230,7 @@ type USeq = Seq Val type IxClosure = GClosure CombIx +{- ORMOLU_DISABLE -} data GClosure comb = GPAp !CombIx @@ -209,7 +248,11 @@ data GClosure comb -- GHC will optimize nullary constructors into singletons. GUnboxedTypeTag !PackedTag | GBlackHole +#ifdef STACK_CHECK + | GUnboxedSentinel +#endif deriving stock (Show, Functor, Foldable, Traversable) +{- ORMOLU_ENABLE -} instance Eq (GClosure comb) where -- This is safe because the embedded CombIx will break disputes @@ -605,6 +648,7 @@ alloc = do pure $ Stack {ap = -1, fp = -1, sp = -1, ustk, bstk} {-# INLINE alloc #-} +{- ORMOLU_DISABLE -} peek :: Stack -> IO Val peek stk = do u <- upeek stk @@ -613,11 +657,19 @@ peek stk = do {-# INLINE peek #-} peekI :: Stack -> IO Int -peekI (Stack _ _ sp ustk _) = readByteArray ustk sp +peekI _stk@(Stack _ _ sp ustk _) = do +#ifdef STACK_CHECK + assertUnboxed _stk sp +#endif + readByteArray ustk sp {-# INLINE peekI #-} peekOffI :: Stack -> Off -> IO Int -peekOffI (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) +peekOffI _stk@(Stack _ _ sp ustk _) i = do +#ifdef STACK_CHECK + assertUnboxed _stk (sp - i) +#endif + readByteArray ustk (sp - i) {-# INLINE peekOffI #-} bpeek :: Stack -> IO BVal @@ -625,7 +677,11 @@ bpeek (Stack _ _ sp _ bstk) = readArray bstk sp {-# INLINE bpeek #-} upeek :: Stack -> IO UVal -upeek (Stack _ _ sp ustk _) = readByteArray ustk sp +upeek _stk@(Stack _ _ sp ustk _) = do +#ifdef STACK_CHECK + assertUnboxed _stk sp +#endif + readByteArray ustk sp {-# INLINE upeek #-} peekOff :: Stack -> Off -> IO Val @@ -640,7 +696,11 @@ bpeekOff (Stack _ _ sp _ bstk) i = readArray bstk (sp - i) {-# INLINE bpeekOff #-} upeekOff :: Stack -> Off -> IO UVal -upeekOff (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) +upeekOff _stk@(Stack _ _ sp ustk _) i = do +#ifdef STACK_CHECK + assertUnboxed _stk (sp - i) +#endif + readByteArray ustk (sp - i) {-# INLINE upeekOff #-} upokeT :: Stack -> UVal -> PackedTag -> IO () @@ -650,7 +710,10 @@ upokeT !stk@(Stack _ _ sp ustk _) !u !t = do {-# INLINE upokeT #-} poke :: Stack -> Val -> IO () -poke (Stack _ _ sp ustk bstk) (Val u b) = do +poke _stk@(Stack _ _ sp ustk bstk) (Val u b) = do +#ifdef STACK_CHECK + assertBumped _stk sp +#endif writeByteArray ustk sp u writeArray bstk sp b {-# INLINE poke #-} @@ -690,11 +753,15 @@ pokeBool stk b = -- | Store a boxed value. -- We don't bother nulling out the unboxed stack, -- it's extra work and there's nothing to garbage collect. -bpoke :: Stack -> BVal -> IO () -bpoke (Stack _ _ sp _ bstk) b = writeArray bstk sp b +bpoke :: DebugCallStack => Stack -> BVal -> IO () +bpoke _stk@(Stack _ _ sp _ustk bstk) b = do +#ifdef STACK_CHECK + assertBumped _stk sp +#endif + writeArray bstk sp b {-# INLINE bpoke #-} -pokeOff :: Stack -> Off -> Val -> IO () +pokeOff :: DebugCallStack => Stack -> Off -> Val -> IO () pokeOff stk i (Val u t) = do bpokeOff stk i t writeByteArray (ustk stk) (sp stk - i) u @@ -706,8 +773,12 @@ upokeOffT stk i u t = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOffT #-} -bpokeOff :: Stack -> Off -> BVal -> IO () -bpokeOff (Stack _ _ sp _ bstk) i b = writeArray bstk (sp - i) b +bpokeOff :: DebugCallStack => Stack -> Off -> BVal -> IO () +bpokeOff _stk@(Stack _ _ sp _ bstk) i b = do +#ifdef STACK_CHECK + assertBumped _stk (sp - i) +#endif + writeArray bstk (sp - i) b {-# INLINE bpokeOff #-} -- | Eats up arguments @@ -756,11 +827,22 @@ ensure stk@(Stack ap fp sp ustk bstk) sze {-# INLINE ensure #-} bump :: Stack -> IO Stack -bump (Stack ap fp sp ustk bstk) = pure $ Stack ap fp (sp + 1) ustk bstk +bump (Stack ap fp sp ustk bstk) = do + let stk' = Stack ap fp (sp + 1) ustk bstk +#ifdef STACK_CHECK + pokeSentinelOff stk' (sp + 1) +#endif + pure stk' {-# INLINE bump #-} bumpn :: Stack -> SZ -> IO Stack -bumpn (Stack ap fp sp ustk bstk) n = pure $ Stack ap fp (sp + n) ustk bstk +bumpn (Stack ap fp sp ustk bstk) n = do + let stk' = Stack ap fp (sp + n) ustk bstk +#ifdef STACK_CHECK + for_ [0..n-1] $ \i -> + pokeSentinelOff stk' i +#endif + pure stk' {-# INLINE bumpn #-} duplicate :: Stack -> IO Stack @@ -892,29 +974,53 @@ asize (Stack ap fp _ _ _) = fp - ap {-# INLINE asize #-} peekN :: Stack -> IO Word64 -peekN (Stack _ _ sp ustk _) = readByteArray ustk sp +peekN _stk@(Stack _ _ sp ustk _) = do +#ifdef STACK_CHECK + assertUnboxed _stk sp +#endif + readByteArray ustk sp {-# INLINE peekN #-} peekD :: Stack -> IO Double -peekD (Stack _ _ sp ustk _) = readByteArray ustk sp +peekD _stk@(Stack _ _ sp ustk _) = do +#ifdef STACK_CHECK + assertUnboxed _stk sp +#endif + readByteArray ustk sp {-# INLINE peekD #-} peekC :: Stack -> IO Char -peekC (Stack _ _ sp ustk _) = Char.chr <$> readByteArray ustk sp +peekC stk = do + Char.chr <$> peekI stk {-# INLINE peekC #-} peekOffN :: Stack -> Int -> IO Word64 -peekOffN (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) +peekOffN _stk@(Stack _ _ sp ustk _) i = do +#ifdef STACK_CHECK + + assertUnboxed _stk (sp - i) +#endif + readByteArray ustk (sp - i) {-# INLINE peekOffN #-} peekOffD :: Stack -> Int -> IO Double -peekOffD (Stack _ _ sp ustk _) i = readByteArray ustk (sp - i) +peekOffD _stk@(Stack _ _ sp ustk _) i = do +#ifdef STACK_CHECK + assertUnboxed _stk (sp - i) +#endif + readByteArray ustk (sp - i) {-# INLINE peekOffD #-} peekOffC :: Stack -> Int -> IO Char -peekOffC (Stack _ _ sp ustk _) i = Char.chr <$> readByteArray ustk (sp - i) +peekOffC _stk@(Stack _ _ sp ustk _) i = do +#ifdef STACK_CHECK + assertUnboxed _stk (sp - i) +#endif + Char.chr <$> readByteArray ustk (sp - i) {-# INLINE peekOffC #-} +{- ORMOLU_ENABLE -} + pokeN :: Stack -> Word64 -> IO () pokeN stk@(Stack _ _ sp ustk _) n = do bpoke stk natTypeTag diff --git a/unison-runtime/unison-runtime.cabal b/unison-runtime/unison-runtime.cabal index ba9a8b095e..4b1e56496c 100644 --- a/unison-runtime/unison-runtime.cabal +++ b/unison-runtime/unison-runtime.cabal @@ -25,6 +25,10 @@ flag optimized manual: True default: True +flag stackchecks + manual: True + default: False + library exposed-modules: Unison.Codebase.Execute @@ -142,6 +146,8 @@ library ghc-options: -funbox-strict-fields -O2 if flag(arraychecks) cpp-options: -DARRAY_CHECK + if flag(stackchecks) + cpp-options: -DSTACK_CHECK test-suite runtime-tests type: exitcode-stdio-1.0 @@ -212,3 +218,5 @@ test-suite runtime-tests ghc-options: -funbox-strict-fields -O2 if flag(arraychecks) cpp-options: -DARRAY_CHECK + if flag(stackchecks) + cpp-options: -DSTACK_CHECK From f85c9588656df7de225959e2f74cc9c70767a928 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 30 Oct 2024 13:27:28 -0700 Subject: [PATCH 057/113] Add stack arg debugging --- unison-runtime/src/Unison/Runtime/Machine.hs | 9 ++++++--- unison-runtime/src/Unison/Runtime/Stack.hs | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 2d1e822eeb..662143d418 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -306,12 +306,15 @@ debugger stk msg a = unsafePerformIO $ do pure False dumpStack :: Stack -> IO () -dumpStack stk@(Stack _ap fp sp _ustk _bstk) +dumpStack stk@(Stack ap fp sp _ustk _bstk) | sp - fp < 0 = Debug.debugLogM Debug.Temp "Stack before 👇: Empty" | otherwise = do - stkResults <- for [0 .. ((sp - fp) - 1)] $ \i -> do + stkLocals <- for [0 .. ((sp - fp) - 1)] $ \i -> do peekOff stk i - Debug.debugM Debug.Temp "Stack before 👇:" stkResults + Debug.debugM Debug.Temp "Stack frame locals 👇:" stkLocals + stkArgs <- for [0 .. ((fp - ap) - 1)] $ \i -> do + peekOff stk (i + (sp - fp)) + Debug.debugM Debug.Temp "Stack args 👇:" stkArgs -- | Execute an instruction exec :: diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 57bcd00ba2..33555671cd 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -501,10 +501,10 @@ uargOnto stk sp cop cp0 (ArgN v) = do let loop i | i < 0 = return () | otherwise = do - (x :: Int) <- readByteArray stk (sp - indexPrimArray v i) + (x :: Int) <- readByteArray stk (sp - indexPrimArray v i) -- writeByteArray buf (boff - i) x loop $ i - 1 - loop $ sz - 1 + loop $ sz - 1 -- 2 when overwrite $ copyMutableByteArray cop (bytes $ cp0 + 1) buf 0 (bytes sz) pure cp From 96fe58e54bc9de5ff35bc4b7431947285a9564fe Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 11:27:44 -0700 Subject: [PATCH 058/113] Debug.Interpreter --- lib/unison-prelude/src/Unison/Debug.hs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/unison-prelude/src/Unison/Debug.hs b/lib/unison-prelude/src/Unison/Debug.hs index 6bbcaa9cac..994b29c96f 100644 --- a/lib/unison-prelude/src/Unison/Debug.hs +++ b/lib/unison-prelude/src/Unison/Debug.hs @@ -36,6 +36,8 @@ data DebugFlag | -- | Useful for adding temporary debugging statements during development. -- Remove uses of Debug.Temp before merging to keep things clean for the next person :) Temp + | -- | Debugging the interpreter + Interpreter | -- | Shows Annotations when printing terms Annotations | -- | Debug endpoints of the local UI (or Share) server @@ -65,6 +67,7 @@ debugFlags = case (unsafePerformIO (lookupEnv "UNISON_DEBUG")) of "LSP" -> pure LSP "TIMING" -> pure Timing "TEMP" -> pure Temp + "INTERPRETER" -> pure Interpreter "ANNOTATIONS" -> pure Annotations "SERVER" -> pure Server "PATTERN_COVERAGE" -> pure PatternCoverage @@ -114,6 +117,10 @@ debugTemp :: Bool debugTemp = Temp `Set.member` debugFlags {-# NOINLINE debugTemp #-} +debugInterpreter :: Bool +debugInterpreter = Interpreter `Set.member` debugFlags +{-# NOINLINE debugInterpreter #-} + debugAnnotations :: Bool debugAnnotations = Annotations `Set.member` debugFlags {-# NOINLINE debugAnnotations #-} @@ -187,6 +194,7 @@ shouldDebug = \case LSP -> debugLSP Timing -> debugTiming Temp -> debugTemp + Interpreter -> debugInterpreter Annotations -> debugAnnotations Server -> debugServer PatternCoverage -> debugPatternCoverage From 494b741ccde6250d0b18600151ce9da1dc32e041 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 12:02:11 -0700 Subject: [PATCH 059/113] Put stack debugging behind preprocessor flag --- unison-runtime/src/Unison/Runtime/Machine.hs | 47 ++++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 662143d418..9d7c06642d 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1,4 +1,5 @@ {-# LANGUAGE BangPatterns #-} +{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} module Unison.Runtime.Machine where @@ -17,11 +18,9 @@ import Data.Text qualified as DTx import Data.Text.IO qualified as Tx import Data.Traversable import GHC.Conc as STM (unsafeIOToSTM) -import System.IO.Unsafe (unsafePerformIO) import Unison.Builtin.Decls (exceptionRef, ioFailureRef) import Unison.Builtin.Decls qualified as Rf import Unison.ConstructorReference qualified as CR -import Unison.Debug qualified as Debug import Unison.Prelude hiding (Text) import Unison.Reference ( Reference, @@ -64,6 +63,13 @@ import UnliftIO (IORef) import UnliftIO qualified import UnliftIO.Concurrent qualified as UnliftIO +{- ORMOLU_DISABLE -} +#ifdef STACK_CHECK +import Unison.Debug qualified as Debug +import System.IO.Unsafe (unsafePerformIO) +#endif +{- ORMOLU_ENABLE -} + -- | A ref storing every currently active thread. -- This is helpful for cleaning up orphaned threads when the main process -- completes. @@ -238,8 +244,6 @@ apply0 !callback !env !threadTracker !i = do let entryCix = (CIx r i 0) case unRComb $ rCombSection cmbs entryCix of Comb entryComb -> do - Debug.debugM Debug.Temp "Entry Comb" entryComb - -- Debug.debugM Debug.Temp "All Combs" cmbs apply env denv threadTracker stk (kf k0) True ZArgs . BoxedVal $ PAp entryCix entryComb nullSeg -- if it's cached, we can just finish @@ -299,22 +303,26 @@ litToVal = \case MD d -> DoubleVal d {-# INLINE litToVal #-} +{- ORMOLU_DISABLE -} +#ifdef STACK_CHECK debugger :: (Show a) => Stack -> String -> a -> Bool debugger stk msg a = unsafePerformIO $ do dumpStack stk - Debug.debugLogM Debug.Temp (msg ++ ": " ++ show a) + Debug.debugLogM Debug.Interpreter (msg ++ ": " ++ show a) pure False dumpStack :: Stack -> IO () dumpStack stk@(Stack ap fp sp _ustk _bstk) - | sp - fp < 0 = Debug.debugLogM Debug.Temp "Stack before 👇: Empty" + | sp - fp < 0 = Debug.debugLogM Debug.Interpreter "Stack before 👇: Empty" | otherwise = do stkLocals <- for [0 .. ((sp - fp) - 1)] $ \i -> do peekOff stk i - Debug.debugM Debug.Temp "Stack frame locals 👇:" stkLocals + Debug.debugM Debug.Interpreter "Stack frame locals 👇:" stkLocals stkArgs <- for [0 .. ((fp - ap) - 1)] $ \i -> do peekOff stk (i + (sp - fp)) - Debug.debugM Debug.Temp "Stack args 👇:" stkArgs + Debug.debugM Debug.Interpreter "Stack args 👇:" stkArgs +#endif +{- ORMOLU_ENABLE -} -- | Execute an instruction exec :: @@ -326,8 +334,12 @@ exec :: Reference -> MInstr -> IO (DEnv, Stack, K) +{- ORMOLU_DISABLE -} +#ifdef STACK_CHECK exec !_ !_ !_ !stk !_ !_ instr | debugger stk "exec" instr = undefined +#endif +{- ORMOLU_ENABLE -} exec !_ !denv !_activeThreads !stk !k _ (Info tx) = do info tx stk info tx k @@ -645,8 +657,12 @@ eval :: Reference -> MSection -> IO () +{- ORMOLU_DISABLE -} +#ifdef STACK_CHECK eval !_ !_ !_ !stk !_ !_ section | debugger stk "eval" section = undefined +#endif +{- ORMOLU_ENABLE -} eval !env !denv !activeThreads !stk !k r (Match i (TestT df cs)) = do t <- peekOffBi stk i eval env denv activeThreads stk k r $ selectTextBranch t df cs @@ -786,30 +802,26 @@ apply :: Args -> Val -> IO () +{- ORMOLU_DISABLE -} +#ifdef STACK_CHECK apply !_env !_denv !_activeThreads !stk !_k !_ck !args !val | debugger stk "apply" (args, val) = undefined +#endif +{- ORMOLU_ENABLE -} apply !env !denv !activeThreads !stk !k !ck !args !val = case val of BoxedVal (PAp cix@(CIx combRef _ _) comb seg) -> case comb of LamI a f entry | ck || a <= ac -> do - !_ <- pure $ debugger stk "apply-LamI-beforeEnsure" () stk <- ensure stk f - !_ <- pure $ debugger stk "apply-LamI-beforeMove" () stk <- moveArgs stk args - !_ <- pure $ debugger stk "apply-LamI-afterMove" () stk <- dumpSeg stk seg A - !_ <- pure $ debugger stk "apply-LamI-afterdumpSeg" () stk <- acceptArgs stk a - !_ <- pure $ debugger stk "apply-LamI-afteracceptArgs" () eval env denv activeThreads stk k combRef entry | otherwise -> do - !_ <- pure $ debugger stk "apply-LamIotherwise-beforeCloseArgs" () seg <- closeArgs C stk seg args - !_ <- pure $ debugger stk "apply-LamIotherwise-afterCloseArgs" () stk <- discardFrame =<< frameArgs stk - !_ <- pure $ debugger stk "apply-LamIotherwise-afterDiscardFrame" () stk <- bump stk bpoke stk $ PAp cix comb seg yield env denv activeThreads stk k @@ -898,9 +910,7 @@ moveArgs !stk (VArgR i l) = do stk <- prepareArgs stk (ArgR i l) pure stk moveArgs !stk (VArgN as) = do - !_ <- pure $ debugger stk "before prepareArgs" as stk <- prepareArgs stk (ArgN as) - !_ <- pure $ debugger stk "after prepareArgs" as pure stk moveArgs !stk (VArgV i) = do stk <- @@ -1395,7 +1405,6 @@ uprim2 !stk CAST !vi !ti = do newTypeTag <- peekOffN stk ti v <- upeekOff stk vi stk <- bump stk - Debug.debugM Debug.Temp "CASTING" (v, newTypeTag) poke stk $ UnboxedVal v (PackedTag newTypeTag) pure stk {-# INLINE uprim2 #-} From 033df415f5680cafc41dc47d37cc99e989fc4003 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 13:52:42 -0700 Subject: [PATCH 060/113] Fix bad toEnum in NatVal --- unison-runtime/src/Unison/Runtime/Stack.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 33555671cd..043fadd715 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -373,7 +373,7 @@ pattern CharVal c <- (matchCharVal -> Just c) matchNatVal :: Val -> Maybe Word64 matchNatVal = \case - (UnboxedVal u tt) | tt == TT.natTag -> Just (toEnum u) + (UnboxedVal u tt) | tt == TT.natTag -> Just (fromIntegral u) _ -> Nothing pattern NatVal :: Word64 -> Val From ba7a4d6ac6d26f345621f394f830a857ef518a28 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 13:52:42 -0700 Subject: [PATCH 061/113] Clean up debugging --- Runtime.hs | 181 ++++++++++++++++++ .../src/Unison/Codebase/Runtime.hs | 2 - 2 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 Runtime.hs diff --git a/Runtime.hs b/Runtime.hs new file mode 100644 index 0000000000..f790076f27 --- /dev/null +++ b/Runtime.hs @@ -0,0 +1,181 @@ +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE RankNTypes #-} + +module Unison.Codebase.Runtime where + +import Data.Map qualified as Map +import Data.Set.NonEmpty (NESet) +import Unison.ABT qualified as ABT +import Unison.Builtin.Decls (tupleTerm, pattern TupleTerm') +import Unison.Codebase.CodeLookup qualified as CL +import Unison.Codebase.CodeLookup.Util qualified as CL +import Unison.Hashing.V2.Convert qualified as Hashing +import Unison.Parser.Ann (Ann) +import Unison.Prelude +import Unison.PrettyPrintEnv qualified as PPE +import Unison.Reference (Reference) +import Unison.Reference qualified as Reference +import Unison.Term qualified as Term +import Unison.Type (Type) +import Unison.UnisonFile (TypecheckedUnisonFile) +import Unison.UnisonFile qualified as UF +import Unison.Util.Pretty qualified as P +import Unison.Var (Var) +import Unison.Var qualified as Var +import Unison.WatchKind (WatchKind) +import Unison.WatchKind qualified as WK + +type Error = P.Pretty P.ColorText + +type Term v = Term.Term v () + +data CompileOpts = COpts + { profile :: Bool + } + +defaultCompileOpts :: CompileOpts +defaultCompileOpts = COpts {profile = False} + +data Runtime v = Runtime + { terminate :: IO (), + evaluate :: + CL.CodeLookup v IO () -> + PPE.PrettyPrintEnv -> + Term v -> + IO (Either Error ([Error], Term v)), + compileTo :: + CompileOpts -> + CL.CodeLookup v IO () -> + PPE.PrettyPrintEnv -> + Reference -> + FilePath -> + IO (Maybe Error), + mainType :: Type v Ann, + ioTestTypes :: NESet (Type v Ann) + } + +type IsCacheHit = Bool + +noCache :: Reference.Id -> IO (Maybe (Term v)) +noCache _ = pure Nothing + +type WatchResults v a = + ( Either + Error + -- Bindings: + ( [(v, Term v)], + -- Map watchName (loc, hash, expression, value, isHit) + [Error], + Map v (a, WatchKind, Reference.Id, Term v, Term v, IsCacheHit) + ) + ) + +-- Evaluates the watch expressions in the file, returning a `Map` of their +-- results. This has to be a bit fancy to handle that the definitions in the +-- file depend on each other and evaluation must proceed in a way that respects +-- these dependencies. +-- +-- Note: The definitions in the file are hashed and looked up in +-- `evaluationCache`. If that returns a result, evaluation of that definition +-- can be skipped. +evaluateWatches :: + forall v a. + (Var v) => + CL.CodeLookup v IO a -> + PPE.PrettyPrintEnv -> + (Reference.Id -> IO (Maybe (Term v))) -> + Runtime v -> + TypecheckedUnisonFile v a -> + IO (WatchResults v a) +evaluateWatches code ppe evaluationCache rt tuf = do + -- 1. compute hashes for everything in the file + let m :: Map v (Reference.Id, Term.Term v a) + m = fmap (\(_a, id, _wk, tm, _tp) -> (id, tm)) (UF.hashTermsId tuf) + watches :: Set v = Map.keysSet watchKinds + watchKinds :: Map v WatchKind + watchKinds = + Map.fromList + [(v, k) | (k, ws) <- UF.watchComponents tuf, (v, _a, _tm, _tp) <- ws] + unann = Term.amap (const ()) + -- 2. use the cache to lookup things already computed + m' <- fmap Map.fromList . for (Map.toList m) $ \(v, (r, t)) -> do + o <- evaluationCache r + case o of + Nothing -> pure (v, (r, ABT.annotation t, unann t, False)) + Just t' -> pure (v, (r, ABT.annotation t, t', True)) + -- 3. create a big ol' let rec whose body is a big tuple of all watches + let rv :: Map Reference.Id v + rv = Map.fromList [(r, v) | (v, (r, _)) <- Map.toList m] + bindings :: [(v, (), Term v)] + bindings = [(v, (), unref rv b) | (v, (_, _, b, _)) <- Map.toList m'] + watchVars = [Term.var () v | v <- toList watches] + bigOl'LetRec = Term.letRec' True bindings (tupleTerm watchVars) + cl = void (CL.fromTypecheckedUnisonFile tuf) <> void code + -- 4. evaluate it and get all the results out of the tuple, then + -- create the result Map + out <- evaluate rt cl ppe bigOl'LetRec + case out of + Right (errs, out) -> do + let (bindings, results) = case out of + TupleTerm' results -> (mempty, results) + Term.LetRecNamed' bs (TupleTerm' results) -> (bs, results) + _ -> error $ "Evaluation should produce a tuple, but gave: " ++ show out + let go v eval (ref, a, uneval, isHit) = + ( a, + Map.findWithDefault (die v) v watchKinds, + ref, + uneval, + Term.etaNormalForm eval, + isHit + ) + watchMap = + Map.intersectionWithKey + go + (Map.fromList (toList watches `zip` results)) + m' + die v = error $ "not sure what kind of watch this is: " <> show v + pure $ Right (bindings, errs, watchMap) + Left e -> pure (Left e) + where + -- unref :: Map Reference.Id v -> Term.Term v a -> Term.Term v a + unref rv t = ABT.visitPure go t + where + go t@(Term.Ref' (Reference.DerivedId r)) = case Map.lookup r rv of + Nothing -> Nothing + Just v -> Just (Term.var (ABT.annotation t) v) + go _ = Nothing + +evaluateTerm' :: + (Var v, Monoid a) => + CL.CodeLookup v IO a -> + (Reference.Id -> IO (Maybe (Term v))) -> + PPE.PrettyPrintEnv -> + Runtime v -> + Term.Term v a -> + IO (Either Error ([Error], Term v)) +evaluateTerm' codeLookup cache ppe rt tm = do + result <- cache (Hashing.hashClosedTerm tm) + case result of + Just r -> pure (Right ([], r)) + Nothing -> do + let tuf = + UF.typecheckedUnisonFile + mempty + mempty + mempty + [(WK.RegularWatch, [(Var.nameds "result", mempty, tm, mempty <$> mainType rt)])] + r <- evaluateWatches (void codeLookup) ppe cache rt (void tuf) + pure $ + r <&> \(_, errs, map) -> + case Map.elems map of + [(_loc, _kind, _hash, _src, value, _isHit)] -> (errs, value) + _ -> error "evaluateTerm': Pattern mismatch on watch results" + +evaluateTerm :: + (Var v, Monoid a) => + CL.CodeLookup v IO a -> + PPE.PrettyPrintEnv -> + Runtime v -> + Term.Term v a -> + IO (Either Error ([Error], Term v)) +evaluateTerm codeLookup = evaluateTerm' codeLookup noCache diff --git a/parser-typechecker/src/Unison/Codebase/Runtime.hs b/parser-typechecker/src/Unison/Codebase/Runtime.hs index 4732457e28..f790076f27 100644 --- a/parser-typechecker/src/Unison/Codebase/Runtime.hs +++ b/parser-typechecker/src/Unison/Codebase/Runtime.hs @@ -9,7 +9,6 @@ import Unison.ABT qualified as ABT import Unison.Builtin.Decls (tupleTerm, pattern TupleTerm') import Unison.Codebase.CodeLookup qualified as CL import Unison.Codebase.CodeLookup.Util qualified as CL -import Unison.Debug qualified as Debug import Unison.Hashing.V2.Convert qualified as Hashing import Unison.Parser.Ann (Ann) import Unison.Prelude @@ -115,7 +114,6 @@ evaluateWatches code ppe evaluationCache rt tuf = do -- 4. evaluate it and get all the results out of the tuple, then -- create the result Map out <- evaluate rt cl ppe bigOl'LetRec - Debug.debugM Debug.Temp "evaluateWatches: out" out case out of Right (errs, out) -> do let (bindings, results) = case out of From 1d3f4395e21e94ea49a79de2a96ebd34fd27e9b8 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 16:14:43 -0700 Subject: [PATCH 062/113] Fix broken stack debugging --- unison-runtime/src/Unison/Runtime/Stack.hs | 94 +++++++++++++--------- 1 file changed, 54 insertions(+), 40 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 043fadd715..43605492ac 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -128,6 +128,7 @@ import Data.Kind (Constraint) import Data.Primitive.ByteArray qualified as BA import Data.Word import GHC.Exts as L (IsList (..)) +import Unison.Debug qualified as Debug import Unison.Prelude import Unison.Reference (Reference) import Unison.Runtime.ANF (PackedTag) @@ -141,6 +142,7 @@ import Prelude hiding (words) {- ORMOLU_DISABLE -} #ifdef STACK_CHECK + type DebugCallStack = (HasCallStack :: Constraint) unboxedSentinel :: Int @@ -152,8 +154,9 @@ boxedSentinel = (Closure GUnboxedSentinel) assertBumped :: HasCallStack => Stack -> Off -> IO () assertBumped (Stack _ _ sp ustk bstk) i = do u <- readByteArray ustk (sp - i) - b <- readArray bstk (sp - i) - when (u /= unboxedSentinel || b /= boxedSentinel) $ error $ "Expected stack slot to have been bumped, but it was:" <> show (Val u b) + b :: BVal <- readArray bstk (sp - i) + when (u /= unboxedSentinel || b /= boxedSentinel) do + error $ "Expected stack slot to have been bumped, but it was:" <> show (Val u b) assertUnboxed :: HasCallStack => Stack -> Off -> IO () assertUnboxed (Stack _ _ sp ustk bstk) i = do @@ -254,11 +257,20 @@ data GClosure comb deriving stock (Show, Functor, Foldable, Traversable) {- ORMOLU_ENABLE -} -instance Eq (GClosure comb) where - -- This is safe because the embedded CombIx will break disputes +-- We derive a basic instance for a version _without_ cyclic references. +deriving instance Eq (GClosure ()) + +-- Then we define the eq instance for cyclic references to just use the derived instance after deleting any possible +-- cycles. +-- This is still correct because each constructor with a cyclic reference also includes +-- a CombIx identifying the cycle. +instance Eq (GClosure (RComb Val)) where a == b = (a $> ()) == (b $> ()) -instance Ord (GClosure comb) where +-- See Eq instance. +deriving instance Ord (GClosure ()) + +instance Ord (GClosure (RComb Val)) where compare a b = compare (a $> ()) (b $> ()) pattern PAp :: CombIx -> GCombInfo (RComb Val) -> Seg -> Closure @@ -649,70 +661,72 @@ alloc = do {-# INLINE alloc #-} {- ORMOLU_DISABLE -} -peek :: Stack -> IO Val -peek stk = do - u <- upeek stk +peek :: DebugCallStack => Stack -> IO Val +peek stk@(Stack _ _ sp ustk _) = do + -- Can't use upeek here because in stack-check mode it will assert that the stack slot is unboxed. + u <- readByteArray ustk sp b <- bpeek stk pure (Val u b) {-# INLINE peek #-} -peekI :: Stack -> IO Int +peekI :: DebugCallStack => Stack -> IO Int peekI _stk@(Stack _ _ sp ustk _) = do #ifdef STACK_CHECK - assertUnboxed _stk sp + assertUnboxed _stk 0 #endif readByteArray ustk sp {-# INLINE peekI #-} -peekOffI :: Stack -> Off -> IO Int +peekOffI :: DebugCallStack => Stack -> Off -> IO Int peekOffI _stk@(Stack _ _ sp ustk _) i = do #ifdef STACK_CHECK - assertUnboxed _stk (sp - i) + assertUnboxed _stk 0 #endif readByteArray ustk (sp - i) {-# INLINE peekOffI #-} -bpeek :: Stack -> IO BVal +bpeek :: DebugCallStack => Stack -> IO BVal bpeek (Stack _ _ sp _ bstk) = readArray bstk sp {-# INLINE bpeek #-} -upeek :: Stack -> IO UVal +upeek :: DebugCallStack => Stack -> IO UVal upeek _stk@(Stack _ _ sp ustk _) = do #ifdef STACK_CHECK - assertUnboxed _stk sp + assertUnboxed _stk 0 #endif readByteArray ustk sp {-# INLINE upeek #-} -peekOff :: Stack -> Off -> IO Val -peekOff stk i = do - u <- upeekOff stk i +peekOff :: DebugCallStack => Stack -> Off -> IO Val +peekOff stk@(Stack _ _ sp ustk _) i = do + -- Can't use upeekOff here because in stack-check mode it will assert that the stack slot is unboxed. + u <- readByteArray ustk (sp - i) b <- bpeekOff stk i pure $ Val u b {-# INLINE peekOff #-} -bpeekOff :: Stack -> Off -> IO BVal +bpeekOff :: DebugCallStack => Stack -> Off -> IO BVal bpeekOff (Stack _ _ sp _ bstk) i = readArray bstk (sp - i) {-# INLINE bpeekOff #-} -upeekOff :: Stack -> Off -> IO UVal +upeekOff :: DebugCallStack => Stack -> Off -> IO UVal upeekOff _stk@(Stack _ _ sp ustk _) i = do #ifdef STACK_CHECK - assertUnboxed _stk (sp - i) + assertUnboxed _stk i #endif readByteArray ustk (sp - i) {-# INLINE upeekOff #-} -upokeT :: Stack -> UVal -> PackedTag -> IO () +upokeT :: DebugCallStack => Stack -> UVal -> PackedTag -> IO () upokeT !stk@(Stack _ _ sp ustk _) !u !t = do bpoke stk (UnboxedTypeTag t) writeByteArray ustk sp u {-# INLINE upokeT #-} -poke :: Stack -> Val -> IO () +poke :: DebugCallStack => Stack -> Val -> IO () poke _stk@(Stack _ _ sp ustk bstk) (Val u b) = do #ifdef STACK_CHECK - assertBumped _stk sp + assertBumped _stk 0 #endif writeByteArray ustk sp u writeArray bstk sp b @@ -721,7 +735,7 @@ poke _stk@(Stack _ _ sp ustk bstk) (Val u b) = do -- | Sometimes we get back an int from a foreign call which we want to use as a Nat. -- If we know it's positive and smaller than 2^63 then we can safely store the Int directly as a Nat without -- checks. -unsafePokeIasN :: Stack -> Int -> IO () +unsafePokeIasN :: DebugCallStack => Stack -> Int -> IO () unsafePokeIasN stk n = do upokeT stk n TT.natTag {-# INLINE unsafePokeIasN #-} @@ -729,21 +743,21 @@ unsafePokeIasN stk n = do -- | Store an unboxed tag to later match on. -- Often used to indicate the constructor of a data type that's been unpacked onto the stack, -- or some tag we're about to branch on. -pokeTag :: Stack -> Int -> IO () +pokeTag :: DebugCallStack => Stack -> Int -> IO () pokeTag = -- For now we just use ints, but maybe should have a separate type for tags so we can detect if we're leaking them. pokeI {-# INLINE pokeTag #-} -peekTag :: Stack -> IO Int +peekTag :: DebugCallStack => Stack -> IO Int peekTag = peekI {-# INLINE peekTag #-} -peekTagOff :: Stack -> Off -> IO Int +peekTagOff :: DebugCallStack => Stack -> Off -> IO Int peekTagOff = peekOffI {-# INLINE peekTagOff #-} -pokeBool :: Stack -> Bool -> IO () +pokeBool :: DebugCallStack => Stack -> Bool -> IO () pokeBool stk b = -- Currently this is implemented as a tag, which is branched on to put a packed bool constructor on the stack, but -- we'll want to change it to have its own unboxed type tag eventually. @@ -754,9 +768,10 @@ pokeBool stk b = -- We don't bother nulling out the unboxed stack, -- it's extra work and there's nothing to garbage collect. bpoke :: DebugCallStack => Stack -> BVal -> IO () -bpoke _stk@(Stack _ _ sp _ustk bstk) b = do +bpoke _stk@(Stack _ _ sp _ bstk) b = do #ifdef STACK_CHECK - assertBumped _stk sp + Debug.debugLogM Debug.Interpreter "before assert bumped" + assertBumped _stk 0 #endif writeArray bstk sp b {-# INLINE bpoke #-} @@ -767,7 +782,7 @@ pokeOff stk i (Val u t) = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE pokeOff #-} -upokeOffT :: Stack -> Off -> UVal -> PackedTag -> IO () +upokeOffT :: DebugCallStack => Stack -> Off -> UVal -> PackedTag -> IO () upokeOffT stk i u t = do bpokeOff stk i (UnboxedTypeTag t) writeByteArray (ustk stk) (sp stk - i) u @@ -776,7 +791,7 @@ upokeOffT stk i u t = do bpokeOff :: DebugCallStack => Stack -> Off -> BVal -> IO () bpokeOff _stk@(Stack _ _ sp _ bstk) i b = do #ifdef STACK_CHECK - assertBumped _stk (sp - i) + assertBumped _stk i #endif writeArray bstk (sp - i) b {-# INLINE bpokeOff #-} @@ -830,7 +845,7 @@ bump :: Stack -> IO Stack bump (Stack ap fp sp ustk bstk) = do let stk' = Stack ap fp (sp + 1) ustk bstk #ifdef STACK_CHECK - pokeSentinelOff stk' (sp + 1) + pokeSentinelOff stk' 0 #endif pure stk' {-# INLINE bump #-} @@ -976,7 +991,7 @@ asize (Stack ap fp _ _ _) = fp - ap peekN :: Stack -> IO Word64 peekN _stk@(Stack _ _ sp ustk _) = do #ifdef STACK_CHECK - assertUnboxed _stk sp + assertUnboxed _stk 0 #endif readByteArray ustk sp {-# INLINE peekN #-} @@ -984,7 +999,7 @@ peekN _stk@(Stack _ _ sp ustk _) = do peekD :: Stack -> IO Double peekD _stk@(Stack _ _ sp ustk _) = do #ifdef STACK_CHECK - assertUnboxed _stk sp + assertUnboxed _stk 0 #endif readByteArray ustk sp {-# INLINE peekD #-} @@ -997,8 +1012,7 @@ peekC stk = do peekOffN :: Stack -> Int -> IO Word64 peekOffN _stk@(Stack _ _ sp ustk _) i = do #ifdef STACK_CHECK - - assertUnboxed _stk (sp - i) + assertUnboxed _stk i #endif readByteArray ustk (sp - i) {-# INLINE peekOffN #-} @@ -1006,7 +1020,7 @@ peekOffN _stk@(Stack _ _ sp ustk _) i = do peekOffD :: Stack -> Int -> IO Double peekOffD _stk@(Stack _ _ sp ustk _) i = do #ifdef STACK_CHECK - assertUnboxed _stk (sp - i) + assertUnboxed _stk i #endif readByteArray ustk (sp - i) {-# INLINE peekOffD #-} @@ -1014,7 +1028,7 @@ peekOffD _stk@(Stack _ _ sp ustk _) i = do peekOffC :: Stack -> Int -> IO Char peekOffC _stk@(Stack _ _ sp ustk _) i = do #ifdef STACK_CHECK - assertUnboxed _stk (sp - i) + assertUnboxed _stk i #endif Char.chr <$> readByteArray ustk (sp - i) {-# INLINE peekOffC #-} From 5c48d51ac7d34d052d047744d35830506287b83c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:26:45 -0700 Subject: [PATCH 063/113] Remove redundant EQLU implementation --- unison-runtime/src/Unison/Runtime/Machine.hs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 9d7c06642d..5412160695 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1589,12 +1589,6 @@ bprim2 :: Int -> Int -> IO Stack -bprim2 !stk EQLU i j = do - x <- peekOff stk i - y <- peekOff stk j - stk <- bump stk - pokeBool stk $ universalEq (==) x y - pure stk bprim2 !stk IXOT i j = do x <- peekOffBi stk i y <- peekOffBi stk j @@ -1783,6 +1777,7 @@ bprim2 !stk CATB i j = do pure stk bprim2 !stk THRO _ _ = pure stk -- impossible bprim2 !stk TRCE _ _ = pure stk -- impossible +bprim2 !stk EQLU _ _ = pure stk -- impossible bprim2 !stk CMPU _ _ = pure stk -- impossible bprim2 !stk SDBX _ _ = pure stk -- impossible bprim2 !stk SDBV _ _ = pure stk -- impossible From fa988953ca845620c002b6270f93a373997aefdc Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:26:45 -0700 Subject: [PATCH 064/113] Fix bad eqlu/cmpu --- unison-runtime/src/Unison/Runtime/Machine.hs | 37 ++++++++++---------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 5412160695..cb8759b4c3 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2370,12 +2370,13 @@ universalEq frn = eqVal && a1 == a2 && eqValList vs1 vs2 eqc (Foreign fl) (Foreign fr) - | Just al <- maybeUnwrapForeign Rf.iarrayRef fl, - Just ar <- maybeUnwrapForeign Rf.iarrayRef fr = - arrayEq eqc al ar - | Just sl <- maybeUnwrapForeign Rf.listRef fl, - Just sr <- maybeUnwrapForeign Rf.listRef fr = - length sl == length sr && and (Sq.zipWith eqc sl sr) + | Just al <- maybeUnwrapForeign @(PA.Array Val) Rf.iarrayRef fl, + Just ar <- maybeUnwrapForeign @(PA.Array Val) Rf.iarrayRef fr = + let (l, r) = Debug.debug Debug.Temp "arrays" $ (al, ar) + in arrayEq eqVal l r + | Just sl <- maybeUnwrapForeign @(Seq Val) Rf.listRef fl, + Just sr <- maybeUnwrapForeign @(Seq Val) Rf.listRef fr = + length sl == length sr && and (Sq.zipWith eqVal sl sr) | otherwise = frn fl fr eqc c d = closureNum c == closureNum d eqValList :: [Val] -> [Val] -> Bool @@ -2388,7 +2389,7 @@ universalEq frn = eqVal || (ct1 == TT.intTag && ct2 == TT.natTag) || (ct1 == TT.natTag && ct2 == TT.intTag) -arrayEq :: (Closure -> Closure -> Bool) -> PA.Array Closure -> PA.Array Closure -> Bool +arrayEq :: (a -> a -> Bool) -> PA.Array a -> PA.Array a -> Bool arrayEq eqc l r | PA.sizeofArray l /= PA.sizeofArray r = False | otherwise = go (PA.sizeofArray l - 1) @@ -2471,13 +2472,13 @@ universalCompare frn = cmpVal False <> compare a1 a2 <> cmpValList True vs1 vs2 (Foreign fl) (Foreign fr) - | Just sl <- maybeUnwrapForeign Rf.listRef fl, - Just sr <- maybeUnwrapForeign Rf.listRef fr -> - fold (Sq.zipWith (cmpc tyEq) sl sr) + | Just sl <- maybeUnwrapForeign @(Seq Val) Rf.listRef fl, + Just sr <- maybeUnwrapForeign @(Seq Val) Rf.listRef fr -> + fold (Sq.zipWith (cmpVal tyEq) sl sr) <> compare (length sl) (length sr) - | Just al <- maybeUnwrapForeign Rf.iarrayRef fl, - Just ar <- maybeUnwrapForeign Rf.iarrayRef fr -> - arrayCmp (cmpc tyEq) al ar + | Just al <- maybeUnwrapForeign @(PA.Array Val) Rf.iarrayRef fl, + Just ar <- maybeUnwrapForeign @(PA.Array Val) Rf.iarrayRef fr -> + arrayCmp (cmpVal tyEq) al ar | otherwise -> frn fl fr (UnboxedTypeTag t1) (UnboxedTypeTag t2) -> compare t1 t2 (BlackHole) (BlackHole) -> EQ @@ -2494,13 +2495,13 @@ universalCompare frn = cmpVal False in cmpl compare us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 arrayCmp :: - (Closure -> Closure -> Ordering) -> - PA.Array Closure -> - PA.Array Closure -> + (a -> a -> Ordering) -> + PA.Array a -> + PA.Array a -> Ordering -arrayCmp cmpc l r = +arrayCmp cmpVal l r = comparing PA.sizeofArray l r <> go (PA.sizeofArray l - 1) where go i | i < 0 = EQ - | otherwise = cmpc (PA.indexArray l i) (PA.indexArray r i) <> go (i - 1) + | otherwise = cmpVal (PA.indexArray l i) (PA.indexArray r i) <> go (i - 1) From 86bd7fb41a01acbc3f1c1d40b5b3cbacb06bfd4f Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:49:49 -0700 Subject: [PATCH 065/113] Fix byte poking --- unison-runtime/src/Unison/Runtime/Stack.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 43605492ac..d38ab6e617 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -128,7 +128,6 @@ import Data.Kind (Constraint) import Data.Primitive.ByteArray qualified as BA import Data.Word import GHC.Exts as L (IsList (..)) -import Unison.Debug qualified as Debug import Unison.Prelude import Unison.Reference (Reference) import Unison.Runtime.ANF (PackedTag) @@ -1062,8 +1061,8 @@ pokeI stk@(Stack _ _ sp ustk _) i = do pokeByte :: Stack -> Word8 -> IO () pokeByte stk b = do - -- NOTE: currently we just store bytes as ints, but we should have a separate type runtime type tag for them. - pokeI stk (fromIntegral b) + -- NOTE: currently we just store bytes as Word64s, but we should have a separate type runtime type tag for them. + pokeN stk (fromIntegral b) {-# INLINE pokeByte #-} pokeOffN :: Stack -> Int -> Word64 -> IO () From 2e0678dda43913e035f2b83dc32cce3b8d7970ea Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:49:49 -0700 Subject: [PATCH 066/113] Remove some debugging --- unison-runtime/src/Unison/Runtime/Machine.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index cb8759b4c3..678013bc24 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2372,8 +2372,7 @@ universalEq frn = eqVal eqc (Foreign fl) (Foreign fr) | Just al <- maybeUnwrapForeign @(PA.Array Val) Rf.iarrayRef fl, Just ar <- maybeUnwrapForeign @(PA.Array Val) Rf.iarrayRef fr = - let (l, r) = Debug.debug Debug.Temp "arrays" $ (al, ar) - in arrayEq eqVal l r + arrayEq eqVal al ar | Just sl <- maybeUnwrapForeign @(Seq Val) Rf.listRef fl, Just sr <- maybeUnwrapForeign @(Seq Val) Rf.listRef fr = length sl == length sr && and (Sq.zipWith eqVal sl sr) From 00f0ee0f17ce394f7704ed41cef9317bad3bec7c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:49:49 -0700 Subject: [PATCH 067/113] Add separate instructions for Int versions of bit-twiddling --- unison-runtime/src/Unison/Runtime/ANF.hs | 4 + .../src/Unison/Runtime/ANF/Serialize.hs | 4 + unison-runtime/src/Unison/Runtime/Builtin.hs | 8 +- unison-runtime/src/Unison/Runtime/MCode.hs | 12 +- unison-runtime/src/Unison/Runtime/Machine.hs | 23 +++ .../src/Unison/Runtime/Serialize.hs | 156 +++++++++--------- 6 files changed, 127 insertions(+), 80 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 7d4421e603..eeb717d14a 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -1252,6 +1252,10 @@ data POp | POWI -- pow | SHLI -- shiftl | SHRI -- shiftr + | ANDI -- and + | IORI -- or + | XORI -- xor + | COMI -- complement | INCI -- inc | DECI -- dec | LEQI -- <= diff --git a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs index 4d46a0cdb8..9c48877d48 100644 --- a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs @@ -649,6 +649,10 @@ pOpCode op = case op of SDBL -> 122 SDBV -> 123 CAST -> 124 + ANDI -> 125 + IORI -> 126 + XORI -> 127 + COMI -> 128 pOpAssoc :: [(POp, Word16)] pOpAssoc = map (\op -> (op, pOpCode op)) [minBound .. maxBound] diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 359b3ee712..90accd94b0 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -417,10 +417,10 @@ andn = binop ANDN orn = binop IORN xorn = binop XORN compln = unop COMN -andi = binop ANDN -ori = binop IORN -xori = binop XORN -compli = unop COMN +andi = binop ANDI +ori = binop IORI +xori = binop XORI +compli = unop COMI addf, subf, diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index aa6377b0c3..e10d5d9f7d 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -297,6 +297,7 @@ data UPrim1 | LZRO -- leadingZeroes | TZRO -- trailingZeroes | COMN -- complement + | COMI -- complement | POPC -- popCount -- floating | ABSF -- abs @@ -346,10 +347,13 @@ data UPrim2 | LEQI -- <= | LEQN | ANDN -- and + | ANDI | IORN -- or + | IORI | XORN -- xor - -- floating - | EQLF -- == + | XORI + | -- floating + EQLF -- == | LEQF -- <= | ADDF -- + | SUBF -- - @@ -1197,9 +1201,13 @@ emitPOp ANF.TZRO = emitP1 TZRO emitPOp ANF.LZRO = emitP1 LZRO emitPOp ANF.POPC = emitP1 POPC emitPOp ANF.ANDN = emitP2 ANDN +emitPOp ANF.ANDI = emitP2 ANDI emitPOp ANF.IORN = emitP2 IORN +emitPOp ANF.IORI = emitP2 IORI +emitPOp ANF.XORI = emitP2 XORI emitPOp ANF.XORN = emitP2 XORN emitPOp ANF.COMN = emitP1 COMN +emitPOp ANF.COMI = emitP1 COMI -- Float emitPOp ANF.ADDF = emitP2 ADDF emitPOp ANF.SUBF = emitP2 SUBF diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 678013bc24..072d07dd75 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1194,6 +1194,11 @@ uprim1 !stk COMN !i = do stk <- bump stk pokeN stk (complement n) pure stk +uprim1 !stk COMI !i = do + n <- peekOffI stk i + stk <- bump stk + pokeI stk (complement n) + pure stk {-# INLINE uprim1 #-} uprim2 :: Stack -> UPrim2 -> Int -> Int -> IO Stack @@ -1389,18 +1394,36 @@ uprim2 !stk ANDN !i !j = do stk <- bump stk pokeN stk (x .&. y) pure stk +uprim2 !stk ANDI !i !j = do + x <- peekOffI stk i + y <- peekOffI stk j + stk <- bump stk + pokeI stk (x .&. y) + pure stk uprim2 !stk IORN !i !j = do x <- peekOffN stk i y <- peekOffN stk j stk <- bump stk pokeN stk (x .|. y) pure stk +uprim2 !stk IORI !i !j = do + x <- peekOffI stk i + y <- peekOffI stk j + stk <- bump stk + pokeI stk (x .|. y) + pure stk uprim2 !stk XORN !i !j = do x <- peekOffN stk i y <- peekOffN stk j stk <- bump stk pokeN stk (xor x y) pure stk +uprim2 !stk XORI !i !j = do + x <- peekOffI stk i + y <- peekOffI stk j + stk <- bump stk + pokeI stk (xor x y) + pure stk uprim2 !stk CAST !vi !ti = do newTypeTag <- peekOffN stk ti v <- upeekOff stk vi diff --git a/unison-runtime/src/Unison/Runtime/Serialize.hs b/unison-runtime/src/Unison/Runtime/Serialize.hs index 5cd5732226..cf74a7b1bb 100644 --- a/unison-runtime/src/Unison/Runtime/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/Serialize.hs @@ -304,29 +304,30 @@ instance Tag UPrim1 where tag2word LZRO = 6 tag2word TZRO = 7 tag2word COMN = 8 - tag2word POPC = 9 - tag2word ABSF = 10 - tag2word EXPF = 11 - tag2word LOGF = 12 - tag2word SQRT = 13 - tag2word COSF = 14 - tag2word ACOS = 15 - tag2word COSH = 16 - tag2word ACSH = 17 - tag2word SINF = 18 - tag2word ASIN = 19 - tag2word SINH = 20 - tag2word ASNH = 21 - tag2word TANF = 22 - tag2word ATAN = 23 - tag2word TANH = 24 - tag2word ATNH = 25 - tag2word ITOF = 26 - tag2word NTOF = 27 - tag2word CEIL = 28 - tag2word FLOR = 29 - tag2word TRNF = 30 - tag2word RNDF = 31 + tag2word COMI = 9 + tag2word POPC = 10 + tag2word ABSF = 11 + tag2word EXPF = 12 + tag2word LOGF = 13 + tag2word SQRT = 14 + tag2word COSF = 15 + tag2word ACOS = 16 + tag2word COSH = 17 + tag2word ACSH = 18 + tag2word SINF = 19 + tag2word ASIN = 20 + tag2word SINH = 21 + tag2word ASNH = 22 + tag2word TANF = 23 + tag2word ATAN = 24 + tag2word TANH = 25 + tag2word ATNH = 26 + tag2word ITOF = 27 + tag2word NTOF = 28 + tag2word CEIL = 29 + tag2word FLOR = 30 + tag2word TRNF = 31 + tag2word RNDF = 32 word2tag 0 = pure DECI word2tag 1 = pure DECN @@ -337,29 +338,30 @@ instance Tag UPrim1 where word2tag 6 = pure LZRO word2tag 7 = pure TZRO word2tag 8 = pure COMN - word2tag 9 = pure POPC - word2tag 10 = pure ABSF - word2tag 11 = pure EXPF - word2tag 12 = pure LOGF - word2tag 13 = pure SQRT - word2tag 14 = pure COSF - word2tag 15 = pure ACOS - word2tag 16 = pure COSH - word2tag 17 = pure ACSH - word2tag 18 = pure SINF - word2tag 19 = pure ASIN - word2tag 20 = pure SINH - word2tag 21 = pure ASNH - word2tag 22 = pure TANF - word2tag 23 = pure ATAN - word2tag 24 = pure TANH - word2tag 25 = pure ATNH - word2tag 26 = pure ITOF - word2tag 27 = pure NTOF - word2tag 28 = pure CEIL - word2tag 29 = pure FLOR - word2tag 30 = pure TRNF - word2tag 31 = pure RNDF + word2tag 9 = pure COMI + word2tag 10 = pure POPC + word2tag 11 = pure ABSF + word2tag 12 = pure EXPF + word2tag 13 = pure LOGF + word2tag 14 = pure SQRT + word2tag 15 = pure COSF + word2tag 16 = pure ACOS + word2tag 17 = pure COSH + word2tag 18 = pure ACSH + word2tag 19 = pure SINF + word2tag 20 = pure ASIN + word2tag 21 = pure SINH + word2tag 22 = pure ASNH + word2tag 23 = pure TANF + word2tag 24 = pure ATAN + word2tag 25 = pure TANH + word2tag 26 = pure ATNH + word2tag 27 = pure ITOF + word2tag 28 = pure NTOF + word2tag 29 = pure CEIL + word2tag 30 = pure FLOR + word2tag 31 = pure TRNF + word2tag 32 = pure RNDF word2tag n = unknownTag "UPrim1" n instance Tag UPrim2 where @@ -384,20 +386,23 @@ instance Tag UPrim2 where tag2word LEQI = 18 tag2word LEQN = 19 tag2word ANDN = 20 - tag2word IORN = 21 - tag2word XORN = 22 - tag2word EQLF = 23 - tag2word LEQF = 24 - tag2word ADDF = 25 - tag2word SUBF = 26 - tag2word MULF = 27 - tag2word DIVF = 28 - tag2word ATN2 = 29 - tag2word POWF = 30 - tag2word LOGB = 31 - tag2word MAXF = 32 - tag2word MINF = 33 - tag2word CAST = 34 + tag2word ANDI = 21 + tag2word IORN = 22 + tag2word IORI = 23 + tag2word XORN = 24 + tag2word XORI = 25 + tag2word EQLF = 26 + tag2word LEQF = 27 + tag2word ADDF = 28 + tag2word SUBF = 29 + tag2word MULF = 30 + tag2word DIVF = 31 + tag2word ATN2 = 32 + tag2word POWF = 33 + tag2word LOGB = 34 + tag2word MAXF = 35 + tag2word MINF = 36 + tag2word CAST = 37 word2tag 0 = pure ADDI word2tag 1 = pure ADDN @@ -420,20 +425,23 @@ instance Tag UPrim2 where word2tag 18 = pure LEQI word2tag 19 = pure LEQN word2tag 20 = pure ANDN - word2tag 21 = pure IORN - word2tag 22 = pure XORN - word2tag 23 = pure EQLF - word2tag 24 = pure LEQF - word2tag 25 = pure ADDF - word2tag 26 = pure SUBF - word2tag 27 = pure MULF - word2tag 28 = pure DIVF - word2tag 29 = pure ATN2 - word2tag 30 = pure POWF - word2tag 31 = pure LOGB - word2tag 32 = pure MAXF - word2tag 33 = pure MINF - word2tag 34 = pure CAST + word2tag 21 = pure ANDI + word2tag 22 = pure IORN + word2tag 23 = pure IORI + word2tag 24 = pure XORN + word2tag 25 = pure XORI + word2tag 26 = pure EQLF + word2tag 27 = pure LEQF + word2tag 28 = pure ADDF + word2tag 29 = pure SUBF + word2tag 30 = pure MULF + word2tag 31 = pure DIVF + word2tag 32 = pure ATN2 + word2tag 33 = pure POWF + word2tag 34 = pure LOGB + word2tag 35 = pure MAXF + word2tag 36 = pure MINF + word2tag 37 = pure CAST word2tag n = unknownTag "UPrim2" n instance Tag BPrim1 where From 679239d7186f650a3eafedf0cdddf6cbb552f500 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:49:49 -0700 Subject: [PATCH 068/113] Fix truncate0 --- unison-runtime/src/Unison/Runtime/Builtin.hs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 90accd94b0..a21479a171 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -489,13 +489,18 @@ i2f = unop ITOF n2f = unop NTOF trni :: (Var v) => SuperNormal v -trni = unop0 2 $ \[x, z, b] -> - TLetD z UN (TLit $ I 0) +trni = unop0 4 $ \[x, z, b, tag, n] -> + -- TODO: Do we need to do all calculations _before_ the branch? + TLetD z UN (TLit $ N 0) . TLetD b UN (TPrm LEQI [x, z]) + . TLetD tag UN (TLit $ I $ fromIntegral nt) + . TLetD n UN (TPrm CAST [x, tag]) . TMatch b $ MatchIntegral (mapSingleton 1 $ TVar z) - (Just $ TVar x) + (Just $ TVar n) + where + PackedTag nt = TT.natTag modular :: (Var v) => POp -> (Bool -> ANormal v) -> SuperNormal v modular pop ret = From 741231b1cf0c75f792e03fa70218727a5118a175 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 31 Oct 2024 23:49:49 -0700 Subject: [PATCH 069/113] Fix dropn output type --- unison-runtime/src/Unison/Runtime/Builtin.hs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index a21479a171..062815603d 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -519,13 +519,20 @@ evnn = modular MODN (\b -> if b then fls else tru) oddn = modular MODN (\b -> if b then tru else fls) dropn :: (Var v) => SuperNormal v -dropn = binop0 1 $ \[x, y, b] -> - TLetD b UN (TPrm LEQN [x, y]) $ +dropn = binop0 4 $ \[x, y, b, r, tag, n] -> + TLetD b UN (TPrm LEQN [x, y]) + -- TODO: Can we avoid this work until after the branch? + . TLetD tag UN (TLit $ I $ fromIntegral nt) + . TLetD r UN (TPrm SUBN [x, y]) + . TLetD n UN (TPrm CAST [r, tag]) + $ ( TMatch b $ MatchIntegral (mapSingleton 1 $ TLit $ N 0) - (Just $ TPrm SUBN [x, y]) + (Just $ TVar n) ) + where + PackedTag nt = TT.natTag appendt, taket, dropt, indext, indexb, sizet, unconst, unsnoct :: (Var v) => SuperNormal v appendt = binop0 0 $ \[x, y] -> TPrm CATT [x, y] From b698ae8dda0c17ef8a7fe97ea580f4850bb152bc Mon Sep 17 00:00:00 2001 From: ChrisPenner Date: Fri, 1 Nov 2024 07:44:08 +0000 Subject: [PATCH 070/113] automatically run ormolu --- unison-runtime/src/Unison/Runtime/Builtin.hs | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 062815603d..ef919b5baf 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -174,6 +174,7 @@ import Unison.Runtime.Foreign qualified as F import Unison.Runtime.Foreign.Function import Unison.Runtime.Stack (Val (..), emptyVal) import Unison.Runtime.Stack qualified as Closure +import Unison.Runtime.TypeTags qualified as TT import Unison.Symbol import Unison.Type qualified as Ty import Unison.Util.Bytes qualified as Bytes @@ -193,7 +194,6 @@ import Unison.Util.Text (Text) import Unison.Util.Text qualified as Util.Text import Unison.Util.Text.Pattern qualified as TPat import Unison.Var -import qualified Unison.Runtime.TypeTags as TT type Failure = F.Failure Val @@ -521,16 +521,15 @@ oddn = modular MODN (\b -> if b then tru else fls) dropn :: (Var v) => SuperNormal v dropn = binop0 4 $ \[x, y, b, r, tag, n] -> TLetD b UN (TPrm LEQN [x, y]) - -- TODO: Can we avoid this work until after the branch? - . TLetD tag UN (TLit $ I $ fromIntegral nt) - . TLetD r UN (TPrm SUBN [x, y]) - . TLetD n UN (TPrm CAST [r, tag]) - $ - ( TMatch b $ - MatchIntegral - (mapSingleton 1 $ TLit $ N 0) - (Just $ TVar n) - ) + -- TODO: Can we avoid this work until after the branch? + . TLetD tag UN (TLit $ I $ fromIntegral nt) + . TLetD r UN (TPrm SUBN [x, y]) + . TLetD n UN (TPrm CAST [r, tag]) + $ ( TMatch b $ + MatchIntegral + (mapSingleton 1 $ TLit $ N 0) + (Just $ TVar n) + ) where PackedTag nt = TT.natTag @@ -817,8 +816,8 @@ andb = binop0 0 $ \[p, q] -> coerceType :: PackedTag -> SuperNormal Symbol coerceType (PackedTag destType) = unop0 1 $ \[v, tag] -> - TLetD tag UN (TLit $ I $ fromIntegral destType) - $ TPrm CAST [v, tag] + TLetD tag UN (TLit $ I $ fromIntegral destType) $ + TPrm CAST [v, tag] -- unbox x0 ri x $ -- TCon ro 0 [x] From e0f047104315767c1e24ccbc1c452053d28daeac Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 1 Nov 2024 09:51:21 -0700 Subject: [PATCH 071/113] Just use nats for buffer tags on the stack --- .../src/Unison/Runtime/Foreign/Function.hs | 13 ++++++------- unison-runtime/src/Unison/Runtime/TypeTags.hs | 4 ---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 8399c7ee13..0afda693ed 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -35,7 +35,6 @@ import Unison.Runtime.Exception import Unison.Runtime.Foreign import Unison.Runtime.MCode import Unison.Runtime.Stack -import Unison.Runtime.TypeTags qualified as TT import Unison.Type ( iarrayRef, ibytearrayRef, @@ -404,7 +403,7 @@ instance stk <- writeForeign stk b writeForeign stk a -no'buf, line'buf, block'buf, sblock'buf :: Int +no'buf, line'buf, block'buf, sblock'buf :: Word64 no'buf = fromIntegral Ty.bufferModeNoBufferingId line'buf = fromIntegral Ty.bufferModeLineBufferingId block'buf = fromIntegral Ty.bufferModeBlockBufferingId @@ -412,7 +411,7 @@ sblock'buf = fromIntegral Ty.bufferModeSizedBlockBufferingId instance ForeignConvention BufferMode where readForeign (i : args) stk = - upeekOff stk i >>= \case + peekOffN stk i >>= \case t | t == no'buf -> pure (args, NoBuffering) | t == line'buf -> pure (args, LineBuffering) @@ -428,13 +427,13 @@ instance ForeignConvention BufferMode where writeForeign stk bm = bump stk >>= \stk -> case bm of - NoBuffering -> stk <$ upokeT stk no'buf TT.bufferModeTag - LineBuffering -> stk <$ upokeT stk line'buf TT.bufferModeTag - BlockBuffering Nothing -> stk <$ upokeT stk block'buf TT.bufferModeTag + NoBuffering -> stk <$ pokeN stk no'buf + LineBuffering -> stk <$ pokeN stk line'buf + BlockBuffering Nothing -> stk <$ pokeN stk block'buf BlockBuffering (Just n) -> do pokeI stk n stk <- bump stk - stk <$ upokeT stk sblock'buf TT.bufferModeTag + stk <$ pokeN stk sblock'buf -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. diff --git a/unison-runtime/src/Unison/Runtime/TypeTags.hs b/unison-runtime/src/Unison/Runtime/TypeTags.hs index 3e8929d944..8bccb00f81 100644 --- a/unison-runtime/src/Unison/Runtime/TypeTags.hs +++ b/unison-runtime/src/Unison/Runtime/TypeTags.hs @@ -11,7 +11,6 @@ module Unison.Runtime.TypeTags intTag, charTag, unitTag, - bufferModeTag, leftTag, rightTag, ) @@ -127,9 +126,6 @@ charTag = mkSimpleTag "charTag" Ty.charRef unitTag :: PackedTag unitTag = mkSimpleTag "unitTag" Ty.unitRef -bufferModeTag :: PackedTag -bufferModeTag = mkSimpleTag "bufferModeTag" Ty.bufferModeRef - leftTag, rightTag :: PackedTag (leftTag, rightTag) | Just n <- Map.lookup Ty.eitherRef builtinTypeNumbering, From 809c23a18c550caa23e5812c37980ff3dfe8f478 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 1 Nov 2024 09:51:21 -0700 Subject: [PATCH 072/113] Split up in-place mutation so the stack debugger works --- unison-runtime/src/Unison/Runtime/Machine.hs | 4 +++- unison-runtime/src/Unison/Runtime/Stack.hs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 072d07dd75..e7d9b7e42a 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1818,7 +1818,9 @@ yield !env !denv !activeThreads !stk !k = leap denv k leap !denv0 (Mark a ps cs k) = do let denv = cs <> EC.withoutKeys denv0 ps val = denv0 EC.! EC.findMin ps - bpoke stk . Data1 Rf.effectRef (PackedTag 0) =<< peek stk + v <- peek stk + stk <- bump stk + bpoke stk $ Data1 Rf.effectRef (PackedTag 0) v stk <- adjustArgs stk a apply env denv activeThreads stk k False (VArg1 0) val leap !denv (Push fsz asz (CIx ref _ _) f nx k) = do diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index d38ab6e617..370c0c18dd 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -141,6 +141,7 @@ import Prelude hiding (words) {- ORMOLU_DISABLE -} #ifdef STACK_CHECK +import Unison.Debug qualified as Debug type DebugCallStack = (HasCallStack :: Constraint) From 0f691a9aeb66d7eead2d692028837bb47fd2bd1e Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 1 Nov 2024 16:56:13 -0700 Subject: [PATCH 073/113] Update transcripts --- unison-src/transcripts/fix2693.output.md | 7996 ++++++++--------- .../transcripts/runtime-tests.output.md | 8 +- 2 files changed, 4005 insertions(+), 3999 deletions(-) diff --git a/unison-src/transcripts/fix2693.output.md b/unison-src/transcripts/fix2693.output.md index 454a449fe7..e5414c32a8 100644 --- a/unison-src/transcripts/fix2693.output.md +++ b/unison-src/transcripts/fix2693.output.md @@ -48,2005 +48,2005 @@ scratch/main> add 1 | > range 2000 ⧩ - [ +1 - , +2 - , +3 - , +4 - , +5 - , +6 - , +7 - , +8 - , +9 - , +10 - , +11 - , +12 - , +13 - , +14 - , +15 - , +16 - , +17 - , +18 - , +19 - , +20 - , +21 - , +22 - , +23 - , +24 - , +25 - , +26 - , +27 - , +28 - , +29 - , +30 - , +31 - , +32 - , +33 - , +34 - , +35 - , +36 - , +37 - , +38 - , +39 - , +40 - , +41 - , +42 - , +43 - , +44 - , +45 - , +46 - , +47 - , +48 - , +49 - , +50 - , +51 - , +52 - , +53 - , +54 - , +55 - , +56 - , +57 - , +58 - , +59 - , +60 - , +61 - , +62 - , +63 - , +64 - , +65 - , +66 - , +67 - , +68 - , +69 - , +70 - , +71 - , +72 - , +73 - , +74 - , +75 - , +76 - , +77 - , +78 - , +79 - , +80 - , +81 - , +82 - , +83 - , +84 - , +85 - , +86 - , +87 - , +88 - , +89 - , +90 - , +91 - , +92 - , +93 - , +94 - , +95 - , +96 - , +97 - , +98 - , +99 - , +100 - , +101 - , +102 - , +103 - , +104 - , +105 - , +106 - , +107 - , +108 - , +109 - , +110 - , +111 - , +112 - , +113 - , +114 - , +115 - , +116 - , +117 - , +118 - , +119 - , +120 - , +121 - , +122 - , +123 - , +124 - , +125 - , +126 - , +127 - , +128 - , +129 - , +130 - , +131 - , +132 - , +133 - , +134 - , +135 - , +136 - , +137 - , +138 - , +139 - , +140 - , +141 - , +142 - , +143 - , +144 - , +145 - , +146 - , +147 - , +148 - , +149 - , +150 - , +151 - , +152 - , +153 - , +154 - , +155 - , +156 - , +157 - , +158 - , +159 - , +160 - , +161 - , +162 - , +163 - , +164 - , +165 - , +166 - , +167 - , +168 - , +169 - , +170 - , +171 - , +172 - , +173 - , +174 - , +175 - , +176 - , +177 - , +178 - , +179 - , +180 - , +181 - , +182 - , +183 - , +184 - , +185 - , +186 - , +187 - , +188 - , +189 - , +190 - , +191 - , +192 - , +193 - , +194 - , +195 - , +196 - , +197 - , +198 - , +199 - , +200 - , +201 - , +202 - , +203 - , +204 - , +205 - , +206 - , +207 - , +208 - , +209 - , +210 - , +211 - , +212 - , +213 - , +214 - , +215 - , +216 - , +217 - , +218 - , +219 - , +220 - , +221 - , +222 - , +223 - , +224 - , +225 - , +226 - , +227 - , +228 - , +229 - , +230 - , +231 - , +232 - , +233 - , +234 - , +235 - , +236 - , +237 - , +238 - , +239 - , +240 - , +241 - , +242 - , +243 - , +244 - , +245 - , +246 - , +247 - , +248 - , +249 - , +250 - , +251 - , +252 - , +253 - , +254 - , +255 - , +256 - , +257 - , +258 - , +259 - , +260 - , +261 - , +262 - , +263 - , +264 - , +265 - , +266 - , +267 - , +268 - , +269 - , +270 - , +271 - , +272 - , +273 - , +274 - , +275 - , +276 - , +277 - , +278 - , +279 - , +280 - , +281 - , +282 - , +283 - , +284 - , +285 - , +286 - , +287 - , +288 - , +289 - , +290 - , +291 - , +292 - , +293 - , +294 - , +295 - , +296 - , +297 - , +298 - , +299 - , +300 - , +301 - , +302 - , +303 - , +304 - , +305 - , +306 - , +307 - , +308 - , +309 - , +310 - , +311 - , +312 - , +313 - , +314 - , +315 - , +316 - , +317 - , +318 - , +319 - , +320 - , +321 - , +322 - , +323 - , +324 - , +325 - , +326 - , +327 - , +328 - , +329 - , +330 - , +331 - , +332 - , +333 - , +334 - , +335 - , +336 - , +337 - , +338 - , +339 - , +340 - , +341 - , +342 - , +343 - , +344 - , +345 - , +346 - , +347 - , +348 - , +349 - , +350 - , +351 - , +352 - , +353 - , +354 - , +355 - , +356 - , +357 - , +358 - , +359 - , +360 - , +361 - , +362 - , +363 - , +364 - , +365 - , +366 - , +367 - , +368 - , +369 - , +370 - , +371 - , +372 - , +373 - , +374 - , +375 - , +376 - , +377 - , +378 - , +379 - , +380 - , +381 - , +382 - , +383 - , +384 - , +385 - , +386 - , +387 - , +388 - , +389 - , +390 - , +391 - , +392 - , +393 - , +394 - , +395 - , +396 - , +397 - , +398 - , +399 - , +400 - , +401 - , +402 - , +403 - , +404 - , +405 - , +406 - , +407 - , +408 - , +409 - , +410 - , +411 - , +412 - , +413 - , +414 - , +415 - , +416 - , +417 - , +418 - , +419 - , +420 - , +421 - , +422 - , +423 - , +424 - , +425 - , +426 - , +427 - , +428 - , +429 - , +430 - , +431 - , +432 - , +433 - , +434 - , +435 - , +436 - , +437 - , +438 - , +439 - , +440 - , +441 - , +442 - , +443 - , +444 - , +445 - , +446 - , +447 - , +448 - , +449 - , +450 - , +451 - , +452 - , +453 - , +454 - , +455 - , +456 - , +457 - , +458 - , +459 - , +460 - , +461 - , +462 - , +463 - , +464 - , +465 - , +466 - , +467 - , +468 - , +469 - , +470 - , +471 - , +472 - , +473 - , +474 - , +475 - , +476 - , +477 - , +478 - , +479 - , +480 - , +481 - , +482 - , +483 - , +484 - , +485 - , +486 - , +487 - , +488 - , +489 - , +490 - , +491 - , +492 - , +493 - , +494 - , +495 - , +496 - , +497 - , +498 - , +499 - , +500 - , +501 - , +502 - , +503 - , +504 - , +505 - , +506 - , +507 - , +508 - , +509 - , +510 - , +511 - , +512 - , +513 - , +514 - , +515 - , +516 - , +517 - , +518 - , +519 - , +520 - , +521 - , +522 - , +523 - , +524 - , +525 - , +526 - , +527 - , +528 - , +529 - , +530 - , +531 - , +532 - , +533 - , +534 - , +535 - , +536 - , +537 - , +538 - , +539 - , +540 - , +541 - , +542 - , +543 - , +544 - , +545 - , +546 - , +547 - , +548 - , +549 - , +550 - , +551 - , +552 - , +553 - , +554 - , +555 - , +556 - , +557 - , +558 - , +559 - , +560 - , +561 - , +562 - , +563 - , +564 - , +565 - , +566 - , +567 - , +568 - , +569 - , +570 - , +571 - , +572 - , +573 - , +574 - , +575 - , +576 - , +577 - , +578 - , +579 - , +580 - , +581 - , +582 - , +583 - , +584 - , +585 - , +586 - , +587 - , +588 - , +589 - , +590 - , +591 - , +592 - , +593 - , +594 - , +595 - , +596 - , +597 - , +598 - , +599 - , +600 - , +601 - , +602 - , +603 - , +604 - , +605 - , +606 - , +607 - , +608 - , +609 - , +610 - , +611 - , +612 - , +613 - , +614 - , +615 - , +616 - , +617 - , +618 - , +619 - , +620 - , +621 - , +622 - , +623 - , +624 - , +625 - , +626 - , +627 - , +628 - , +629 - , +630 - , +631 - , +632 - , +633 - , +634 - , +635 - , +636 - , +637 - , +638 - , +639 - , +640 - , +641 - , +642 - , +643 - , +644 - , +645 - , +646 - , +647 - , +648 - , +649 - , +650 - , +651 - , +652 - , +653 - , +654 - , +655 - , +656 - , +657 - , +658 - , +659 - , +660 - , +661 - , +662 - , +663 - , +664 - , +665 - , +666 - , +667 - , +668 - , +669 - , +670 - , +671 - , +672 - , +673 - , +674 - , +675 - , +676 - , +677 - , +678 - , +679 - , +680 - , +681 - , +682 - , +683 - , +684 - , +685 - , +686 - , +687 - , +688 - , +689 - , +690 - , +691 - , +692 - , +693 - , +694 - , +695 - , +696 - , +697 - , +698 - , +699 - , +700 - , +701 - , +702 - , +703 - , +704 - , +705 - , +706 - , +707 - , +708 - , +709 - , +710 - , +711 - , +712 - , +713 - , +714 - , +715 - , +716 - , +717 - , +718 - , +719 - , +720 - , +721 - , +722 - , +723 - , +724 - , +725 - , +726 - , +727 - , +728 - , +729 - , +730 - , +731 - , +732 - , +733 - , +734 - , +735 - , +736 - , +737 - , +738 - , +739 - , +740 - , +741 - , +742 - , +743 - , +744 - , +745 - , +746 - , +747 - , +748 - , +749 - , +750 - , +751 - , +752 - , +753 - , +754 - , +755 - , +756 - , +757 - , +758 - , +759 - , +760 - , +761 - , +762 - , +763 - , +764 - , +765 - , +766 - , +767 - , +768 - , +769 - , +770 - , +771 - , +772 - , +773 - , +774 - , +775 - , +776 - , +777 - , +778 - , +779 - , +780 - , +781 - , +782 - , +783 - , +784 - , +785 - , +786 - , +787 - , +788 - , +789 - , +790 - , +791 - , +792 - , +793 - , +794 - , +795 - , +796 - , +797 - , +798 - , +799 - , +800 - , +801 - , +802 - , +803 - , +804 - , +805 - , +806 - , +807 - , +808 - , +809 - , +810 - , +811 - , +812 - , +813 - , +814 - , +815 - , +816 - , +817 - , +818 - , +819 - , +820 - , +821 - , +822 - , +823 - , +824 - , +825 - , +826 - , +827 - , +828 - , +829 - , +830 - , +831 - , +832 - , +833 - , +834 - , +835 - , +836 - , +837 - , +838 - , +839 - , +840 - , +841 - , +842 - , +843 - , +844 - , +845 - , +846 - , +847 - , +848 - , +849 - , +850 - , +851 - , +852 - , +853 - , +854 - , +855 - , +856 - , +857 - , +858 - , +859 - , +860 - , +861 - , +862 - , +863 - , +864 - , +865 - , +866 - , +867 - , +868 - , +869 - , +870 - , +871 - , +872 - , +873 - , +874 - , +875 - , +876 - , +877 - , +878 - , +879 - , +880 - , +881 - , +882 - , +883 - , +884 - , +885 - , +886 - , +887 - , +888 - , +889 - , +890 - , +891 - , +892 - , +893 - , +894 - , +895 - , +896 - , +897 - , +898 - , +899 - , +900 - , +901 - , +902 - , +903 - , +904 - , +905 - , +906 - , +907 - , +908 - , +909 - , +910 - , +911 - , +912 - , +913 - , +914 - , +915 - , +916 - , +917 - , +918 - , +919 - , +920 - , +921 - , +922 - , +923 - , +924 - , +925 - , +926 - , +927 - , +928 - , +929 - , +930 - , +931 - , +932 - , +933 - , +934 - , +935 - , +936 - , +937 - , +938 - , +939 - , +940 - , +941 - , +942 - , +943 - , +944 - , +945 - , +946 - , +947 - , +948 - , +949 - , +950 - , +951 - , +952 - , +953 - , +954 - , +955 - , +956 - , +957 - , +958 - , +959 - , +960 - , +961 - , +962 - , +963 - , +964 - , +965 - , +966 - , +967 - , +968 - , +969 - , +970 - , +971 - , +972 - , +973 - , +974 - , +975 - , +976 - , +977 - , +978 - , +979 - , +980 - , +981 - , +982 - , +983 - , +984 - , +985 - , +986 - , +987 - , +988 - , +989 - , +990 - , +991 - , +992 - , +993 - , +994 - , +995 - , +996 - , +997 - , +998 - , +999 - , +1000 - , +1001 - , +1002 - , +1003 - , +1004 - , +1005 - , +1006 - , +1007 - , +1008 - , +1009 - , +1010 - , +1011 - , +1012 - , +1013 - , +1014 - , +1015 - , +1016 - , +1017 - , +1018 - , +1019 - , +1020 - , +1021 - , +1022 - , +1023 - , +1024 - , +1025 - , +1026 - , +1027 - , +1028 - , +1029 - , +1030 - , +1031 - , +1032 - , +1033 - , +1034 - , +1035 - , +1036 - , +1037 - , +1038 - , +1039 - , +1040 - , +1041 - , +1042 - , +1043 - , +1044 - , +1045 - , +1046 - , +1047 - , +1048 - , +1049 - , +1050 - , +1051 - , +1052 - , +1053 - , +1054 - , +1055 - , +1056 - , +1057 - , +1058 - , +1059 - , +1060 - , +1061 - , +1062 - , +1063 - , +1064 - , +1065 - , +1066 - , +1067 - , +1068 - , +1069 - , +1070 - , +1071 - , +1072 - , +1073 - , +1074 - , +1075 - , +1076 - , +1077 - , +1078 - , +1079 - , +1080 - , +1081 - , +1082 - , +1083 - , +1084 - , +1085 - , +1086 - , +1087 - , +1088 - , +1089 - , +1090 - , +1091 - , +1092 - , +1093 - , +1094 - , +1095 - , +1096 - , +1097 - , +1098 - , +1099 - , +1100 - , +1101 - , +1102 - , +1103 - , +1104 - , +1105 - , +1106 - , +1107 - , +1108 - , +1109 - , +1110 - , +1111 - , +1112 - , +1113 - , +1114 - , +1115 - , +1116 - , +1117 - , +1118 - , +1119 - , +1120 - , +1121 - , +1122 - , +1123 - , +1124 - , +1125 - , +1126 - , +1127 - , +1128 - , +1129 - , +1130 - , +1131 - , +1132 - , +1133 - , +1134 - , +1135 - , +1136 - , +1137 - , +1138 - , +1139 - , +1140 - , +1141 - , +1142 - , +1143 - , +1144 - , +1145 - , +1146 - , +1147 - , +1148 - , +1149 - , +1150 - , +1151 - , +1152 - , +1153 - , +1154 - , +1155 - , +1156 - , +1157 - , +1158 - , +1159 - , +1160 - , +1161 - , +1162 - , +1163 - , +1164 - , +1165 - , +1166 - , +1167 - , +1168 - , +1169 - , +1170 - , +1171 - , +1172 - , +1173 - , +1174 - , +1175 - , +1176 - , +1177 - , +1178 - , +1179 - , +1180 - , +1181 - , +1182 - , +1183 - , +1184 - , +1185 - , +1186 - , +1187 - , +1188 - , +1189 - , +1190 - , +1191 - , +1192 - , +1193 - , +1194 - , +1195 - , +1196 - , +1197 - , +1198 - , +1199 - , +1200 - , +1201 - , +1202 - , +1203 - , +1204 - , +1205 - , +1206 - , +1207 - , +1208 - , +1209 - , +1210 - , +1211 - , +1212 - , +1213 - , +1214 - , +1215 - , +1216 - , +1217 - , +1218 - , +1219 - , +1220 - , +1221 - , +1222 - , +1223 - , +1224 - , +1225 - , +1226 - , +1227 - , +1228 - , +1229 - , +1230 - , +1231 - , +1232 - , +1233 - , +1234 - , +1235 - , +1236 - , +1237 - , +1238 - , +1239 - , +1240 - , +1241 - , +1242 - , +1243 - , +1244 - , +1245 - , +1246 - , +1247 - , +1248 - , +1249 - , +1250 - , +1251 - , +1252 - , +1253 - , +1254 - , +1255 - , +1256 - , +1257 - , +1258 - , +1259 - , +1260 - , +1261 - , +1262 - , +1263 - , +1264 - , +1265 - , +1266 - , +1267 - , +1268 - , +1269 - , +1270 - , +1271 - , +1272 - , +1273 - , +1274 - , +1275 - , +1276 - , +1277 - , +1278 - , +1279 - , +1280 - , +1281 - , +1282 - , +1283 - , +1284 - , +1285 - , +1286 - , +1287 - , +1288 - , +1289 - , +1290 - , +1291 - , +1292 - , +1293 - , +1294 - , +1295 - , +1296 - , +1297 - , +1298 - , +1299 - , +1300 - , +1301 - , +1302 - , +1303 - , +1304 - , +1305 - , +1306 - , +1307 - , +1308 - , +1309 - , +1310 - , +1311 - , +1312 - , +1313 - , +1314 - , +1315 - , +1316 - , +1317 - , +1318 - , +1319 - , +1320 - , +1321 - , +1322 - , +1323 - , +1324 - , +1325 - , +1326 - , +1327 - , +1328 - , +1329 - , +1330 - , +1331 - , +1332 - , +1333 - , +1334 - , +1335 - , +1336 - , +1337 - , +1338 - , +1339 - , +1340 - , +1341 - , +1342 - , +1343 - , +1344 - , +1345 - , +1346 - , +1347 - , +1348 - , +1349 - , +1350 - , +1351 - , +1352 - , +1353 - , +1354 - , +1355 - , +1356 - , +1357 - , +1358 - , +1359 - , +1360 - , +1361 - , +1362 - , +1363 - , +1364 - , +1365 - , +1366 - , +1367 - , +1368 - , +1369 - , +1370 - , +1371 - , +1372 - , +1373 - , +1374 - , +1375 - , +1376 - , +1377 - , +1378 - , +1379 - , +1380 - , +1381 - , +1382 - , +1383 - , +1384 - , +1385 - , +1386 - , +1387 - , +1388 - , +1389 - , +1390 - , +1391 - , +1392 - , +1393 - , +1394 - , +1395 - , +1396 - , +1397 - , +1398 - , +1399 - , +1400 - , +1401 - , +1402 - , +1403 - , +1404 - , +1405 - , +1406 - , +1407 - , +1408 - , +1409 - , +1410 - , +1411 - , +1412 - , +1413 - , +1414 - , +1415 - , +1416 - , +1417 - , +1418 - , +1419 - , +1420 - , +1421 - , +1422 - , +1423 - , +1424 - , +1425 - , +1426 - , +1427 - , +1428 - , +1429 - , +1430 - , +1431 - , +1432 - , +1433 - , +1434 - , +1435 - , +1436 - , +1437 - , +1438 - , +1439 - , +1440 - , +1441 - , +1442 - , +1443 - , +1444 - , +1445 - , +1446 - , +1447 - , +1448 - , +1449 - , +1450 - , +1451 - , +1452 - , +1453 - , +1454 - , +1455 - , +1456 - , +1457 - , +1458 - , +1459 - , +1460 - , +1461 - , +1462 - , +1463 - , +1464 - , +1465 - , +1466 - , +1467 - , +1468 - , +1469 - , +1470 - , +1471 - , +1472 - , +1473 - , +1474 - , +1475 - , +1476 - , +1477 - , +1478 - , +1479 - , +1480 - , +1481 - , +1482 - , +1483 - , +1484 - , +1485 - , +1486 - , +1487 - , +1488 - , +1489 - , +1490 - , +1491 - , +1492 - , +1493 - , +1494 - , +1495 - , +1496 - , +1497 - , +1498 - , +1499 - , +1500 - , +1501 - , +1502 - , +1503 - , +1504 - , +1505 - , +1506 - , +1507 - , +1508 - , +1509 - , +1510 - , +1511 - , +1512 - , +1513 - , +1514 - , +1515 - , +1516 - , +1517 - , +1518 - , +1519 - , +1520 - , +1521 - , +1522 - , +1523 - , +1524 - , +1525 - , +1526 - , +1527 - , +1528 - , +1529 - , +1530 - , +1531 - , +1532 - , +1533 - , +1534 - , +1535 - , +1536 - , +1537 - , +1538 - , +1539 - , +1540 - , +1541 - , +1542 - , +1543 - , +1544 - , +1545 - , +1546 - , +1547 - , +1548 - , +1549 - , +1550 - , +1551 - , +1552 - , +1553 - , +1554 - , +1555 - , +1556 - , +1557 - , +1558 - , +1559 - , +1560 - , +1561 - , +1562 - , +1563 - , +1564 - , +1565 - , +1566 - , +1567 - , +1568 - , +1569 - , +1570 - , +1571 - , +1572 - , +1573 - , +1574 - , +1575 - , +1576 - , +1577 - , +1578 - , +1579 - , +1580 - , +1581 - , +1582 - , +1583 - , +1584 - , +1585 - , +1586 - , +1587 - , +1588 - , +1589 - , +1590 - , +1591 - , +1592 - , +1593 - , +1594 - , +1595 - , +1596 - , +1597 - , +1598 - , +1599 - , +1600 - , +1601 - , +1602 - , +1603 - , +1604 - , +1605 - , +1606 - , +1607 - , +1608 - , +1609 - , +1610 - , +1611 - , +1612 - , +1613 - , +1614 - , +1615 - , +1616 - , +1617 - , +1618 - , +1619 - , +1620 - , +1621 - , +1622 - , +1623 - , +1624 - , +1625 - , +1626 - , +1627 - , +1628 - , +1629 - , +1630 - , +1631 - , +1632 - , +1633 - , +1634 - , +1635 - , +1636 - , +1637 - , +1638 - , +1639 - , +1640 - , +1641 - , +1642 - , +1643 - , +1644 - , +1645 - , +1646 - , +1647 - , +1648 - , +1649 - , +1650 - , +1651 - , +1652 - , +1653 - , +1654 - , +1655 - , +1656 - , +1657 - , +1658 - , +1659 - , +1660 - , +1661 - , +1662 - , +1663 - , +1664 - , +1665 - , +1666 - , +1667 - , +1668 - , +1669 - , +1670 - , +1671 - , +1672 - , +1673 - , +1674 - , +1675 - , +1676 - , +1677 - , +1678 - , +1679 - , +1680 - , +1681 - , +1682 - , +1683 - , +1684 - , +1685 - , +1686 - , +1687 - , +1688 - , +1689 - , +1690 - , +1691 - , +1692 - , +1693 - , +1694 - , +1695 - , +1696 - , +1697 - , +1698 - , +1699 - , +1700 - , +1701 - , +1702 - , +1703 - , +1704 - , +1705 - , +1706 - , +1707 - , +1708 - , +1709 - , +1710 - , +1711 - , +1712 - , +1713 - , +1714 - , +1715 - , +1716 - , +1717 - , +1718 - , +1719 - , +1720 - , +1721 - , +1722 - , +1723 - , +1724 - , +1725 - , +1726 - , +1727 - , +1728 - , +1729 - , +1730 - , +1731 - , +1732 - , +1733 - , +1734 - , +1735 - , +1736 - , +1737 - , +1738 - , +1739 - , +1740 - , +1741 - , +1742 - , +1743 - , +1744 - , +1745 - , +1746 - , +1747 - , +1748 - , +1749 - , +1750 - , +1751 - , +1752 - , +1753 - , +1754 - , +1755 - , +1756 - , +1757 - , +1758 - , +1759 - , +1760 - , +1761 - , +1762 - , +1763 - , +1764 - , +1765 - , +1766 - , +1767 - , +1768 - , +1769 - , +1770 - , +1771 - , +1772 - , +1773 - , +1774 - , +1775 - , +1776 - , +1777 - , +1778 - , +1779 - , +1780 - , +1781 - , +1782 - , +1783 - , +1784 - , +1785 - , +1786 - , +1787 - , +1788 - , +1789 - , +1790 - , +1791 - , +1792 - , +1793 - , +1794 - , +1795 - , +1796 - , +1797 - , +1798 - , +1799 - , +1800 - , +1801 - , +1802 - , +1803 - , +1804 - , +1805 - , +1806 - , +1807 - , +1808 - , +1809 - , +1810 - , +1811 - , +1812 - , +1813 - , +1814 - , +1815 - , +1816 - , +1817 - , +1818 - , +1819 - , +1820 - , +1821 - , +1822 - , +1823 - , +1824 - , +1825 - , +1826 - , +1827 - , +1828 - , +1829 - , +1830 - , +1831 - , +1832 - , +1833 - , +1834 - , +1835 - , +1836 - , +1837 - , +1838 - , +1839 - , +1840 - , +1841 - , +1842 - , +1843 - , +1844 - , +1845 - , +1846 - , +1847 - , +1848 - , +1849 - , +1850 - , +1851 - , +1852 - , +1853 - , +1854 - , +1855 - , +1856 - , +1857 - , +1858 - , +1859 - , +1860 - , +1861 - , +1862 - , +1863 - , +1864 - , +1865 - , +1866 - , +1867 - , +1868 - , +1869 - , +1870 - , +1871 - , +1872 - , +1873 - , +1874 - , +1875 - , +1876 - , +1877 - , +1878 - , +1879 - , +1880 - , +1881 - , +1882 - , +1883 - , +1884 - , +1885 - , +1886 - , +1887 - , +1888 - , +1889 - , +1890 - , +1891 - , +1892 - , +1893 - , +1894 - , +1895 - , +1896 - , +1897 - , +1898 - , +1899 - , +1900 - , +1901 - , +1902 - , +1903 - , +1904 - , +1905 - , +1906 - , +1907 - , +1908 - , +1909 - , +1910 - , +1911 - , +1912 - , +1913 - , +1914 - , +1915 - , +1916 - , +1917 - , +1918 - , +1919 - , +1920 - , +1921 - , +1922 - , +1923 - , +1924 - , +1925 - , +1926 - , +1927 - , +1928 - , +1929 - , +1930 - , +1931 - , +1932 - , +1933 - , +1934 - , +1935 - , +1936 - , +1937 - , +1938 - , +1939 - , +1940 - , +1941 - , +1942 - , +1943 - , +1944 - , +1945 - , +1946 - , +1947 - , +1948 - , +1949 - , +1950 - , +1951 - , +1952 - , +1953 - , +1954 - , +1955 - , +1956 - , +1957 - , +1958 - , +1959 - , +1960 - , +1961 - , +1962 - , +1963 - , +1964 - , +1965 - , +1966 - , +1967 - , +1968 - , +1969 - , +1970 - , +1971 - , +1972 - , +1973 - , +1974 - , +1975 - , +1976 - , +1977 - , +1978 - , +1979 - , +1980 - , +1981 - , +1982 - , +1983 - , +1984 - , +1985 - , +1986 - , +1987 - , +1988 - , +1989 - , +1990 - , +1991 - , +1992 - , +1993 - , +1994 - , +1995 - , +1996 - , +1997 - , +1998 - , +1999 + [ 1 + , 2 + , 3 + , 4 + , 5 + , 6 + , 7 + , 8 + , 9 + , 10 + , 11 + , 12 + , 13 + , 14 + , 15 + , 16 + , 17 + , 18 + , 19 + , 20 + , 21 + , 22 + , 23 + , 24 + , 25 + , 26 + , 27 + , 28 + , 29 + , 30 + , 31 + , 32 + , 33 + , 34 + , 35 + , 36 + , 37 + , 38 + , 39 + , 40 + , 41 + , 42 + , 43 + , 44 + , 45 + , 46 + , 47 + , 48 + , 49 + , 50 + , 51 + , 52 + , 53 + , 54 + , 55 + , 56 + , 57 + , 58 + , 59 + , 60 + , 61 + , 62 + , 63 + , 64 + , 65 + , 66 + , 67 + , 68 + , 69 + , 70 + , 71 + , 72 + , 73 + , 74 + , 75 + , 76 + , 77 + , 78 + , 79 + , 80 + , 81 + , 82 + , 83 + , 84 + , 85 + , 86 + , 87 + , 88 + , 89 + , 90 + , 91 + , 92 + , 93 + , 94 + , 95 + , 96 + , 97 + , 98 + , 99 + , 100 + , 101 + , 102 + , 103 + , 104 + , 105 + , 106 + , 107 + , 108 + , 109 + , 110 + , 111 + , 112 + , 113 + , 114 + , 115 + , 116 + , 117 + , 118 + , 119 + , 120 + , 121 + , 122 + , 123 + , 124 + , 125 + , 126 + , 127 + , 128 + , 129 + , 130 + , 131 + , 132 + , 133 + , 134 + , 135 + , 136 + , 137 + , 138 + , 139 + , 140 + , 141 + , 142 + , 143 + , 144 + , 145 + , 146 + , 147 + , 148 + , 149 + , 150 + , 151 + , 152 + , 153 + , 154 + , 155 + , 156 + , 157 + , 158 + , 159 + , 160 + , 161 + , 162 + , 163 + , 164 + , 165 + , 166 + , 167 + , 168 + , 169 + , 170 + , 171 + , 172 + , 173 + , 174 + , 175 + , 176 + , 177 + , 178 + , 179 + , 180 + , 181 + , 182 + , 183 + , 184 + , 185 + , 186 + , 187 + , 188 + , 189 + , 190 + , 191 + , 192 + , 193 + , 194 + , 195 + , 196 + , 197 + , 198 + , 199 + , 200 + , 201 + , 202 + , 203 + , 204 + , 205 + , 206 + , 207 + , 208 + , 209 + , 210 + , 211 + , 212 + , 213 + , 214 + , 215 + , 216 + , 217 + , 218 + , 219 + , 220 + , 221 + , 222 + , 223 + , 224 + , 225 + , 226 + , 227 + , 228 + , 229 + , 230 + , 231 + , 232 + , 233 + , 234 + , 235 + , 236 + , 237 + , 238 + , 239 + , 240 + , 241 + , 242 + , 243 + , 244 + , 245 + , 246 + , 247 + , 248 + , 249 + , 250 + , 251 + , 252 + , 253 + , 254 + , 255 + , 256 + , 257 + , 258 + , 259 + , 260 + , 261 + , 262 + , 263 + , 264 + , 265 + , 266 + , 267 + , 268 + , 269 + , 270 + , 271 + , 272 + , 273 + , 274 + , 275 + , 276 + , 277 + , 278 + , 279 + , 280 + , 281 + , 282 + , 283 + , 284 + , 285 + , 286 + , 287 + , 288 + , 289 + , 290 + , 291 + , 292 + , 293 + , 294 + , 295 + , 296 + , 297 + , 298 + , 299 + , 300 + , 301 + , 302 + , 303 + , 304 + , 305 + , 306 + , 307 + , 308 + , 309 + , 310 + , 311 + , 312 + , 313 + , 314 + , 315 + , 316 + , 317 + , 318 + , 319 + , 320 + , 321 + , 322 + , 323 + , 324 + , 325 + , 326 + , 327 + , 328 + , 329 + , 330 + , 331 + , 332 + , 333 + , 334 + , 335 + , 336 + , 337 + , 338 + , 339 + , 340 + , 341 + , 342 + , 343 + , 344 + , 345 + , 346 + , 347 + , 348 + , 349 + , 350 + , 351 + , 352 + , 353 + , 354 + , 355 + , 356 + , 357 + , 358 + , 359 + , 360 + , 361 + , 362 + , 363 + , 364 + , 365 + , 366 + , 367 + , 368 + , 369 + , 370 + , 371 + , 372 + , 373 + , 374 + , 375 + , 376 + , 377 + , 378 + , 379 + , 380 + , 381 + , 382 + , 383 + , 384 + , 385 + , 386 + , 387 + , 388 + , 389 + , 390 + , 391 + , 392 + , 393 + , 394 + , 395 + , 396 + , 397 + , 398 + , 399 + , 400 + , 401 + , 402 + , 403 + , 404 + , 405 + , 406 + , 407 + , 408 + , 409 + , 410 + , 411 + , 412 + , 413 + , 414 + , 415 + , 416 + , 417 + , 418 + , 419 + , 420 + , 421 + , 422 + , 423 + , 424 + , 425 + , 426 + , 427 + , 428 + , 429 + , 430 + , 431 + , 432 + , 433 + , 434 + , 435 + , 436 + , 437 + , 438 + , 439 + , 440 + , 441 + , 442 + , 443 + , 444 + , 445 + , 446 + , 447 + , 448 + , 449 + , 450 + , 451 + , 452 + , 453 + , 454 + , 455 + , 456 + , 457 + , 458 + , 459 + , 460 + , 461 + , 462 + , 463 + , 464 + , 465 + , 466 + , 467 + , 468 + , 469 + , 470 + , 471 + , 472 + , 473 + , 474 + , 475 + , 476 + , 477 + , 478 + , 479 + , 480 + , 481 + , 482 + , 483 + , 484 + , 485 + , 486 + , 487 + , 488 + , 489 + , 490 + , 491 + , 492 + , 493 + , 494 + , 495 + , 496 + , 497 + , 498 + , 499 + , 500 + , 501 + , 502 + , 503 + , 504 + , 505 + , 506 + , 507 + , 508 + , 509 + , 510 + , 511 + , 512 + , 513 + , 514 + , 515 + , 516 + , 517 + , 518 + , 519 + , 520 + , 521 + , 522 + , 523 + , 524 + , 525 + , 526 + , 527 + , 528 + , 529 + , 530 + , 531 + , 532 + , 533 + , 534 + , 535 + , 536 + , 537 + , 538 + , 539 + , 540 + , 541 + , 542 + , 543 + , 544 + , 545 + , 546 + , 547 + , 548 + , 549 + , 550 + , 551 + , 552 + , 553 + , 554 + , 555 + , 556 + , 557 + , 558 + , 559 + , 560 + , 561 + , 562 + , 563 + , 564 + , 565 + , 566 + , 567 + , 568 + , 569 + , 570 + , 571 + , 572 + , 573 + , 574 + , 575 + , 576 + , 577 + , 578 + , 579 + , 580 + , 581 + , 582 + , 583 + , 584 + , 585 + , 586 + , 587 + , 588 + , 589 + , 590 + , 591 + , 592 + , 593 + , 594 + , 595 + , 596 + , 597 + , 598 + , 599 + , 600 + , 601 + , 602 + , 603 + , 604 + , 605 + , 606 + , 607 + , 608 + , 609 + , 610 + , 611 + , 612 + , 613 + , 614 + , 615 + , 616 + , 617 + , 618 + , 619 + , 620 + , 621 + , 622 + , 623 + , 624 + , 625 + , 626 + , 627 + , 628 + , 629 + , 630 + , 631 + , 632 + , 633 + , 634 + , 635 + , 636 + , 637 + , 638 + , 639 + , 640 + , 641 + , 642 + , 643 + , 644 + , 645 + , 646 + , 647 + , 648 + , 649 + , 650 + , 651 + , 652 + , 653 + , 654 + , 655 + , 656 + , 657 + , 658 + , 659 + , 660 + , 661 + , 662 + , 663 + , 664 + , 665 + , 666 + , 667 + , 668 + , 669 + , 670 + , 671 + , 672 + , 673 + , 674 + , 675 + , 676 + , 677 + , 678 + , 679 + , 680 + , 681 + , 682 + , 683 + , 684 + , 685 + , 686 + , 687 + , 688 + , 689 + , 690 + , 691 + , 692 + , 693 + , 694 + , 695 + , 696 + , 697 + , 698 + , 699 + , 700 + , 701 + , 702 + , 703 + , 704 + , 705 + , 706 + , 707 + , 708 + , 709 + , 710 + , 711 + , 712 + , 713 + , 714 + , 715 + , 716 + , 717 + , 718 + , 719 + , 720 + , 721 + , 722 + , 723 + , 724 + , 725 + , 726 + , 727 + , 728 + , 729 + , 730 + , 731 + , 732 + , 733 + , 734 + , 735 + , 736 + , 737 + , 738 + , 739 + , 740 + , 741 + , 742 + , 743 + , 744 + , 745 + , 746 + , 747 + , 748 + , 749 + , 750 + , 751 + , 752 + , 753 + , 754 + , 755 + , 756 + , 757 + , 758 + , 759 + , 760 + , 761 + , 762 + , 763 + , 764 + , 765 + , 766 + , 767 + , 768 + , 769 + , 770 + , 771 + , 772 + , 773 + , 774 + , 775 + , 776 + , 777 + , 778 + , 779 + , 780 + , 781 + , 782 + , 783 + , 784 + , 785 + , 786 + , 787 + , 788 + , 789 + , 790 + , 791 + , 792 + , 793 + , 794 + , 795 + , 796 + , 797 + , 798 + , 799 + , 800 + , 801 + , 802 + , 803 + , 804 + , 805 + , 806 + , 807 + , 808 + , 809 + , 810 + , 811 + , 812 + , 813 + , 814 + , 815 + , 816 + , 817 + , 818 + , 819 + , 820 + , 821 + , 822 + , 823 + , 824 + , 825 + , 826 + , 827 + , 828 + , 829 + , 830 + , 831 + , 832 + , 833 + , 834 + , 835 + , 836 + , 837 + , 838 + , 839 + , 840 + , 841 + , 842 + , 843 + , 844 + , 845 + , 846 + , 847 + , 848 + , 849 + , 850 + , 851 + , 852 + , 853 + , 854 + , 855 + , 856 + , 857 + , 858 + , 859 + , 860 + , 861 + , 862 + , 863 + , 864 + , 865 + , 866 + , 867 + , 868 + , 869 + , 870 + , 871 + , 872 + , 873 + , 874 + , 875 + , 876 + , 877 + , 878 + , 879 + , 880 + , 881 + , 882 + , 883 + , 884 + , 885 + , 886 + , 887 + , 888 + , 889 + , 890 + , 891 + , 892 + , 893 + , 894 + , 895 + , 896 + , 897 + , 898 + , 899 + , 900 + , 901 + , 902 + , 903 + , 904 + , 905 + , 906 + , 907 + , 908 + , 909 + , 910 + , 911 + , 912 + , 913 + , 914 + , 915 + , 916 + , 917 + , 918 + , 919 + , 920 + , 921 + , 922 + , 923 + , 924 + , 925 + , 926 + , 927 + , 928 + , 929 + , 930 + , 931 + , 932 + , 933 + , 934 + , 935 + , 936 + , 937 + , 938 + , 939 + , 940 + , 941 + , 942 + , 943 + , 944 + , 945 + , 946 + , 947 + , 948 + , 949 + , 950 + , 951 + , 952 + , 953 + , 954 + , 955 + , 956 + , 957 + , 958 + , 959 + , 960 + , 961 + , 962 + , 963 + , 964 + , 965 + , 966 + , 967 + , 968 + , 969 + , 970 + , 971 + , 972 + , 973 + , 974 + , 975 + , 976 + , 977 + , 978 + , 979 + , 980 + , 981 + , 982 + , 983 + , 984 + , 985 + , 986 + , 987 + , 988 + , 989 + , 990 + , 991 + , 992 + , 993 + , 994 + , 995 + , 996 + , 997 + , 998 + , 999 + , 1000 + , 1001 + , 1002 + , 1003 + , 1004 + , 1005 + , 1006 + , 1007 + , 1008 + , 1009 + , 1010 + , 1011 + , 1012 + , 1013 + , 1014 + , 1015 + , 1016 + , 1017 + , 1018 + , 1019 + , 1020 + , 1021 + , 1022 + , 1023 + , 1024 + , 1025 + , 1026 + , 1027 + , 1028 + , 1029 + , 1030 + , 1031 + , 1032 + , 1033 + , 1034 + , 1035 + , 1036 + , 1037 + , 1038 + , 1039 + , 1040 + , 1041 + , 1042 + , 1043 + , 1044 + , 1045 + , 1046 + , 1047 + , 1048 + , 1049 + , 1050 + , 1051 + , 1052 + , 1053 + , 1054 + , 1055 + , 1056 + , 1057 + , 1058 + , 1059 + , 1060 + , 1061 + , 1062 + , 1063 + , 1064 + , 1065 + , 1066 + , 1067 + , 1068 + , 1069 + , 1070 + , 1071 + , 1072 + , 1073 + , 1074 + , 1075 + , 1076 + , 1077 + , 1078 + , 1079 + , 1080 + , 1081 + , 1082 + , 1083 + , 1084 + , 1085 + , 1086 + , 1087 + , 1088 + , 1089 + , 1090 + , 1091 + , 1092 + , 1093 + , 1094 + , 1095 + , 1096 + , 1097 + , 1098 + , 1099 + , 1100 + , 1101 + , 1102 + , 1103 + , 1104 + , 1105 + , 1106 + , 1107 + , 1108 + , 1109 + , 1110 + , 1111 + , 1112 + , 1113 + , 1114 + , 1115 + , 1116 + , 1117 + , 1118 + , 1119 + , 1120 + , 1121 + , 1122 + , 1123 + , 1124 + , 1125 + , 1126 + , 1127 + , 1128 + , 1129 + , 1130 + , 1131 + , 1132 + , 1133 + , 1134 + , 1135 + , 1136 + , 1137 + , 1138 + , 1139 + , 1140 + , 1141 + , 1142 + , 1143 + , 1144 + , 1145 + , 1146 + , 1147 + , 1148 + , 1149 + , 1150 + , 1151 + , 1152 + , 1153 + , 1154 + , 1155 + , 1156 + , 1157 + , 1158 + , 1159 + , 1160 + , 1161 + , 1162 + , 1163 + , 1164 + , 1165 + , 1166 + , 1167 + , 1168 + , 1169 + , 1170 + , 1171 + , 1172 + , 1173 + , 1174 + , 1175 + , 1176 + , 1177 + , 1178 + , 1179 + , 1180 + , 1181 + , 1182 + , 1183 + , 1184 + , 1185 + , 1186 + , 1187 + , 1188 + , 1189 + , 1190 + , 1191 + , 1192 + , 1193 + , 1194 + , 1195 + , 1196 + , 1197 + , 1198 + , 1199 + , 1200 + , 1201 + , 1202 + , 1203 + , 1204 + , 1205 + , 1206 + , 1207 + , 1208 + , 1209 + , 1210 + , 1211 + , 1212 + , 1213 + , 1214 + , 1215 + , 1216 + , 1217 + , 1218 + , 1219 + , 1220 + , 1221 + , 1222 + , 1223 + , 1224 + , 1225 + , 1226 + , 1227 + , 1228 + , 1229 + , 1230 + , 1231 + , 1232 + , 1233 + , 1234 + , 1235 + , 1236 + , 1237 + , 1238 + , 1239 + , 1240 + , 1241 + , 1242 + , 1243 + , 1244 + , 1245 + , 1246 + , 1247 + , 1248 + , 1249 + , 1250 + , 1251 + , 1252 + , 1253 + , 1254 + , 1255 + , 1256 + , 1257 + , 1258 + , 1259 + , 1260 + , 1261 + , 1262 + , 1263 + , 1264 + , 1265 + , 1266 + , 1267 + , 1268 + , 1269 + , 1270 + , 1271 + , 1272 + , 1273 + , 1274 + , 1275 + , 1276 + , 1277 + , 1278 + , 1279 + , 1280 + , 1281 + , 1282 + , 1283 + , 1284 + , 1285 + , 1286 + , 1287 + , 1288 + , 1289 + , 1290 + , 1291 + , 1292 + , 1293 + , 1294 + , 1295 + , 1296 + , 1297 + , 1298 + , 1299 + , 1300 + , 1301 + , 1302 + , 1303 + , 1304 + , 1305 + , 1306 + , 1307 + , 1308 + , 1309 + , 1310 + , 1311 + , 1312 + , 1313 + , 1314 + , 1315 + , 1316 + , 1317 + , 1318 + , 1319 + , 1320 + , 1321 + , 1322 + , 1323 + , 1324 + , 1325 + , 1326 + , 1327 + , 1328 + , 1329 + , 1330 + , 1331 + , 1332 + , 1333 + , 1334 + , 1335 + , 1336 + , 1337 + , 1338 + , 1339 + , 1340 + , 1341 + , 1342 + , 1343 + , 1344 + , 1345 + , 1346 + , 1347 + , 1348 + , 1349 + , 1350 + , 1351 + , 1352 + , 1353 + , 1354 + , 1355 + , 1356 + , 1357 + , 1358 + , 1359 + , 1360 + , 1361 + , 1362 + , 1363 + , 1364 + , 1365 + , 1366 + , 1367 + , 1368 + , 1369 + , 1370 + , 1371 + , 1372 + , 1373 + , 1374 + , 1375 + , 1376 + , 1377 + , 1378 + , 1379 + , 1380 + , 1381 + , 1382 + , 1383 + , 1384 + , 1385 + , 1386 + , 1387 + , 1388 + , 1389 + , 1390 + , 1391 + , 1392 + , 1393 + , 1394 + , 1395 + , 1396 + , 1397 + , 1398 + , 1399 + , 1400 + , 1401 + , 1402 + , 1403 + , 1404 + , 1405 + , 1406 + , 1407 + , 1408 + , 1409 + , 1410 + , 1411 + , 1412 + , 1413 + , 1414 + , 1415 + , 1416 + , 1417 + , 1418 + , 1419 + , 1420 + , 1421 + , 1422 + , 1423 + , 1424 + , 1425 + , 1426 + , 1427 + , 1428 + , 1429 + , 1430 + , 1431 + , 1432 + , 1433 + , 1434 + , 1435 + , 1436 + , 1437 + , 1438 + , 1439 + , 1440 + , 1441 + , 1442 + , 1443 + , 1444 + , 1445 + , 1446 + , 1447 + , 1448 + , 1449 + , 1450 + , 1451 + , 1452 + , 1453 + , 1454 + , 1455 + , 1456 + , 1457 + , 1458 + , 1459 + , 1460 + , 1461 + , 1462 + , 1463 + , 1464 + , 1465 + , 1466 + , 1467 + , 1468 + , 1469 + , 1470 + , 1471 + , 1472 + , 1473 + , 1474 + , 1475 + , 1476 + , 1477 + , 1478 + , 1479 + , 1480 + , 1481 + , 1482 + , 1483 + , 1484 + , 1485 + , 1486 + , 1487 + , 1488 + , 1489 + , 1490 + , 1491 + , 1492 + , 1493 + , 1494 + , 1495 + , 1496 + , 1497 + , 1498 + , 1499 + , 1500 + , 1501 + , 1502 + , 1503 + , 1504 + , 1505 + , 1506 + , 1507 + , 1508 + , 1509 + , 1510 + , 1511 + , 1512 + , 1513 + , 1514 + , 1515 + , 1516 + , 1517 + , 1518 + , 1519 + , 1520 + , 1521 + , 1522 + , 1523 + , 1524 + , 1525 + , 1526 + , 1527 + , 1528 + , 1529 + , 1530 + , 1531 + , 1532 + , 1533 + , 1534 + , 1535 + , 1536 + , 1537 + , 1538 + , 1539 + , 1540 + , 1541 + , 1542 + , 1543 + , 1544 + , 1545 + , 1546 + , 1547 + , 1548 + , 1549 + , 1550 + , 1551 + , 1552 + , 1553 + , 1554 + , 1555 + , 1556 + , 1557 + , 1558 + , 1559 + , 1560 + , 1561 + , 1562 + , 1563 + , 1564 + , 1565 + , 1566 + , 1567 + , 1568 + , 1569 + , 1570 + , 1571 + , 1572 + , 1573 + , 1574 + , 1575 + , 1576 + , 1577 + , 1578 + , 1579 + , 1580 + , 1581 + , 1582 + , 1583 + , 1584 + , 1585 + , 1586 + , 1587 + , 1588 + , 1589 + , 1590 + , 1591 + , 1592 + , 1593 + , 1594 + , 1595 + , 1596 + , 1597 + , 1598 + , 1599 + , 1600 + , 1601 + , 1602 + , 1603 + , 1604 + , 1605 + , 1606 + , 1607 + , 1608 + , 1609 + , 1610 + , 1611 + , 1612 + , 1613 + , 1614 + , 1615 + , 1616 + , 1617 + , 1618 + , 1619 + , 1620 + , 1621 + , 1622 + , 1623 + , 1624 + , 1625 + , 1626 + , 1627 + , 1628 + , 1629 + , 1630 + , 1631 + , 1632 + , 1633 + , 1634 + , 1635 + , 1636 + , 1637 + , 1638 + , 1639 + , 1640 + , 1641 + , 1642 + , 1643 + , 1644 + , 1645 + , 1646 + , 1647 + , 1648 + , 1649 + , 1650 + , 1651 + , 1652 + , 1653 + , 1654 + , 1655 + , 1656 + , 1657 + , 1658 + , 1659 + , 1660 + , 1661 + , 1662 + , 1663 + , 1664 + , 1665 + , 1666 + , 1667 + , 1668 + , 1669 + , 1670 + , 1671 + , 1672 + , 1673 + , 1674 + , 1675 + , 1676 + , 1677 + , 1678 + , 1679 + , 1680 + , 1681 + , 1682 + , 1683 + , 1684 + , 1685 + , 1686 + , 1687 + , 1688 + , 1689 + , 1690 + , 1691 + , 1692 + , 1693 + , 1694 + , 1695 + , 1696 + , 1697 + , 1698 + , 1699 + , 1700 + , 1701 + , 1702 + , 1703 + , 1704 + , 1705 + , 1706 + , 1707 + , 1708 + , 1709 + , 1710 + , 1711 + , 1712 + , 1713 + , 1714 + , 1715 + , 1716 + , 1717 + , 1718 + , 1719 + , 1720 + , 1721 + , 1722 + , 1723 + , 1724 + , 1725 + , 1726 + , 1727 + , 1728 + , 1729 + , 1730 + , 1731 + , 1732 + , 1733 + , 1734 + , 1735 + , 1736 + , 1737 + , 1738 + , 1739 + , 1740 + , 1741 + , 1742 + , 1743 + , 1744 + , 1745 + , 1746 + , 1747 + , 1748 + , 1749 + , 1750 + , 1751 + , 1752 + , 1753 + , 1754 + , 1755 + , 1756 + , 1757 + , 1758 + , 1759 + , 1760 + , 1761 + , 1762 + , 1763 + , 1764 + , 1765 + , 1766 + , 1767 + , 1768 + , 1769 + , 1770 + , 1771 + , 1772 + , 1773 + , 1774 + , 1775 + , 1776 + , 1777 + , 1778 + , 1779 + , 1780 + , 1781 + , 1782 + , 1783 + , 1784 + , 1785 + , 1786 + , 1787 + , 1788 + , 1789 + , 1790 + , 1791 + , 1792 + , 1793 + , 1794 + , 1795 + , 1796 + , 1797 + , 1798 + , 1799 + , 1800 + , 1801 + , 1802 + , 1803 + , 1804 + , 1805 + , 1806 + , 1807 + , 1808 + , 1809 + , 1810 + , 1811 + , 1812 + , 1813 + , 1814 + , 1815 + , 1816 + , 1817 + , 1818 + , 1819 + , 1820 + , 1821 + , 1822 + , 1823 + , 1824 + , 1825 + , 1826 + , 1827 + , 1828 + , 1829 + , 1830 + , 1831 + , 1832 + , 1833 + , 1834 + , 1835 + , 1836 + , 1837 + , 1838 + , 1839 + , 1840 + , 1841 + , 1842 + , 1843 + , 1844 + , 1845 + , 1846 + , 1847 + , 1848 + , 1849 + , 1850 + , 1851 + , 1852 + , 1853 + , 1854 + , 1855 + , 1856 + , 1857 + , 1858 + , 1859 + , 1860 + , 1861 + , 1862 + , 1863 + , 1864 + , 1865 + , 1866 + , 1867 + , 1868 + , 1869 + , 1870 + , 1871 + , 1872 + , 1873 + , 1874 + , 1875 + , 1876 + , 1877 + , 1878 + , 1879 + , 1880 + , 1881 + , 1882 + , 1883 + , 1884 + , 1885 + , 1886 + , 1887 + , 1888 + , 1889 + , 1890 + , 1891 + , 1892 + , 1893 + , 1894 + , 1895 + , 1896 + , 1897 + , 1898 + , 1899 + , 1900 + , 1901 + , 1902 + , 1903 + , 1904 + , 1905 + , 1906 + , 1907 + , 1908 + , 1909 + , 1910 + , 1911 + , 1912 + , 1913 + , 1914 + , 1915 + , 1916 + , 1917 + , 1918 + , 1919 + , 1920 + , 1921 + , 1922 + , 1923 + , 1924 + , 1925 + , 1926 + , 1927 + , 1928 + , 1929 + , 1930 + , 1931 + , 1932 + , 1933 + , 1934 + , 1935 + , 1936 + , 1937 + , 1938 + , 1939 + , 1940 + , 1941 + , 1942 + , 1943 + , 1944 + , 1945 + , 1946 + , 1947 + , 1948 + , 1949 + , 1950 + , 1951 + , 1952 + , 1953 + , 1954 + , 1955 + , 1956 + , 1957 + , 1958 + , 1959 + , 1960 + , 1961 + , 1962 + , 1963 + , 1964 + , 1965 + , 1966 + , 1967 + , 1968 + , 1969 + , 1970 + , 1971 + , 1972 + , 1973 + , 1974 + , 1975 + , 1976 + , 1977 + , 1978 + , 1979 + , 1980 + , 1981 + , 1982 + , 1983 + , 1984 + , 1985 + , 1986 + , 1987 + , 1988 + , 1989 + , 1990 + , 1991 + , 1992 + , 1993 + , 1994 + , 1995 + , 1996 + , 1997 + , 1998 + , 1999 , 2000 ] @@ -2070,2005 +2070,2005 @@ Should be cached: 1 | > range 2000 ⧩ - [ +1 - , +2 - , +3 - , +4 - , +5 - , +6 - , +7 - , +8 - , +9 - , +10 - , +11 - , +12 - , +13 - , +14 - , +15 - , +16 - , +17 - , +18 - , +19 - , +20 - , +21 - , +22 - , +23 - , +24 - , +25 - , +26 - , +27 - , +28 - , +29 - , +30 - , +31 - , +32 - , +33 - , +34 - , +35 - , +36 - , +37 - , +38 - , +39 - , +40 - , +41 - , +42 - , +43 - , +44 - , +45 - , +46 - , +47 - , +48 - , +49 - , +50 - , +51 - , +52 - , +53 - , +54 - , +55 - , +56 - , +57 - , +58 - , +59 - , +60 - , +61 - , +62 - , +63 - , +64 - , +65 - , +66 - , +67 - , +68 - , +69 - , +70 - , +71 - , +72 - , +73 - , +74 - , +75 - , +76 - , +77 - , +78 - , +79 - , +80 - , +81 - , +82 - , +83 - , +84 - , +85 - , +86 - , +87 - , +88 - , +89 - , +90 - , +91 - , +92 - , +93 - , +94 - , +95 - , +96 - , +97 - , +98 - , +99 - , +100 - , +101 - , +102 - , +103 - , +104 - , +105 - , +106 - , +107 - , +108 - , +109 - , +110 - , +111 - , +112 - , +113 - , +114 - , +115 - , +116 - , +117 - , +118 - , +119 - , +120 - , +121 - , +122 - , +123 - , +124 - , +125 - , +126 - , +127 - , +128 - , +129 - , +130 - , +131 - , +132 - , +133 - , +134 - , +135 - , +136 - , +137 - , +138 - , +139 - , +140 - , +141 - , +142 - , +143 - , +144 - , +145 - , +146 - , +147 - , +148 - , +149 - , +150 - , +151 - , +152 - , +153 - , +154 - , +155 - , +156 - , +157 - , +158 - , +159 - , +160 - , +161 - , +162 - , +163 - , +164 - , +165 - , +166 - , +167 - , +168 - , +169 - , +170 - , +171 - , +172 - , +173 - , +174 - , +175 - , +176 - , +177 - , +178 - , +179 - , +180 - , +181 - , +182 - , +183 - , +184 - , +185 - , +186 - , +187 - , +188 - , +189 - , +190 - , +191 - , +192 - , +193 - , +194 - , +195 - , +196 - , +197 - , +198 - , +199 - , +200 - , +201 - , +202 - , +203 - , +204 - , +205 - , +206 - , +207 - , +208 - , +209 - , +210 - , +211 - , +212 - , +213 - , +214 - , +215 - , +216 - , +217 - , +218 - , +219 - , +220 - , +221 - , +222 - , +223 - , +224 - , +225 - , +226 - , +227 - , +228 - , +229 - , +230 - , +231 - , +232 - , +233 - , +234 - , +235 - , +236 - , +237 - , +238 - , +239 - , +240 - , +241 - , +242 - , +243 - , +244 - , +245 - , +246 - , +247 - , +248 - , +249 - , +250 - , +251 - , +252 - , +253 - , +254 - , +255 - , +256 - , +257 - , +258 - , +259 - , +260 - , +261 - , +262 - , +263 - , +264 - , +265 - , +266 - , +267 - , +268 - , +269 - , +270 - , +271 - , +272 - , +273 - , +274 - , +275 - , +276 - , +277 - , +278 - , +279 - , +280 - , +281 - , +282 - , +283 - , +284 - , +285 - , +286 - , +287 - , +288 - , +289 - , +290 - , +291 - , +292 - , +293 - , +294 - , +295 - , +296 - , +297 - , +298 - , +299 - , +300 - , +301 - , +302 - , +303 - , +304 - , +305 - , +306 - , +307 - , +308 - , +309 - , +310 - , +311 - , +312 - , +313 - , +314 - , +315 - , +316 - , +317 - , +318 - , +319 - , +320 - , +321 - , +322 - , +323 - , +324 - , +325 - , +326 - , +327 - , +328 - , +329 - , +330 - , +331 - , +332 - , +333 - , +334 - , +335 - , +336 - , +337 - , +338 - , +339 - , +340 - , +341 - , +342 - , +343 - , +344 - , +345 - , +346 - , +347 - , +348 - , +349 - , +350 - , +351 - , +352 - , +353 - , +354 - , +355 - , +356 - , +357 - , +358 - , +359 - , +360 - , +361 - , +362 - , +363 - , +364 - , +365 - , +366 - , +367 - , +368 - , +369 - , +370 - , +371 - , +372 - , +373 - , +374 - , +375 - , +376 - , +377 - , +378 - , +379 - , +380 - , +381 - , +382 - , +383 - , +384 - , +385 - , +386 - , +387 - , +388 - , +389 - , +390 - , +391 - , +392 - , +393 - , +394 - , +395 - , +396 - , +397 - , +398 - , +399 - , +400 - , +401 - , +402 - , +403 - , +404 - , +405 - , +406 - , +407 - , +408 - , +409 - , +410 - , +411 - , +412 - , +413 - , +414 - , +415 - , +416 - , +417 - , +418 - , +419 - , +420 - , +421 - , +422 - , +423 - , +424 - , +425 - , +426 - , +427 - , +428 - , +429 - , +430 - , +431 - , +432 - , +433 - , +434 - , +435 - , +436 - , +437 - , +438 - , +439 - , +440 - , +441 - , +442 - , +443 - , +444 - , +445 - , +446 - , +447 - , +448 - , +449 - , +450 - , +451 - , +452 - , +453 - , +454 - , +455 - , +456 - , +457 - , +458 - , +459 - , +460 - , +461 - , +462 - , +463 - , +464 - , +465 - , +466 - , +467 - , +468 - , +469 - , +470 - , +471 - , +472 - , +473 - , +474 - , +475 - , +476 - , +477 - , +478 - , +479 - , +480 - , +481 - , +482 - , +483 - , +484 - , +485 - , +486 - , +487 - , +488 - , +489 - , +490 - , +491 - , +492 - , +493 - , +494 - , +495 - , +496 - , +497 - , +498 - , +499 - , +500 - , +501 - , +502 - , +503 - , +504 - , +505 - , +506 - , +507 - , +508 - , +509 - , +510 - , +511 - , +512 - , +513 - , +514 - , +515 - , +516 - , +517 - , +518 - , +519 - , +520 - , +521 - , +522 - , +523 - , +524 - , +525 - , +526 - , +527 - , +528 - , +529 - , +530 - , +531 - , +532 - , +533 - , +534 - , +535 - , +536 - , +537 - , +538 - , +539 - , +540 - , +541 - , +542 - , +543 - , +544 - , +545 - , +546 - , +547 - , +548 - , +549 - , +550 - , +551 - , +552 - , +553 - , +554 - , +555 - , +556 - , +557 - , +558 - , +559 - , +560 - , +561 - , +562 - , +563 - , +564 - , +565 - , +566 - , +567 - , +568 - , +569 - , +570 - , +571 - , +572 - , +573 - , +574 - , +575 - , +576 - , +577 - , +578 - , +579 - , +580 - , +581 - , +582 - , +583 - , +584 - , +585 - , +586 - , +587 - , +588 - , +589 - , +590 - , +591 - , +592 - , +593 - , +594 - , +595 - , +596 - , +597 - , +598 - , +599 - , +600 - , +601 - , +602 - , +603 - , +604 - , +605 - , +606 - , +607 - , +608 - , +609 - , +610 - , +611 - , +612 - , +613 - , +614 - , +615 - , +616 - , +617 - , +618 - , +619 - , +620 - , +621 - , +622 - , +623 - , +624 - , +625 - , +626 - , +627 - , +628 - , +629 - , +630 - , +631 - , +632 - , +633 - , +634 - , +635 - , +636 - , +637 - , +638 - , +639 - , +640 - , +641 - , +642 - , +643 - , +644 - , +645 - , +646 - , +647 - , +648 - , +649 - , +650 - , +651 - , +652 - , +653 - , +654 - , +655 - , +656 - , +657 - , +658 - , +659 - , +660 - , +661 - , +662 - , +663 - , +664 - , +665 - , +666 - , +667 - , +668 - , +669 - , +670 - , +671 - , +672 - , +673 - , +674 - , +675 - , +676 - , +677 - , +678 - , +679 - , +680 - , +681 - , +682 - , +683 - , +684 - , +685 - , +686 - , +687 - , +688 - , +689 - , +690 - , +691 - , +692 - , +693 - , +694 - , +695 - , +696 - , +697 - , +698 - , +699 - , +700 - , +701 - , +702 - , +703 - , +704 - , +705 - , +706 - , +707 - , +708 - , +709 - , +710 - , +711 - , +712 - , +713 - , +714 - , +715 - , +716 - , +717 - , +718 - , +719 - , +720 - , +721 - , +722 - , +723 - , +724 - , +725 - , +726 - , +727 - , +728 - , +729 - , +730 - , +731 - , +732 - , +733 - , +734 - , +735 - , +736 - , +737 - , +738 - , +739 - , +740 - , +741 - , +742 - , +743 - , +744 - , +745 - , +746 - , +747 - , +748 - , +749 - , +750 - , +751 - , +752 - , +753 - , +754 - , +755 - , +756 - , +757 - , +758 - , +759 - , +760 - , +761 - , +762 - , +763 - , +764 - , +765 - , +766 - , +767 - , +768 - , +769 - , +770 - , +771 - , +772 - , +773 - , +774 - , +775 - , +776 - , +777 - , +778 - , +779 - , +780 - , +781 - , +782 - , +783 - , +784 - , +785 - , +786 - , +787 - , +788 - , +789 - , +790 - , +791 - , +792 - , +793 - , +794 - , +795 - , +796 - , +797 - , +798 - , +799 - , +800 - , +801 - , +802 - , +803 - , +804 - , +805 - , +806 - , +807 - , +808 - , +809 - , +810 - , +811 - , +812 - , +813 - , +814 - , +815 - , +816 - , +817 - , +818 - , +819 - , +820 - , +821 - , +822 - , +823 - , +824 - , +825 - , +826 - , +827 - , +828 - , +829 - , +830 - , +831 - , +832 - , +833 - , +834 - , +835 - , +836 - , +837 - , +838 - , +839 - , +840 - , +841 - , +842 - , +843 - , +844 - , +845 - , +846 - , +847 - , +848 - , +849 - , +850 - , +851 - , +852 - , +853 - , +854 - , +855 - , +856 - , +857 - , +858 - , +859 - , +860 - , +861 - , +862 - , +863 - , +864 - , +865 - , +866 - , +867 - , +868 - , +869 - , +870 - , +871 - , +872 - , +873 - , +874 - , +875 - , +876 - , +877 - , +878 - , +879 - , +880 - , +881 - , +882 - , +883 - , +884 - , +885 - , +886 - , +887 - , +888 - , +889 - , +890 - , +891 - , +892 - , +893 - , +894 - , +895 - , +896 - , +897 - , +898 - , +899 - , +900 - , +901 - , +902 - , +903 - , +904 - , +905 - , +906 - , +907 - , +908 - , +909 - , +910 - , +911 - , +912 - , +913 - , +914 - , +915 - , +916 - , +917 - , +918 - , +919 - , +920 - , +921 - , +922 - , +923 - , +924 - , +925 - , +926 - , +927 - , +928 - , +929 - , +930 - , +931 - , +932 - , +933 - , +934 - , +935 - , +936 - , +937 - , +938 - , +939 - , +940 - , +941 - , +942 - , +943 - , +944 - , +945 - , +946 - , +947 - , +948 - , +949 - , +950 - , +951 - , +952 - , +953 - , +954 - , +955 - , +956 - , +957 - , +958 - , +959 - , +960 - , +961 - , +962 - , +963 - , +964 - , +965 - , +966 - , +967 - , +968 - , +969 - , +970 - , +971 - , +972 - , +973 - , +974 - , +975 - , +976 - , +977 - , +978 - , +979 - , +980 - , +981 - , +982 - , +983 - , +984 - , +985 - , +986 - , +987 - , +988 - , +989 - , +990 - , +991 - , +992 - , +993 - , +994 - , +995 - , +996 - , +997 - , +998 - , +999 - , +1000 - , +1001 - , +1002 - , +1003 - , +1004 - , +1005 - , +1006 - , +1007 - , +1008 - , +1009 - , +1010 - , +1011 - , +1012 - , +1013 - , +1014 - , +1015 - , +1016 - , +1017 - , +1018 - , +1019 - , +1020 - , +1021 - , +1022 - , +1023 - , +1024 - , +1025 - , +1026 - , +1027 - , +1028 - , +1029 - , +1030 - , +1031 - , +1032 - , +1033 - , +1034 - , +1035 - , +1036 - , +1037 - , +1038 - , +1039 - , +1040 - , +1041 - , +1042 - , +1043 - , +1044 - , +1045 - , +1046 - , +1047 - , +1048 - , +1049 - , +1050 - , +1051 - , +1052 - , +1053 - , +1054 - , +1055 - , +1056 - , +1057 - , +1058 - , +1059 - , +1060 - , +1061 - , +1062 - , +1063 - , +1064 - , +1065 - , +1066 - , +1067 - , +1068 - , +1069 - , +1070 - , +1071 - , +1072 - , +1073 - , +1074 - , +1075 - , +1076 - , +1077 - , +1078 - , +1079 - , +1080 - , +1081 - , +1082 - , +1083 - , +1084 - , +1085 - , +1086 - , +1087 - , +1088 - , +1089 - , +1090 - , +1091 - , +1092 - , +1093 - , +1094 - , +1095 - , +1096 - , +1097 - , +1098 - , +1099 - , +1100 - , +1101 - , +1102 - , +1103 - , +1104 - , +1105 - , +1106 - , +1107 - , +1108 - , +1109 - , +1110 - , +1111 - , +1112 - , +1113 - , +1114 - , +1115 - , +1116 - , +1117 - , +1118 - , +1119 - , +1120 - , +1121 - , +1122 - , +1123 - , +1124 - , +1125 - , +1126 - , +1127 - , +1128 - , +1129 - , +1130 - , +1131 - , +1132 - , +1133 - , +1134 - , +1135 - , +1136 - , +1137 - , +1138 - , +1139 - , +1140 - , +1141 - , +1142 - , +1143 - , +1144 - , +1145 - , +1146 - , +1147 - , +1148 - , +1149 - , +1150 - , +1151 - , +1152 - , +1153 - , +1154 - , +1155 - , +1156 - , +1157 - , +1158 - , +1159 - , +1160 - , +1161 - , +1162 - , +1163 - , +1164 - , +1165 - , +1166 - , +1167 - , +1168 - , +1169 - , +1170 - , +1171 - , +1172 - , +1173 - , +1174 - , +1175 - , +1176 - , +1177 - , +1178 - , +1179 - , +1180 - , +1181 - , +1182 - , +1183 - , +1184 - , +1185 - , +1186 - , +1187 - , +1188 - , +1189 - , +1190 - , +1191 - , +1192 - , +1193 - , +1194 - , +1195 - , +1196 - , +1197 - , +1198 - , +1199 - , +1200 - , +1201 - , +1202 - , +1203 - , +1204 - , +1205 - , +1206 - , +1207 - , +1208 - , +1209 - , +1210 - , +1211 - , +1212 - , +1213 - , +1214 - , +1215 - , +1216 - , +1217 - , +1218 - , +1219 - , +1220 - , +1221 - , +1222 - , +1223 - , +1224 - , +1225 - , +1226 - , +1227 - , +1228 - , +1229 - , +1230 - , +1231 - , +1232 - , +1233 - , +1234 - , +1235 - , +1236 - , +1237 - , +1238 - , +1239 - , +1240 - , +1241 - , +1242 - , +1243 - , +1244 - , +1245 - , +1246 - , +1247 - , +1248 - , +1249 - , +1250 - , +1251 - , +1252 - , +1253 - , +1254 - , +1255 - , +1256 - , +1257 - , +1258 - , +1259 - , +1260 - , +1261 - , +1262 - , +1263 - , +1264 - , +1265 - , +1266 - , +1267 - , +1268 - , +1269 - , +1270 - , +1271 - , +1272 - , +1273 - , +1274 - , +1275 - , +1276 - , +1277 - , +1278 - , +1279 - , +1280 - , +1281 - , +1282 - , +1283 - , +1284 - , +1285 - , +1286 - , +1287 - , +1288 - , +1289 - , +1290 - , +1291 - , +1292 - , +1293 - , +1294 - , +1295 - , +1296 - , +1297 - , +1298 - , +1299 - , +1300 - , +1301 - , +1302 - , +1303 - , +1304 - , +1305 - , +1306 - , +1307 - , +1308 - , +1309 - , +1310 - , +1311 - , +1312 - , +1313 - , +1314 - , +1315 - , +1316 - , +1317 - , +1318 - , +1319 - , +1320 - , +1321 - , +1322 - , +1323 - , +1324 - , +1325 - , +1326 - , +1327 - , +1328 - , +1329 - , +1330 - , +1331 - , +1332 - , +1333 - , +1334 - , +1335 - , +1336 - , +1337 - , +1338 - , +1339 - , +1340 - , +1341 - , +1342 - , +1343 - , +1344 - , +1345 - , +1346 - , +1347 - , +1348 - , +1349 - , +1350 - , +1351 - , +1352 - , +1353 - , +1354 - , +1355 - , +1356 - , +1357 - , +1358 - , +1359 - , +1360 - , +1361 - , +1362 - , +1363 - , +1364 - , +1365 - , +1366 - , +1367 - , +1368 - , +1369 - , +1370 - , +1371 - , +1372 - , +1373 - , +1374 - , +1375 - , +1376 - , +1377 - , +1378 - , +1379 - , +1380 - , +1381 - , +1382 - , +1383 - , +1384 - , +1385 - , +1386 - , +1387 - , +1388 - , +1389 - , +1390 - , +1391 - , +1392 - , +1393 - , +1394 - , +1395 - , +1396 - , +1397 - , +1398 - , +1399 - , +1400 - , +1401 - , +1402 - , +1403 - , +1404 - , +1405 - , +1406 - , +1407 - , +1408 - , +1409 - , +1410 - , +1411 - , +1412 - , +1413 - , +1414 - , +1415 - , +1416 - , +1417 - , +1418 - , +1419 - , +1420 - , +1421 - , +1422 - , +1423 - , +1424 - , +1425 - , +1426 - , +1427 - , +1428 - , +1429 - , +1430 - , +1431 - , +1432 - , +1433 - , +1434 - , +1435 - , +1436 - , +1437 - , +1438 - , +1439 - , +1440 - , +1441 - , +1442 - , +1443 - , +1444 - , +1445 - , +1446 - , +1447 - , +1448 - , +1449 - , +1450 - , +1451 - , +1452 - , +1453 - , +1454 - , +1455 - , +1456 - , +1457 - , +1458 - , +1459 - , +1460 - , +1461 - , +1462 - , +1463 - , +1464 - , +1465 - , +1466 - , +1467 - , +1468 - , +1469 - , +1470 - , +1471 - , +1472 - , +1473 - , +1474 - , +1475 - , +1476 - , +1477 - , +1478 - , +1479 - , +1480 - , +1481 - , +1482 - , +1483 - , +1484 - , +1485 - , +1486 - , +1487 - , +1488 - , +1489 - , +1490 - , +1491 - , +1492 - , +1493 - , +1494 - , +1495 - , +1496 - , +1497 - , +1498 - , +1499 - , +1500 - , +1501 - , +1502 - , +1503 - , +1504 - , +1505 - , +1506 - , +1507 - , +1508 - , +1509 - , +1510 - , +1511 - , +1512 - , +1513 - , +1514 - , +1515 - , +1516 - , +1517 - , +1518 - , +1519 - , +1520 - , +1521 - , +1522 - , +1523 - , +1524 - , +1525 - , +1526 - , +1527 - , +1528 - , +1529 - , +1530 - , +1531 - , +1532 - , +1533 - , +1534 - , +1535 - , +1536 - , +1537 - , +1538 - , +1539 - , +1540 - , +1541 - , +1542 - , +1543 - , +1544 - , +1545 - , +1546 - , +1547 - , +1548 - , +1549 - , +1550 - , +1551 - , +1552 - , +1553 - , +1554 - , +1555 - , +1556 - , +1557 - , +1558 - , +1559 - , +1560 - , +1561 - , +1562 - , +1563 - , +1564 - , +1565 - , +1566 - , +1567 - , +1568 - , +1569 - , +1570 - , +1571 - , +1572 - , +1573 - , +1574 - , +1575 - , +1576 - , +1577 - , +1578 - , +1579 - , +1580 - , +1581 - , +1582 - , +1583 - , +1584 - , +1585 - , +1586 - , +1587 - , +1588 - , +1589 - , +1590 - , +1591 - , +1592 - , +1593 - , +1594 - , +1595 - , +1596 - , +1597 - , +1598 - , +1599 - , +1600 - , +1601 - , +1602 - , +1603 - , +1604 - , +1605 - , +1606 - , +1607 - , +1608 - , +1609 - , +1610 - , +1611 - , +1612 - , +1613 - , +1614 - , +1615 - , +1616 - , +1617 - , +1618 - , +1619 - , +1620 - , +1621 - , +1622 - , +1623 - , +1624 - , +1625 - , +1626 - , +1627 - , +1628 - , +1629 - , +1630 - , +1631 - , +1632 - , +1633 - , +1634 - , +1635 - , +1636 - , +1637 - , +1638 - , +1639 - , +1640 - , +1641 - , +1642 - , +1643 - , +1644 - , +1645 - , +1646 - , +1647 - , +1648 - , +1649 - , +1650 - , +1651 - , +1652 - , +1653 - , +1654 - , +1655 - , +1656 - , +1657 - , +1658 - , +1659 - , +1660 - , +1661 - , +1662 - , +1663 - , +1664 - , +1665 - , +1666 - , +1667 - , +1668 - , +1669 - , +1670 - , +1671 - , +1672 - , +1673 - , +1674 - , +1675 - , +1676 - , +1677 - , +1678 - , +1679 - , +1680 - , +1681 - , +1682 - , +1683 - , +1684 - , +1685 - , +1686 - , +1687 - , +1688 - , +1689 - , +1690 - , +1691 - , +1692 - , +1693 - , +1694 - , +1695 - , +1696 - , +1697 - , +1698 - , +1699 - , +1700 - , +1701 - , +1702 - , +1703 - , +1704 - , +1705 - , +1706 - , +1707 - , +1708 - , +1709 - , +1710 - , +1711 - , +1712 - , +1713 - , +1714 - , +1715 - , +1716 - , +1717 - , +1718 - , +1719 - , +1720 - , +1721 - , +1722 - , +1723 - , +1724 - , +1725 - , +1726 - , +1727 - , +1728 - , +1729 - , +1730 - , +1731 - , +1732 - , +1733 - , +1734 - , +1735 - , +1736 - , +1737 - , +1738 - , +1739 - , +1740 - , +1741 - , +1742 - , +1743 - , +1744 - , +1745 - , +1746 - , +1747 - , +1748 - , +1749 - , +1750 - , +1751 - , +1752 - , +1753 - , +1754 - , +1755 - , +1756 - , +1757 - , +1758 - , +1759 - , +1760 - , +1761 - , +1762 - , +1763 - , +1764 - , +1765 - , +1766 - , +1767 - , +1768 - , +1769 - , +1770 - , +1771 - , +1772 - , +1773 - , +1774 - , +1775 - , +1776 - , +1777 - , +1778 - , +1779 - , +1780 - , +1781 - , +1782 - , +1783 - , +1784 - , +1785 - , +1786 - , +1787 - , +1788 - , +1789 - , +1790 - , +1791 - , +1792 - , +1793 - , +1794 - , +1795 - , +1796 - , +1797 - , +1798 - , +1799 - , +1800 - , +1801 - , +1802 - , +1803 - , +1804 - , +1805 - , +1806 - , +1807 - , +1808 - , +1809 - , +1810 - , +1811 - , +1812 - , +1813 - , +1814 - , +1815 - , +1816 - , +1817 - , +1818 - , +1819 - , +1820 - , +1821 - , +1822 - , +1823 - , +1824 - , +1825 - , +1826 - , +1827 - , +1828 - , +1829 - , +1830 - , +1831 - , +1832 - , +1833 - , +1834 - , +1835 - , +1836 - , +1837 - , +1838 - , +1839 - , +1840 - , +1841 - , +1842 - , +1843 - , +1844 - , +1845 - , +1846 - , +1847 - , +1848 - , +1849 - , +1850 - , +1851 - , +1852 - , +1853 - , +1854 - , +1855 - , +1856 - , +1857 - , +1858 - , +1859 - , +1860 - , +1861 - , +1862 - , +1863 - , +1864 - , +1865 - , +1866 - , +1867 - , +1868 - , +1869 - , +1870 - , +1871 - , +1872 - , +1873 - , +1874 - , +1875 - , +1876 - , +1877 - , +1878 - , +1879 - , +1880 - , +1881 - , +1882 - , +1883 - , +1884 - , +1885 - , +1886 - , +1887 - , +1888 - , +1889 - , +1890 - , +1891 - , +1892 - , +1893 - , +1894 - , +1895 - , +1896 - , +1897 - , +1898 - , +1899 - , +1900 - , +1901 - , +1902 - , +1903 - , +1904 - , +1905 - , +1906 - , +1907 - , +1908 - , +1909 - , +1910 - , +1911 - , +1912 - , +1913 - , +1914 - , +1915 - , +1916 - , +1917 - , +1918 - , +1919 - , +1920 - , +1921 - , +1922 - , +1923 - , +1924 - , +1925 - , +1926 - , +1927 - , +1928 - , +1929 - , +1930 - , +1931 - , +1932 - , +1933 - , +1934 - , +1935 - , +1936 - , +1937 - , +1938 - , +1939 - , +1940 - , +1941 - , +1942 - , +1943 - , +1944 - , +1945 - , +1946 - , +1947 - , +1948 - , +1949 - , +1950 - , +1951 - , +1952 - , +1953 - , +1954 - , +1955 - , +1956 - , +1957 - , +1958 - , +1959 - , +1960 - , +1961 - , +1962 - , +1963 - , +1964 - , +1965 - , +1966 - , +1967 - , +1968 - , +1969 - , +1970 - , +1971 - , +1972 - , +1973 - , +1974 - , +1975 - , +1976 - , +1977 - , +1978 - , +1979 - , +1980 - , +1981 - , +1982 - , +1983 - , +1984 - , +1985 - , +1986 - , +1987 - , +1988 - , +1989 - , +1990 - , +1991 - , +1992 - , +1993 - , +1994 - , +1995 - , +1996 - , +1997 - , +1998 - , +1999 + [ 1 + , 2 + , 3 + , 4 + , 5 + , 6 + , 7 + , 8 + , 9 + , 10 + , 11 + , 12 + , 13 + , 14 + , 15 + , 16 + , 17 + , 18 + , 19 + , 20 + , 21 + , 22 + , 23 + , 24 + , 25 + , 26 + , 27 + , 28 + , 29 + , 30 + , 31 + , 32 + , 33 + , 34 + , 35 + , 36 + , 37 + , 38 + , 39 + , 40 + , 41 + , 42 + , 43 + , 44 + , 45 + , 46 + , 47 + , 48 + , 49 + , 50 + , 51 + , 52 + , 53 + , 54 + , 55 + , 56 + , 57 + , 58 + , 59 + , 60 + , 61 + , 62 + , 63 + , 64 + , 65 + , 66 + , 67 + , 68 + , 69 + , 70 + , 71 + , 72 + , 73 + , 74 + , 75 + , 76 + , 77 + , 78 + , 79 + , 80 + , 81 + , 82 + , 83 + , 84 + , 85 + , 86 + , 87 + , 88 + , 89 + , 90 + , 91 + , 92 + , 93 + , 94 + , 95 + , 96 + , 97 + , 98 + , 99 + , 100 + , 101 + , 102 + , 103 + , 104 + , 105 + , 106 + , 107 + , 108 + , 109 + , 110 + , 111 + , 112 + , 113 + , 114 + , 115 + , 116 + , 117 + , 118 + , 119 + , 120 + , 121 + , 122 + , 123 + , 124 + , 125 + , 126 + , 127 + , 128 + , 129 + , 130 + , 131 + , 132 + , 133 + , 134 + , 135 + , 136 + , 137 + , 138 + , 139 + , 140 + , 141 + , 142 + , 143 + , 144 + , 145 + , 146 + , 147 + , 148 + , 149 + , 150 + , 151 + , 152 + , 153 + , 154 + , 155 + , 156 + , 157 + , 158 + , 159 + , 160 + , 161 + , 162 + , 163 + , 164 + , 165 + , 166 + , 167 + , 168 + , 169 + , 170 + , 171 + , 172 + , 173 + , 174 + , 175 + , 176 + , 177 + , 178 + , 179 + , 180 + , 181 + , 182 + , 183 + , 184 + , 185 + , 186 + , 187 + , 188 + , 189 + , 190 + , 191 + , 192 + , 193 + , 194 + , 195 + , 196 + , 197 + , 198 + , 199 + , 200 + , 201 + , 202 + , 203 + , 204 + , 205 + , 206 + , 207 + , 208 + , 209 + , 210 + , 211 + , 212 + , 213 + , 214 + , 215 + , 216 + , 217 + , 218 + , 219 + , 220 + , 221 + , 222 + , 223 + , 224 + , 225 + , 226 + , 227 + , 228 + , 229 + , 230 + , 231 + , 232 + , 233 + , 234 + , 235 + , 236 + , 237 + , 238 + , 239 + , 240 + , 241 + , 242 + , 243 + , 244 + , 245 + , 246 + , 247 + , 248 + , 249 + , 250 + , 251 + , 252 + , 253 + , 254 + , 255 + , 256 + , 257 + , 258 + , 259 + , 260 + , 261 + , 262 + , 263 + , 264 + , 265 + , 266 + , 267 + , 268 + , 269 + , 270 + , 271 + , 272 + , 273 + , 274 + , 275 + , 276 + , 277 + , 278 + , 279 + , 280 + , 281 + , 282 + , 283 + , 284 + , 285 + , 286 + , 287 + , 288 + , 289 + , 290 + , 291 + , 292 + , 293 + , 294 + , 295 + , 296 + , 297 + , 298 + , 299 + , 300 + , 301 + , 302 + , 303 + , 304 + , 305 + , 306 + , 307 + , 308 + , 309 + , 310 + , 311 + , 312 + , 313 + , 314 + , 315 + , 316 + , 317 + , 318 + , 319 + , 320 + , 321 + , 322 + , 323 + , 324 + , 325 + , 326 + , 327 + , 328 + , 329 + , 330 + , 331 + , 332 + , 333 + , 334 + , 335 + , 336 + , 337 + , 338 + , 339 + , 340 + , 341 + , 342 + , 343 + , 344 + , 345 + , 346 + , 347 + , 348 + , 349 + , 350 + , 351 + , 352 + , 353 + , 354 + , 355 + , 356 + , 357 + , 358 + , 359 + , 360 + , 361 + , 362 + , 363 + , 364 + , 365 + , 366 + , 367 + , 368 + , 369 + , 370 + , 371 + , 372 + , 373 + , 374 + , 375 + , 376 + , 377 + , 378 + , 379 + , 380 + , 381 + , 382 + , 383 + , 384 + , 385 + , 386 + , 387 + , 388 + , 389 + , 390 + , 391 + , 392 + , 393 + , 394 + , 395 + , 396 + , 397 + , 398 + , 399 + , 400 + , 401 + , 402 + , 403 + , 404 + , 405 + , 406 + , 407 + , 408 + , 409 + , 410 + , 411 + , 412 + , 413 + , 414 + , 415 + , 416 + , 417 + , 418 + , 419 + , 420 + , 421 + , 422 + , 423 + , 424 + , 425 + , 426 + , 427 + , 428 + , 429 + , 430 + , 431 + , 432 + , 433 + , 434 + , 435 + , 436 + , 437 + , 438 + , 439 + , 440 + , 441 + , 442 + , 443 + , 444 + , 445 + , 446 + , 447 + , 448 + , 449 + , 450 + , 451 + , 452 + , 453 + , 454 + , 455 + , 456 + , 457 + , 458 + , 459 + , 460 + , 461 + , 462 + , 463 + , 464 + , 465 + , 466 + , 467 + , 468 + , 469 + , 470 + , 471 + , 472 + , 473 + , 474 + , 475 + , 476 + , 477 + , 478 + , 479 + , 480 + , 481 + , 482 + , 483 + , 484 + , 485 + , 486 + , 487 + , 488 + , 489 + , 490 + , 491 + , 492 + , 493 + , 494 + , 495 + , 496 + , 497 + , 498 + , 499 + , 500 + , 501 + , 502 + , 503 + , 504 + , 505 + , 506 + , 507 + , 508 + , 509 + , 510 + , 511 + , 512 + , 513 + , 514 + , 515 + , 516 + , 517 + , 518 + , 519 + , 520 + , 521 + , 522 + , 523 + , 524 + , 525 + , 526 + , 527 + , 528 + , 529 + , 530 + , 531 + , 532 + , 533 + , 534 + , 535 + , 536 + , 537 + , 538 + , 539 + , 540 + , 541 + , 542 + , 543 + , 544 + , 545 + , 546 + , 547 + , 548 + , 549 + , 550 + , 551 + , 552 + , 553 + , 554 + , 555 + , 556 + , 557 + , 558 + , 559 + , 560 + , 561 + , 562 + , 563 + , 564 + , 565 + , 566 + , 567 + , 568 + , 569 + , 570 + , 571 + , 572 + , 573 + , 574 + , 575 + , 576 + , 577 + , 578 + , 579 + , 580 + , 581 + , 582 + , 583 + , 584 + , 585 + , 586 + , 587 + , 588 + , 589 + , 590 + , 591 + , 592 + , 593 + , 594 + , 595 + , 596 + , 597 + , 598 + , 599 + , 600 + , 601 + , 602 + , 603 + , 604 + , 605 + , 606 + , 607 + , 608 + , 609 + , 610 + , 611 + , 612 + , 613 + , 614 + , 615 + , 616 + , 617 + , 618 + , 619 + , 620 + , 621 + , 622 + , 623 + , 624 + , 625 + , 626 + , 627 + , 628 + , 629 + , 630 + , 631 + , 632 + , 633 + , 634 + , 635 + , 636 + , 637 + , 638 + , 639 + , 640 + , 641 + , 642 + , 643 + , 644 + , 645 + , 646 + , 647 + , 648 + , 649 + , 650 + , 651 + , 652 + , 653 + , 654 + , 655 + , 656 + , 657 + , 658 + , 659 + , 660 + , 661 + , 662 + , 663 + , 664 + , 665 + , 666 + , 667 + , 668 + , 669 + , 670 + , 671 + , 672 + , 673 + , 674 + , 675 + , 676 + , 677 + , 678 + , 679 + , 680 + , 681 + , 682 + , 683 + , 684 + , 685 + , 686 + , 687 + , 688 + , 689 + , 690 + , 691 + , 692 + , 693 + , 694 + , 695 + , 696 + , 697 + , 698 + , 699 + , 700 + , 701 + , 702 + , 703 + , 704 + , 705 + , 706 + , 707 + , 708 + , 709 + , 710 + , 711 + , 712 + , 713 + , 714 + , 715 + , 716 + , 717 + , 718 + , 719 + , 720 + , 721 + , 722 + , 723 + , 724 + , 725 + , 726 + , 727 + , 728 + , 729 + , 730 + , 731 + , 732 + , 733 + , 734 + , 735 + , 736 + , 737 + , 738 + , 739 + , 740 + , 741 + , 742 + , 743 + , 744 + , 745 + , 746 + , 747 + , 748 + , 749 + , 750 + , 751 + , 752 + , 753 + , 754 + , 755 + , 756 + , 757 + , 758 + , 759 + , 760 + , 761 + , 762 + , 763 + , 764 + , 765 + , 766 + , 767 + , 768 + , 769 + , 770 + , 771 + , 772 + , 773 + , 774 + , 775 + , 776 + , 777 + , 778 + , 779 + , 780 + , 781 + , 782 + , 783 + , 784 + , 785 + , 786 + , 787 + , 788 + , 789 + , 790 + , 791 + , 792 + , 793 + , 794 + , 795 + , 796 + , 797 + , 798 + , 799 + , 800 + , 801 + , 802 + , 803 + , 804 + , 805 + , 806 + , 807 + , 808 + , 809 + , 810 + , 811 + , 812 + , 813 + , 814 + , 815 + , 816 + , 817 + , 818 + , 819 + , 820 + , 821 + , 822 + , 823 + , 824 + , 825 + , 826 + , 827 + , 828 + , 829 + , 830 + , 831 + , 832 + , 833 + , 834 + , 835 + , 836 + , 837 + , 838 + , 839 + , 840 + , 841 + , 842 + , 843 + , 844 + , 845 + , 846 + , 847 + , 848 + , 849 + , 850 + , 851 + , 852 + , 853 + , 854 + , 855 + , 856 + , 857 + , 858 + , 859 + , 860 + , 861 + , 862 + , 863 + , 864 + , 865 + , 866 + , 867 + , 868 + , 869 + , 870 + , 871 + , 872 + , 873 + , 874 + , 875 + , 876 + , 877 + , 878 + , 879 + , 880 + , 881 + , 882 + , 883 + , 884 + , 885 + , 886 + , 887 + , 888 + , 889 + , 890 + , 891 + , 892 + , 893 + , 894 + , 895 + , 896 + , 897 + , 898 + , 899 + , 900 + , 901 + , 902 + , 903 + , 904 + , 905 + , 906 + , 907 + , 908 + , 909 + , 910 + , 911 + , 912 + , 913 + , 914 + , 915 + , 916 + , 917 + , 918 + , 919 + , 920 + , 921 + , 922 + , 923 + , 924 + , 925 + , 926 + , 927 + , 928 + , 929 + , 930 + , 931 + , 932 + , 933 + , 934 + , 935 + , 936 + , 937 + , 938 + , 939 + , 940 + , 941 + , 942 + , 943 + , 944 + , 945 + , 946 + , 947 + , 948 + , 949 + , 950 + , 951 + , 952 + , 953 + , 954 + , 955 + , 956 + , 957 + , 958 + , 959 + , 960 + , 961 + , 962 + , 963 + , 964 + , 965 + , 966 + , 967 + , 968 + , 969 + , 970 + , 971 + , 972 + , 973 + , 974 + , 975 + , 976 + , 977 + , 978 + , 979 + , 980 + , 981 + , 982 + , 983 + , 984 + , 985 + , 986 + , 987 + , 988 + , 989 + , 990 + , 991 + , 992 + , 993 + , 994 + , 995 + , 996 + , 997 + , 998 + , 999 + , 1000 + , 1001 + , 1002 + , 1003 + , 1004 + , 1005 + , 1006 + , 1007 + , 1008 + , 1009 + , 1010 + , 1011 + , 1012 + , 1013 + , 1014 + , 1015 + , 1016 + , 1017 + , 1018 + , 1019 + , 1020 + , 1021 + , 1022 + , 1023 + , 1024 + , 1025 + , 1026 + , 1027 + , 1028 + , 1029 + , 1030 + , 1031 + , 1032 + , 1033 + , 1034 + , 1035 + , 1036 + , 1037 + , 1038 + , 1039 + , 1040 + , 1041 + , 1042 + , 1043 + , 1044 + , 1045 + , 1046 + , 1047 + , 1048 + , 1049 + , 1050 + , 1051 + , 1052 + , 1053 + , 1054 + , 1055 + , 1056 + , 1057 + , 1058 + , 1059 + , 1060 + , 1061 + , 1062 + , 1063 + , 1064 + , 1065 + , 1066 + , 1067 + , 1068 + , 1069 + , 1070 + , 1071 + , 1072 + , 1073 + , 1074 + , 1075 + , 1076 + , 1077 + , 1078 + , 1079 + , 1080 + , 1081 + , 1082 + , 1083 + , 1084 + , 1085 + , 1086 + , 1087 + , 1088 + , 1089 + , 1090 + , 1091 + , 1092 + , 1093 + , 1094 + , 1095 + , 1096 + , 1097 + , 1098 + , 1099 + , 1100 + , 1101 + , 1102 + , 1103 + , 1104 + , 1105 + , 1106 + , 1107 + , 1108 + , 1109 + , 1110 + , 1111 + , 1112 + , 1113 + , 1114 + , 1115 + , 1116 + , 1117 + , 1118 + , 1119 + , 1120 + , 1121 + , 1122 + , 1123 + , 1124 + , 1125 + , 1126 + , 1127 + , 1128 + , 1129 + , 1130 + , 1131 + , 1132 + , 1133 + , 1134 + , 1135 + , 1136 + , 1137 + , 1138 + , 1139 + , 1140 + , 1141 + , 1142 + , 1143 + , 1144 + , 1145 + , 1146 + , 1147 + , 1148 + , 1149 + , 1150 + , 1151 + , 1152 + , 1153 + , 1154 + , 1155 + , 1156 + , 1157 + , 1158 + , 1159 + , 1160 + , 1161 + , 1162 + , 1163 + , 1164 + , 1165 + , 1166 + , 1167 + , 1168 + , 1169 + , 1170 + , 1171 + , 1172 + , 1173 + , 1174 + , 1175 + , 1176 + , 1177 + , 1178 + , 1179 + , 1180 + , 1181 + , 1182 + , 1183 + , 1184 + , 1185 + , 1186 + , 1187 + , 1188 + , 1189 + , 1190 + , 1191 + , 1192 + , 1193 + , 1194 + , 1195 + , 1196 + , 1197 + , 1198 + , 1199 + , 1200 + , 1201 + , 1202 + , 1203 + , 1204 + , 1205 + , 1206 + , 1207 + , 1208 + , 1209 + , 1210 + , 1211 + , 1212 + , 1213 + , 1214 + , 1215 + , 1216 + , 1217 + , 1218 + , 1219 + , 1220 + , 1221 + , 1222 + , 1223 + , 1224 + , 1225 + , 1226 + , 1227 + , 1228 + , 1229 + , 1230 + , 1231 + , 1232 + , 1233 + , 1234 + , 1235 + , 1236 + , 1237 + , 1238 + , 1239 + , 1240 + , 1241 + , 1242 + , 1243 + , 1244 + , 1245 + , 1246 + , 1247 + , 1248 + , 1249 + , 1250 + , 1251 + , 1252 + , 1253 + , 1254 + , 1255 + , 1256 + , 1257 + , 1258 + , 1259 + , 1260 + , 1261 + , 1262 + , 1263 + , 1264 + , 1265 + , 1266 + , 1267 + , 1268 + , 1269 + , 1270 + , 1271 + , 1272 + , 1273 + , 1274 + , 1275 + , 1276 + , 1277 + , 1278 + , 1279 + , 1280 + , 1281 + , 1282 + , 1283 + , 1284 + , 1285 + , 1286 + , 1287 + , 1288 + , 1289 + , 1290 + , 1291 + , 1292 + , 1293 + , 1294 + , 1295 + , 1296 + , 1297 + , 1298 + , 1299 + , 1300 + , 1301 + , 1302 + , 1303 + , 1304 + , 1305 + , 1306 + , 1307 + , 1308 + , 1309 + , 1310 + , 1311 + , 1312 + , 1313 + , 1314 + , 1315 + , 1316 + , 1317 + , 1318 + , 1319 + , 1320 + , 1321 + , 1322 + , 1323 + , 1324 + , 1325 + , 1326 + , 1327 + , 1328 + , 1329 + , 1330 + , 1331 + , 1332 + , 1333 + , 1334 + , 1335 + , 1336 + , 1337 + , 1338 + , 1339 + , 1340 + , 1341 + , 1342 + , 1343 + , 1344 + , 1345 + , 1346 + , 1347 + , 1348 + , 1349 + , 1350 + , 1351 + , 1352 + , 1353 + , 1354 + , 1355 + , 1356 + , 1357 + , 1358 + , 1359 + , 1360 + , 1361 + , 1362 + , 1363 + , 1364 + , 1365 + , 1366 + , 1367 + , 1368 + , 1369 + , 1370 + , 1371 + , 1372 + , 1373 + , 1374 + , 1375 + , 1376 + , 1377 + , 1378 + , 1379 + , 1380 + , 1381 + , 1382 + , 1383 + , 1384 + , 1385 + , 1386 + , 1387 + , 1388 + , 1389 + , 1390 + , 1391 + , 1392 + , 1393 + , 1394 + , 1395 + , 1396 + , 1397 + , 1398 + , 1399 + , 1400 + , 1401 + , 1402 + , 1403 + , 1404 + , 1405 + , 1406 + , 1407 + , 1408 + , 1409 + , 1410 + , 1411 + , 1412 + , 1413 + , 1414 + , 1415 + , 1416 + , 1417 + , 1418 + , 1419 + , 1420 + , 1421 + , 1422 + , 1423 + , 1424 + , 1425 + , 1426 + , 1427 + , 1428 + , 1429 + , 1430 + , 1431 + , 1432 + , 1433 + , 1434 + , 1435 + , 1436 + , 1437 + , 1438 + , 1439 + , 1440 + , 1441 + , 1442 + , 1443 + , 1444 + , 1445 + , 1446 + , 1447 + , 1448 + , 1449 + , 1450 + , 1451 + , 1452 + , 1453 + , 1454 + , 1455 + , 1456 + , 1457 + , 1458 + , 1459 + , 1460 + , 1461 + , 1462 + , 1463 + , 1464 + , 1465 + , 1466 + , 1467 + , 1468 + , 1469 + , 1470 + , 1471 + , 1472 + , 1473 + , 1474 + , 1475 + , 1476 + , 1477 + , 1478 + , 1479 + , 1480 + , 1481 + , 1482 + , 1483 + , 1484 + , 1485 + , 1486 + , 1487 + , 1488 + , 1489 + , 1490 + , 1491 + , 1492 + , 1493 + , 1494 + , 1495 + , 1496 + , 1497 + , 1498 + , 1499 + , 1500 + , 1501 + , 1502 + , 1503 + , 1504 + , 1505 + , 1506 + , 1507 + , 1508 + , 1509 + , 1510 + , 1511 + , 1512 + , 1513 + , 1514 + , 1515 + , 1516 + , 1517 + , 1518 + , 1519 + , 1520 + , 1521 + , 1522 + , 1523 + , 1524 + , 1525 + , 1526 + , 1527 + , 1528 + , 1529 + , 1530 + , 1531 + , 1532 + , 1533 + , 1534 + , 1535 + , 1536 + , 1537 + , 1538 + , 1539 + , 1540 + , 1541 + , 1542 + , 1543 + , 1544 + , 1545 + , 1546 + , 1547 + , 1548 + , 1549 + , 1550 + , 1551 + , 1552 + , 1553 + , 1554 + , 1555 + , 1556 + , 1557 + , 1558 + , 1559 + , 1560 + , 1561 + , 1562 + , 1563 + , 1564 + , 1565 + , 1566 + , 1567 + , 1568 + , 1569 + , 1570 + , 1571 + , 1572 + , 1573 + , 1574 + , 1575 + , 1576 + , 1577 + , 1578 + , 1579 + , 1580 + , 1581 + , 1582 + , 1583 + , 1584 + , 1585 + , 1586 + , 1587 + , 1588 + , 1589 + , 1590 + , 1591 + , 1592 + , 1593 + , 1594 + , 1595 + , 1596 + , 1597 + , 1598 + , 1599 + , 1600 + , 1601 + , 1602 + , 1603 + , 1604 + , 1605 + , 1606 + , 1607 + , 1608 + , 1609 + , 1610 + , 1611 + , 1612 + , 1613 + , 1614 + , 1615 + , 1616 + , 1617 + , 1618 + , 1619 + , 1620 + , 1621 + , 1622 + , 1623 + , 1624 + , 1625 + , 1626 + , 1627 + , 1628 + , 1629 + , 1630 + , 1631 + , 1632 + , 1633 + , 1634 + , 1635 + , 1636 + , 1637 + , 1638 + , 1639 + , 1640 + , 1641 + , 1642 + , 1643 + , 1644 + , 1645 + , 1646 + , 1647 + , 1648 + , 1649 + , 1650 + , 1651 + , 1652 + , 1653 + , 1654 + , 1655 + , 1656 + , 1657 + , 1658 + , 1659 + , 1660 + , 1661 + , 1662 + , 1663 + , 1664 + , 1665 + , 1666 + , 1667 + , 1668 + , 1669 + , 1670 + , 1671 + , 1672 + , 1673 + , 1674 + , 1675 + , 1676 + , 1677 + , 1678 + , 1679 + , 1680 + , 1681 + , 1682 + , 1683 + , 1684 + , 1685 + , 1686 + , 1687 + , 1688 + , 1689 + , 1690 + , 1691 + , 1692 + , 1693 + , 1694 + , 1695 + , 1696 + , 1697 + , 1698 + , 1699 + , 1700 + , 1701 + , 1702 + , 1703 + , 1704 + , 1705 + , 1706 + , 1707 + , 1708 + , 1709 + , 1710 + , 1711 + , 1712 + , 1713 + , 1714 + , 1715 + , 1716 + , 1717 + , 1718 + , 1719 + , 1720 + , 1721 + , 1722 + , 1723 + , 1724 + , 1725 + , 1726 + , 1727 + , 1728 + , 1729 + , 1730 + , 1731 + , 1732 + , 1733 + , 1734 + , 1735 + , 1736 + , 1737 + , 1738 + , 1739 + , 1740 + , 1741 + , 1742 + , 1743 + , 1744 + , 1745 + , 1746 + , 1747 + , 1748 + , 1749 + , 1750 + , 1751 + , 1752 + , 1753 + , 1754 + , 1755 + , 1756 + , 1757 + , 1758 + , 1759 + , 1760 + , 1761 + , 1762 + , 1763 + , 1764 + , 1765 + , 1766 + , 1767 + , 1768 + , 1769 + , 1770 + , 1771 + , 1772 + , 1773 + , 1774 + , 1775 + , 1776 + , 1777 + , 1778 + , 1779 + , 1780 + , 1781 + , 1782 + , 1783 + , 1784 + , 1785 + , 1786 + , 1787 + , 1788 + , 1789 + , 1790 + , 1791 + , 1792 + , 1793 + , 1794 + , 1795 + , 1796 + , 1797 + , 1798 + , 1799 + , 1800 + , 1801 + , 1802 + , 1803 + , 1804 + , 1805 + , 1806 + , 1807 + , 1808 + , 1809 + , 1810 + , 1811 + , 1812 + , 1813 + , 1814 + , 1815 + , 1816 + , 1817 + , 1818 + , 1819 + , 1820 + , 1821 + , 1822 + , 1823 + , 1824 + , 1825 + , 1826 + , 1827 + , 1828 + , 1829 + , 1830 + , 1831 + , 1832 + , 1833 + , 1834 + , 1835 + , 1836 + , 1837 + , 1838 + , 1839 + , 1840 + , 1841 + , 1842 + , 1843 + , 1844 + , 1845 + , 1846 + , 1847 + , 1848 + , 1849 + , 1850 + , 1851 + , 1852 + , 1853 + , 1854 + , 1855 + , 1856 + , 1857 + , 1858 + , 1859 + , 1860 + , 1861 + , 1862 + , 1863 + , 1864 + , 1865 + , 1866 + , 1867 + , 1868 + , 1869 + , 1870 + , 1871 + , 1872 + , 1873 + , 1874 + , 1875 + , 1876 + , 1877 + , 1878 + , 1879 + , 1880 + , 1881 + , 1882 + , 1883 + , 1884 + , 1885 + , 1886 + , 1887 + , 1888 + , 1889 + , 1890 + , 1891 + , 1892 + , 1893 + , 1894 + , 1895 + , 1896 + , 1897 + , 1898 + , 1899 + , 1900 + , 1901 + , 1902 + , 1903 + , 1904 + , 1905 + , 1906 + , 1907 + , 1908 + , 1909 + , 1910 + , 1911 + , 1912 + , 1913 + , 1914 + , 1915 + , 1916 + , 1917 + , 1918 + , 1919 + , 1920 + , 1921 + , 1922 + , 1923 + , 1924 + , 1925 + , 1926 + , 1927 + , 1928 + , 1929 + , 1930 + , 1931 + , 1932 + , 1933 + , 1934 + , 1935 + , 1936 + , 1937 + , 1938 + , 1939 + , 1940 + , 1941 + , 1942 + , 1943 + , 1944 + , 1945 + , 1946 + , 1947 + , 1948 + , 1949 + , 1950 + , 1951 + , 1952 + , 1953 + , 1954 + , 1955 + , 1956 + , 1957 + , 1958 + , 1959 + , 1960 + , 1961 + , 1962 + , 1963 + , 1964 + , 1965 + , 1966 + , 1967 + , 1968 + , 1969 + , 1970 + , 1971 + , 1972 + , 1973 + , 1974 + , 1975 + , 1976 + , 1977 + , 1978 + , 1979 + , 1980 + , 1981 + , 1982 + , 1983 + , 1984 + , 1985 + , 1986 + , 1987 + , 1988 + , 1989 + , 1990 + , 1991 + , 1992 + , 1993 + , 1994 + , 1995 + , 1996 + , 1997 + , 1998 + , 1999 , 2000 ] diff --git a/unison-src/transcripts/runtime-tests.output.md b/unison-src/transcripts/runtime-tests.output.md index a8d9795aa1..582333433c 100644 --- a/unison-src/transcripts/runtime-tests.output.md +++ b/unison-src/transcripts/runtime-tests.output.md @@ -77,6 +77,12 @@ casting = (Nat.toInt 100, 29 | > casting ⧩ - (100, 3.14, 4614253070214989087, 100, +10, -10) + ( +100 + , 4614253070214989087 + , 3.14 + , +100 + , 10 + , 18446744073709551606 + ) ``` From 80a74735cdeaf04733c85cd353fd7da3df6a8b1c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 10:22:59 -0800 Subject: [PATCH 074/113] Fix runtime Serialization tests --- .../tests/Unison/Test/Runtime/ANF/Serialization.hs | 10 +--------- .../tests/Unison/Test/Runtime/MCode/Serialization.hs | 7 +++++-- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/unison-runtime/tests/Unison/Test/Runtime/ANF/Serialization.hs b/unison-runtime/tests/Unison/Test/Runtime/ANF/Serialization.hs index 1d6f9dc554..92b206ea56 100644 --- a/unison-runtime/tests/Unison/Test/Runtime/ANF/Serialization.hs +++ b/unison-runtime/tests/Unison/Test/Runtime/ANF/Serialization.hs @@ -40,16 +40,8 @@ genUBytes = Util.Bytes.fromByteString <$> Gen.bytes (Range.linear 0 4) genGroupRef :: Gen GroupRef genGroupRef = GR <$> genReference <*> genSmallWord64 -genUBValue :: Gen UBValue -genUBValue = - Gen.choice - [ -- Unboxed values are no longer valid in ANF serialization. - -- Left <$> genSmallWord64, - Right <$> genValue - ] - genValList :: Gen ValList -genValList = Gen.list (Range.linear 0 4) genUBValue +genValList = Gen.list (Range.linear 0 4) genValue genCont :: Gen Cont genCont = do diff --git a/unison-runtime/tests/Unison/Test/Runtime/MCode/Serialization.hs b/unison-runtime/tests/Unison/Test/Runtime/MCode/Serialization.hs index ef05644c22..18e4529001 100644 --- a/unison-runtime/tests/Unison/Test/Runtime/MCode/Serialization.hs +++ b/unison-runtime/tests/Unison/Test/Runtime/MCode/Serialization.hs @@ -16,6 +16,7 @@ import Unison.Prelude import Unison.Runtime.Interface import Unison.Runtime.MCode (Args (..), BPrim1, BPrim2, Branch, Comb, CombIx (..), GBranch (..), GComb (..), GCombInfo (..), GInstr (..), GRef (..), GSection (..), Instr, MLit (..), Ref, Section, UPrim1, UPrim2) import Unison.Runtime.Machine (Combs) +import Unison.Runtime.TypeTags (PackedTag(..)) import Unison.Test.Gen import Unison.Util.EnumContainers (EnumMap, EnumSet) import Unison.Util.EnumContainers qualified as EC @@ -105,6 +106,9 @@ genMLit = MY <$> genReference ] +genPackedTag :: Gen PackedTag +genPackedTag = PackedTag <$> genSmallWord64 + genInstr :: Gen Instr genInstr = Gen.choice @@ -117,9 +121,8 @@ genInstr = Capture <$> genSmallWord64, Name <$> genGRef <*> genArgs, Info <$> Gen.string (Range.linear 0 10) Gen.alphaNum, - Pack <$> genReference <*> genSmallWord64 <*> genArgs, + Pack <$> genReference <*> genPackedTag <*> genArgs, Lit <$> genMLit, - BLit <$> genReference <*> genSmallWord64 <*> genMLit, Print <$> genSmallInt, Reset <$> genEnumSet genSmallWord64, Fork <$> genSmallInt, From ca2d1f639e4dc8d191003b2a9484e725dfe26b6e Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 10:22:59 -0800 Subject: [PATCH 075/113] Fix bad unsafeCoerce to Closure --- unison-runtime/src/Unison/Runtime/Decompile.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 1e21a760e5..9c000df0aa 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -219,9 +219,9 @@ decompileForeign backref topTerms f _ -> l | Just l <- maybeUnwrapForeign typeLinkRef f = pure $ typeLink () l - | Just (a :: Array Closure) <- maybeUnwrapForeign iarrayRef f = + | Just (a :: Array Val) <- maybeUnwrapForeign iarrayRef f = app () (ref () iarrayFromListRef) . list () - <$> traverse (decompile backref topTerms . BoxedVal) (toList a) + <$> traverse (decompile backref topTerms) (toList a) | Just (a :: ByteArray) <- maybeUnwrapForeign ibytearrayRef f = pure $ app From d604eb97ccac4bb01c6a2cb5b1f5caea9a4cc50b Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 11:38:10 -0800 Subject: [PATCH 076/113] Use the proper unit calling conventions for builtins --- unison-runtime/src/Unison/Runtime/Builtin.hs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index b6208a179a..d401aa9d13 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -1499,6 +1499,12 @@ argNDirect n instr = where args = freshes n +-- () -> a +-- +-- Unit is unique in that we don't actually pass it as an arg +unitDirect :: ForeignOp +unitDirect instr = ([BX],) . TAbs arg $ TFOp instr [] where arg = fresh1 + -- a -> Either Failure b argToEF :: ForeignOp argToEF = @@ -2284,7 +2290,7 @@ declareForeigns = do . mkForeign $ \(c :: Val) -> newMVar c - declareForeign Tracked "MVar.newEmpty.v2" (argNDirect 1) + declareForeign Tracked "MVar.newEmpty.v2" unitDirect . mkForeign $ \() -> newEmptyMVar @Val @@ -2390,7 +2396,7 @@ declareForeigns = do declareForeign Tracked "TVar.swap" (argNDirect 2) . mkForeign $ \(v, c :: Val) -> unsafeSTMToIO $ STM.swapTVar v c - declareForeign Tracked "STM.retry" (argNDirect 1) . mkForeign $ + declareForeign Tracked "STM.retry" unitDirect . mkForeign $ \() -> unsafeSTMToIO STM.retry :: IO Val -- Scope and Ref stuff @@ -2440,7 +2446,7 @@ declareForeigns = do t <- evaluate t casIORef r t v - declareForeign Tracked "Promise.new" (argNDirect 1) . mkForeign $ + declareForeign Tracked "Promise.new" unitDirect . mkForeign $ \() -> newPromise @Val -- the only exceptions from Promise.read are async and shouldn't be caught @@ -3303,7 +3309,7 @@ baseSandboxInfo = builtinArities :: Map Reference Int builtinArities = Map.fromList $ - [ (r, arity s) | (r, (_, s)) <- Map.toList builtinLookup ] + [(r, arity s) | (r, (_, s)) <- Map.toList builtinLookup] unsafeSTMToIO :: STM.STM a -> IO a unsafeSTMToIO (STM.STM m) = IO m From 4b06b4c2fb94f5b27b57945c28d6965d29dac8a5 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 11:41:06 -0800 Subject: [PATCH 077/113] Relax int/nat equality/comparisons to account for loss of information in load/save roundtrips --- unison-runtime/src/Unison/Runtime/Machine.hs | 27 +++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 72a2e29304..97057ac793 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2381,7 +2381,7 @@ universalEq frn = eqVal eql :: (a -> b -> Bool) -> [a] -> [b] -> Bool eql cm l r = length l == length r && and (zipWith cm l r) eqVal :: Val -> Val -> Bool - eqVal (UnboxedVal v1 t1) (UnboxedVal v2 t2) = t1 == t2 && v1 == v2 + eqVal (UnboxedVal v1 t1) (UnboxedVal v2 t2) = matchTags t1 t2 && v1 == v2 eqVal (BoxedVal x) (BoxedVal y) = eqc x y eqVal _ _ = False eqc :: Closure -> Closure -> Bool @@ -2409,12 +2409,13 @@ universalEq frn = eqVal eqValList :: [Val] -> [Val] -> Bool eqValList vs1 vs2 = eql eqVal vs1 vs2 - -- serialization doesn't necessarily preserve Int tags, so be - -- more accepting for those. - matchTags ct1 ct2 = - ct1 == ct2 - || (ct1 == TT.intTag && ct2 == TT.natTag) - || (ct1 == TT.natTag && ct2 == TT.intTag) +-- serialization doesn't necessarily preserve Int tags, so be +-- more accepting for those. +matchTags :: PackedTag -> PackedTag -> Bool +matchTags ct1 ct2 = + ct1 == ct2 + || (ct1 == TT.intTag && ct2 == TT.natTag) + || (ct1 == TT.natTag && ct2 == TT.intTag) arrayEq :: (a -> a -> Bool) -> PA.Array a -> PA.Array a -> Bool arrayEq eqc l r @@ -2478,8 +2479,12 @@ universalCompare frn = cmpVal False (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> -- We don't need to mask the tags since unboxed types are -- always treated like nullary constructors and have an empty ctag. - Monoid.whenM tyEq (compare t1 t2) + Monoid.whenM tyEq (compareTags t1 t2) <> compare v1 v2 + compareTags t1 t2 = + if matchTags t1 t2 + then EQ + else compare t1 t2 cmpl :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) @@ -2510,6 +2515,10 @@ universalCompare frn = cmpVal False (UnboxedTypeTag t1) (UnboxedTypeTag t2) -> compare t1 t2 (BlackHole) (BlackHole) -> EQ c d -> comparing closureNum c d + cmpUnboxed :: Bool -> (PackedTag, Int) -> (PackedTag, Int) -> Ordering + cmpUnboxed tyEq (t1, v1) (t2, v2) = + Monoid.whenM tyEq (compareTags t1 t2) + <> compare v1 v2 cmpValList :: Bool -> [Val] -> [Val] -> Ordering cmpValList tyEq vs1 vs2 = -- Written in a strange way way to maintain back-compat with the @@ -2519,7 +2528,7 @@ universalCompare frn = cmpVal False BoxedVal clos -> (mempty, [clos]) (us1, bs1) = partitionVals vs1 (us2, bs2) = partitionVals vs2 - in cmpl compare us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 + in cmpl (cmpUnboxed tyEq) us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 arrayCmp :: (a -> a -> Ordering) -> From 0e98a5f77c3da98cd45cbfbf1338cef225aa3cd1 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 12:28:29 -0800 Subject: [PATCH 078/113] Re-run transcripts --- unison-src/transcripts/io.output.md | 549 +++++++++++++++++++++++++++- 1 file changed, 538 insertions(+), 11 deletions(-) diff --git a/unison-src/transcripts/io.output.md b/unison-src/transcripts/io.output.md index 7cf1e4f95b..77c84aea6b 100644 --- a/unison-src/transcripts/io.output.md +++ b/unison-src/transcripts/io.output.md @@ -156,37 +156,564 @@ scratch/main> io.test testOpenClose New test results: 1. testOpenClose ◉ file should be open + ◉ file handle buffering should match what we just set. ◉ file should be closed ◉ bytes have been written ◉ bytes have been written ◉ file should be closed - 2. testOpenClose ✗ file handle buffering should match what we just set. + ✅ 6 test(s) passing - 🚫 1 test(s) failing, ✅ 5 test(s) passing + Tip: Use view 1 to view the source of a test. + +``` +### Reading files with getSomeBytes + +Tests: + + - getSomeBytes + - putBytes + - isFileOpen + - seekHandle + +``` unison +testGetSomeBytes : '{io2.IO} [Result] +testGetSomeBytes _ = + test = 'let + tempDir = (newTempDir "getSomeBytes") + fooFile = tempDir ++ "/foo" + + testData = "0123456789" + testSize = size testData + + chunkSize = 7 + check "chunk size splits data into 2 uneven sides" ((chunkSize > (testSize / 2)) && (chunkSize < testSize)) + + + -- write testData to a temporary file + fooWrite = openFile fooFile Write + putBytes fooWrite (toUtf8 testData) + closeFile fooWrite + check "file should be closed" (not (isFileOpen fooWrite)) + + -- reopen for reading back the data in chunks + fooRead = openFile fooFile Read + + -- read first part of file + chunk1 = getSomeBytes fooRead chunkSize |> fromUtf8 + check "first chunk matches first part of testData" (chunk1 == take chunkSize testData) + + -- read rest of file + chunk2 = getSomeBytes fooRead chunkSize |> fromUtf8 + check "second chunk matches rest of testData" (chunk2 == drop chunkSize testData) + + check "should be at end of file" (isFileEOF fooRead) + + readAtEOF = getSomeBytes fooRead chunkSize + check "reading at end of file results in Bytes.empty" (readAtEOF == Bytes.empty) + + -- request many bytes from the start of the file + seekHandle fooRead AbsoluteSeek +0 + bigRead = getSomeBytes fooRead (testSize * 999) |> fromUtf8 + check "requesting many bytes results in what's available" (bigRead == testData) + + closeFile fooRead + check "file should be closed" (not (isFileOpen fooRead)) + + runTest test +``` + +``` 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`: + + testGetSomeBytes : '{IO} [Result] + +``` +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testGetSomeBytes : '{IO} [Result] + +scratch/main> io.test testGetSomeBytes + + New test results: + + 1. testGetSomeBytes ◉ chunk size splits data into 2 uneven sides + ◉ file should be closed + ◉ first chunk matches first part of testData + ◉ second chunk matches rest of testData + ◉ should be at end of file + ◉ reading at end of file results in Bytes.empty + ◉ requesting many bytes results in what's available + ◉ file should be closed + + ✅ 8 test(s) passing Tip: Use view 1 to view the source of a test. ``` +### Seeking in open files + +Tests: + + - openFile + - putBytes + - closeFile + - isSeekable + - isFileEOF + - seekHandle + - getBytes + - getLine + +``` unison +testSeek : '{io2.IO} [Result] +testSeek _ = + test = 'let + tempDir = newTempDir "seek" + emit (Ok "seeked") + fooFile = tempDir ++ "/foo" + handle1 = openFile fooFile FileMode.Append + putBytes handle1 (toUtf8 "12345678") + closeFile handle1 + + handle3 = openFile fooFile FileMode.Read + check "readable file should be seekable" (isSeekable handle3) + check "shouldn't be the EOF" (not (isFileEOF handle3)) + expectU "we should be at position 0" 0 (handlePosition handle3) + + seekHandle handle3 AbsoluteSeek +1 + expectU "we should be at position 1" 1 (handlePosition handle3) + bytes3a = getBytes handle3 1000 + text3a = Text.fromUtf8 bytes3a + expectU "should be able to read our temporary file after seeking" "2345678" text3a + closeFile handle3 + + barFile = tempDir ++ "/bar" + handle4 = openFile barFile FileMode.Append + putBytes handle4 (toUtf8 "foobar\n") + closeFile handle4 + + handle5 = openFile barFile FileMode.Read + expectU "getLine should get a line" "foobar" (getLine handle5) + closeFile handle5 + + runTest test + +testAppend : '{io2.IO} [Result] +testAppend _ = + test = 'let + tempDir = newTempDir "openFile" + fooFile = tempDir ++ "/foo" + handle1 = openFile fooFile FileMode.Write + putBytes handle1 (toUtf8 "test1") + closeFile handle1 + + handle2 = openFile fooFile FileMode.Append + putBytes handle2 (toUtf8 "test2") + closeFile handle2 + + handle3 = openFile fooFile FileMode.Read + bytes3 = getBytes handle3 1000 + text3 = Text.fromUtf8 bytes3 + + expectU "should be able to read our temporary file" "test1test2" text3 + + closeFile handle3 + + runTest test +``` +``` 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`: + + testAppend : '{IO} [Result] + testSeek : '{IO} [Result] -The transcript failed due to an error in the stanza above. The error is: +``` +``` ucm +scratch/main> add + ⍟ I've added these definitions: + + testAppend : '{IO} [Result] + testSeek : '{IO} [Result] + +scratch/main> io.test testSeek New test results: - 1. testOpenClose ◉ file should be open - ◉ file should be closed - ◉ bytes have been written - ◉ bytes have been written - ◉ file should be closed + 1. testSeek ◉ seeked + ◉ readable file should be seekable + ◉ shouldn't be the EOF + ◉ we should be at position 0 + ◉ we should be at position 1 + ◉ should be able to read our temporary file after seeking + ◉ getLine should get a line + + ✅ 7 test(s) passing - 2. testOpenClose ✗ file handle buffering should match what we just set. + Tip: Use view 1 to view the source of a test. + +scratch/main> io.test testAppend + + New test results: - 🚫 1 test(s) failing, ✅ 5 test(s) passing + 1. testAppend ◉ should be able to read our temporary file + + ✅ 1 test(s) passing Tip: Use view 1 to view the source of a test. +``` +### SystemTime + +``` unison +testSystemTime : '{io2.IO} [Result] +testSystemTime _ = + test = 'let + t = !systemTime + check "systemTime should be sane" ((t > 1600000000) && (t < 2000000000)) + + runTest test +``` + +``` 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`: + + testSystemTime : '{IO} [Result] + +``` +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testSystemTime : '{IO} [Result] + +scratch/main> io.test testSystemTime + + New test results: + + 1. testSystemTime ◉ systemTime should be sane + + ✅ 1 test(s) passing + + Tip: Use view 1 to view the source of a test. + +``` +### Get temp directory + +``` unison +testGetTempDirectory : '{io2.IO} [Result] +testGetTempDirectory _ = + test = 'let + tempDir = reraise !getTempDirectory.impl + check "Temp directory is directory" (isDirectory tempDir) + check "Temp directory should exist" (fileExists tempDir) + runTest test +``` + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testGetTempDirectory : '{IO} [Result] + +scratch/main> io.test testGetTempDirectory + + New test results: + + 1. testGetTempDirectory ◉ Temp directory is directory + ◉ Temp directory should exist + + ✅ 2 test(s) passing + + Tip: Use view 1 to view the source of a test. + +``` +### Get current directory + +``` unison +testGetCurrentDirectory : '{io2.IO} [Result] +testGetCurrentDirectory _ = + test = 'let + currentDir = reraise !getCurrentDirectory.impl + check "Current directory is directory" (isDirectory currentDir) + check "Current directory should exist" (fileExists currentDir) + runTest test +``` + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testGetCurrentDirectory : '{IO} [Result] + +scratch/main> io.test testGetCurrentDirectory + + New test results: + + 1. testGetCurrentDirectory ◉ Current directory is directory + ◉ Current directory should exist + + ✅ 2 test(s) passing + + Tip: Use view 1 to view the source of a test. + +``` +### Get directory contents + +``` unison +testDirContents : '{io2.IO} [Result] +testDirContents _ = + test = 'let + tempDir = newTempDir "dircontents" + c = reraise (directoryContents.impl tempDir) + check "directory size should be" (size c == 2) + check "directory contents should have current directory and parent" let + (c == [".", ".."]) || (c == ["..", "."]) + runTest test +``` + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testDirContents : '{IO} [Result] + +scratch/main> io.test testDirContents + + New test results: + + 1. testDirContents ◉ directory size should be + ◉ directory contents should have current directory and parent + + ✅ 2 test(s) passing + + Tip: Use view 1 to view the source of a test. + +``` +### Read environment variables + +``` unison +testGetEnv : '{io2.IO} [Result] +testGetEnv _ = + test = 'let + path = reraise (getEnv.impl "PATH") -- PATH exists on windows, mac and linux. + check "PATH environent variable should be set" (size path > 0) + match getEnv.impl "DOESNTEXIST" with + Right _ -> emit (Fail "env var shouldn't exist") + Left _ -> emit (Ok "DOESNTEXIST didn't exist") + runTest test +``` + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testGetEnv : '{IO} [Result] + +scratch/main> io.test testGetEnv + + New test results: + + 1. testGetEnv ◉ PATH environent variable should be set + ◉ DOESNTEXIST didn't exist + + ✅ 2 test(s) passing + + Tip: Use view 1 to view the source of a test. + +``` +### Read command line args + +`runMeWithNoArgs`, `runMeWithOneArg`, and `runMeWithTwoArgs` raise exceptions +unless they called with the right number of arguments. + +``` unison +testGetArgs.fail : Text -> Failure +testGetArgs.fail descr = Failure (typeLink IOFailure) descr !Any + +testGetArgs.runMeWithNoArgs : '{io2.IO, Exception} () +testGetArgs.runMeWithNoArgs = 'let + args = reraise !getArgs.impl + match args with + [] -> printLine "called with no args" + _ -> raise (testGetArgs.fail "called with args") + +testGetArgs.runMeWithOneArg : '{io2.IO, Exception} () +testGetArgs.runMeWithOneArg = 'let + args = reraise !getArgs.impl + match args with + [] -> raise (testGetArgs.fail "called with no args") + [_] -> printLine "called with one arg" + _ -> raise (testGetArgs.fail "called with too many args") + +testGetArgs.runMeWithTwoArgs : '{io2.IO, Exception} () +testGetArgs.runMeWithTwoArgs = 'let + args = reraise !getArgs.impl + match args with + [] -> raise (testGetArgs.fail "called with no args") + [_] -> raise (testGetArgs.fail "called with one arg") + [_, _] -> printLine "called with two args" + _ -> raise (testGetArgs.fail "called with too many args") +``` + +Test that they can be run with the right number of args. + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testGetArgs.fail : Text -> Failure + testGetArgs.runMeWithNoArgs : '{IO, Exception} () + testGetArgs.runMeWithOneArg : '{IO, Exception} () + testGetArgs.runMeWithTwoArgs : '{IO, Exception} () + +scratch/main> run runMeWithNoArgs + + () + +scratch/main> run runMeWithOneArg foo + + () + +scratch/main> run runMeWithTwoArgs foo bar + + () + +``` +Calling our examples with the wrong number of args will error. + +``` ucm +scratch/main> run runMeWithNoArgs foo + + 💔💥 + + The program halted with an unhandled exception: + + Failure (typeLink IOFailure) "called with args" (Any ()) + + Stack trace: + ##raise + +``` +``` ucm +scratch/main> run runMeWithOneArg + + 💔💥 + + The program halted with an unhandled exception: + + Failure (typeLink IOFailure) "called with no args" (Any ()) + + Stack trace: + ##raise + +``` +``` ucm +scratch/main> run runMeWithOneArg foo bar + + 💔💥 + + The program halted with an unhandled exception: + + Failure + (typeLink IOFailure) "called with too many args" (Any ()) + + Stack trace: + ##raise + +``` +``` ucm +scratch/main> run runMeWithTwoArgs + + 💔💥 + + The program halted with an unhandled exception: + + Failure (typeLink IOFailure) "called with no args" (Any ()) + + Stack trace: + ##raise + +``` +### Get the time zone + +``` unison +testTimeZone = do + (offset, summer, name) = Clock.internals.systemTimeZone +0 + _ = (offset : Int, summer : Nat, name : Text) + () +``` + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testTimeZone : '{IO} () + +scratch/main> run testTimeZone + + () + +``` +### Get some random bytes + +``` unison +testRandom : '{io2.IO} [Result] +testRandom = do + test = do + bytes = IO.randomBytes 10 + check "randomBytes returns the right number of bytes" (size bytes == 10) + runTest test +``` + +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + testRandom : '{IO} [Result] + +scratch/main> io.test testGetEnv + + New test results: + + 1. testGetEnv ◉ PATH environent variable should be set + ◉ DOESNTEXIST didn't exist + + ✅ 2 test(s) passing + + Tip: Use view 1 to view the source of a test. + +``` From f9630305877a5ddaf0e63ae7bac4dec13afd8556 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 13:09:40 -0800 Subject: [PATCH 079/113] Don't need to peek boxed stack --- unison-runtime/src/Unison/Runtime/Machine.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 97057ac793..626e371b2a 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -673,8 +673,8 @@ eval !env !denv !activeThreads !stk !k r (DMatch mr i br) = do (t, stk) <- dumpDataNoTag mr stk =<< peekOff stk i eval env denv activeThreads stk k r $ selectBranch (maskTags t) br -eval !env !denv !activeThreads !stk !k r (NMatch mr i br) = do - n <- numValue mr =<< peekOff stk i +eval !env !denv !activeThreads !stk !k r (NMatch _mr i br) = do + n <- peekOffN stk i eval env denv activeThreads stk k r $ selectBranch n br eval !env !denv !activeThreads !stk !k r (RMatch i pu br) = do (t, stk) <- dumpDataNoTag Nothing stk =<< peekOff stk i From 2c0595105b185411d1682278a44f11830ebcd56d Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 16:41:26 -0800 Subject: [PATCH 080/113] Fix up universalCompare some more --- unison-runtime/src/Unison/Runtime/Machine.hs | 27 +++++++++----------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 626e371b2a..350b02d537 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2457,13 +2457,6 @@ compareAsFloat i j where clear k = clearBit k 64 -compareAsNat :: Int -> Int -> Ordering -compareAsNat i j = compare ni nj - where - ni, nj :: Word - ni = fromIntegral i - nj = fromIntegral j - universalCompare :: (Foreign -> Foreign -> Ordering) -> Val -> @@ -2476,11 +2469,8 @@ universalCompare frn = cmpVal False (BoxedVal c1) (BoxedVal c2) -> cmpc tyEq c1 c2 (UnboxedVal {}) (BoxedVal {}) -> LT (BoxedVal {}) (UnboxedVal {}) -> GT - (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> - -- We don't need to mask the tags since unboxed types are - -- always treated like nullary constructors and have an empty ctag. - Monoid.whenM tyEq (compareTags t1 t2) - <> compare v1 v2 + (NatVal i) (NatVal j) -> compare i j + (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> cmpUnboxed tyEq (t1, v1) (t2, v2) compareTags t1 t2 = if matchTags t1 t2 then EQ @@ -2516,9 +2506,16 @@ universalCompare frn = cmpVal False (BlackHole) (BlackHole) -> EQ c d -> comparing closureNum c d cmpUnboxed :: Bool -> (PackedTag, Int) -> (PackedTag, Int) -> Ordering - cmpUnboxed tyEq (t1, v1) (t2, v2) = - Monoid.whenM tyEq (compareTags t1 t2) - <> compare v1 v2 + cmpUnboxed tyEq (t1, v1) (t2, v2) + | (t1 == TT.intTag || t1 == TT.natTag) && (t2 == TT.intTag || t2 == TT.natTag) = + compare v1 v2 + | t1 == TT.floatTag && t2 == TT.floatTag = + compareAsFloat v1 v2 + | otherwise = + -- We don't need to mask the tags since unboxed types are + -- always treated like nullary constructors and have an empty ctag. + Monoid.whenM tyEq (compareTags t1 t2) + <> compare v1 v2 cmpValList :: Bool -> [Val] -> [Val] -> Ordering cmpValList tyEq vs1 vs2 = -- Written in a strange way way to maintain back-compat with the From 8a455ab3d5d564fc8d4dd667f296ec2b0c4f7147 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 17:00:30 -0800 Subject: [PATCH 081/113] Add some more runtime tests --- unison-src/transcripts/runtime-tests.md | 25 +++++++ .../transcripts/runtime-tests.output.md | 73 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/unison-src/transcripts/runtime-tests.md b/unison-src/transcripts/runtime-tests.md index fe83465195..624614c633 100644 --- a/unison-src/transcripts/runtime-tests.md +++ b/unison-src/transcripts/runtime-tests.md @@ -35,4 +35,29 @@ casting = (Nat.toInt 100, Int.toRepresentation +10, Int.toRepresentation -10) > casting + + +> 1 Universal.== Int.toRepresentation +1 +> [1, 2, 3] Universal.== [Int.toRepresentation +1, Int.toRepresentation +2, Int.toRepresentation +3] + +-- Float edge cases +> compare 0.0 0.0 +> compare +0.0 (-0.0) +> compare -0.0 (+0.0) +> compare -1.0 1.0 + +-- Currently, the same NaN's are equal, but different NaN's are not... +> (0.0/0.0) == (0.0/0.0) +> (0.0/0.0) == (1.0/0.0) + +> Universal.compare [] [1] +> Universal.compare [1, 2] [2, 3] +> Universal.compare [2, 3] [1, 2] + +-- Values in 'Any' are compared a bit strangely. +-- Currently we have special-cases to compare the values of Nats and Ints directly, ignoring their type, for better or +-- worse. +-- This helps to counter a different issue we have, where `load (save +10)` will load a `Nat` runtime type rather than +-- an Int, since we don't actually store the type of numerics in the ANF.Value type. +> Universal.compare (Any [1, 2]) (Any [+1, +2]) ``` diff --git a/unison-src/transcripts/runtime-tests.output.md b/unison-src/transcripts/runtime-tests.output.md index 582333433c..d4be777480 100644 --- a/unison-src/transcripts/runtime-tests.output.md +++ b/unison-src/transcripts/runtime-tests.output.md @@ -30,6 +30,31 @@ casting = (Nat.toInt 100, Int.toRepresentation +10, Int.toRepresentation -10) > casting + + +> 1 Universal.== Int.toRepresentation +1 +> [1, 2, 3] Universal.== [Int.toRepresentation +1, Int.toRepresentation +2, Int.toRepresentation +3] + +-- Float edge cases +> compare 0.0 0.0 +> compare +0.0 (-0.0) +> compare -0.0 (+0.0) +> compare -1.0 1.0 + +-- Currently, the same NaN's are equal, but different NaN's are not... +> (0.0/0.0) == (0.0/0.0) +> (0.0/0.0) == (1.0/0.0) + +> Universal.compare [] [1] +> Universal.compare [1, 2] [2, 3] +> Universal.compare [2, 3] [1, 2] + +-- Values in 'Any' are compared a bit strangely. +-- Currently we have special-cases to compare the values of Nats and Ints directly, ignoring their type, for better or +-- worse. +-- This helps to counter a different issue we have, where `load (save +10)` will load a `Nat` runtime type rather than +-- an Int, since we don't actually store the type of numerics in the ANF.Value type. +> Universal.compare (Any [1, 2]) (Any [+1, +2]) ``` ``` ucm @@ -84,5 +109,53 @@ casting = (Nat.toInt 100, , 10 , 18446744073709551606 ) + + 32 | > 1 Universal.== Int.toRepresentation +1 + ⧩ + true + + 33 | > [1, 2, 3] Universal.== [Int.toRepresentation +1, Int.toRepresentation +2, Int.toRepresentation +3] + ⧩ + true + + 36 | > compare 0.0 0.0 + ⧩ + +0 + + 37 | > compare +0.0 (-0.0) + ⧩ + -1 + + 38 | > compare -0.0 (+0.0) + ⧩ + +1 + + 39 | > compare -1.0 1.0 + ⧩ + -1 + + 42 | > (0.0/0.0) == (0.0/0.0) + ⧩ + true + + 43 | > (0.0/0.0) == (1.0/0.0) + ⧩ + false + + 45 | > Universal.compare [] [1] + ⧩ + -1 + + 46 | > Universal.compare [1, 2] [2, 3] + ⧩ + -1 + + 47 | > Universal.compare [2, 3] [1, 2] + ⧩ + +1 + + 54 | > Universal.compare (Any [1, 2]) (Any [+1, +2]) + ⧩ + +0 ``` From 5e64b29577bbf665c82259f9d685cb262b42d22b Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 4 Nov 2024 18:07:28 -0800 Subject: [PATCH 082/113] Replace PackedTag runtime types with a custom type --- unison-runtime/src/Unison/Runtime/Builtin.hs | 35 +++++------ .../src/Unison/Runtime/Decompile.hs | 14 ++--- unison-runtime/src/Unison/Runtime/Machine.hs | 37 +++++++---- unison-runtime/src/Unison/Runtime/Stack.hs | 63 +++++++++++++------ 4 files changed, 92 insertions(+), 57 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index d401aa9d13..7e294bbbc7 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -173,9 +173,8 @@ import Unison.Runtime.Foreign ) import Unison.Runtime.Foreign qualified as F import Unison.Runtime.Foreign.Function -import Unison.Runtime.Stack (Val (..), emptyVal) +import Unison.Runtime.Stack (UnboxedTypeTag (..), Val (..), emptyVal, unboxedTypeTagToInt) import Unison.Runtime.Stack qualified as Closure -import Unison.Runtime.TypeTags qualified as TT import Unison.Symbol import Unison.Type qualified as Ty import Unison.Util.Bytes qualified as Bytes @@ -492,16 +491,15 @@ n2f = unop NTOF trni :: (Var v) => SuperNormal v trni = unop0 4 $ \[x, z, b, tag, n] -> -- TODO: Do we need to do all calculations _before_ the branch? + -- Should probably just replace this with an instruction. TLetD z UN (TLit $ N 0) . TLetD b UN (TPrm LEQI [x, z]) - . TLetD tag UN (TLit $ I $ fromIntegral nt) + . TLetD tag UN (TLit $ I $ fromIntegral $ unboxedTypeTagToInt NatTag) . TLetD n UN (TPrm CAST [x, tag]) . TMatch b $ MatchIntegral (mapSingleton 1 $ TVar z) (Just $ TVar n) - where - PackedTag nt = TT.natTag modular :: (Var v) => POp -> (Bool -> ANormal v) -> SuperNormal v modular pop ret = @@ -523,7 +521,8 @@ dropn :: (Var v) => SuperNormal v dropn = binop0 4 $ \[x, y, b, r, tag, n] -> TLetD b UN (TPrm LEQN [x, y]) -- TODO: Can we avoid this work until after the branch? - . TLetD tag UN (TLit $ I $ fromIntegral nt) + -- Should probably just replace this with an instruction. + . TLetD tag UN (TLit $ I $ fromIntegral $ unboxedTypeTagToInt NatTag) . TLetD r UN (TPrm SUBN [x, y]) . TLetD n UN (TPrm CAST [r, tag]) $ ( TMatch b $ @@ -531,8 +530,6 @@ dropn = binop0 4 $ \[x, y, b, r, tag, n] -> (mapSingleton 1 $ TLit $ N 0) (Just $ TVar n) ) - where - PackedTag nt = TT.natTag appendt, taket, dropt, indext, indexb, sizet, unconst, unsnoct :: (Var v) => SuperNormal v appendt = binop0 0 $ \[x, y] -> TPrm CATT [x, y] @@ -814,11 +811,11 @@ andb = binop0 0 $ \[p, q] -> -- A runtime type-cast. Used to unsafely coerce between unboxed -- types at runtime without changing their representation. -coerceType :: PackedTag -> SuperNormal Symbol -coerceType (PackedTag destType) = +coerceType :: UnboxedTypeTag -> SuperNormal Symbol +coerceType destType = unop0 1 $ \[v, tag] -> - TLetD tag UN (TLit $ I $ fromIntegral destType) $ - TPrm CAST [v, tag] + TLetD tag UN (TLit $ I $ fromIntegral $ unboxedTypeTagToInt destType) $ + TPrm CAST [v, tag] -- unbox x0 ri x $ -- TCon ro 0 [x] @@ -1735,8 +1732,8 @@ builtinLookup = ("Int.<=", (Untracked, lei)), ("Int.>", (Untracked, gti)), ("Int.>=", (Untracked, gei)), - ("Int.fromRepresentation", (Untracked, coerceType TT.intTag)), - ("Int.toRepresentation", (Untracked, coerceType TT.natTag)), + ("Int.fromRepresentation", (Untracked, coerceType IntTag)), + ("Int.toRepresentation", (Untracked, coerceType NatTag)), ("Int.increment", (Untracked, inci)), ("Int.signum", (Untracked, sgni)), ("Int.negate", (Untracked, negi)), @@ -1780,7 +1777,7 @@ builtinLookup = ("Nat.complement", (Untracked, compln)), ("Nat.pow", (Untracked, pown)), ("Nat.drop", (Untracked, dropn)), - ("Nat.toInt", (Untracked, coerceType TT.intTag)), + ("Nat.toInt", (Untracked, coerceType IntTag)), ("Nat.toFloat", (Untracked, n2f)), ("Nat.toText", (Untracked, n2t)), ("Nat.fromText", (Untracked, t2n)), @@ -1793,8 +1790,8 @@ builtinLookup = ("Float.log", (Untracked, logf)), ("Float.logBase", (Untracked, logbf)), ("Float.sqrt", (Untracked, sqrtf)), - ("Float.fromRepresentation", (Untracked, coerceType TT.floatTag)), - ("Float.toRepresentation", (Untracked, coerceType TT.natTag)), + ("Float.fromRepresentation", (Untracked, coerceType FloatTag)), + ("Float.toRepresentation", (Untracked, coerceType NatTag)), ("Float.min", (Untracked, minf)), ("Float.max", (Untracked, maxf)), ("Float.<", (Untracked, ltf)), @@ -1850,8 +1847,8 @@ builtinLookup = ("Debug.trace", (Tracked, gen'trace)), ("Debug.toText", (Tracked, debug'text)), ("unsafe.coerceAbilities", (Untracked, poly'coerce)), - ("Char.toNat", (Untracked, coerceType TT.natTag)), - ("Char.fromNat", (Untracked, coerceType TT.charTag)), + ("Char.toNat", (Untracked, coerceType NatTag)), + ("Char.fromNat", (Untracked, coerceType CharTag)), ("Bytes.empty", (Untracked, emptyb)), ("Bytes.fromList", (Untracked, packb)), ("Bytes.toList", (Untracked, unpackb)), diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 9c000df0aa..b650f450c9 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -36,13 +36,11 @@ import Unison.Runtime.MCode (CombIx (..)) import Unison.Runtime.Stack ( Closure (..), USeq, + UnboxedTypeTag (..), Val (..), pattern DataC, pattern PApV, ) --- for Int -> Double - -import Unison.Runtime.TypeTags qualified as TT import Unison.Syntax.NamePrinter (prettyReference) import Unison.Term ( Term, @@ -90,7 +88,7 @@ err err x = (singleton err, x) data DecompError = BadBool !Word64 - | BadUnboxed !TT.PackedTag + | BadUnboxed !UnboxedTypeTag | BadForeign !Reference | BadData !Reference | BadPAp !Reference @@ -105,8 +103,8 @@ type DecompResult v = (Set DecompError, Term v ()) prf :: Reference -> Error prf = syntaxToColor . prettyReference 10 -printPackedTag :: TT.PackedTag -> Error -printPackedTag t = shown $ TT.unpackTags t +printUnboxedTypeTag :: UnboxedTypeTag -> Error +printUnboxedTypeTag = shown renderDecompError :: DecompError -> Error renderDecompError (BadBool n) = @@ -114,10 +112,10 @@ renderDecompError (BadBool n) = [ wrap "A boolean value had an unexpected constructor tag:", indentN 2 . lit . fromString $ show n ] -renderDecompError (BadUnboxed rf) = +renderDecompError (BadUnboxed tt) = lines [ wrap "An apparent numeric type had an unrecognized packed tag:", - indentN 2 $ printPackedTag rf + indentN 2 $ printUnboxedTypeTag tt ] renderDecompError (BadForeign rf) = lines diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 350b02d537..6c4835e624 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -979,7 +979,7 @@ dumpDataNoTag !mr !stk = \case val@(UnboxedVal _ t) -> do stk <- bump stk poke stk val - pure (t, stk) + pure (unboxedPackedTag t, stk) BoxedVal clos -> case clos of (Enum _ t) -> pure (t, stk) (Data1 _ t x) -> do @@ -999,6 +999,13 @@ dumpDataNoTag !mr !stk = \case "dumpDataNoTag: bad closure: " ++ show clo ++ maybe "" (\r -> "\nexpected type: " ++ show r) mr + where + unboxedPackedTag :: UnboxedTypeTag -> PackedTag + unboxedPackedTag = \case + CharTag -> TT.charTag + FloatTag -> TT.floatTag + IntTag -> TT.intTag + NatTag -> TT.natTag {-# INLINE dumpDataNoTag #-} -- Note: although the representation allows it, it is impossible @@ -1201,7 +1208,7 @@ uprim1 !stk COMI !i = do pure stk {-# INLINE uprim1 #-} -uprim2 :: Stack -> UPrim2 -> Int -> Int -> IO Stack +uprim2 :: (HasCallStack) => Stack -> UPrim2 -> Int -> Int -> IO Stack uprim2 !stk ADDI !i !j = do m <- upeekOff stk i n <- upeekOff stk j @@ -1425,10 +1432,10 @@ uprim2 !stk XORI !i !j = do pokeI stk (xor x y) pure stk uprim2 !stk CAST !vi !ti = do - newTypeTag <- peekOffN stk ti + newTypeTag <- peekOffI stk ti v <- upeekOff stk vi stk <- bump stk - poke stk $ UnboxedVal v (PackedTag newTypeTag) + poke stk $ UnboxedVal v (unboxedTypeTagFromInt newTypeTag) pure stk {-# INLINE uprim2 #-} @@ -2381,7 +2388,7 @@ universalEq frn = eqVal eql :: (a -> b -> Bool) -> [a] -> [b] -> Bool eql cm l r = length l == length r && and (zipWith cm l r) eqVal :: Val -> Val -> Bool - eqVal (UnboxedVal v1 t1) (UnboxedVal v2 t2) = matchTags t1 t2 && v1 == v2 + eqVal (UnboxedVal v1 t1) (UnboxedVal v2 t2) = matchUnboxedTypes t1 t2 && v1 == v2 eqVal (BoxedVal x) (BoxedVal y) = eqc x y eqVal _ _ = False eqc :: Closure -> Closure -> Bool @@ -2417,6 +2424,14 @@ matchTags ct1 ct2 = || (ct1 == TT.intTag && ct2 == TT.natTag) || (ct1 == TT.natTag && ct2 == TT.intTag) +-- serialization doesn't necessarily preserve Int tags, so be +-- more accepting for those. +matchUnboxedTypes :: UnboxedTypeTag -> UnboxedTypeTag -> Bool +matchUnboxedTypes ct1 ct2 = + ct1 == ct2 + || (ct1 == IntTag && ct2 == NatTag) + || (ct1 == NatTag && ct2 == IntTag) + arrayEq :: (a -> a -> Bool) -> PA.Array a -> PA.Array a -> Bool arrayEq eqc l r | PA.sizeofArray l /= PA.sizeofArray r = False @@ -2471,8 +2486,8 @@ universalCompare frn = cmpVal False (BoxedVal {}) (UnboxedVal {}) -> GT (NatVal i) (NatVal j) -> compare i j (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> cmpUnboxed tyEq (t1, v1) (t2, v2) - compareTags t1 t2 = - if matchTags t1 t2 + compareUnboxedTypes t1 t2 = + if matchUnboxedTypes t1 t2 then EQ else compare t1 t2 cmpl :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering @@ -2505,16 +2520,16 @@ universalCompare frn = cmpVal False (UnboxedTypeTag t1) (UnboxedTypeTag t2) -> compare t1 t2 (BlackHole) (BlackHole) -> EQ c d -> comparing closureNum c d - cmpUnboxed :: Bool -> (PackedTag, Int) -> (PackedTag, Int) -> Ordering + cmpUnboxed :: Bool -> (UnboxedTypeTag, Int) -> (UnboxedTypeTag, Int) -> Ordering cmpUnboxed tyEq (t1, v1) (t2, v2) - | (t1 == TT.intTag || t1 == TT.natTag) && (t2 == TT.intTag || t2 == TT.natTag) = + | (t1 == IntTag || t1 == NatTag) && (t2 == IntTag || t2 == NatTag) = compare v1 v2 - | t1 == TT.floatTag && t2 == TT.floatTag = + | t1 == FloatTag && t2 == FloatTag = compareAsFloat v1 v2 | otherwise = -- We don't need to mask the tags since unboxed types are -- always treated like nullary constructors and have an empty ctag. - Monoid.whenM tyEq (compareTags t1 t2) + Monoid.whenM tyEq (compareUnboxedTypes t1 t2) <> compare v1 v2 cmpValList :: Bool -> [Val] -> [Val] -> Ordering cmpValList tyEq vs1 vs2 = diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 7a48920ca2..d9cf02b828 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -19,6 +19,9 @@ module Unison.Runtime.Stack BlackHole, UnboxedTypeTag ), + UnboxedTypeTag (..), + unboxedTypeTagToInt, + unboxedTypeTagFromInt, IxClosure, Callback (..), Augment (..), @@ -135,7 +138,6 @@ import Unison.Runtime.ANF (PackedTag) import Unison.Runtime.Array import Unison.Runtime.Foreign import Unison.Runtime.MCode -import Unison.Runtime.TypeTags qualified as TT import Unison.Type qualified as Ty import Unison.Util.EnumContainers as EC import Prelude hiding (words) @@ -234,6 +236,29 @@ type USeq = Seq Val type IxClosure = GClosure CombIx +-- Don't re-order these, the ord instance affects Universal.compare +data UnboxedTypeTag + = CharTag + | FloatTag + | IntTag + | NatTag + deriving stock (Show, Eq, Ord) + +unboxedTypeTagToInt :: UnboxedTypeTag -> Int +unboxedTypeTagToInt = \case + CharTag -> 0 + FloatTag -> 1 + IntTag -> 2 + NatTag -> 3 + +unboxedTypeTagFromInt :: (HasCallStack) => Int -> UnboxedTypeTag +unboxedTypeTagFromInt = \case + 0 -> CharTag + 1 -> FloatTag + 2 -> IntTag + 3 -> NatTag + _ -> error "intToUnboxedTypeTag: invalid tag" + {- ORMOLU_DISABLE -} data GClosure comb = GPAp @@ -250,7 +275,7 @@ data GClosure comb | -- The type tag for the value in the corresponding unboxed stack slot. -- We should consider adding separate constructors for common builtin type tags. -- GHC will optimize nullary constructors into singletons. - GUnboxedTypeTag !PackedTag + GUnboxedTypeTag !UnboxedTypeTag | GBlackHole #ifdef STACK_CHECK | GUnboxedSentinel @@ -304,19 +329,19 @@ pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) -- We can avoid allocating a closure for common type tags on each poke by having shared top-level closures for them. natTypeTag :: Closure -natTypeTag = UnboxedTypeTag TT.natTag +natTypeTag = UnboxedTypeTag NatTag {-# NOINLINE natTypeTag #-} intTypeTag :: Closure -intTypeTag = UnboxedTypeTag TT.intTag +intTypeTag = UnboxedTypeTag IntTag {-# NOINLINE intTypeTag #-} charTypeTag :: Closure -charTypeTag = UnboxedTypeTag TT.charTag +charTypeTag = UnboxedTypeTag CharTag {-# NOINLINE charTypeTag #-} floatTypeTag :: Closure -floatTypeTag = UnboxedTypeTag TT.floatTag +floatTypeTag = UnboxedTypeTag FloatTag {-# NOINLINE floatTypeTag #-} traceK :: Reference -> K -> [(Reference, Int)] @@ -376,43 +401,43 @@ pattern DataC rf ct segs <- matchCharVal :: Val -> Maybe Char matchCharVal = \case - (UnboxedVal u tt) | tt == TT.charTag -> Just (Char.chr u) + (UnboxedVal u CharTag) -> Just (Char.chr u) _ -> Nothing pattern CharVal :: Char -> Val pattern CharVal c <- (matchCharVal -> Just c) where - CharVal c = UnboxedVal (Char.ord c) TT.charTag + CharVal c = UnboxedVal (Char.ord c) CharTag matchNatVal :: Val -> Maybe Word64 matchNatVal = \case - (UnboxedVal u tt) | tt == TT.natTag -> Just (fromIntegral u) + (UnboxedVal u NatTag) -> Just (fromIntegral u) _ -> Nothing pattern NatVal :: Word64 -> Val pattern NatVal n <- (matchNatVal -> Just n) where - NatVal n = UnboxedVal (fromIntegral n) TT.natTag + NatVal n = UnboxedVal (fromIntegral n) NatTag matchDoubleVal :: Val -> Maybe Double matchDoubleVal = \case - (UnboxedVal u tt) | tt == TT.floatTag -> Just (intToDouble u) + (UnboxedVal u FloatTag) -> Just (intToDouble u) _ -> Nothing pattern DoubleVal :: Double -> Val pattern DoubleVal d <- (matchDoubleVal -> Just d) where - DoubleVal d = UnboxedVal (doubleToInt d) TT.floatTag + DoubleVal d = UnboxedVal (doubleToInt d) FloatTag matchIntVal :: Val -> Maybe Int matchIntVal = \case - (UnboxedVal u tt) | tt == TT.intTag -> Just u + (UnboxedVal u IntTag) -> Just u _ -> Nothing pattern IntVal :: Int -> Val pattern IntVal i <- (matchIntVal -> Just i) where - IntVal i = UnboxedVal i TT.intTag + IntVal i = UnboxedVal i IntTag doubleToInt :: Double -> Int doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 @@ -630,7 +655,7 @@ instance Ord Val where emptyVal :: Val emptyVal = Val (-1) BlackHole -pattern UnboxedVal :: Int -> PackedTag -> Val +pattern UnboxedVal :: Int -> UnboxedTypeTag -> Val pattern UnboxedVal v t = (Val v (UnboxedTypeTag t)) valToBoxed :: Val -> Maybe Closure @@ -721,7 +746,7 @@ upeekOff _stk@(Stack _ _ sp ustk _) i = do readByteArray ustk (sp - i) {-# INLINE upeekOff #-} -upokeT :: DebugCallStack => Stack -> UVal -> PackedTag -> IO () +upokeT :: DebugCallStack => Stack -> UVal -> UnboxedTypeTag -> IO () upokeT !stk@(Stack _ _ sp ustk _) !u !t = do bpoke stk (UnboxedTypeTag t) writeByteArray ustk sp u @@ -741,7 +766,7 @@ poke _stk@(Stack _ _ sp ustk bstk) (Val u b) = do -- checks. unsafePokeIasN :: DebugCallStack => Stack -> Int -> IO () unsafePokeIasN stk n = do - upokeT stk n TT.natTag + upokeT stk n NatTag {-# INLINE unsafePokeIasN #-} -- | Store an unboxed tag to later match on. @@ -786,7 +811,7 @@ pokeOff stk i (Val u t) = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE pokeOff #-} -upokeOffT :: DebugCallStack => Stack -> Off -> UVal -> PackedTag -> IO () +upokeOffT :: DebugCallStack => Stack -> Off -> UVal -> UnboxedTypeTag -> IO () upokeOffT stk i u t = do bpokeOff stk i (UnboxedTypeTag t) writeByteArray (ustk stk) (sp stk - i) u @@ -1090,7 +1115,7 @@ pokeOffI stk@(Stack _ _ sp ustk _) i n = do pokeOffC :: Stack -> Int -> Char -> IO () pokeOffC stk i c = do - upokeOffT stk i (Char.ord c) TT.charTag + upokeOffT stk i (Char.ord c) CharTag {-# INLINE pokeOffC #-} pokeBi :: (BuiltinForeign b) => Stack -> b -> IO () From d7dce7862109f76b84908865b973c2bdce1eb277 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 5 Nov 2024 10:56:35 -0800 Subject: [PATCH 083/113] Remove borked copied file --- Runtime.hs | 181 ----------------------------------------------------- 1 file changed, 181 deletions(-) delete mode 100644 Runtime.hs diff --git a/Runtime.hs b/Runtime.hs deleted file mode 100644 index f790076f27..0000000000 --- a/Runtime.hs +++ /dev/null @@ -1,181 +0,0 @@ -{-# LANGUAGE PatternSynonyms #-} -{-# LANGUAGE RankNTypes #-} - -module Unison.Codebase.Runtime where - -import Data.Map qualified as Map -import Data.Set.NonEmpty (NESet) -import Unison.ABT qualified as ABT -import Unison.Builtin.Decls (tupleTerm, pattern TupleTerm') -import Unison.Codebase.CodeLookup qualified as CL -import Unison.Codebase.CodeLookup.Util qualified as CL -import Unison.Hashing.V2.Convert qualified as Hashing -import Unison.Parser.Ann (Ann) -import Unison.Prelude -import Unison.PrettyPrintEnv qualified as PPE -import Unison.Reference (Reference) -import Unison.Reference qualified as Reference -import Unison.Term qualified as Term -import Unison.Type (Type) -import Unison.UnisonFile (TypecheckedUnisonFile) -import Unison.UnisonFile qualified as UF -import Unison.Util.Pretty qualified as P -import Unison.Var (Var) -import Unison.Var qualified as Var -import Unison.WatchKind (WatchKind) -import Unison.WatchKind qualified as WK - -type Error = P.Pretty P.ColorText - -type Term v = Term.Term v () - -data CompileOpts = COpts - { profile :: Bool - } - -defaultCompileOpts :: CompileOpts -defaultCompileOpts = COpts {profile = False} - -data Runtime v = Runtime - { terminate :: IO (), - evaluate :: - CL.CodeLookup v IO () -> - PPE.PrettyPrintEnv -> - Term v -> - IO (Either Error ([Error], Term v)), - compileTo :: - CompileOpts -> - CL.CodeLookup v IO () -> - PPE.PrettyPrintEnv -> - Reference -> - FilePath -> - IO (Maybe Error), - mainType :: Type v Ann, - ioTestTypes :: NESet (Type v Ann) - } - -type IsCacheHit = Bool - -noCache :: Reference.Id -> IO (Maybe (Term v)) -noCache _ = pure Nothing - -type WatchResults v a = - ( Either - Error - -- Bindings: - ( [(v, Term v)], - -- Map watchName (loc, hash, expression, value, isHit) - [Error], - Map v (a, WatchKind, Reference.Id, Term v, Term v, IsCacheHit) - ) - ) - --- Evaluates the watch expressions in the file, returning a `Map` of their --- results. This has to be a bit fancy to handle that the definitions in the --- file depend on each other and evaluation must proceed in a way that respects --- these dependencies. --- --- Note: The definitions in the file are hashed and looked up in --- `evaluationCache`. If that returns a result, evaluation of that definition --- can be skipped. -evaluateWatches :: - forall v a. - (Var v) => - CL.CodeLookup v IO a -> - PPE.PrettyPrintEnv -> - (Reference.Id -> IO (Maybe (Term v))) -> - Runtime v -> - TypecheckedUnisonFile v a -> - IO (WatchResults v a) -evaluateWatches code ppe evaluationCache rt tuf = do - -- 1. compute hashes for everything in the file - let m :: Map v (Reference.Id, Term.Term v a) - m = fmap (\(_a, id, _wk, tm, _tp) -> (id, tm)) (UF.hashTermsId tuf) - watches :: Set v = Map.keysSet watchKinds - watchKinds :: Map v WatchKind - watchKinds = - Map.fromList - [(v, k) | (k, ws) <- UF.watchComponents tuf, (v, _a, _tm, _tp) <- ws] - unann = Term.amap (const ()) - -- 2. use the cache to lookup things already computed - m' <- fmap Map.fromList . for (Map.toList m) $ \(v, (r, t)) -> do - o <- evaluationCache r - case o of - Nothing -> pure (v, (r, ABT.annotation t, unann t, False)) - Just t' -> pure (v, (r, ABT.annotation t, t', True)) - -- 3. create a big ol' let rec whose body is a big tuple of all watches - let rv :: Map Reference.Id v - rv = Map.fromList [(r, v) | (v, (r, _)) <- Map.toList m] - bindings :: [(v, (), Term v)] - bindings = [(v, (), unref rv b) | (v, (_, _, b, _)) <- Map.toList m'] - watchVars = [Term.var () v | v <- toList watches] - bigOl'LetRec = Term.letRec' True bindings (tupleTerm watchVars) - cl = void (CL.fromTypecheckedUnisonFile tuf) <> void code - -- 4. evaluate it and get all the results out of the tuple, then - -- create the result Map - out <- evaluate rt cl ppe bigOl'LetRec - case out of - Right (errs, out) -> do - let (bindings, results) = case out of - TupleTerm' results -> (mempty, results) - Term.LetRecNamed' bs (TupleTerm' results) -> (bs, results) - _ -> error $ "Evaluation should produce a tuple, but gave: " ++ show out - let go v eval (ref, a, uneval, isHit) = - ( a, - Map.findWithDefault (die v) v watchKinds, - ref, - uneval, - Term.etaNormalForm eval, - isHit - ) - watchMap = - Map.intersectionWithKey - go - (Map.fromList (toList watches `zip` results)) - m' - die v = error $ "not sure what kind of watch this is: " <> show v - pure $ Right (bindings, errs, watchMap) - Left e -> pure (Left e) - where - -- unref :: Map Reference.Id v -> Term.Term v a -> Term.Term v a - unref rv t = ABT.visitPure go t - where - go t@(Term.Ref' (Reference.DerivedId r)) = case Map.lookup r rv of - Nothing -> Nothing - Just v -> Just (Term.var (ABT.annotation t) v) - go _ = Nothing - -evaluateTerm' :: - (Var v, Monoid a) => - CL.CodeLookup v IO a -> - (Reference.Id -> IO (Maybe (Term v))) -> - PPE.PrettyPrintEnv -> - Runtime v -> - Term.Term v a -> - IO (Either Error ([Error], Term v)) -evaluateTerm' codeLookup cache ppe rt tm = do - result <- cache (Hashing.hashClosedTerm tm) - case result of - Just r -> pure (Right ([], r)) - Nothing -> do - let tuf = - UF.typecheckedUnisonFile - mempty - mempty - mempty - [(WK.RegularWatch, [(Var.nameds "result", mempty, tm, mempty <$> mainType rt)])] - r <- evaluateWatches (void codeLookup) ppe cache rt (void tuf) - pure $ - r <&> \(_, errs, map) -> - case Map.elems map of - [(_loc, _kind, _hash, _src, value, _isHit)] -> (errs, value) - _ -> error "evaluateTerm': Pattern mismatch on watch results" - -evaluateTerm :: - (Var v, Monoid a) => - CL.CodeLookup v IO a -> - PPE.PrettyPrintEnv -> - Runtime v -> - Term.Term v a -> - IO (Either Error ([Error], Term v)) -evaluateTerm codeLookup = evaluateTerm' codeLookup noCache From b9dbf4991e71673a081e80413611b38909f69545 Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Tue, 5 Nov 2024 14:15:59 -0500 Subject: [PATCH 084/113] add some merge progress output messages --- .../src/Unison/Codebase/Editor/HandleInput/Merge2.hs | 11 +++++++++++ unison-cli/src/Unison/Codebase/Editor/Output.hs | 11 +++++++++++ unison-cli/src/Unison/CommandLine/OutputMessages.hs | 7 +++++++ 3 files changed, 29 insertions(+) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs index cb39f76ad0..fdd3aa27d7 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs @@ -182,6 +182,8 @@ doMerge info = do _ <- Cli.updateAt info.description (PP.projectBranchRoot info.alice.projectAndBranch) (\_aliceBranch -> bobBranch) done (Output.MergeSuccessFastForward mergeSourceAndTarget) + Cli.respond (Output.MergeProgress Output.MergeProgress'LoadingBranches) + -- Load Alice/Bob/LCA causals causals <- Cli.runTransaction do @@ -251,6 +253,8 @@ doMerge info = do in bimap f g <$> blob0.defns ) + Cli.respond (Output.MergeProgress Output.MergeProgress'DiffingBranches) + blob1 <- Merge.makeMergeblob1 blob0 hydratedDefns & onLeft \case Merge.Alice reason -> done (Output.IncoherentDeclDuringMerge mergeTarget reason) @@ -271,11 +275,15 @@ doMerge info = do liftIO (debugFunctions.debugPartitionedDiff blob2.conflicts blob2.unconflicts) + Cli.respond (Output.MergeProgress Output.MergeProgress'LoadingDependents) + dependents0 <- Cli.runTransaction $ for ((,) <$> ThreeWay.forgetLca blob2.defns <*> blob2.coreDependencies) \(defns, deps) -> getNamespaceDependentsOf3 defns deps + Cli.respond (Output.MergeProgress Output.MergeProgress'LoadingAndMergingLibdeps) + -- Load and merge Alice's and Bob's libdeps mergedLibdeps <- Cli.runTransaction (libdepsToBranch0 (Codebase.getDeclType env.codebase) blob2.libdeps) @@ -283,6 +291,8 @@ doMerge info = do let hasConflicts = blob2.hasConflicts + Cli.respond (Output.MergeProgress Output.MergeProgress'RenderingUnisonFile) + let blob3 = Merge.makeMergeblob3 blob2 @@ -308,6 +318,7 @@ doMerge info = do else case Merge.makeMergeblob4 blob3 of Left _parseErr -> pure Nothing Right blob4 -> do + Cli.respond (Output.MergeProgress Output.MergeProgress'TypecheckingUnisonFile) typeLookup <- Cli.runTransaction (Codebase.typeLookupForDependencies env.codebase blob4.dependencies) pure case Merge.makeMergeblob5 blob4 typeLookup of Left _typecheckErr -> Nothing diff --git a/unison-cli/src/Unison/Codebase/Editor/Output.hs b/unison-cli/src/Unison/Codebase/Editor/Output.hs index c85542c2fe..486298c413 100644 --- a/unison-cli/src/Unison/Codebase/Editor/Output.hs +++ b/unison-cli/src/Unison/Codebase/Editor/Output.hs @@ -16,6 +16,7 @@ module Unison.Codebase.Editor.Output UpdateOrUpgrade (..), isFailure, isNumberedFailure, + MergeProgress (..), ) where @@ -438,6 +439,15 @@ data Output | ConflictedDefn !Text {- what operation? -} !(Defn (Conflicted Name Referent) (Conflicted Name TypeReference)) | IncoherentDeclDuringMerge !MergeSourceOrTarget !IncoherentDeclReason | IncoherentDeclDuringUpdate !IncoherentDeclReason + | MergeProgress !MergeProgress + +data MergeProgress + = MergeProgress'LoadingBranches + | MergeProgress'DiffingBranches + | MergeProgress'LoadingDependents + | MergeProgress'LoadingAndMergingLibdeps + | MergeProgress'RenderingUnisonFile + | MergeProgress'TypecheckingUnisonFile data MoreEntriesThanShown = MoreEntriesThanShown | AllEntriesShown deriving (Eq, Show) @@ -677,6 +687,7 @@ isFailure o = case o of ConflictedDefn {} -> True IncoherentDeclDuringMerge {} -> True IncoherentDeclDuringUpdate {} -> True + MergeProgress _ -> False isNumberedFailure :: NumberedOutput -> Bool isNumberedFailure = \case diff --git a/unison-cli/src/Unison/CommandLine/OutputMessages.hs b/unison-cli/src/Unison/CommandLine/OutputMessages.hs index 1f1f6aac14..8e83b489f0 100644 --- a/unison-cli/src/Unison/CommandLine/OutputMessages.hs +++ b/unison-cli/src/Unison/CommandLine/OutputMessages.hs @@ -49,6 +49,7 @@ import Unison.Codebase.Editor.Input (BranchIdG (..)) import Unison.Codebase.Editor.Input qualified as Input import Unison.Codebase.Editor.Output ( CreatedProjectBranchFrom (..), + MergeProgress (..), NumberedArgs, NumberedOutput (..), Output (..), @@ -2220,6 +2221,12 @@ notifyUser dir = \case <> IP.makeExample' IP.delete <> "it. Then try the update again." ] + MergeProgress MergeProgress'LoadingBranches -> pure "Loading branches..." + MergeProgress MergeProgress'DiffingBranches -> pure "Computing diff between branches..." + MergeProgress MergeProgress'LoadingDependents -> pure "Loading dependents of changes..." + MergeProgress MergeProgress'LoadingAndMergingLibdeps -> pure "Loading and merging library dependencies..." + MergeProgress MergeProgress'RenderingUnisonFile -> pure "Rendering Unison file..." + MergeProgress MergeProgress'TypecheckingUnisonFile -> pure "Typechecking Unison file..." prettyShareError :: ShareError -> Pretty prettyShareError = From 18287d586a925c39619bbafe2dd0d0be59b5be55 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 5 Nov 2024 11:16:47 -0800 Subject: [PATCH 085/113] PR cleanup --- unison-runtime/src/Unison/Runtime/Builtin.hs | 3 --- unison-runtime/src/Unison/Runtime/Stack.hs | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 7e294bbbc7..9445ae28bd 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -817,9 +817,6 @@ coerceType destType = TLetD tag UN (TLit $ I $ fromIntegral $ unboxedTypeTagToInt destType) $ TPrm CAST [v, tag] --- unbox x0 ri x $ --- TCon ro 0 [x] - -- This version of unsafeCoerce is the identity function. It works -- only if the two types being coerced between are actually the same, -- because it keeps the same representation. It is not capable of diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index d9cf02b828..296b9522f6 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -542,10 +542,10 @@ uargOnto stk sp cop cp0 (ArgN v) = do let loop i | i < 0 = return () | otherwise = do - (x :: Int) <- readByteArray stk (sp - indexPrimArray v i) -- + (x :: Int) <- readByteArray stk (sp - indexPrimArray v i) writeByteArray buf (boff - i) x loop $ i - 1 - loop $ sz - 1 -- 2 + loop $ sz - 1 when overwrite $ copyMutableByteArray cop (bytes $ cp0 + 1) buf 0 (bytes sz) pure cp From afb65c9340616d3d5c9ca39736d3d252a0808ed0 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 5 Nov 2024 14:25:02 -0800 Subject: [PATCH 086/113] Make universalCompare more consistent --- .../src/Unison/Util/EnumContainers.hs | 5 +- unison-runtime/src/Unison/Runtime/MCode.hs | 14 ++++- unison-runtime/src/Unison/Runtime/Machine.hs | 38 ++++++++++++- unison-runtime/src/Unison/Runtime/Stack.hs | 55 +------------------ 4 files changed, 54 insertions(+), 58 deletions(-) diff --git a/parser-typechecker/src/Unison/Util/EnumContainers.hs b/parser-typechecker/src/Unison/Util/EnumContainers.hs index 0a84aa4dd2..fe62ee69d7 100644 --- a/parser-typechecker/src/Unison/Util/EnumContainers.hs +++ b/parser-typechecker/src/Unison/Util/EnumContainers.hs @@ -32,6 +32,7 @@ module Unison.Util.EnumContainers where import Data.Bifunctor +import Data.Functor.Classes (Eq1, Ord1) import Data.IntMap.Strict qualified as IM import Data.IntSet qualified as IS import Data.Word (Word16, Word64) @@ -60,7 +61,9 @@ newtype EnumMap k a = EM (IM.IntMap a) ) deriving newtype ( Monoid, - Semigroup + Semigroup, + Eq1, + Ord1 ) newtype EnumSet k = ES IS.IntSet diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index c90f90808e..26d392d99a 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -667,7 +667,19 @@ data GRef comb = Stk !Int -- stack reference to a closure | Env !CombIx {- Lazy! Might be cyclic -} comb | Dyn !Word64 -- dynamic scope reference to a closure - deriving (Show, Eq, Ord, Functor, Foldable, Traversable) + deriving (Show, Functor, Foldable, Traversable) + +instance Eq (GRef comb) where + a == b = compare a b == EQ + +instance Ord (GRef comb) where + compare (Stk a) (Stk b) = compare a b + compare (Stk {}) _ = LT + compare _ (Stk {}) = GT + compare (Env a _) (Env b _) = compare a b + compare (Env {}) _ = LT + compare _ (Env {}) = GT + compare (Dyn a) (Dyn b) = compare a b type Branch = GBranch CombIx diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 6c4835e624..f28f49fe1e 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -9,6 +9,7 @@ import Control.Concurrent.STM as STM import Control.Exception import Control.Lens import Data.Bits +import Data.Functor.Classes (Eq1 (..), Ord1 (..)) import Data.Map.Strict qualified as M import Data.Ord (comparing) import Data.Sequence qualified as Sq @@ -2401,7 +2402,7 @@ universalEq frn = eqVal cix1 == cix2 && eqValList segs1 segs2 eqc (CapV k1 a1 vs1) (CapV k2 a2 vs2) = - k1 == k2 + eqK k1 k2 && a1 == a2 && eqValList vs1 vs2 eqc (Foreign fl) (Foreign fr) @@ -2413,9 +2414,19 @@ universalEq frn = eqVal length sl == length sr && and (Sq.zipWith eqVal sl sr) | otherwise = frn fl fr eqc c d = closureNum c == closureNum d + eqValList :: [Val] -> [Val] -> Bool eqValList vs1 vs2 = eql eqVal vs1 vs2 + eqK :: K -> K -> Bool + eqK KE KE = True + eqK (CB cb) (CB cb') = cb == cb' + eqK (Mark a ps m k) (Mark a' ps' m' k') = + a == a' && ps == ps' && liftEq eqVal m m' && eqK k k' + eqK (Push f a ci _ _sect k) (Push f' a' ci' _ _sect' k') = + f == f' && a == a' && ci == ci' && eqK k k' + eqK _ _ = False + -- serialization doesn't necessarily preserve Int tags, so be -- more accepting for those. matchTags :: PackedTag -> PackedTag -> Bool @@ -2505,7 +2516,7 @@ universalCompare frn = cmpVal False compare cix1 cix2 <> cmpValList tyEq segs1 segs2 (CapV k1 a1 vs1) (CapV k2 a2 vs2) -> - compare k1 k2 + cmpK tyEq k1 k2 <> compare a1 a2 <> cmpValList True vs1 vs2 (Foreign fl) (Foreign fr) @@ -2520,6 +2531,7 @@ universalCompare frn = cmpVal False (UnboxedTypeTag t1) (UnboxedTypeTag t2) -> compare t1 t2 (BlackHole) (BlackHole) -> EQ c d -> comparing closureNum c d + cmpUnboxed :: Bool -> (UnboxedTypeTag, Int) -> (UnboxedTypeTag, Int) -> Ordering cmpUnboxed tyEq (t1, v1) (t2, v2) | (t1 == IntTag || t1 == NatTag) && (t2 == IntTag || t2 == NatTag) = @@ -2531,6 +2543,7 @@ universalCompare frn = cmpVal False -- always treated like nullary constructors and have an empty ctag. Monoid.whenM tyEq (compareUnboxedTypes t1 t2) <> compare v1 v2 + cmpValList :: Bool -> [Val] -> [Val] -> Ordering cmpValList tyEq vs1 vs2 = -- Written in a strange way way to maintain back-compat with the @@ -2542,6 +2555,27 @@ universalCompare frn = cmpVal False (us2, bs2) = partitionVals vs2 in cmpl (cmpUnboxed tyEq) us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 + cmpK :: Bool -> K -> K -> Ordering + cmpK tyEq = \cases + KE KE -> EQ + (CB cb) (CB cb') -> compare cb cb' + (Mark a ps m k) (Mark a' ps' m' k') -> + compare a a' + <> compare ps ps' + <> liftCompare (cmpVal tyEq) m m' + <> cmpK tyEq k k' + (Push f a ci _ _sect k) (Push f' a' ci' _ _sect' k') -> + compare f f' + <> compare a a' + <> compare ci ci' + <> cmpK tyEq k k' + KE _ -> LT + _ KE -> GT + (CB {}) _ -> LT + _ (CB {}) -> GT + (Mark {}) _ -> LT + _ (Mark {}) -> GT + arrayCmp :: (a -> a -> Ordering) -> PA.Array a -> diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 296b9522f6..671d3a108e 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -205,31 +205,8 @@ data K !(RSection Val) -- resumption section !K -instance Eq K where - KE == KE = True - (CB cb) == (CB cb') = cb == cb' - (Mark a ps m k) == (Mark a' ps' m' k') = - a == a' && ps == ps' && m == m' && k == k' - (Push f a ci _ _sect k) == (Push f' a' ci' _ _sect' k') = - f == f' && a == a' && ci == ci' && k == k' - _ == _ = False - -instance Ord K where - compare KE KE = EQ - compare (CB cb) (CB cb') = compare cb cb' - compare (Mark a ps m k) (Mark a' ps' m' k') = - compare (a, ps, m, k) (a', ps', m', k') - compare (Push f a ci _ _sect k) (Push f' a' ci' _ _sect' k') = - compare (f, a, ci, k) (f', a', ci', k') - compare KE _ = LT - compare _ KE = GT - compare (CB {}) _ = LT - compare _ (CB {}) = GT - compare (Mark {}) _ = LT - compare _ (Mark {}) = GT - newtype Closure = Closure {unClosure :: (GClosure (RComb Val))} - deriving stock (Show, Eq, Ord) + deriving stock (Show) -- | Implementation for Unison sequences. type USeq = Seq Val @@ -283,22 +260,6 @@ data GClosure comb deriving stock (Show, Functor, Foldable, Traversable) {- ORMOLU_ENABLE -} --- We derive a basic instance for a version _without_ cyclic references. -deriving instance Eq (GClosure ()) - --- Then we define the eq instance for cyclic references to just use the derived instance after deleting any possible --- cycles. --- This is still correct because each constructor with a cyclic reference also includes --- a CombIx identifying the cycle. -instance Eq (GClosure (RComb Val)) where - a == b = (a $> ()) == (b $> ()) - --- See Eq instance. -deriving instance Ord (GClosure ()) - -instance Ord (GClosure (RComb Val)) where - compare a b = compare (a $> ()) (b $> ()) - pattern PAp :: CombIx -> GCombInfo (RComb Val) -> Seg -> Closure pattern PAp cix comb seg = Closure (GPAp cix comb seg) @@ -637,20 +598,6 @@ data Val = Val {getUnboxedVal :: !UVal, getBoxedVal :: !BVal} -- See universalEq. deriving (Show) -instance Eq Val where - (==) = \cases - (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> t1 == t2 && v1 == v2 - (BoxedVal x) (BoxedVal y) -> x == y - (UnboxedVal {}) (BoxedVal {}) -> False - (BoxedVal {}) (UnboxedVal {}) -> False - -instance Ord Val where - compare = \cases - (BoxedVal c1) (BoxedVal c2) -> compare c1 c2 - (UnboxedVal i1 t1) (UnboxedVal i2 t2) -> compare t1 t2 <> compare i1 i2 - (UnboxedVal {}) (BoxedVal _) -> LT - (BoxedVal _) (UnboxedVal {}) -> GT - -- | A nulled out value you can use when filling empty arrays, etc. emptyVal :: Val emptyVal = Val (-1) BlackHole From 570b1866b21852b7f8520f9cd6144e9241fc9c02 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 5 Nov 2024 14:25:02 -0800 Subject: [PATCH 087/113] Fix universalCompare's handling of value lists and nats/ints --- unison-runtime/src/Unison/Runtime/Machine.hs | 39 ++++++++------------ unison-src/transcripts/runtime-tests.md | 8 ++++ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index f28f49fe1e..ba6f5d8402 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2497,10 +2497,6 @@ universalCompare frn = cmpVal False (BoxedVal {}) (UnboxedVal {}) -> GT (NatVal i) (NatVal j) -> compare i j (UnboxedVal v1 t1) (UnboxedVal v2 t2) -> cmpUnboxed tyEq (t1, v1) (t2, v2) - compareUnboxedTypes t1 t2 = - if matchUnboxedTypes t1 t2 - then EQ - else compare t1 t2 cmpl :: (a -> b -> Ordering) -> [a] -> [b] -> Ordering cmpl cm l r = compare (length l) (length r) <> fold (zipWith cm l r) @@ -2533,27 +2529,24 @@ universalCompare frn = cmpVal False c d -> comparing closureNum c d cmpUnboxed :: Bool -> (UnboxedTypeTag, Int) -> (UnboxedTypeTag, Int) -> Ordering - cmpUnboxed tyEq (t1, v1) (t2, v2) - | (t1 == IntTag || t1 == NatTag) && (t2 == IntTag || t2 == NatTag) = - compare v1 v2 - | t1 == FloatTag && t2 == FloatTag = - compareAsFloat v1 v2 - | otherwise = - -- We don't need to mask the tags since unboxed types are - -- always treated like nullary constructors and have an empty ctag. - Monoid.whenM tyEq (compareUnboxedTypes t1 t2) - <> compare v1 v2 + cmpUnboxed tyEq = \cases + -- Need to cast to Nat or else maxNat == -1 and it flips comparisons of large Nats. + -- TODO: Investigate whether bit-twiddling is faster than using Haskell's fromIntegral. + (IntTag, n1) (IntTag, n2) -> compare n1 n2 + (NatTag, n1) (NatTag, n2) -> compare (fromIntegral n1 :: Word64) (fromIntegral n2 :: Word64) + (NatTag, n1) (IntTag, n2) + | n2 < 0 -> GT + | otherwise -> compare (fromIntegral n1 :: Word64) (fromIntegral n2 :: Word64) + (IntTag, n1) (NatTag, n2) + | n1 < 0 -> LT + | otherwise -> compare (fromIntegral n1 :: Word64) (fromIntegral n2 :: Word64) + (FloatTag, n1) (FloatTag, n2) -> compareAsFloat n1 n2 + (t1, v1) (t2, v2) -> + Monoid.whenM tyEq (compare t1 t2) + <> compare v1 v2 cmpValList :: Bool -> [Val] -> [Val] -> Ordering - cmpValList tyEq vs1 vs2 = - -- Written in a strange way way to maintain back-compat with the - -- old val lists which had boxed/unboxed separated - let partitionVals = foldMap \case - UnboxedVal v tt -> ([(tt, v)], mempty) - BoxedVal clos -> (mempty, [clos]) - (us1, bs1) = partitionVals vs1 - (us2, bs2) = partitionVals vs2 - in cmpl (cmpUnboxed tyEq) us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 + cmpValList tyEq vs1 vs2 = cmpl (cmpVal tyEq) vs1 vs2 cmpK :: Bool -> K -> K -> Ordering cmpK tyEq = \cases diff --git a/unison-src/transcripts/runtime-tests.md b/unison-src/transcripts/runtime-tests.md index 624614c633..78c33fbc89 100644 --- a/unison-src/transcripts/runtime-tests.md +++ b/unison-src/transcripts/runtime-tests.md @@ -60,4 +60,12 @@ casting = (Nat.toInt 100, -- This helps to counter a different issue we have, where `load (save +10)` will load a `Nat` runtime type rather than -- an Int, since we don't actually store the type of numerics in the ANF.Value type. > Universal.compare (Any [1, 2]) (Any [+1, +2]) + +-- Regression test for a problem with universalCompare where Nats larger than maxInt would compare incorrectly, but only +-- when nested within other types due to how lists of constructor fields were compared. +> Universal.compare (1,()) (maxNat, ()) + +-- Types in tuples should compare one by one left-to-right +> Universal.compare (1, "", 2) (1, "", 3) +> Universal.compare (1, "", 3) (1, "", 2) ``` From 237947ec61078ee2318b571b2046eb6b973d3f3c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 5 Nov 2024 15:18:03 -0800 Subject: [PATCH 088/113] Rerun runtime tests transcript --- unison-src/transcripts/runtime-tests.md | 2 +- .../transcripts/runtime-tests.output.md | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/unison-src/transcripts/runtime-tests.md b/unison-src/transcripts/runtime-tests.md index 78c33fbc89..0691e7ce21 100644 --- a/unison-src/transcripts/runtime-tests.md +++ b/unison-src/transcripts/runtime-tests.md @@ -63,7 +63,7 @@ casting = (Nat.toInt 100, -- Regression test for a problem with universalCompare where Nats larger than maxInt would compare incorrectly, but only -- when nested within other types due to how lists of constructor fields were compared. -> Universal.compare (1,()) (maxNat, ()) +> Universal.compare (1,()) (18446744073709551615, ()) -- Types in tuples should compare one by one left-to-right > Universal.compare (1, "", 2) (1, "", 3) diff --git a/unison-src/transcripts/runtime-tests.output.md b/unison-src/transcripts/runtime-tests.output.md index d4be777480..4696419b79 100644 --- a/unison-src/transcripts/runtime-tests.output.md +++ b/unison-src/transcripts/runtime-tests.output.md @@ -55,6 +55,14 @@ casting = (Nat.toInt 100, -- This helps to counter a different issue we have, where `load (save +10)` will load a `Nat` runtime type rather than -- an Int, since we don't actually store the type of numerics in the ANF.Value type. > Universal.compare (Any [1, 2]) (Any [+1, +2]) + +-- Regression test for a problem with universalCompare where Nats larger than maxInt would compare incorrectly, but only +-- when nested within other types due to how lists of constructor fields were compared. +> Universal.compare (1,()) (18446744073709551615, ()) + +-- Types in tuples should compare one by one left-to-right +> Universal.compare (1, "", 2) (1, "", 3) +> Universal.compare (1, "", 3) (1, "", 2) ``` ``` ucm @@ -157,5 +165,17 @@ casting = (Nat.toInt 100, 54 | > Universal.compare (Any [1, 2]) (Any [+1, +2]) ⧩ +0 + + 58 | > Universal.compare (1,()) (18446744073709551615, ()) + ⧩ + -1 + + 61 | > Universal.compare (1, "", 2) (1, "", 3) + ⧩ + -1 + + 62 | > Universal.compare (1, "", 3) (1, "", 2) + ⧩ + +1 ``` From f1ba8359a1c2d52294aa937d839f256993f91c77 Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Wed, 6 Nov 2024 10:43:38 -0500 Subject: [PATCH 089/113] switch to console regions for merge progress output --- unison-cli/src/Unison/Cli/Monad.hs | 16 + .../Codebase/Editor/HandleInput/Merge2.hs | 491 +++++++++--------- .../src/Unison/CommandLine/OutputMessages.hs | 24 +- 3 files changed, 272 insertions(+), 259 deletions(-) diff --git a/unison-cli/src/Unison/Cli/Monad.hs b/unison-cli/src/Unison/Cli/Monad.hs index 7f9d97cde4..4656cc1d5d 100644 --- a/unison-cli/src/Unison/Cli/Monad.hs +++ b/unison-cli/src/Unison/Cli/Monad.hs @@ -39,6 +39,7 @@ module Unison.Cli.Monad -- * Communicating output to the user respond, respondNumbered, + withRespondRegion, setNumberedArgs, -- * Debug-timing actions @@ -70,6 +71,7 @@ import Data.Time.Clock.System (getSystemTime, systemToTAITime) import Data.Time.Clock.TAI (diffAbsoluteTime) import Data.Unique (Unique, newUnique) import System.CPUTime (getCPUTime) +import System.Console.Regions qualified as Console.Regions import Text.Printf (printf) import U.Codebase.Sqlite.DbId (ProjectBranchId, ProjectId) import U.Codebase.Sqlite.Queries qualified as Q @@ -83,10 +85,12 @@ import Unison.Codebase.Editor.UCMVersion (UCMVersion) import Unison.Codebase.Path qualified as Path import Unison.Codebase.ProjectPath qualified as PP import Unison.Codebase.Runtime (Runtime) +import Unison.CommandLine.OutputMessages qualified as OutputMessages import Unison.Core.Project (ProjectAndBranch (..)) import Unison.Debug qualified as Debug import Unison.Parser.Ann (Ann) import Unison.Prelude +import Unison.PrettyTerminal qualified as PrettyTerminal import Unison.Server.CodebaseServer qualified as Server import Unison.Sqlite qualified as Sqlite import Unison.Symbol (Symbol) @@ -94,6 +98,7 @@ import Unison.Syntax.Parser qualified as Parser import Unison.Term (Term) import Unison.Type (Type) import Unison.UnisonFile qualified as UF +import Unison.Util.Pretty qualified as Pretty import Unsafe.Coerce (unsafeCoerce) -- | The main command-line app monad. @@ -425,6 +430,17 @@ respondNumbered output = do args <- liftIO (notifyNumbered output) setNumberedArgs args +-- | Perform a Cli action with access to a console region, which is closed upon completion. +withRespondRegion :: ((Output -> Cli ()) -> Cli a) -> Cli a +withRespondRegion action = + with_ Console.Regions.displayConsoleRegions do + with (Console.Regions.withConsoleRegion Console.Regions.Linear) \region -> + action \output -> + liftIO do + string <- (OutputMessages.notifyUser "." output) + width <- PrettyTerminal.getAvailableWidth + Console.Regions.setConsoleRegion region (Pretty.toANSI width (Pretty.border 2 string)) + -- | Updates the numbered args, but only if the new args are non-empty. setNumberedArgs :: NumberedArgs -> Cli () setNumberedArgs args = do diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs index ccb1f4eca6..1dec15d091 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/Merge2.hs @@ -188,255 +188,256 @@ doMerge info = do _ <- Cli.updateAt info.description (PP.projectBranchRoot info.alice.projectAndBranch) (\_aliceBranch -> bobBranch) done (Output.MergeSuccessFastForward mergeSourceAndTarget) - Cli.respond (Output.MergeProgress Output.MergeProgress'LoadingBranches) - - -- Load Alice/Bob/LCA causals - causals <- - Cli.runTransaction do - traverse - Operations.expectCausalBranchByCausalHash - Merge.TwoOrThreeWay - { alice = info.alice.causalHash, - bob = info.bob.causalHash, - lca = info.lca.causalHash - } - - liftIO (debugFunctions.debugCausals causals) - - -- Load Alice/Bob/LCA branches - branches <- - Cli.runTransaction do - alice <- causals.alice.value - bob <- causals.bob.value - lca <- for causals.lca \causal -> causal.value - pure Merge.TwoOrThreeWay {lca, alice, bob} - - -- Assert that neither Alice nor Bob have defns in lib - for_ [(mergeTarget, branches.alice), (mergeSource, branches.bob)] \(who, branch) -> do - whenM (Cli.runTransaction (hasDefnsInLib branch)) do - done (Output.MergeDefnsInLib who) - - -- Load Alice/Bob/LCA definitions - -- - -- FIXME: Oops, if this fails due to a conflicted name, we don't actually say where the conflicted name came from. - -- We should have a better error message (even though you can't do anything about conflicted names in the LCA). - nametrees3 :: Merge.ThreeWay (Nametree (DefnsF (Map NameSegment) Referent TypeReference)) <- do - let referent2to1 = Conversions.referent2to1 (Codebase.getDeclType env.codebase) - let action :: - (forall a. Defn (Conflicted Name Referent) (Conflicted Name TypeReference) -> Transaction a) -> - Transaction (Merge.ThreeWay (Nametree (DefnsF (Map NameSegment) Referent TypeReference))) - action rollback = do - alice <- loadNamespaceDefinitions referent2to1 branches.alice & onLeftM rollback - bob <- loadNamespaceDefinitions referent2to1 branches.bob & onLeftM rollback - lca <- - case branches.lca of - Nothing -> pure Nametree {value = Defns Map.empty Map.empty, children = Map.empty} - Just lca -> loadNamespaceDefinitions referent2to1 lca & onLeftM rollback - pure Merge.ThreeWay {alice, bob, lca} - Cli.runTransactionWithRollback2 (\rollback -> Right <$> action (rollback . Left)) - & onLeftM (done . Output.ConflictedDefn "merge") - - libdeps3 <- Cli.runTransaction (loadLibdeps branches) - - let blob0 = Merge.makeMergeblob0 nametrees3 libdeps3 - - -- Hydrate - hydratedDefns :: - Merge.ThreeWay - ( DefnsF - (Map Name) - (TermReferenceId, (Term Symbol Ann, Type Symbol Ann)) - (TypeReferenceId, Decl Symbol Ann) - ) <- - Cli.runTransaction $ - traverse - ( hydrateDefns - (Codebase.unsafeGetTermComponent env.codebase) - Operations.expectDeclComponent - ) - ( let f = Map.mapMaybe Referent.toTermReferenceId . BiMultimap.range - g = Map.mapMaybe Reference.toId . BiMultimap.range - in bimap f g <$> blob0.defns - ) - - Cli.respond (Output.MergeProgress Output.MergeProgress'DiffingBranches) - - blob1 <- - Merge.makeMergeblob1 blob0 hydratedDefns & onLeft \case - Merge.Alice reason -> done (Output.IncoherentDeclDuringMerge mergeTarget reason) - Merge.Bob reason -> done (Output.IncoherentDeclDuringMerge mergeSource reason) - - liftIO (debugFunctions.debugDiffs blob1.diffs) - - liftIO (debugFunctions.debugCombinedDiff blob1.diff) - - blob2 <- - Merge.makeMergeblob2 blob1 & onLeft \err -> - done case err of - Merge.Mergeblob2Error'ConflictedAlias defn0 -> - case defn0 of - Merge.Alice defn -> Output.MergeConflictedAliases mergeTarget defn - Merge.Bob defn -> Output.MergeConflictedAliases mergeSource defn - Merge.Mergeblob2Error'ConflictedBuiltin defn -> Output.MergeConflictInvolvingBuiltin defn - - liftIO (debugFunctions.debugPartitionedDiff blob2.conflicts blob2.unconflicts) - - Cli.respond (Output.MergeProgress Output.MergeProgress'LoadingDependents) - - dependents0 <- - Cli.runTransaction $ - for ((,) <$> ThreeWay.forgetLca blob2.defns <*> blob2.coreDependencies) \(defns, deps) -> - getNamespaceDependentsOf3 defns deps - - Cli.respond (Output.MergeProgress Output.MergeProgress'LoadingAndMergingLibdeps) - - -- Load libdeps - (mergedLibdeps, lcaLibdeps) <- do - -- We make a fresh branch cache to load the branch of libdeps. - -- It would probably be better to reuse the codebase's branch cache. - -- FIXME how slow/bad is this without that branch cache? - Cli.runTransaction do - branchCache <- Sqlite.unsafeIO newBranchCache - let load children = - Conversions.branch2to1 - branchCache - (Codebase.getDeclType env.codebase) - V2.Branch {terms = Map.empty, types = Map.empty, patches = Map.empty, children} - mergedLibdeps <- load blob2.libdeps - lcaLibdeps <- load blob2.lcaLibdeps - pure (mergedLibdeps, lcaLibdeps) - - let hasConflicts = - blob2.hasConflicts - - Cli.respond (Output.MergeProgress Output.MergeProgress'RenderingUnisonFile) - - let blob3 = - Merge.makeMergeblob3 - blob2 - dependents0 - (Branch.toNames mergedLibdeps) - (Branch.toNames lcaLibdeps) - Merge.TwoWay - { alice = into @Text aliceBranchNames, - bob = - case info.bob.source of - MergeSource'LocalProjectBranch bobBranchNames -> into @Text bobBranchNames - MergeSource'RemoteProjectBranch bobBranchNames - | aliceBranchNames == bobBranchNames -> "remote " <> into @Text bobBranchNames - | otherwise -> into @Text bobBranchNames - MergeSource'RemoteLooseCode info -> - case Path.toName info.path of - Nothing -> "" - Just name -> Name.toText name + Cli.withRespondRegion \respondRegion -> do + respondRegion (Output.MergeProgress Output.MergeProgress'LoadingBranches) + + -- Load Alice/Bob/LCA causals + causals <- + Cli.runTransaction do + traverse + Operations.expectCausalBranchByCausalHash + Merge.TwoOrThreeWay + { alice = info.alice.causalHash, + bob = info.bob.causalHash, + lca = info.lca.causalHash } - maybeBlob5 <- - if hasConflicts - then pure Nothing - else case Merge.makeMergeblob4 blob3 of - Left _parseErr -> pure Nothing - Right blob4 -> do - Cli.respond (Output.MergeProgress Output.MergeProgress'TypecheckingUnisonFile) - typeLookup <- Cli.runTransaction (Codebase.typeLookupForDependencies env.codebase blob4.dependencies) - pure case Merge.makeMergeblob5 blob4 typeLookup of - Left _typecheckErr -> Nothing - Right blob5 -> Just blob5 - - let parents = - causals <&> \causal -> (causal.causalHash, Codebase.expectBranchForHash env.codebase causal.causalHash) - - blob5 <- - maybeBlob5 & onNothing do - env <- ask - (_temporaryBranchId, temporaryBranchName) <- - HandleInput.Branch.createBranch - info.description - ( HandleInput.Branch.CreateFrom'NamespaceWithParent - info.alice.projectAndBranch.branch - ( Branch.mergeNode - (defnsAndLibdepsToBranch0 env.codebase blob3.stageTwo mergedLibdeps) - parents.alice - parents.bob - ) + liftIO (debugFunctions.debugCausals causals) + + -- Load Alice/Bob/LCA branches + branches <- + Cli.runTransaction do + alice <- causals.alice.value + bob <- causals.bob.value + lca <- for causals.lca \causal -> causal.value + pure Merge.TwoOrThreeWay {lca, alice, bob} + + -- Assert that neither Alice nor Bob have defns in lib + for_ [(mergeTarget, branches.alice), (mergeSource, branches.bob)] \(who, branch) -> do + whenM (Cli.runTransaction (hasDefnsInLib branch)) do + done (Output.MergeDefnsInLib who) + + -- Load Alice/Bob/LCA definitions + -- + -- FIXME: Oops, if this fails due to a conflicted name, we don't actually say where the conflicted name came from. + -- We should have a better error message (even though you can't do anything about conflicted names in the LCA). + nametrees3 :: Merge.ThreeWay (Nametree (DefnsF (Map NameSegment) Referent TypeReference)) <- do + let referent2to1 = Conversions.referent2to1 (Codebase.getDeclType env.codebase) + let action :: + (forall a. Defn (Conflicted Name Referent) (Conflicted Name TypeReference) -> Transaction a) -> + Transaction (Merge.ThreeWay (Nametree (DefnsF (Map NameSegment) Referent TypeReference))) + action rollback = do + alice <- loadNamespaceDefinitions referent2to1 branches.alice & onLeftM rollback + bob <- loadNamespaceDefinitions referent2to1 branches.bob & onLeftM rollback + lca <- + case branches.lca of + Nothing -> pure Nametree {value = Defns Map.empty Map.empty, children = Map.empty} + Just lca -> loadNamespaceDefinitions referent2to1 lca & onLeftM rollback + pure Merge.ThreeWay {alice, bob, lca} + Cli.runTransactionWithRollback2 (\rollback -> Right <$> action (rollback . Left)) + & onLeftM (done . Output.ConflictedDefn "merge") + + libdeps3 <- Cli.runTransaction (loadLibdeps branches) + + let blob0 = Merge.makeMergeblob0 nametrees3 libdeps3 + + -- Hydrate + hydratedDefns :: + Merge.ThreeWay + ( DefnsF + (Map Name) + (TermReferenceId, (Term Symbol Ann, Type Symbol Ann)) + (TypeReferenceId, Decl Symbol Ann) + ) <- + Cli.runTransaction $ + traverse + ( hydrateDefns + (Codebase.unsafeGetTermComponent env.codebase) + Operations.expectDeclComponent ) - info.alice.projectAndBranch.project - (findTemporaryBranchName info.alice.projectAndBranch.project.projectId mergeSourceAndTarget) - - -- Merge conflicts? Have UCM_MERGETOOL? Result - -- ---------------- ------------------- ------------------------------------------------------------ - -- No No Put code that doesn't parse or typecheck in scratch.u - -- No Yes Put code that doesn't parse or typecheck in scratch.u - -- Yes No Put code that doesn't parse (because conflicts) in scratch.u - -- Yes Yes Run that cool tool - - maybeMergetool <- - if hasConflicts - then liftIO (lookupEnv "UCM_MERGETOOL") - else pure Nothing - - case maybeMergetool of - Nothing -> do - scratchFilePath <- - Cli.getLatestFile <&> \case - Nothing -> "scratch.u" - Just (file, _) -> file - liftIO $ env.writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 blob3.unparsedFile) True - done (Output.MergeFailure scratchFilePath mergeSourceAndTarget temporaryBranchName) - Just mergetool0 -> do - let aliceFilenameSlug = mangleBranchName mergeSourceAndTarget.alice.branch - let bobFilenameSlug = mangleMergeSource mergeSourceAndTarget.bob - makeTempFilename <- - liftIO do - tmpdir0 <- getTemporaryDirectory - tmpdir1 <- canonicalizePath tmpdir0 - tmpdir2 <- Temporary.createTempDirectory tmpdir1 "unison-merge" - pure \filename -> Text.pack (tmpdir2 Text.unpack (Text.Builder.run filename)) - let lcaFilename = makeTempFilename (aliceFilenameSlug <> "-" <> bobFilenameSlug <> "-base.u") - let aliceFilename = makeTempFilename (aliceFilenameSlug <> ".u") - let bobFilename = makeTempFilename (bobFilenameSlug <> ".u") - let mergedFilename = Text.Builder.run (aliceFilenameSlug <> "-" <> bobFilenameSlug <> "-merged.u") - let mergetool = - mergetool0 - & Text.pack - & Text.replace "$BASE" lcaFilename - & Text.replace "$LOCAL" aliceFilename - & Text.replace "$MERGED" mergedFilename - & Text.replace "$REMOTE" bobFilename - exitCode <- - liftIO do - let aliceFileContents = Text.pack (Pretty.toPlain 80 blob3.unparsedSoloFiles.alice) - let bobFileContents = Text.pack (Pretty.toPlain 80 blob3.unparsedSoloFiles.bob) - removeFile (Text.unpack mergedFilename) <|> pure () - env.writeSource lcaFilename (Text.pack (Pretty.toPlain 80 blob3.unparsedSoloFiles.lca)) True - env.writeSource aliceFilename aliceFileContents True - env.writeSource bobFilename bobFileContents True - env.writeSource - mergedFilename - ( makeMergedFileContents - mergeSourceAndTarget - aliceFileContents - bobFileContents - ) - True - let createProcess = (Process.shell (Text.unpack mergetool)) {Process.delegate_ctlc = True} - Process.withCreateProcess createProcess \_ _ _ -> Process.waitForProcess - done (Output.MergeFailureWithMergetool mergeSourceAndTarget temporaryBranchName mergetool exitCode) - - Cli.runTransaction (Codebase.addDefsToCodebase env.codebase blob5.file) - Cli.updateProjectBranchRoot_ - info.alice.projectAndBranch.branch - info.description - ( \_aliceBranch -> - Branch.mergeNode - ( Branch.batchUpdates - (typecheckedUnisonFileToBranchAdds blob5.file) - (defnsAndLibdepsToBranch0 env.codebase blob3.stageOne mergedLibdeps) + ( let f = Map.mapMaybe Referent.toTermReferenceId . BiMultimap.range + g = Map.mapMaybe Reference.toId . BiMultimap.range + in bimap f g <$> blob0.defns ) - parents.alice - parents.bob - ) - pure (Output.MergeSuccess mergeSourceAndTarget) + + respondRegion (Output.MergeProgress Output.MergeProgress'DiffingBranches) + + blob1 <- + Merge.makeMergeblob1 blob0 hydratedDefns & onLeft \case + Merge.Alice reason -> done (Output.IncoherentDeclDuringMerge mergeTarget reason) + Merge.Bob reason -> done (Output.IncoherentDeclDuringMerge mergeSource reason) + + liftIO (debugFunctions.debugDiffs blob1.diffs) + + liftIO (debugFunctions.debugCombinedDiff blob1.diff) + + blob2 <- + Merge.makeMergeblob2 blob1 & onLeft \err -> + done case err of + Merge.Mergeblob2Error'ConflictedAlias defn0 -> + case defn0 of + Merge.Alice defn -> Output.MergeConflictedAliases mergeTarget defn + Merge.Bob defn -> Output.MergeConflictedAliases mergeSource defn + Merge.Mergeblob2Error'ConflictedBuiltin defn -> Output.MergeConflictInvolvingBuiltin defn + + liftIO (debugFunctions.debugPartitionedDiff blob2.conflicts blob2.unconflicts) + + respondRegion (Output.MergeProgress Output.MergeProgress'LoadingDependents) + + dependents0 <- + Cli.runTransaction $ + for ((,) <$> ThreeWay.forgetLca blob2.defns <*> blob2.coreDependencies) \(defns, deps) -> + getNamespaceDependentsOf3 defns deps + + respondRegion (Output.MergeProgress Output.MergeProgress'LoadingAndMergingLibdeps) + + -- Load libdeps + (mergedLibdeps, lcaLibdeps) <- do + -- We make a fresh branch cache to load the branch of libdeps. + -- It would probably be better to reuse the codebase's branch cache. + -- FIXME how slow/bad is this without that branch cache? + Cli.runTransaction do + branchCache <- Sqlite.unsafeIO newBranchCache + let load children = + Conversions.branch2to1 + branchCache + (Codebase.getDeclType env.codebase) + V2.Branch {terms = Map.empty, types = Map.empty, patches = Map.empty, children} + mergedLibdeps <- load blob2.libdeps + lcaLibdeps <- load blob2.lcaLibdeps + pure (mergedLibdeps, lcaLibdeps) + + let hasConflicts = + blob2.hasConflicts + + respondRegion (Output.MergeProgress Output.MergeProgress'RenderingUnisonFile) + + let blob3 = + Merge.makeMergeblob3 + blob2 + dependents0 + (Branch.toNames mergedLibdeps) + (Branch.toNames lcaLibdeps) + Merge.TwoWay + { alice = into @Text aliceBranchNames, + bob = + case info.bob.source of + MergeSource'LocalProjectBranch bobBranchNames -> into @Text bobBranchNames + MergeSource'RemoteProjectBranch bobBranchNames + | aliceBranchNames == bobBranchNames -> "remote " <> into @Text bobBranchNames + | otherwise -> into @Text bobBranchNames + MergeSource'RemoteLooseCode info -> + case Path.toName info.path of + Nothing -> "" + Just name -> Name.toText name + } + + maybeBlob5 <- + if hasConflicts + then pure Nothing + else case Merge.makeMergeblob4 blob3 of + Left _parseErr -> pure Nothing + Right blob4 -> do + respondRegion (Output.MergeProgress Output.MergeProgress'TypecheckingUnisonFile) + typeLookup <- Cli.runTransaction (Codebase.typeLookupForDependencies env.codebase blob4.dependencies) + pure case Merge.makeMergeblob5 blob4 typeLookup of + Left _typecheckErr -> Nothing + Right blob5 -> Just blob5 + + let parents = + causals <&> \causal -> (causal.causalHash, Codebase.expectBranchForHash env.codebase causal.causalHash) + + blob5 <- + maybeBlob5 & onNothing do + env <- ask + (_temporaryBranchId, temporaryBranchName) <- + HandleInput.Branch.createBranch + info.description + ( HandleInput.Branch.CreateFrom'NamespaceWithParent + info.alice.projectAndBranch.branch + ( Branch.mergeNode + (defnsAndLibdepsToBranch0 env.codebase blob3.stageTwo mergedLibdeps) + parents.alice + parents.bob + ) + ) + info.alice.projectAndBranch.project + (findTemporaryBranchName info.alice.projectAndBranch.project.projectId mergeSourceAndTarget) + + -- Merge conflicts? Have UCM_MERGETOOL? Result + -- ---------------- ------------------- ------------------------------------------------------------ + -- No No Put code that doesn't parse or typecheck in scratch.u + -- No Yes Put code that doesn't parse or typecheck in scratch.u + -- Yes No Put code that doesn't parse (because conflicts) in scratch.u + -- Yes Yes Run that cool tool + + maybeMergetool <- + if hasConflicts + then liftIO (lookupEnv "UCM_MERGETOOL") + else pure Nothing + + case maybeMergetool of + Nothing -> do + scratchFilePath <- + Cli.getLatestFile <&> \case + Nothing -> "scratch.u" + Just (file, _) -> file + liftIO $ env.writeSource (Text.pack scratchFilePath) (Text.pack $ Pretty.toPlain 80 blob3.unparsedFile) True + done (Output.MergeFailure scratchFilePath mergeSourceAndTarget temporaryBranchName) + Just mergetool0 -> do + let aliceFilenameSlug = mangleBranchName mergeSourceAndTarget.alice.branch + let bobFilenameSlug = mangleMergeSource mergeSourceAndTarget.bob + makeTempFilename <- + liftIO do + tmpdir0 <- getTemporaryDirectory + tmpdir1 <- canonicalizePath tmpdir0 + tmpdir2 <- Temporary.createTempDirectory tmpdir1 "unison-merge" + pure \filename -> Text.pack (tmpdir2 Text.unpack (Text.Builder.run filename)) + let lcaFilename = makeTempFilename (aliceFilenameSlug <> "-" <> bobFilenameSlug <> "-base.u") + let aliceFilename = makeTempFilename (aliceFilenameSlug <> ".u") + let bobFilename = makeTempFilename (bobFilenameSlug <> ".u") + let mergedFilename = Text.Builder.run (aliceFilenameSlug <> "-" <> bobFilenameSlug <> "-merged.u") + let mergetool = + mergetool0 + & Text.pack + & Text.replace "$BASE" lcaFilename + & Text.replace "$LOCAL" aliceFilename + & Text.replace "$MERGED" mergedFilename + & Text.replace "$REMOTE" bobFilename + exitCode <- + liftIO do + let aliceFileContents = Text.pack (Pretty.toPlain 80 blob3.unparsedSoloFiles.alice) + let bobFileContents = Text.pack (Pretty.toPlain 80 blob3.unparsedSoloFiles.bob) + removeFile (Text.unpack mergedFilename) <|> pure () + env.writeSource lcaFilename (Text.pack (Pretty.toPlain 80 blob3.unparsedSoloFiles.lca)) True + env.writeSource aliceFilename aliceFileContents True + env.writeSource bobFilename bobFileContents True + env.writeSource + mergedFilename + ( makeMergedFileContents + mergeSourceAndTarget + aliceFileContents + bobFileContents + ) + True + let createProcess = (Process.shell (Text.unpack mergetool)) {Process.delegate_ctlc = True} + Process.withCreateProcess createProcess \_ _ _ -> Process.waitForProcess + done (Output.MergeFailureWithMergetool mergeSourceAndTarget temporaryBranchName mergetool exitCode) + + Cli.runTransaction (Codebase.addDefsToCodebase env.codebase blob5.file) + Cli.updateProjectBranchRoot_ + info.alice.projectAndBranch.branch + info.description + ( \_aliceBranch -> + Branch.mergeNode + ( Branch.batchUpdates + (typecheckedUnisonFileToBranchAdds blob5.file) + (defnsAndLibdepsToBranch0 env.codebase blob3.stageOne mergedLibdeps) + ) + parents.alice + parents.bob + ) + pure (Output.MergeSuccess mergeSourceAndTarget) Cli.respond finalOutput diff --git a/unison-cli/src/Unison/CommandLine/OutputMessages.hs b/unison-cli/src/Unison/CommandLine/OutputMessages.hs index 2083bf2f4d..147b3f32f4 100644 --- a/unison-cli/src/Unison/CommandLine/OutputMessages.hs +++ b/unison-cli/src/Unison/CommandLine/OutputMessages.hs @@ -99,10 +99,7 @@ import Unison.Prelude import Unison.PrettyPrintEnv qualified as PPE import Unison.PrettyPrintEnv.Util qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED -import Unison.PrettyTerminal - ( clearCurrentLine, - putPretty', - ) +import Unison.PrettyTerminal (clearCurrentLine, putPretty') import Unison.PrintError ( prettyParseError, prettyResolutionFailures, @@ -120,8 +117,7 @@ import Unison.Result qualified as Result import Unison.Server.Backend (ShallowListEntry (..), TypeEntry (..)) import Unison.Server.Backend qualified as Backend import Unison.Server.SearchResultPrime qualified as SR' -import Unison.Share.Sync qualified as Share -import Unison.Share.Sync.Types (CodeserverTransportError (..)) +import Unison.Share.Sync.Types qualified as Share (CodeserverTransportError (..), GetCausalHashByPathError (..), PullError (..)) import Unison.Sync.Types qualified as Share import Unison.Syntax.DeclPrinter qualified as DeclPrinter import Unison.Syntax.HashQualified qualified as HQ (toText, unsafeFromVar) @@ -2353,28 +2349,28 @@ prettyEntityValidationFailure = \case Share.NamespaceDiffType -> "namespace diff" Share.CausalType -> "causal" -prettyTransportError :: CodeserverTransportError -> Pretty +prettyTransportError :: Share.CodeserverTransportError -> Pretty prettyTransportError = \case - DecodeFailure msg resp -> + Share.DecodeFailure msg resp -> (P.lines . catMaybes) [ Just ("The server sent a response that we couldn't decode: " <> P.text msg), responseRequestId resp <&> \responseId -> P.newline <> "Request ID: " <> P.blue (P.text responseId) ] - Unauthenticated codeServerURL -> + Share.Unauthenticated codeServerURL -> P.wrap . P.lines $ [ "Authentication with this code server (" <> P.string (Servant.showBaseUrl codeServerURL) <> ") is missing or expired.", "Please run " <> makeExample' IP.authLogin <> "." ] - PermissionDenied msg -> P.hang "Permission denied:" (P.text msg) - UnreachableCodeserver codeServerURL -> + Share.PermissionDenied msg -> P.hang "Permission denied:" (P.text msg) + Share.UnreachableCodeserver codeServerURL -> P.lines $ [ P.wrap $ "Unable to reach the code server hosted at:" <> P.string (Servant.showBaseUrl codeServerURL), "", P.wrap "Please check your network, ensure you've provided the correct location, or try again later." ] - RateLimitExceeded -> "Rate limit exceeded, please try again later." - Timeout -> "The code server timed-out when responding to your request. Please try again later or report an issue if the problem persists." - UnexpectedResponse resp -> + Share.RateLimitExceeded -> "Rate limit exceeded, please try again later." + Share.Timeout -> "The code server timed-out when responding to your request. Please try again later or report an issue if the problem persists." + Share.UnexpectedResponse resp -> (P.lines . catMaybes) [ Just ( "The server sent a " From 2c11caaba68952b8577b2eb34d39b1c3b63d001f Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Wed, 6 Nov 2024 12:54:24 -0500 Subject: [PATCH 090/113] move delete.namespace implementation into its own module --- .../src/Unison/Codebase/Editor/HandleInput.hs | 89 +----------- .../Editor/HandleInput/DeleteNamespace.hs | 132 ++++++++++++++++++ unison-cli/unison-cli.cabal | 1 + 3 files changed, 135 insertions(+), 87 deletions(-) create mode 100644 unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs index bc2b81cbd3..472329298e 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs @@ -17,7 +17,6 @@ import Data.List.Extra (nubOrd) import Data.List.NonEmpty qualified as Nel import Data.Map qualified as Map import Data.Set qualified as Set -import Data.Set.NonEmpty (NESet) import Data.Set.NonEmpty qualified as NESet import Data.Text qualified as Text import Data.Time (UTCTime) @@ -150,7 +149,6 @@ import Unison.Server.SearchResult (SearchResult) import Unison.Server.SearchResult qualified as SR import Unison.Share.Codeserver qualified as Codeserver import Unison.ShortHash qualified as SH -import Unison.Sqlite qualified as Sqlite import Unison.Symbol (Symbol) import Unison.Syntax.HashQualified qualified as HQ (parseTextWith, toText) import Unison.Syntax.Lexer.Unison qualified as L @@ -178,6 +176,7 @@ import Unison.Var (Var) import Unison.Var qualified as Var import Unison.WatchKind qualified as WK import UnliftIO.Directory qualified as Directory +import Unison.Codebase.Editor.HandleInput.DeleteNamespace (handleDeleteNamespace, getEndangeredDependents) ------------------------------------------------------------------------------------------------------------------------ -- Main loop @@ -573,43 +572,7 @@ loop e = do delete input doutput getTerms getTypes hqs DeleteTarget'Type doutput hqs -> delete input doutput (const (pure Set.empty)) getTypes hqs DeleteTarget'Term doutput hqs -> delete input doutput getTerms (const (pure Set.empty)) hqs - DeleteTarget'Namespace insistence Nothing -> do - hasConfirmed <- confirmedCommand input - if hasConfirmed || insistence == Force - then do - description <- inputDescription input - pp <- Cli.getCurrentProjectPath - _ <- Cli.updateAt description pp (const Branch.empty) - Cli.respond DeletedEverything - else Cli.respond DeleteEverythingConfirmation - DeleteTarget'Namespace insistence (Just p@(parentPath, childName)) -> do - branch <- Cli.expectBranchAtPath (Path.unsplit p) - description <- inputDescription input - let toDelete = - Names.prefix0 - (Path.nameFromSplit' $ first (Path.RelativePath' . Path.Relative) p) - (Branch.toNames (Branch.head branch)) - afterDelete <- do - names <- Cli.currentNames - endangerments <- Cli.runTransaction (getEndangeredDependents toDelete Set.empty names) - case (null endangerments, insistence) of - (True, _) -> pure (Cli.respond Success) - (False, Force) -> do - let ppeDecl = PPED.makePPED (PPE.hqNamer 10 names) (PPE.suffixifyByHash names) - pure do - Cli.respond Success - Cli.respondNumbered $ DeletedDespiteDependents ppeDecl endangerments - (False, Try) -> do - let ppeDecl = PPED.makePPED (PPE.hqNamer 10 names) (PPE.suffixifyByHash names) - Cli.respondNumbered $ CantDeleteNamespace ppeDecl endangerments - Cli.returnEarlyWithoutOutput - parentPathAbs <- Cli.resolvePath parentPath - -- We have to modify the parent in order to also wipe out the history at the - -- child. - Cli.updateAt description parentPathAbs \parentBranch -> - parentBranch - & Branch.modifyAt (Path.singleton childName) \_ -> Branch.empty - afterDelete + DeleteTarget'Namespace insistence path -> handleDeleteNamespace input inputDescription insistence path DeleteTarget'ProjectBranch name -> handleDeleteBranch name DeleteTarget'Project name -> handleDeleteProject name DisplayI outputLoc namesToDisplay -> do @@ -1523,54 +1486,6 @@ checkDeletes typesTermsTuples doutput inputs = do let combineRefs = List.foldl (Map.unionWith NESet.union) Map.empty endangeredDeletions Cli.respondNumbered (CantDeleteDefinitions ppeDecl combineRefs) --- | Goal: When deleting, we might be removing the last name of a given definition (i.e. the --- definition is going "extinct"). In this case we may wish to take some action or warn the --- user about these "endangered" definitions which would now contain unnamed references. --- The argument `otherDesiredDeletions` is included in this function because the user might want to --- delete a term and all its dependencies in one command, so we give this function access to --- the full set of entities that the user wishes to delete. -getEndangeredDependents :: - -- | Prospective target for deletion - Names -> - -- | All entities we want to delete (including the target) - Set LabeledDependency -> - -- | Names from the current branch - Names -> - -- | map from references going extinct to the set of endangered dependents - Sqlite.Transaction (Map LabeledDependency (NESet LabeledDependency)) -getEndangeredDependents targetToDelete otherDesiredDeletions rootNames = do - -- names of terms left over after target deletion - let remainingNames :: Names - remainingNames = rootNames `Names.difference` targetToDelete - -- target refs for deletion - let refsToDelete :: Set LabeledDependency - refsToDelete = Names.labeledReferences targetToDelete - -- refs left over after deleting target - let remainingRefs :: Set LabeledDependency - remainingRefs = Names.labeledReferences remainingNames - -- remove the other targets for deletion from the remaining terms - let remainingRefsWithoutOtherTargets :: Set LabeledDependency - remainingRefsWithoutOtherTargets = Set.difference remainingRefs otherDesiredDeletions - -- deleting and not left over - let extinct :: Set LabeledDependency - extinct = refsToDelete `Set.difference` remainingRefs - let accumulateDependents :: LabeledDependency -> Sqlite.Transaction (Map LabeledDependency (Set LabeledDependency)) - accumulateDependents ld = - let ref = LD.fold id Referent.toReference ld - in Map.singleton ld . Set.map LD.termRef <$> Codebase.dependents Queries.ExcludeOwnComponent ref - -- All dependents of extinct, including terms which might themselves be in the process of being deleted. - allDependentsOfExtinct :: Map LabeledDependency (Set LabeledDependency) <- - Map.unionsWith (<>) <$> for (Set.toList extinct) accumulateDependents - - -- Filtered to only include dependencies which are not being deleted, but depend one which - -- is going extinct. - let extinctToEndangered :: Map LabeledDependency (NESet LabeledDependency) - extinctToEndangered = - allDependentsOfExtinct & Map.mapMaybe \endangeredDeps -> - let remainingEndangered = endangeredDeps `Set.intersection` remainingRefsWithoutOtherTargets - in NESet.nonEmptySet remainingEndangered - pure extinctToEndangered - displayI :: OutputLocation -> HQ.HashQualified Name -> diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs new file mode 100644 index 0000000000..9bb920685e --- /dev/null +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs @@ -0,0 +1,132 @@ +module Unison.Codebase.Editor.HandleInput.DeleteNamespace + ( handleDeleteNamespace, + getEndangeredDependents, + ) +where + +import Control.Lens hiding (from) +import Control.Monad.State qualified as State +import Data.Map qualified as Map +import Data.Set qualified as Set +import Data.Set.NonEmpty (NESet) +import Data.Set.NonEmpty qualified as NESet +import U.Codebase.Sqlite.Queries qualified as Queries +import Unison.Cli.Monad (Cli) +import Unison.Cli.Monad qualified as Cli +import Unison.Cli.MonadUtils qualified as Cli +import Unison.Cli.NamesUtils qualified as Cli +import Unison.Codebase qualified as Codebase +import Unison.Codebase.Branch qualified as Branch +import Unison.Codebase.Branch.Names qualified as Branch +import Unison.Codebase.Editor.Input +import Unison.Codebase.Editor.Output +import Unison.Codebase.Path (Path) +import Unison.Codebase.Path qualified as Path +import Unison.LabeledDependency (LabeledDependency) +import Unison.LabeledDependency qualified as LD +import Unison.NameSegment qualified as NameSegment +import Unison.Names (Names) +import Unison.Names qualified as Names +import Unison.Prelude +import Unison.PrettyPrintEnv.Names qualified as PPE +import Unison.PrettyPrintEnvDecl.Names qualified as PPED +import Unison.Referent qualified as Referent +import Unison.Sqlite qualified as Sqlite + +handleDeleteNamespace :: + Input -> + (Input -> Cli Text) -> + Insistence -> + Maybe (Path, NameSegment.NameSegment) -> + Cli () +handleDeleteNamespace input inputDescription insistence = \case + Nothing -> do + hasConfirmed <- confirmedCommand input + if hasConfirmed || insistence == Force + then do + description <- inputDescription input + pp <- Cli.getCurrentProjectPath + _ <- Cli.updateAt description pp (const Branch.empty) + Cli.respond DeletedEverything + else Cli.respond DeleteEverythingConfirmation + Just p@(parentPath, childName) -> do + branch <- Cli.expectBranchAtPath (Path.unsplit p) + description <- inputDescription input + let toDelete = + Names.prefix0 + (Path.nameFromSplit' $ first (Path.RelativePath' . Path.Relative) p) + (Branch.toNames (Branch.head branch)) + afterDelete <- do + names <- Cli.currentNames + endangerments <- Cli.runTransaction (getEndangeredDependents toDelete Set.empty names) + case (null endangerments, insistence) of + (True, _) -> pure (Cli.respond Success) + (False, Force) -> do + let ppeDecl = PPED.makePPED (PPE.hqNamer 10 names) (PPE.suffixifyByHash names) + pure do + Cli.respond Success + Cli.respondNumbered $ DeletedDespiteDependents ppeDecl endangerments + (False, Try) -> do + let ppeDecl = PPED.makePPED (PPE.hqNamer 10 names) (PPE.suffixifyByHash names) + Cli.respondNumbered $ CantDeleteNamespace ppeDecl endangerments + Cli.returnEarlyWithoutOutput + parentPathAbs <- Cli.resolvePath parentPath + -- We have to modify the parent in order to also wipe out the history at the + -- child. + Cli.updateAt description parentPathAbs \parentBranch -> + parentBranch + & Branch.modifyAt (Path.singleton childName) \_ -> Branch.empty + afterDelete + +confirmedCommand :: Input -> Cli Bool +confirmedCommand i = do + loopState <- State.get + pure $ Just i == (loopState ^. #lastInput) + +-- | Goal: When deleting, we might be removing the last name of a given definition (i.e. the +-- definition is going "extinct"). In this case we may wish to take some action or warn the +-- user about these "endangered" definitions which would now contain unnamed references. +-- The argument `otherDesiredDeletions` is included in this function because the user might want to +-- delete a term and all its dependencies in one command, so we give this function access to +-- the full set of entities that the user wishes to delete. +getEndangeredDependents :: + -- | Prospective target for deletion + Names -> + -- | All entities we want to delete (including the target) + Set LabeledDependency -> + -- | Names from the current branch + Names -> + -- | map from references going extinct to the set of endangered dependents + Sqlite.Transaction (Map LabeledDependency (NESet LabeledDependency)) +getEndangeredDependents targetToDelete otherDesiredDeletions rootNames = do + -- names of terms left over after target deletion + let remainingNames :: Names + remainingNames = rootNames `Names.difference` targetToDelete + -- target refs for deletion + let refsToDelete :: Set LabeledDependency + refsToDelete = Names.labeledReferences targetToDelete + -- refs left over after deleting target + let remainingRefs :: Set LabeledDependency + remainingRefs = Names.labeledReferences remainingNames + -- remove the other targets for deletion from the remaining terms + let remainingRefsWithoutOtherTargets :: Set LabeledDependency + remainingRefsWithoutOtherTargets = Set.difference remainingRefs otherDesiredDeletions + -- deleting and not left over + let extinct :: Set LabeledDependency + extinct = refsToDelete `Set.difference` remainingRefs + let accumulateDependents :: LabeledDependency -> Sqlite.Transaction (Map LabeledDependency (Set LabeledDependency)) + accumulateDependents ld = + let ref = LD.fold id Referent.toReference ld + in Map.singleton ld . Set.map LD.termRef <$> Codebase.dependents Queries.ExcludeOwnComponent ref + -- All dependents of extinct, including terms which might themselves be in the process of being deleted. + allDependentsOfExtinct :: Map LabeledDependency (Set LabeledDependency) <- + Map.unionsWith (<>) <$> for (Set.toList extinct) accumulateDependents + + -- Filtered to only include dependencies which are not being deleted, but depend one which + -- is going extinct. + let extinctToEndangered :: Map LabeledDependency (NESet LabeledDependency) + extinctToEndangered = + allDependentsOfExtinct & Map.mapMaybe \endangeredDeps -> + let remainingEndangered = endangeredDeps `Set.intersection` remainingRefsWithoutOtherTargets + in NESet.nonEmptySet remainingEndangered + pure extinctToEndangered diff --git a/unison-cli/unison-cli.cabal b/unison-cli/unison-cli.cabal index 82c1c89373..896dc8c3c1 100644 --- a/unison-cli/unison-cli.cabal +++ b/unison-cli/unison-cli.cabal @@ -60,6 +60,7 @@ library Unison.Codebase.Editor.HandleInput.DebugFoldRanges Unison.Codebase.Editor.HandleInput.DebugSynhashTerm Unison.Codebase.Editor.HandleInput.DeleteBranch + Unison.Codebase.Editor.HandleInput.DeleteNamespace Unison.Codebase.Editor.HandleInput.DeleteProject Unison.Codebase.Editor.HandleInput.EditNamespace Unison.Codebase.Editor.HandleInput.FindAndReplace From 1355300954bd93f10b1502b2a2d2f564c3cc2b02 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 6 Nov 2024 12:28:16 -0800 Subject: [PATCH 091/113] Remove unnecessary allocations of unboxed type tags --- unison-runtime/src/Unison/Runtime/Stack.hs | 36 +++++++++++++--------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 671d3a108e..f05d457606 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -278,7 +278,13 @@ pattern Foreign x = Closure (GForeign x) pattern BlackHole = Closure GBlackHole -pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) +pattern UnboxedTypeTag t <- Closure (GUnboxedTypeTag t) + where + UnboxedTypeTag t = case t of + CharTag -> charTypeTag + FloatTag -> floatTypeTag + IntTag -> intTypeTag + NatTag -> natTypeTag {-# COMPLETE PAp, Enum, Data1, Data2, DataG, Captured, Foreign, UnboxedTypeTag, BlackHole #-} @@ -290,19 +296,19 @@ pattern UnboxedTypeTag t = Closure (GUnboxedTypeTag t) -- We can avoid allocating a closure for common type tags on each poke by having shared top-level closures for them. natTypeTag :: Closure -natTypeTag = UnboxedTypeTag NatTag +natTypeTag = (Closure (GUnboxedTypeTag NatTag)) {-# NOINLINE natTypeTag #-} intTypeTag :: Closure -intTypeTag = UnboxedTypeTag IntTag +intTypeTag = (Closure (GUnboxedTypeTag IntTag)) {-# NOINLINE intTypeTag #-} charTypeTag :: Closure -charTypeTag = UnboxedTypeTag CharTag +charTypeTag = (Closure (GUnboxedTypeTag CharTag)) {-# NOINLINE charTypeTag #-} floatTypeTag :: Closure -floatTypeTag = UnboxedTypeTag FloatTag +floatTypeTag = (Closure (GUnboxedTypeTag FloatTag)) {-# NOINLINE floatTypeTag #-} traceK :: Reference -> K -> [(Reference, Int)] @@ -368,7 +374,7 @@ matchCharVal = \case pattern CharVal :: Char -> Val pattern CharVal c <- (matchCharVal -> Just c) where - CharVal c = UnboxedVal (Char.ord c) CharTag + CharVal c = Val (Char.ord c) charTypeTag matchNatVal :: Val -> Maybe Word64 matchNatVal = \case @@ -378,7 +384,7 @@ matchNatVal = \case pattern NatVal :: Word64 -> Val pattern NatVal n <- (matchNatVal -> Just n) where - NatVal n = UnboxedVal (fromIntegral n) NatTag + NatVal n = Val (fromIntegral n) natTypeTag matchDoubleVal :: Val -> Maybe Double matchDoubleVal = \case @@ -388,7 +394,7 @@ matchDoubleVal = \case pattern DoubleVal :: Double -> Val pattern DoubleVal d <- (matchDoubleVal -> Just d) where - DoubleVal d = UnboxedVal (doubleToInt d) FloatTag + DoubleVal d = Val (doubleToInt d) floatTypeTag matchIntVal :: Val -> Maybe Int matchIntVal = \case @@ -398,7 +404,7 @@ matchIntVal = \case pattern IntVal :: Int -> Val pattern IntVal i <- (matchIntVal -> Just i) where - IntVal i = UnboxedVal i IntTag + IntVal i = Val i intTypeTag doubleToInt :: Double -> Int doubleToInt d = indexByteArray (BA.byteArrayFromList [d]) 0 @@ -693,9 +699,9 @@ upeekOff _stk@(Stack _ _ sp ustk _) i = do readByteArray ustk (sp - i) {-# INLINE upeekOff #-} -upokeT :: DebugCallStack => Stack -> UVal -> UnboxedTypeTag -> IO () +upokeT :: DebugCallStack => Stack -> UVal -> BVal -> IO () upokeT !stk@(Stack _ _ sp ustk _) !u !t = do - bpoke stk (UnboxedTypeTag t) + bpoke stk t writeByteArray ustk sp u {-# INLINE upokeT #-} @@ -713,7 +719,7 @@ poke _stk@(Stack _ _ sp ustk bstk) (Val u b) = do -- checks. unsafePokeIasN :: DebugCallStack => Stack -> Int -> IO () unsafePokeIasN stk n = do - upokeT stk n NatTag + upokeT stk n natTypeTag {-# INLINE unsafePokeIasN #-} -- | Store an unboxed tag to later match on. @@ -758,9 +764,9 @@ pokeOff stk i (Val u t) = do writeByteArray (ustk stk) (sp stk - i) u {-# INLINE pokeOff #-} -upokeOffT :: DebugCallStack => Stack -> Off -> UVal -> UnboxedTypeTag -> IO () +upokeOffT :: DebugCallStack => Stack -> Off -> UVal -> BVal -> IO () upokeOffT stk i u t = do - bpokeOff stk i (UnboxedTypeTag t) + bpokeOff stk i t writeByteArray (ustk stk) (sp stk - i) u {-# INLINE upokeOffT #-} @@ -1062,7 +1068,7 @@ pokeOffI stk@(Stack _ _ sp ustk _) i n = do pokeOffC :: Stack -> Int -> Char -> IO () pokeOffC stk i c = do - upokeOffT stk i (Char.ord c) CharTag + upokeOffT stk i (Char.ord c) charTypeTag {-# INLINE pokeOffC #-} pokeBi :: (BuiltinForeign b) => Stack -> b -> IO () From 78cbe726087851f25833ec766dbe08e2d2c3a377 Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Thu, 7 Nov 2024 12:38:41 -0500 Subject: [PATCH 092/113] add failing transcript --- .../src/Unison/Codebase/Editor/HandleInput.hs | 4 +- .../Editor/HandleInput/DeleteNamespace.hs | 39 ++++++------ unison-src/transcripts/fix-5446.md | 18 ++++++ unison-src/transcripts/fix-5446.output.md | 60 +++++++++++++++++++ 4 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 unison-src/transcripts/fix-5446.md create mode 100644 unison-src/transcripts/fix-5446.output.md diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs index 472329298e..6bd03f1ca2 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs @@ -572,7 +572,7 @@ loop e = do delete input doutput getTerms getTypes hqs DeleteTarget'Type doutput hqs -> delete input doutput (const (pure Set.empty)) getTypes hqs DeleteTarget'Term doutput hqs -> delete input doutput getTerms (const (pure Set.empty)) hqs - DeleteTarget'Namespace insistence path -> handleDeleteNamespace input inputDescription insistence path + DeleteTarget'Namespace insistence path -> handleDeleteNamespace input insistence path DeleteTarget'ProjectBranch name -> handleDeleteBranch name DeleteTarget'Project name -> handleDeleteProject name DisplayI outputLoc namesToDisplay -> do @@ -1457,7 +1457,7 @@ checkDeletes typesTermsTuples doutput inputs = do Cli.runTransaction $ traverse ( \targetToDelete -> - getEndangeredDependents targetToDelete (allTermsToDelete) projectNames + getEndangeredDependents targetToDelete allTermsToDelete projectNames ) toDelete -- If the overall dependency map is not completely empty, abort deletion diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs index 9bb920685e..e6713ef3f7 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs @@ -5,6 +5,7 @@ module Unison.Codebase.Editor.HandleInput.DeleteNamespace where import Control.Lens hiding (from) +import Control.Lens qualified as Lens import Control.Monad.State qualified as State import Data.Map qualified as Map import Data.Set qualified as Set @@ -22,6 +23,7 @@ import Unison.Codebase.Editor.Input import Unison.Codebase.Editor.Output import Unison.Codebase.Path (Path) import Unison.Codebase.Path qualified as Path +import Unison.Codebase.ProjectPath qualified as ProjectPath import Unison.LabeledDependency (LabeledDependency) import Unison.LabeledDependency qualified as LD import Unison.NameSegment qualified as NameSegment @@ -33,25 +35,18 @@ import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Referent qualified as Referent import Unison.Sqlite qualified as Sqlite -handleDeleteNamespace :: - Input -> - (Input -> Cli Text) -> - Insistence -> - Maybe (Path, NameSegment.NameSegment) -> - Cli () -handleDeleteNamespace input inputDescription insistence = \case +handleDeleteNamespace :: Input -> Insistence -> Maybe (Path, NameSegment.NameSegment) -> Cli () +handleDeleteNamespace input insistence = \case Nothing -> do - hasConfirmed <- confirmedCommand input - if hasConfirmed || insistence == Force + loopState <- State.get + if loopState.lastInput == Just input || insistence == Force then do - description <- inputDescription input pp <- Cli.getCurrentProjectPath - _ <- Cli.updateAt description pp (const Branch.empty) + _ <- Cli.updateAt (commandName <> " .") pp (const Branch.empty) Cli.respond DeletedEverything else Cli.respond DeleteEverythingConfirmation Just p@(parentPath, childName) -> do branch <- Cli.expectBranchAtPath (Path.unsplit p) - description <- inputDescription input let toDelete = Names.prefix0 (Path.nameFromSplit' $ first (Path.RelativePath' . Path.Relative) p) @@ -71,17 +66,23 @@ handleDeleteNamespace input inputDescription insistence = \case Cli.respondNumbered $ CantDeleteNamespace ppeDecl endangerments Cli.returnEarlyWithoutOutput parentPathAbs <- Cli.resolvePath parentPath + let description = commandName <> " " <> into @Text (parentPathAbs & ProjectPath.absPath_ %~ (`Lens.snoc` childName)) -- We have to modify the parent in order to also wipe out the history at the -- child. - Cli.updateAt description parentPathAbs \parentBranch -> - parentBranch - & Branch.modifyAt (Path.singleton childName) \_ -> Branch.empty + Cli.updateAt description parentPathAbs (Branch.modifyAt (Path.singleton childName) \_ -> Branch.empty) afterDelete + where + commandName :: Text + commandName = + case insistence of + Try -> "delete.namespace" + Force -> "delete.namespace.force" -confirmedCommand :: Input -> Cli Bool -confirmedCommand i = do - loopState <- State.get - pure $ Just i == (loopState ^. #lastInput) +-- How I might do it (is this any better than the current algorithm?) +-- +-- 1. Get all direct dependents of the deleted things in the current namespace. +-- 2. For each direct dependent, check a Names built from the deleted namespace – is it there? If not it's the last +-- name. -- | Goal: When deleting, we might be removing the last name of a given definition (i.e. the -- definition is going "extinct"). In this case we may wish to take some action or warn the diff --git a/unison-src/transcripts/fix-5446.md b/unison-src/transcripts/fix-5446.md new file mode 100644 index 0000000000..e1048800be --- /dev/null +++ b/unison-src/transcripts/fix-5446.md @@ -0,0 +1,18 @@ +Previously `delete.namespace` would refuse to delete a namespace if it would leave any nameless references in `lib`. + +```ucm:hide +scratch/main> builtins.merge lib.builtin +``` + +```unison +lib.one.foo = 17 +lib.two.bar = foo Nat.+ foo +``` + +```ucm +scratch/main> add +``` + +```ucm:error +scratch/main> delete.namespace lib.one +``` diff --git a/unison-src/transcripts/fix-5446.output.md b/unison-src/transcripts/fix-5446.output.md new file mode 100644 index 0000000000..969c22142b --- /dev/null +++ b/unison-src/transcripts/fix-5446.output.md @@ -0,0 +1,60 @@ +``` unison +lib.one.foo = 17 +lib.two.bar = foo Nat.+ foo +``` + +``` ucm + + Loading changes detected in scratch.u. + + I found and typechecked these definitions in scratch.u. If you + do an `add` or `update`, here's how your codebase would + change: + + ⍟ These new definitions are ok to `add`: + + lib.one.foo : Nat + lib.two.bar : Nat + +``` +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + lib.one.foo : Nat + lib.two.bar : Nat + +scratch/main> delete.namespace lib.one + + ⚠️ + + I didn't delete the namespace because the following + definitions are still in use. + + Dependency Referenced In + foo 1. lib.two.bar + + If you want to proceed anyways and leave those definitions + without names, use delete.namespace.force + +``` + + + +🛑 + +The transcript failed due to an error in the stanza above. The error is: + + + ⚠️ + + I didn't delete the namespace because the following + definitions are still in use. + + Dependency Referenced In + foo 1. lib.two.bar + + If you want to proceed anyways and leave those definitions + without names, use delete.namespace.force + From 2775b5808fa56b12112bacb3a64f928a393bfd34 Mon Sep 17 00:00:00 2001 From: Greg Pfeil Date: Mon, 11 Nov 2024 17:34:27 -0700 Subject: [PATCH 093/113] =?UTF-8?q?Unify=20`@keyword{=E2=80=A6}`=20constru?= =?UTF-8?q?cts=20in=20Doc=20parser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a number of these that had previously been duplicated. This gives them a single implementation, with the contents being parsed based on the keyword. --- unison-syntax/src/Unison/Syntax/Parser/Doc.hs | 70 +++++-------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/unison-syntax/src/Unison/Syntax/Parser/Doc.hs b/unison-syntax/src/Unison/Syntax/Parser/Doc.hs index d2279ba4c0..715666866f 100644 --- a/unison-syntax/src/Unison/Syntax/Parser/Doc.hs +++ b/unison-syntax/src/Unison/Syntax/Parser/Doc.hs @@ -36,18 +36,13 @@ module Unison.Syntax.Parser.Doc italic, strikethrough, verbatim, - source, - foldedSource, - evalInline, - signatures, - signatureInline, + keyedInline, group, word, -- * other components column', embedLink, - embedSignatureLink, join, ) where @@ -57,10 +52,10 @@ import Control.Monad.Reader qualified as R import Data.Char (isControl, isSpace) import Data.List qualified as List import Data.List.Extra qualified as List -import Data.List.NonEmpty (NonEmpty ((:|))) +import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty) import Data.List.NonEmpty qualified as NonEmpty import Text.Megaparsec qualified as P -import Text.Megaparsec.Char (char) +import Text.Megaparsec.Char (char, letterChar) import Text.Megaparsec.Char qualified as CP import Text.Megaparsec.Char.Lexer qualified as LP import Unison.Parser.Ann (Ann (Ann)) @@ -143,11 +138,7 @@ leaf ident code closing = <|> italic ident code closing <|> strikethrough ident code closing <|> verbatim - <|> source ident code - <|> foldedSource ident code - <|> evalInline code - <|> signatures ident - <|> signatureInline ident + <|> keyedInline ident code <|> (Word' <$> word closing) leafy :: @@ -166,22 +157,18 @@ leafy ident code closing = do comma :: (P.MonadParsec e String m) => m String comma = lit "," <* CP.space -source :: (Ord e, P.MonadParsec e String m) => m ident -> (m () -> m code) -> m (Leaf ident code a) -source ident = fmap Source . (lit "@source" *>) . sourceElements ident - -foldedSource :: (Ord e, P.MonadParsec e String m) => m ident -> (m () -> m code) -> m (Leaf ident code a) -foldedSource ident = fmap FoldedSource . (lit "@foldedSource" *>) . sourceElements ident - -sourceElements :: - (Ord e, P.MonadParsec e String m) => - m ident -> - (m () -> m code) -> - m (NonEmpty (SourceElement ident (Transclude code))) -sourceElements ident code = do - _ <- (lit " {" <|> lit "{") *> CP.space - s <- sepBy1' srcElem comma - _ <- lit "}" - pure s +-- | A syntactic pattern of “@keyword{…}”, where we process the contents differently depending on the keyword provided. +keyedInline :: (Ord e, P.MonadParsec e String m) => m ident -> (m () -> m code) -> m (Leaf ident code a) +keyedInline ident code = P.try do + keyword <- lit "@" *> P.many letterChar <* (lit " {" <|> lit "{") + case keyword of + "source" -> Source <$> sepBy1' srcElem comma <* lit "}" + "foldedSource" -> FoldedSource <$> sepBy1' srcElem comma <* lit "}" + "eval" -> fmap EvalInline . code . void $ lit "}" + "signature" -> Signature <$> sepBy1' (embedSignatureLink ident) comma <* lit "}" + "signatures" -> Signature <$> sepBy1' (embedSignatureLink ident) comma <* lit "}" + "inlineSignature" -> SignatureInline <$> embedSignatureLink ident <* lit "}" + keyword -> P.unexpected . maybe (P.Label $ '@' :| "keyword{...}") P.Tokens $ nonEmpty keyword where srcElem = SourceElement @@ -192,35 +179,12 @@ sourceElements ident code = do where annotation = fmap Left ident <|> fmap Right (transclude code) <* CP.space annotations = P.some (EmbedAnnotation <$> annotation) - -signatures :: (Ord e, P.MonadParsec e String m) => m ident -> m (Leaf ident code a) -signatures ident = fmap Signature $ do - _ <- (lit "@signatures" <|> lit "@signature") *> (lit " {" <|> lit "{") *> CP.space - s <- sepBy1' (embedSignatureLink ident) comma - _ <- lit "}" - pure s - -signatureInline :: (Ord e, P.MonadParsec e String m) => m ident -> m (Leaf ident code a) -signatureInline ident = fmap SignatureInline $ do - _ <- lit "@inlineSignature" *> (lit " {" <|> lit "{") *> CP.space - s <- embedSignatureLink ident - _ <- lit "}" - pure s - -evalInline :: (P.MonadParsec e String m) => (m () -> m code) -> m (Leaf ident code a) -evalInline code = fmap EvalInline $ do - _ <- lit "@eval" *> (lit " {" <|> lit "{") *> CP.space - let inlineEvalClose = void $ lit "}" - s <- code inlineEvalClose - pure s + embedSignatureLink ident = EmbedSignatureLink <$> ident <* CP.space -- | Not an actual node, but this pattern is referenced in multiple places embedLink :: (Ord e, P.MonadParsec e s m, P.TraversableStream s) => m ident -> m (EmbedLink ident) embedLink = fmap EmbedLink -embedSignatureLink :: (Ord e, P.MonadParsec e String m) => m ident -> m (EmbedSignatureLink ident) -embedSignatureLink ident = EmbedSignatureLink <$> ident <* CP.space - verbatim :: (Ord e, P.MonadParsec e String m) => m (Leaf ident code a) verbatim = P.label "code (examples: ''**unformatted**'', `words` or '''_words_''')" $ do From 5ee47945c7efa799a0ff0e8f8a843be543e5af56 Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Tue, 12 Nov 2024 11:25:30 -0500 Subject: [PATCH 094/113] in `delete.namespace`, don't worry about endangered definitions in `lib` itself --- .../src/Unison/Codebase/Editor/HandleInput.hs | 13 +++--- .../Editor/HandleInput/DeleteNamespace.hs | 45 ++++++++++--------- unison-src/transcripts/fix-5446.md | 2 +- unison-src/transcripts/fix-5446.output.md | 34 +++----------- 4 files changed, 36 insertions(+), 58 deletions(-) diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs index 6bd03f1ca2..3300abdf1a 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput.hs @@ -56,6 +56,7 @@ import Unison.Codebase.Editor.HandleInput.DebugDefinition qualified as DebugDefi import Unison.Codebase.Editor.HandleInput.DebugFoldRanges qualified as DebugFoldRanges import Unison.Codebase.Editor.HandleInput.DebugSynhashTerm (handleDebugSynhashTerm) import Unison.Codebase.Editor.HandleInput.DeleteBranch (handleDeleteBranch) +import Unison.Codebase.Editor.HandleInput.DeleteNamespace (getEndangeredDependents, handleDeleteNamespace) import Unison.Codebase.Editor.HandleInput.DeleteProject (handleDeleteProject) import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace) import Unison.Codebase.Editor.HandleInput.FindAndReplace (handleStructuredFindI, handleStructuredFindReplaceI, handleTextFindI) @@ -176,7 +177,6 @@ import Unison.Var (Var) import Unison.Var qualified as Var import Unison.WatchKind qualified as WK import UnliftIO.Directory qualified as Directory -import Unison.Codebase.Editor.HandleInput.DeleteNamespace (handleDeleteNamespace, getEndangeredDependents) ------------------------------------------------------------------------------------------------------------------------ -- Main loop @@ -938,7 +938,8 @@ inputDescription input = UndoI {} -> pure "undo" ExecuteI s args -> pure ("execute " <> Text.unwords (HQ.toText s : fmap Text.pack args)) IOTestI native hq -> pure (cmd <> HQ.toText hq) - where cmd | native = "io.test.native " | otherwise = "io.test " + where + cmd | native = "io.test.native " | otherwise = "io.test " IOTestAllI native -> pure (if native then "io.test.native.all" else "io.test.all") UpdateBuiltinsI -> pure "builtins.update" @@ -1448,7 +1449,9 @@ 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 - projectNames <- Branch.toNames <$> Cli.getCurrentProjectRoot0 + currentBranch <- Cli.getCurrentProjectRoot0 + let projectNames = Branch.toNames currentBranch + projectNamesSansLib = Branch.toNames (Branch.deleteLibdeps currentBranch) -- get only once for the entire deletion set let allTermsToDelete :: Set LabeledDependency allTermsToDelete = Set.unions (fmap Names.labeledReferences toDelete) @@ -1456,9 +1459,7 @@ checkDeletes typesTermsTuples doutput inputs = do endangered <- Cli.runTransaction $ traverse - ( \targetToDelete -> - getEndangeredDependents targetToDelete allTermsToDelete projectNames - ) + (\targetToDelete -> getEndangeredDependents targetToDelete allTermsToDelete projectNames projectNamesSansLib) toDelete -- If the overall dependency map is not completely empty, abort deletion let endangeredDeletions = List.filter (\m -> not $ null m || Map.foldr (\s b -> null s || b) False m) endangered diff --git a/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs b/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs index e6713ef3f7..14281adc33 100644 --- a/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs +++ b/unison-cli/src/Unison/Codebase/Editor/HandleInput/DeleteNamespace.hs @@ -15,7 +15,6 @@ import U.Codebase.Sqlite.Queries qualified as Queries import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.MonadUtils qualified as Cli -import Unison.Cli.NamesUtils qualified as Cli import Unison.Codebase qualified as Codebase import Unison.Codebase.Branch qualified as Branch import Unison.Codebase.Branch.Names qualified as Branch @@ -52,8 +51,10 @@ handleDeleteNamespace input insistence = \case (Path.nameFromSplit' $ first (Path.RelativePath' . Path.Relative) p) (Branch.toNames (Branch.head branch)) afterDelete <- do - names <- Cli.currentNames - endangerments <- Cli.runTransaction (getEndangeredDependents toDelete Set.empty names) + currentBranch <- Cli.getCurrentProjectRoot0 + let names = Branch.toNames currentBranch + namesSansLib = Branch.toNames (Branch.deleteLibdeps currentBranch) + endangerments <- Cli.runTransaction (getEndangeredDependents toDelete Set.empty names namesSansLib) case (null endangerments, insistence) of (True, _) -> pure (Cli.respond Success) (False, Force) -> do @@ -97,37 +98,37 @@ getEndangeredDependents :: Set LabeledDependency -> -- | Names from the current branch Names -> + -- | Names from the current branch, sans `lib` + Names -> -- | map from references going extinct to the set of endangered dependents Sqlite.Transaction (Map LabeledDependency (NESet LabeledDependency)) -getEndangeredDependents targetToDelete otherDesiredDeletions rootNames = do - -- names of terms left over after target deletion - let remainingNames :: Names - remainingNames = rootNames `Names.difference` targetToDelete - -- target refs for deletion - let refsToDelete :: Set LabeledDependency - refsToDelete = Names.labeledReferences targetToDelete - -- refs left over after deleting target - let remainingRefs :: Set LabeledDependency - remainingRefs = Names.labeledReferences remainingNames - -- remove the other targets for deletion from the remaining terms - let remainingRefsWithoutOtherTargets :: Set LabeledDependency - remainingRefsWithoutOtherTargets = Set.difference remainingRefs otherDesiredDeletions +getEndangeredDependents targetToDelete otherDesiredDeletions rootNames rootNamesSansLib = do -- deleting and not left over let extinct :: Set LabeledDependency - extinct = refsToDelete `Set.difference` remainingRefs + extinct = Names.labeledReferences targetToDelete `Set.difference` refsAfterDeletingTarget rootNames + let accumulateDependents :: LabeledDependency -> Sqlite.Transaction (Map LabeledDependency (Set LabeledDependency)) accumulateDependents ld = let ref = LD.fold id Referent.toReference ld in Map.singleton ld . Set.map LD.termRef <$> Codebase.dependents Queries.ExcludeOwnComponent ref + -- All dependents of extinct, including terms which might themselves be in the process of being deleted. allDependentsOfExtinct :: Map LabeledDependency (Set LabeledDependency) <- Map.unionsWith (<>) <$> for (Set.toList extinct) accumulateDependents - -- Filtered to only include dependencies which are not being deleted, but depend one which - -- is going extinct. + -- Of all the dependents of things going extinct, we filter down to only those that are not themselves being deleted + -- too (per `otherDesiredDeletion`), and are also somewhere outside `lib`. This allows us to proceed with deleting + -- an entire dependency out of `lib` even if for some reason it contains the only source of names for some other + -- dependency. let extinctToEndangered :: Map LabeledDependency (NESet LabeledDependency) extinctToEndangered = - allDependentsOfExtinct & Map.mapMaybe \endangeredDeps -> - let remainingEndangered = endangeredDeps `Set.intersection` remainingRefsWithoutOtherTargets - in NESet.nonEmptySet remainingEndangered + Map.mapMaybe + ( NESet.nonEmptySet + . Set.intersection (Set.difference (refsAfterDeletingTarget rootNamesSansLib) otherDesiredDeletions) + ) + allDependentsOfExtinct pure extinctToEndangered + where + refsAfterDeletingTarget :: Names -> Set LabeledDependency + refsAfterDeletingTarget names = + Names.labeledReferences (names `Names.difference` targetToDelete) diff --git a/unison-src/transcripts/fix-5446.md b/unison-src/transcripts/fix-5446.md index e1048800be..344da5279e 100644 --- a/unison-src/transcripts/fix-5446.md +++ b/unison-src/transcripts/fix-5446.md @@ -13,6 +13,6 @@ lib.two.bar = foo Nat.+ foo scratch/main> add ``` -```ucm:error +```ucm scratch/main> delete.namespace lib.one ``` diff --git a/unison-src/transcripts/fix-5446.output.md b/unison-src/transcripts/fix-5446.output.md index 969c22142b..1746d3fd5d 100644 --- a/unison-src/transcripts/fix-5446.output.md +++ b/unison-src/transcripts/fix-5446.output.md @@ -1,3 +1,5 @@ +Previously `delete.namespace` would refuse to delete a namespace if it would leave any nameless references in `lib`. + ``` unison lib.one.foo = 17 lib.two.bar = foo Nat.+ foo @@ -25,36 +27,10 @@ scratch/main> add lib.one.foo : Nat lib.two.bar : Nat +``` +``` ucm scratch/main> delete.namespace lib.one - ⚠️ - - I didn't delete the namespace because the following - definitions are still in use. - - Dependency Referenced In - foo 1. lib.two.bar - - If you want to proceed anyways and leave those definitions - without names, use delete.namespace.force + Done. ``` - - - -🛑 - -The transcript failed due to an error in the stanza above. The error is: - - - ⚠️ - - I didn't delete the namespace because the following - definitions are still in use. - - Dependency Referenced In - foo 1. lib.two.bar - - If you want to proceed anyways and leave those definitions - without names, use delete.namespace.force - From e05237ec9fd8560160328eaa1972269c93c8aa9b Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 11 Nov 2024 22:58:06 -0800 Subject: [PATCH 095/113] Fix stackchecks --- unison-runtime/src/Unison/Runtime/Stack.hs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index f05d457606..f879fbeb5e 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -158,8 +158,12 @@ assertBumped :: HasCallStack => Stack -> Off -> IO () assertBumped (Stack _ _ sp ustk bstk) i = do u <- readByteArray ustk (sp - i) b :: BVal <- readArray bstk (sp - i) - when (u /= unboxedSentinel || b /= boxedSentinel) do + when (u /= unboxedSentinel || not (isBoxedSentinel b)) do error $ "Expected stack slot to have been bumped, but it was:" <> show (Val u b) + where + isBoxedSentinel :: Closure -> Bool + isBoxedSentinel (Closure GUnboxedSentinel) = True + isBoxedSentinel _ = False assertUnboxed :: HasCallStack => Stack -> Off -> IO () assertUnboxed (Stack _ _ sp ustk bstk) i = do From 77757dde296e82d9c6d280ad181d8aac37f44ebe Mon Sep 17 00:00:00 2001 From: Dan Doel Date: Wed, 13 Nov 2024 15:34:04 -0500 Subject: [PATCH 096/113] Actually calculate inlining info for builtins --- unison-runtime/src/Unison/Runtime/Builtin.hs | 5 +++++ unison-runtime/src/Unison/Runtime/Machine.hs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 0bb41d834c..1044e1ceb5 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -15,6 +15,7 @@ module Unison.Runtime.Builtin builtinTypeBackref, builtinForeigns, builtinArities, + builtinInlineInfo, sandboxedForeigns, numberedTermLookup, Sandbox (..), @@ -3666,5 +3667,9 @@ builtinArities = Map.fromList $ [ (r, arity s) | (r, (_, s)) <- Map.toList builtinLookup ] +builtinInlineInfo :: Map Reference (Int, ANormal Symbol) +builtinInlineInfo = + ANF.buildInlineMap $ fmap (Rec [] . snd) builtinLookup + unsafeSTMToIO :: STM.STM a -> IO a unsafeSTMToIO (STM.STM m) = IO m diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index f1f277968a..41858d1201 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2026,7 +2026,7 @@ cacheAdd0 ntys0 termSuperGroups sands cc = do rtm <- updateMap (M.fromList $ zip rs [ntm ..]) (refTm cc) -- check for missing references let arities = fmap (head . ANF.arities) int <> builtinArities - inlinfo = ANF.buildInlineMap int + inlinfo = ANF.buildInlineMap int <> builtinInlineInfo rns = RN (refLookup "ty" rty) (refLookup "tm" rtm) (flip M.lookup arities) combinate :: Word64 -> (Reference, SuperGroup Symbol) -> (Word64, EnumMap Word64 Comb) combinate n (r, g) = From d4ea9a24341c241bcae88c3f2c182208e76dc75f Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 13 Nov 2024 09:40:35 -0800 Subject: [PATCH 097/113] Fix stack debugging --- unison-runtime/src/Unison/Runtime/Stack.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index f879fbeb5e..ebc9ef33dd 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -144,7 +144,9 @@ import Prelude hiding (words) {- ORMOLU_DISABLE -} #ifdef STACK_CHECK -import Unison.Debug qualified as Debug +import Data.Text.IO (hPutStrLn) +import UnliftIO (stderr, throwIO) +import GHC.Stack (CallStack, callStack) type DebugCallStack = (HasCallStack :: Constraint) @@ -666,7 +668,7 @@ peekI _stk@(Stack _ _ sp ustk _) = do peekOffI :: DebugCallStack => Stack -> Off -> IO Int peekOffI _stk@(Stack _ _ sp ustk _) i = do #ifdef STACK_CHECK - assertUnboxed _stk 0 + assertUnboxed _stk i #endif readByteArray ustk (sp - i) {-# INLINE peekOffI #-} @@ -756,7 +758,6 @@ pokeBool stk b = bpoke :: DebugCallStack => Stack -> BVal -> IO () bpoke _stk@(Stack _ _ sp _ bstk) b = do #ifdef STACK_CHECK - Debug.debugLogM Debug.Interpreter "before assert bumped" assertBumped _stk 0 #endif writeArray bstk sp b From a8e18d897bc7d557e70a00f3123e34b4686e6bdb Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 15 Nov 2024 12:58:50 -0800 Subject: [PATCH 098/113] Remove ANF.inline --- unison-runtime/src/Unison/Runtime/Machine.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 41858d1201..58c6630d96 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -2026,11 +2026,10 @@ cacheAdd0 ntys0 termSuperGroups sands cc = do rtm <- updateMap (M.fromList $ zip rs [ntm ..]) (refTm cc) -- check for missing references let arities = fmap (head . ANF.arities) int <> builtinArities - inlinfo = ANF.buildInlineMap int <> builtinInlineInfo rns = RN (refLookup "ty" rty) (refLookup "tm" rtm) (flip M.lookup arities) combinate :: Word64 -> (Reference, SuperGroup Symbol) -> (Word64, EnumMap Word64 Comb) combinate n (r, g) = - (n, emitCombs rns r n $ ANF.inline inlinfo g) + (n, emitCombs rns r n g) let combRefUpdates = (mapFromList $ zip [ntm ..] rs) let combIdFromRefMap = (M.fromList $ zip rs [ntm ..]) let newCacheableCombs = From 30526127ed5397e693d9b890335fe3e8635329cb Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 18 Nov 2024 15:32:31 -0800 Subject: [PATCH 099/113] Add indicator to prompt when on staging --- unison-cli/src/Unison/CommandLine/Main.hs | 11 ++++++++- unison-cli/src/Unison/Share/Codeserver.hs | 30 ++++++++++++++++------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/unison-cli/src/Unison/CommandLine/Main.hs b/unison-cli/src/Unison/CommandLine/Main.hs index 64e070be74..3b86508eb0 100644 --- a/unison-cli/src/Unison/CommandLine/Main.hs +++ b/unison-cli/src/Unison/CommandLine/Main.hs @@ -47,6 +47,8 @@ import Unison.Prelude import Unison.PrettyTerminal import Unison.Runtime.IOSource qualified as IOSource import Unison.Server.CodebaseServer qualified as Server +import Unison.Share.Codeserver (isCustomCodeserver) +import Unison.Share.Codeserver qualified as Codeserver import Unison.Symbol (Symbol) import Unison.Syntax.Parser qualified as Parser import Unison.Util.Pretty qualified as P @@ -75,10 +77,17 @@ getUserInput codebase authHTTPClient pp currentProjectRoot numberedArgs = Line.handleInterrupt (pure Nothing) (Line.withInterrupt (Just <$> act)) >>= \case Nothing -> haskelineCtrlCHandling act Just a -> pure a + + codeserverPrompt :: String + codeserverPrompt = + if isCustomCodeserver Codeserver.defaultCodeserver + then "🌐" <> Codeserver.codeserverRegName Codeserver.defaultCodeserver <> maybe "" (":" <>) (show <$> Codeserver.codeserverPort Codeserver.defaultCodeserver) <> "\n" + else "" + go :: Line.InputT IO Input go = do let promptString = P.prettyProjectPath pp - let fullPrompt = P.toANSI 80 (promptString <> fromString prompt) + let fullPrompt = P.toANSI 80 (P.red (P.string codeserverPrompt) <> promptString <> fromString prompt) line <- Line.getInputLine fullPrompt case line of Nothing -> pure QuitI diff --git a/unison-cli/src/Unison/Share/Codeserver.hs b/unison-cli/src/Unison/Share/Codeserver.hs index a1617a4411..ea7aee4b73 100644 --- a/unison-cli/src/Unison/Share/Codeserver.hs +++ b/unison-cli/src/Unison/Share/Codeserver.hs @@ -1,4 +1,10 @@ -module Unison.Share.Codeserver where +module Unison.Share.Codeserver + ( isCustomCodeserver, + defaultCodeserver, + resolveCodeserver, + CodeserverURI (..), + ) +where import Network.URI (parseURI) import System.IO.Unsafe (unsafePerformIO) @@ -8,18 +14,24 @@ import Unison.Share.Types import Unison.Share.Types qualified as Share import UnliftIO.Environment (lookupEnv) +shareProd :: CodeserverURI +shareProd = + CodeserverURI + { codeserverScheme = Share.Https, + codeserverUserInfo = "", + codeserverRegName = "api.unison-lang.org", + codeserverPort = Nothing, + codeserverPath = [] + } + +isCustomCodeserver :: CodeserverURI -> Bool +isCustomCodeserver = (/=) shareProd + -- | This is the URI where the share API is based. defaultCodeserver :: CodeserverURI defaultCodeserver = unsafePerformIO $ do lookupEnv "UNISON_SHARE_HOST" <&> \case - Nothing -> - CodeserverURI - { codeserverScheme = Share.Https, - codeserverUserInfo = "", - codeserverRegName = "api.unison-lang.org", - codeserverPort = Nothing, - codeserverPath = [] - } + Nothing -> shareProd Just shareHost -> fromMaybe (error $ "Share Host is not a valid URI: " <> shareHost) $ do uri <- parseURI shareHost From cfc85bb915aeeff7a01c2022ea150658767c1bc1 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 19 Nov 2024 10:12:56 -0800 Subject: [PATCH 100/113] Don't treat blocks with null annotations as equal by default --- unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs index c38c532574..38063c983b 100644 --- a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs +++ b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs @@ -38,7 +38,8 @@ diffSyntaxText (AnnotatedText fromST) (AnnotatedText toST) = -- So, we treat these elements as equal then detect them in a post-processing step. diffEq :: AT.Segment Syntax.Element -> AT.Segment Syntax.Element -> Bool diffEq (AT.Segment {segment = fromSegment, annotation = fromAnnotation}) (AT.Segment {segment = toSegment, annotation = toAnnotation}) = - fromSegment == toSegment || fromAnnotation == toAnnotation + fromSegment == toSegment || + (isJust fromAnnotation && fromAnnotation == toAnnotation) expandSpecialCases :: [Diff.Diff [AT.Segment (Syntax.Element)]] -> [SemanticSyntaxDiff] expandSpecialCases xs = From c60cbbccfcfb5833ae303acac60267eea837686d Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 19 Nov 2024 10:22:34 -0800 Subject: [PATCH 101/113] Make `unsafe.force-push` visible --- unison-cli/src/Unison/CommandLine/InputPatterns.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/unison-cli/src/Unison/CommandLine/InputPatterns.hs b/unison-cli/src/Unison/CommandLine/InputPatterns.hs index 40623a8c63..179c1d1567 100644 --- a/unison-cli/src/Unison/CommandLine/InputPatterns.hs +++ b/unison-cli/src/Unison/CommandLine/InputPatterns.hs @@ -2021,10 +2021,10 @@ pushForce :: InputPattern pushForce = InputPattern "unsafe.force-push" - [] - I.Hidden + ["push.unsafe-force"] + I.Visible [("remote destination", Optional, remoteNamespaceArg), ("local source", Optional, namespaceOrProjectBranchArg suggestionsConfig)] - (P.wrap "Like `push`, but overwrites any remote namespace.") + (P.wrap "Like `push`, but forcibly overwrites the remote namespace.") $ fmap ( \sourceTarget -> Input.PushRemoteBranchI From cad3c76268d57168dadca49aba57eae71ceed128 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 19 Nov 2024 11:24:57 -0800 Subject: [PATCH 102/113] Simplify special cases to just hash-references --- .../src/Unison/Server/Backend/DefinitionDiff.hs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs index 38063c983b..898f6c91dc 100644 --- a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs +++ b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs @@ -35,11 +35,23 @@ diffSyntaxText (AnnotatedText fromST) (AnnotatedText toST) = where -- We special-case situations where the name of a definition changed but its hash didn't; -- and cases where the name didn't change but the hash did. - -- So, we treat these elements as equal then detect them in a post-processing step. + -- + -- The diff algorithm only understands whether items are equal or not, so in order to add this special behavior we + -- treat these special cases as equal, then we can detect and expand them in a post-processing step. diffEq :: AT.Segment Syntax.Element -> AT.Segment Syntax.Element -> Bool diffEq (AT.Segment {segment = fromSegment, annotation = fromAnnotation}) (AT.Segment {segment = toSegment, annotation = toAnnotation}) = fromSegment == toSegment || - (isJust fromAnnotation && fromAnnotation == toAnnotation) + case (fromAnnotation, toAnnotation) of + (Nothing, _) -> False + (Just a), (Just b) -> + case a of + -- The set of annotations we want to special-case + TypeReference{} -> a == b + TermReference{} -> a == b + DataConstructorReference{} -> a == b + AbilityConstructorReference{} -> a == b + HashQualifier{} -> a == b + _ -> False expandSpecialCases :: [Diff.Diff [AT.Segment (Syntax.Element)]] -> [SemanticSyntaxDiff] expandSpecialCases xs = From 5d11b23dfd8ab2c218218d695834e447d5ed0557 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 19 Nov 2024 11:29:11 -0800 Subject: [PATCH 103/113] Get compiling --- .../src/Unison/Server/Backend/DefinitionDiff.hs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs index 898f6c91dc..37fa76a697 100644 --- a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs +++ b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs @@ -43,14 +43,15 @@ diffSyntaxText (AnnotatedText fromST) (AnnotatedText toST) = fromSegment == toSegment || case (fromAnnotation, toAnnotation) of (Nothing, _) -> False - (Just a), (Just b) -> + (_, Nothing) -> False + (Just a, Just b) -> case a of -- The set of annotations we want to special-case - TypeReference{} -> a == b - TermReference{} -> a == b - DataConstructorReference{} -> a == b - AbilityConstructorReference{} -> a == b - HashQualifier{} -> a == b + Syntax.TypeReference{} -> a == b + Syntax.TermReference{} -> a == b + Syntax.DataConstructorReference{} -> a == b + Syntax.AbilityConstructorReference{} -> a == b + Syntax.HashQualifier{} -> a == b _ -> False expandSpecialCases :: [Diff.Diff [AT.Segment (Syntax.Element)]] -> [SemanticSyntaxDiff] From d39e1a0ba478fd7f11bcb898a40186c7d0962936 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 19 Nov 2024 11:51:31 -0800 Subject: [PATCH 104/113] Re-run transcripts --- .../transcripts/definition-diff-api.output.md | 255 +++++++++--------- 1 file changed, 124 insertions(+), 131 deletions(-) diff --git a/unison-src/transcripts/definition-diff-api.output.md b/unison-src/transcripts/definition-diff-api.output.md index 8934749d03..140c200688 100644 --- a/unison-src/transcripts/definition-diff-api.output.md +++ b/unison-src/transcripts/definition-diff-api.output.md @@ -228,12 +228,26 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=te ] }, { - "annotation": { - "tag": "TextLiteral" - }, - "diffTag": "segmentChange", - "fromSegment": "\"Here's some text\"", - "toSegment": "\"Here's some different text\"" + "diffTag": "old", + "elements": [ + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"Here's some text\"" + } + ] + }, + { + "diffTag": "new", + "elements": [ + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"Here's some different text\"" + } + ] }, { "diffTag": "both", @@ -270,12 +284,26 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=te ] }, { - "annotation": { - "tag": "NumericLiteral" - }, - "diffTag": "segmentChange", - "fromSegment": "1", - "toSegment": "2" + "diffTag": "old", + "elements": [ + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "1" + } + ] + }, + { + "diffTag": "new", + "elements": [ + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "2" + } + ] } ], "tag": "UserObject" @@ -1019,11 +1047,31 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta "tag": "ControlKeyword" }, "segment": " then" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": " " } ] }, { - "diffTag": "new", + "diffTag": "both", "elements": [ { "annotation": { @@ -1031,35 +1079,21 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta "tag": "TermReference" }, "segment": "emit" - } - ] - }, - { - "annotation": null, - "diffTag": "segmentChange", - "fromSegment": "\n", - "toSegment": " " - }, - { - "diffTag": "new", - "elements": [ + }, + { + "annotation": null, + "segment": " " + }, { "annotation": { "tag": "Var" }, "segment": "a" - } - ] - }, - { - "annotation": null, - "diffTag": "segmentChange", - "fromSegment": " ", - "toSegment": "\n" - }, - { - "diffTag": "both", - "elements": [ + }, + { + "annotation": null, + "segment": "\n" + }, { "annotation": null, "segment": " " @@ -1078,11 +1112,8 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta "diffTag": "old", "elements": [ { - "annotation": { - "contents": "#b035k0tpdv9jbs80ig29hujmv9kpkubda6or4320o5g7aj7edsudislnp2uovntgu5b0e6a18p0p7j8r2hcpr20blls7am8nll6t2ro#a0", - "tag": "TermReference" - }, - "segment": "emit" + "annotation": null, + "segment": " " } ] }, @@ -1094,66 +1125,32 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta "tag": "ControlKeyword" }, "segment": "if" - } - ] - }, - { - "diffTag": "both", - "elements": [ + }, { "annotation": null, "segment": " " - } - ] - }, - { - "annotation": { - "tag": "Var" - }, - "diffTag": "segmentChange", - "fromSegment": "a", - "toSegment": "n" - }, - { - "annotation": null, - "diffTag": "segmentChange", - "fromSegment": "\n", - "toSegment": " " - }, - { - "diffTag": "old", - "elements": [ + }, { - "annotation": null, - "segment": " " + "annotation": { + "tag": "Var" + }, + "segment": "n" }, { "annotation": null, - "segment": " " - } - ] - }, - { - "diffTag": "new", - "elements": [ + "segment": " " + }, { "annotation": { "contents": "##Nat.>", "tag": "TermReference" }, "segment": ">" - } - ] - }, - { - "annotation": null, - "diffTag": "segmentChange", - "fromSegment": " ", - "toSegment": " " - }, - { - "diffTag": "new", - "elements": [ + }, + { + "annotation": null, + "segment": " " + }, { "annotation": { "tag": "NumericLiteral" @@ -1165,15 +1162,13 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta "tag": "ControlKeyword" }, "segment": " then" + }, + { + "annotation": null, + "segment": " " } ] }, - { - "annotation": null, - "diffTag": "segmentChange", - "fromSegment": " ", - "toSegment": " " - }, { "diffTag": "both", "elements": [ @@ -1264,15 +1259,13 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta } ] }, - { - "annotation": null, - "diffTag": "segmentChange", - "fromSegment": "\n", - "toSegment": " " - }, { "diffTag": "old", "elements": [ + { + "annotation": null, + "segment": "\n" + }, { "annotation": null, "segment": " " @@ -1287,6 +1280,15 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta } ] }, + { + "diffTag": "new", + "elements": [ + { + "annotation": null, + "segment": " " + } + ] + }, { "diffTag": "both", "elements": [ @@ -1387,33 +1389,24 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta ] }, { - "annotation": { - "tag": "ControlKeyword" - }, - "diffTag": "segmentChange", - "fromSegment": "handle", - "toSegment": "if" - }, - { - "diffTag": "both", + "diffTag": "new", "elements": [ + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": "if" + }, { "annotation": null, "segment": " " - } - ] - }, - { - "annotation": { - "tag": "Var" - }, - "diffTag": "segmentChange", - "fromSegment": "s", - "toSegment": "n" - }, - { - "diffTag": "new", - "elements": [ + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "n" + }, { "annotation": null, "segment": " " @@ -1444,7 +1437,12 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta { "annotation": null, "segment": " " - }, + } + ] + }, + { + "diffTag": "both", + "elements": [ { "annotation": { "tag": "ControlKeyword" @@ -1460,12 +1458,7 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta "tag": "Var" }, "segment": "s" - } - ] - }, - { - "diffTag": "both", - "elements": [ + }, { "annotation": { "tag": "Unit" From f80caa693bca9b03261c513912ab1506e10e21d0 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 20 Nov 2024 09:22:03 -0800 Subject: [PATCH 105/113] Provide proper fallback for case where things are actually equal. --- .../Unison/Server/Backend/DefinitionDiff.hs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs index 37fa76a697..027b0dbeb3 100644 --- a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs +++ b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs @@ -40,18 +40,18 @@ diffSyntaxText (AnnotatedText fromST) (AnnotatedText toST) = -- treat these special cases as equal, then we can detect and expand them in a post-processing step. diffEq :: AT.Segment Syntax.Element -> AT.Segment Syntax.Element -> Bool diffEq (AT.Segment {segment = fromSegment, annotation = fromAnnotation}) (AT.Segment {segment = toSegment, annotation = toAnnotation}) = - fromSegment == toSegment || - case (fromAnnotation, toAnnotation) of + fromSegment == toSegment + || case (fromAnnotation, toAnnotation) of (Nothing, _) -> False (_, Nothing) -> False (Just a, Just b) -> case a of -- The set of annotations we want to special-case - Syntax.TypeReference{} -> a == b - Syntax.TermReference{} -> a == b - Syntax.DataConstructorReference{} -> a == b - Syntax.AbilityConstructorReference{} -> a == b - Syntax.HashQualifier{} -> a == b + Syntax.TypeReference {} -> a == b + Syntax.TermReference {} -> a == b + Syntax.DataConstructorReference {} -> a == b + Syntax.AbilityConstructorReference {} -> a == b + Syntax.HashQualifier {} -> a == b _ -> False expandSpecialCases :: [Diff.Diff [AT.Segment (Syntax.Element)]] -> [SemanticSyntaxDiff] @@ -78,7 +78,9 @@ diffSyntaxText (AnnotatedText fromST) (AnnotatedText toST) = Just _fromHash <- AT.annotation fromSegment >>= elementHash, Just _toHash <- AT.annotation toSegment >>= elementHash = Right (AnnotationChange (AT.segment fromSegment) (AT.annotation fromSegment, AT.annotation toSegment)) - | otherwise = error "diffSyntaxText: found Syntax Elements in 'both' which have nothing in common." + | otherwise = + -- Otherwise it must not be a special-case, just something that's equal. + Left toSegment where elementHash :: Syntax.Element -> Maybe Syntax.UnisonHash elementHash = \case From 5c3f615ef6e5e6c0df068b515cd3ec4fde8a2854 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 20 Nov 2024 13:55:43 -0800 Subject: [PATCH 106/113] Update transcripts --- unison-src/transcripts/definition-diff-api.md | 35 + .../transcripts/definition-diff-api.output.md | 1130 ++++++++++++++++- 2 files changed, 1159 insertions(+), 6 deletions(-) diff --git a/unison-src/transcripts/definition-diff-api.md b/unison-src/transcripts/definition-diff-api.md index 945b088501..f6cc52827a 100644 --- a/unison-src/transcripts/definition-diff-api.md +++ b/unison-src/transcripts/definition-diff-api.md @@ -24,6 +24,21 @@ take n s = else None { r } -> Some r handle s() with h n + +fakeRefModify f g = g [] + +foreach f xs = match xs with + [] -> () + x +: rest -> let + f x + foreach f rest + +handleRequest = + use List +: + finalizers = [1, 2, 3] + addFinalizer f = fakeRefModify finalizers (fs -> f +: fs) + foreach (f -> ()) finalizers + ``` ``` ucm @@ -53,6 +68,20 @@ take n s = if n > 0 then handle s () with h (n - 1) else None + +fakeRefModify2 f g = g [] + +foreach xs f = match xs with + [] -> () + x +: rest -> let + f x + foreach rest f + +handleRequest = + use List +: + finalizers = [1, 2, 3] + addFinalizer f = fakeRefModify2 finalizers (fs -> (f +: fs, ())) + foreach finalizers (f -> ()) ``` ``` ucm @@ -71,6 +100,12 @@ More complex diff GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=take&newTerm=take ``` +Regression test + +``` api +GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=handleRequest&newTerm=handleRequest +``` + Diff types diff --git a/unison-src/transcripts/definition-diff-api.output.md b/unison-src/transcripts/definition-diff-api.output.md index 140c200688..45e6265040 100644 --- a/unison-src/transcripts/definition-diff-api.output.md +++ b/unison-src/transcripts/definition-diff-api.output.md @@ -32,6 +32,21 @@ take n s = else None { r } -> Some r handle s() with h n + +fakeRefModify f g = g [] + +foreach f xs = match xs with + [] -> () + x +: rest -> let + f x + foreach f rest + +handleRequest = + use List +: + finalizers = [1, 2, 3] + addFinalizer f = fakeRefModify finalizers (fs -> f +: fs) + foreach (f -> ()) finalizers + ``` ``` ucm @@ -46,8 +61,11 @@ take n s = ability Stream a type Type - take : Nat -> '{g} t ->{g, Stream a} Optional t - term : Nat + fakeRefModify : f -> ([elem] ->{g} t) ->{g} t + foreach : (i ->{g} ()) -> [i] ->{g} () + handleRequest : () + take : Nat -> '{g} t ->{g, Stream a} Optional t + term : Nat ``` ``` ucm @@ -57,8 +75,11 @@ diffs/main> add ability Stream a type Type - take : Nat -> '{g} t ->{g, Stream a} Optional t - term : Nat + fakeRefModify : f -> ([elem] ->{g} t) ->{g} t + foreach : (i ->{g} ()) -> [i] ->{g} () + handleRequest : () + take : Nat -> '{g} t ->{g, Stream a} Optional t + term : Nat diffs/main> branch.create new @@ -90,6 +111,20 @@ take n s = if n > 0 then handle s () with h (n - 1) else None + +fakeRefModify2 f g = g [] + +foreach xs f = match xs with + [] -> () + x +: rest -> let + f x + foreach rest f + +handleRequest = + use List +: + finalizers = [1, 2, 3] + addFinalizer f = fakeRefModify2 finalizers (fs -> (f +: fs, ())) + foreach finalizers (f -> ()) ``` ``` ucm @@ -102,12 +137,19 @@ take n s = ⊡ Previously added definitions will be ignored: Stream + ⍟ These new definitions are ok to `add`: + + fakeRefModify2 : f -> ([elem] ->{g} t) ->{g} t + (also named fakeRefModify) + ⍟ These names already exist. You can `update` them to your new definition: type Type a - take : Nat -> '{g} t ->{g, Stream a} Optional t - term : Nat + foreach : [t] -> (t ->{g} ()) ->{g} () + handleRequest : () + take : Nat -> '{g} t ->{g, Stream a} Optional t + term : Nat ``` ``` ucm @@ -3345,6 +3387,1082 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta } ``` +Regression test + +``` api +GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=handleRequest&newTerm=handleRequest +{ + "diff": { + "contents": [ + { + "diffTag": "both", + "elements": [ + { + "annotation": { + "contents": "handleRequest", + "tag": "HashQualifier" + }, + "segment": "handleRequest" + }, + { + "annotation": { + "tag": "TypeAscriptionColon" + }, + "segment": " :" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": "(" + }, + { + "annotation": null, + "segment": ")" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": { + "contents": "handleRequest", + "tag": "HashQualifier" + }, + "segment": "handleRequest" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "finalizers", + "tag": "HashQualifier" + }, + "segment": "finalizers" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": "[" + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "1" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "2" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "3" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": "]" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "addFinalizer", + "tag": "HashQualifier" + }, + "segment": "addFinalizer" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "f" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#a85req9b0u8gkt82fgebosrcu3ba5g1aoqgt1vu5ohd93vpbdlo184e9pf9hgc4nml73aeohru6enhnnpch5oqilutaf0h40uv8dfvg", + "tag": "TermReference" + }, + "segment": "fakeRefModify" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": null, + "segment": "fs" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " ->" + }, + { + "annotation": null, + "segment": " " + } + ] + }, + { + "diffTag": "new", + "elements": [ + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + } + ] + }, + { + "diffTag": "both", + "elements": [ + { + "annotation": { + "tag": "Var" + }, + "segment": "f" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##List.cons", + "tag": "TermReference" + }, + "segment": "+:" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "fs" + } + ] + }, + { + "diffTag": "new", + "elements": [ + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + } + ] + }, + { + "diffTag": "both", + "elements": [ + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + } + ] + }, + { + "diffTag": "new", + "elements": [ + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + } + ] + }, + { + "diffTag": "both", + "elements": [ + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + } + ] + }, + { + "diffTag": "annotationChange", + "fromAnnotation": { + "contents": "#bcar3v5qe5466tnl5vc1crcpo13mv0pbspfmtm0g9d9i66pp3og6f75bmk6bhv7ah09igb3un5pmdjdo5ghm0n6krnbne7u2ngi770g", + "tag": "TermReference" + }, + "segment": "foreach", + "toAnnotation": { + "contents": "#jb1dd16mkieu352mk4ijml6ksvobs3e31b6q0mt219rrnk9dt6o7rgs87b3kglpfo27nsqmu8ts4q8e55t44e6v894kg9d4361gj4po", + "tag": "TermReference" + } + }, + { + "diffTag": "both", + "elements": [ + { + "annotation": null, + "segment": " " + } + ] + }, + { + "diffTag": "new", + "elements": [ + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + }, + { + "annotation": null, + "segment": " " + } + ] + }, + { + "diffTag": "both", + "elements": [ + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": null, + "segment": "f" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " ->" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + } + ] + }, + { + "diffTag": "old", + "elements": [ + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + } + ] + } + ], + "tag": "UserObject" + }, + "diffKind": "diff", + "newBranchRef": "new", + "newTerm": { + "bestTermName": "handleRequest", + "defnTermTag": "Plain", + "signature": [ + { + "annotation": null, + "segment": "(" + }, + { + "annotation": null, + "segment": ")" + } + ], + "termDefinition": { + "contents": [ + { + "annotation": { + "contents": "handleRequest", + "tag": "HashQualifier" + }, + "segment": "handleRequest" + }, + { + "annotation": { + "tag": "TypeAscriptionColon" + }, + "segment": " :" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": "(" + }, + { + "annotation": null, + "segment": ")" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": { + "contents": "handleRequest", + "tag": "HashQualifier" + }, + "segment": "handleRequest" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "finalizers", + "tag": "HashQualifier" + }, + "segment": "finalizers" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": "[" + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "1" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "2" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "3" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": "]" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "addFinalizer", + "tag": "HashQualifier" + }, + "segment": "addFinalizer" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "f" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#a85req9b0u8gkt82fgebosrcu3ba5g1aoqgt1vu5ohd93vpbdlo184e9pf9hgc4nml73aeohru6enhnnpch5oqilutaf0h40uv8dfvg", + "tag": "TermReference" + }, + "segment": "fakeRefModify" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": null, + "segment": "fs" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " ->" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "f" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##List.cons", + "tag": "TermReference" + }, + "segment": "+:" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "fs" + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#jb1dd16mkieu352mk4ijml6ksvobs3e31b6q0mt219rrnk9dt6o7rgs87b3kglpfo27nsqmu8ts4q8e55t44e6v894kg9d4361gj4po", + "tag": "TermReference" + }, + "segment": "foreach" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": null, + "segment": "f" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " ->" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + } + ], + "tag": "UserObject" + }, + "termDocs": [], + "termNames": [ + "handleRequest" + ] + }, + "oldBranchRef": "main", + "oldTerm": { + "bestTermName": "handleRequest", + "defnTermTag": "Plain", + "signature": [ + { + "annotation": null, + "segment": "(" + }, + { + "annotation": null, + "segment": ")" + } + ], + "termDefinition": { + "contents": [ + { + "annotation": { + "contents": "handleRequest", + "tag": "HashQualifier" + }, + "segment": "handleRequest" + }, + { + "annotation": { + "tag": "TypeAscriptionColon" + }, + "segment": " :" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": "(" + }, + { + "annotation": null, + "segment": ")" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": { + "contents": "handleRequest", + "tag": "HashQualifier" + }, + "segment": "handleRequest" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "finalizers", + "tag": "HashQualifier" + }, + "segment": "finalizers" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": "[" + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "1" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "2" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": ", " + }, + { + "annotation": { + "tag": "NumericLiteral" + }, + "segment": "3" + }, + { + "annotation": { + "contents": "##Sequence", + "tag": "TypeReference" + }, + "segment": "]" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "addFinalizer", + "tag": "HashQualifier" + }, + "segment": "addFinalizer" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "f" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#a85req9b0u8gkt82fgebosrcu3ba5g1aoqgt1vu5ohd93vpbdlo184e9pf9hgc4nml73aeohru6enhnnpch5oqilutaf0h40uv8dfvg", + "tag": "TermReference" + }, + "segment": "fakeRefModify" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": null, + "segment": "fs" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " ->" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "f" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##List.cons", + "tag": "TermReference" + }, + "segment": "+:" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "fs" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#bcar3v5qe5466tnl5vc1crcpo13mv0pbspfmtm0g9d9i66pp3og6f75bmk6bhv7ah09igb3un5pmdjdo5ghm0n6krnbne7u2ngi770g", + "tag": "TermReference" + }, + "segment": "foreach" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": null, + "segment": "f" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " ->" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": "(" + }, + { + "annotation": { + "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", + "tag": "TypeReference" + }, + "segment": ")" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "finalizers" + } + ], + "tag": "UserObject" + }, + "termDocs": [], + "termNames": [ + "handleRequest" + ] + }, + "project": "diffs" +} +``` + Diff types ``` api From b6f8895cde123af8b347217680db054a4d47cd9b Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 20 Nov 2024 14:11:10 -0800 Subject: [PATCH 107/113] Better handling of weird tuple case --- .../src/Unison/Server/Backend/DefinitionDiff.hs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs index 027b0dbeb3..abef221e37 100644 --- a/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs +++ b/unison-share-api/src/Unison/Server/Backend/DefinitionDiff.hs @@ -67,20 +67,23 @@ diffSyntaxText (AnnotatedText fromST) (AnnotatedText toST) = ( \next acc -> case (acc, next) of (Both xs : rest, Left seg) -> Both (seg : xs) : rest (_, Left seg) -> Both [seg] : acc - (_, Right diff) -> diff : acc + (_, Right diff) -> diff ++ acc ) - detectSpecialCase :: AT.Segment Syntax.Element -> AT.Segment Syntax.Element -> Either (AT.Segment Syntax.Element) SemanticSyntaxDiff + detectSpecialCase :: AT.Segment Syntax.Element -> AT.Segment Syntax.Element -> Either (AT.Segment Syntax.Element) [SemanticSyntaxDiff] detectSpecialCase fromSegment toSegment | fromSegment == toSegment = Left fromSegment - | AT.annotation fromSegment == AT.annotation toSegment = Right (SegmentChange (AT.segment fromSegment, AT.segment toSegment) (AT.annotation fromSegment)) + | AT.annotation fromSegment == AT.annotation toSegment = Right [SegmentChange (AT.segment fromSegment, AT.segment toSegment) (AT.annotation fromSegment)] -- We only emit an annotation change if it's a change in just the hash of the element (optionally the KIND of hash reference can change too). | AT.segment fromSegment == AT.segment toSegment, Just _fromHash <- AT.annotation fromSegment >>= elementHash, Just _toHash <- AT.annotation toSegment >>= elementHash = - Right (AnnotationChange (AT.segment fromSegment) (AT.annotation fromSegment, AT.annotation toSegment)) + Right [AnnotationChange (AT.segment fromSegment) (AT.annotation fromSegment, AT.annotation toSegment)] | otherwise = - -- Otherwise it must not be a special-case, just something that's equal. - Left toSegment + -- the annotation changed, but it's not a recognized hash change. + -- This can happen in certain special cases, e.g. a paren changed from being a syntax element into being part + -- of a unit. + -- We just emit both as old/new segments. + Right [Old [fromSegment], New [toSegment]] where elementHash :: Syntax.Element -> Maybe Syntax.UnisonHash elementHash = \case From 4495ac2aed5d92641c8b19c1101dbe78ab637f19 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 20 Nov 2024 14:11:10 -0800 Subject: [PATCH 108/113] Rerun transcripts --- unison-src/transcripts/definition-diff-api.md | 34 +- .../transcripts/definition-diff-api.output.md | 862 ++++-------------- 2 files changed, 198 insertions(+), 698 deletions(-) diff --git a/unison-src/transcripts/definition-diff-api.md b/unison-src/transcripts/definition-diff-api.md index f6cc52827a..6a1a0044f8 100644 --- a/unison-src/transcripts/definition-diff-api.md +++ b/unison-src/transcripts/definition-diff-api.md @@ -25,19 +25,8 @@ take n s = { r } -> Some r handle s() with h n -fakeRefModify f g = g [] - -foreach f xs = match xs with - [] -> () - x +: rest -> let - f x - foreach f rest - -handleRequest = - use List +: - finalizers = [1, 2, 3] - addFinalizer f = fakeRefModify finalizers (fs -> f +: fs) - foreach (f -> ()) finalizers +id x = x +unitCase = id (x -> 1) ``` @@ -69,19 +58,8 @@ take n s = then handle s () with h (n - 1) else None -fakeRefModify2 f g = g [] - -foreach xs f = match xs with - [] -> () - x +: rest -> let - f x - foreach rest f - -handleRequest = - use List +: - finalizers = [1, 2, 3] - addFinalizer f = fakeRefModify2 finalizers (fs -> (f +: fs, ())) - foreach finalizers (f -> ()) +id x = x +unitCase = id (x -> (1, ())) ``` ``` ucm @@ -100,10 +78,10 @@ More complex diff GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=take&newTerm=take ``` -Regression test +Regression test for weird behavior w/r to unit and parens. ``` api -GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=handleRequest&newTerm=handleRequest +GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=unitCase&newTerm=unitCase ``` diff --git a/unison-src/transcripts/definition-diff-api.output.md b/unison-src/transcripts/definition-diff-api.output.md index 45e6265040..119f81d47f 100644 --- a/unison-src/transcripts/definition-diff-api.output.md +++ b/unison-src/transcripts/definition-diff-api.output.md @@ -33,19 +33,8 @@ take n s = { r } -> Some r handle s() with h n -fakeRefModify f g = g [] - -foreach f xs = match xs with - [] -> () - x +: rest -> let - f x - foreach f rest - -handleRequest = - use List +: - finalizers = [1, 2, 3] - addFinalizer f = fakeRefModify finalizers (fs -> f +: fs) - foreach (f -> ()) finalizers +id x = x +unitCase = id (x -> 1) ``` @@ -61,11 +50,10 @@ handleRequest = ability Stream a type Type - fakeRefModify : f -> ([elem] ->{g} t) ->{g} t - foreach : (i ->{g} ()) -> [i] ->{g} () - handleRequest : () - take : Nat -> '{g} t ->{g, Stream a} Optional t - term : Nat + id : x -> x + take : Nat -> '{g} t ->{g, Stream a} Optional t + term : Nat + unitCase : x -> Nat ``` ``` ucm @@ -75,11 +63,10 @@ diffs/main> add ability Stream a type Type - fakeRefModify : f -> ([elem] ->{g} t) ->{g} t - foreach : (i ->{g} ()) -> [i] ->{g} () - handleRequest : () - take : Nat -> '{g} t ->{g, Stream a} Optional t - term : Nat + id : x -> x + take : Nat -> '{g} t ->{g, Stream a} Optional t + term : Nat + unitCase : x -> Nat diffs/main> branch.create new @@ -112,19 +99,8 @@ take n s = then handle s () with h (n - 1) else None -fakeRefModify2 f g = g [] - -foreach xs f = match xs with - [] -> () - x +: rest -> let - f x - foreach rest f - -handleRequest = - use List +: - finalizers = [1, 2, 3] - addFinalizer f = fakeRefModify2 finalizers (fs -> (f +: fs, ())) - foreach finalizers (f -> ()) +id x = x +unitCase = id (x -> (1, ())) ``` ``` ucm @@ -135,21 +111,15 @@ handleRequest = do an `add` or `update`, here's how your codebase would change: - ⊡ Previously added definitions will be ignored: Stream - - ⍟ These new definitions are ok to `add`: - - fakeRefModify2 : f -> ([elem] ->{g} t) ->{g} t - (also named fakeRefModify) + ⊡ Previously added definitions will be ignored: Stream id ⍟ These names already exist. You can `update` them to your new definition: type Type a - foreach : [t] -> (t ->{g} ()) ->{g} () - handleRequest : () - take : Nat -> '{g} t ->{g, Stream a} Optional t - term : Nat + take : Nat -> '{g} t ->{g, Stream a} Optional t + term : Nat + unitCase : x -> (Nat, ()) ``` ``` ucm @@ -3387,10 +3357,10 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ta } ``` -Regression test +Regression test for weird behavior w/r to unit and parens. ``` api -GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=handleRequest&newTerm=handleRequest +GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=unitCase&newTerm=unitCase { "diff": { "contents": [ @@ -3399,10 +3369,10 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "elements": [ { "annotation": { - "contents": "handleRequest", + "contents": "unitCase", "tag": "HashQualifier" }, - "segment": "handleRequest" + "segment": "unitCase" }, { "annotation": { @@ -3414,126 +3384,87 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "annotation": null, "segment": " " }, - { - "annotation": null, - "segment": "(" - }, - { - "annotation": null, - "segment": ")" - }, - { - "annotation": null, - "segment": "\n" - }, - { - "annotation": { - "contents": "handleRequest", - "tag": "HashQualifier" - }, - "segment": "handleRequest" - }, { "annotation": { - "tag": "BindingEquals" + "tag": "Var" }, - "segment": " =" - }, - { - "annotation": null, - "segment": "\n" + "segment": "x" }, { "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "finalizers", - "tag": "HashQualifier" - }, - "segment": "finalizers" + "segment": " " }, { "annotation": { - "tag": "BindingEquals" + "tag": "TypeOperator" }, - "segment": " =" + "segment": "->" }, { "annotation": null, "segment": " " - }, - { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": "[" - }, - { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "1" - }, - { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": ", " - }, + } + ] + }, + { + "diffTag": "new", + "elements": [ { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "2" - }, + "annotation": null, + "segment": "(" + } + ] + }, + { + "diffTag": "both", + "elements": [ { "annotation": { - "contents": "##Sequence", + "contents": "##Nat", "tag": "TypeReference" }, - "segment": ", " - }, + "segment": "Nat" + } + ] + }, + { + "diffTag": "new", + "elements": [ { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "3" + "annotation": null, + "segment": "," }, { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": "]" + "annotation": null, + "segment": " " }, { "annotation": null, - "segment": "\n" + "segment": "(" }, { "annotation": null, - "segment": " " + "segment": ")" }, { - "annotation": { - "contents": "addFinalizer", - "tag": "HashQualifier" - }, - "segment": "addFinalizer" - }, + "annotation": null, + "segment": ")" + } + ] + }, + { + "diffTag": "both", + "elements": [ { "annotation": null, - "segment": " " + "segment": "\n" }, { "annotation": { - "tag": "Var" + "contents": "unitCase", + "tag": "HashQualifier" }, - "segment": "f" + "segment": "unitCase" }, { "annotation": { @@ -3547,20 +3478,10 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": { - "contents": "#a85req9b0u8gkt82fgebosrcu3ba5g1aoqgt1vu5ohd93vpbdlo184e9pf9hgc4nml73aeohru6enhnnpch5oqilutaf0h40uv8dfvg", + "contents": "#ttjui80dbufvf3vgaddmcr065dpgl0rtp68i5cdht6tq4t2vk3i2vg60hi77rug368qijgijf8oui27te7o5oq0t0osm6dg65c080i0", "tag": "TermReference" }, - "segment": "fakeRefModify" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" + "segment": "id" }, { "annotation": null, @@ -3574,7 +3495,7 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": null, - "segment": "fs" + "segment": "x" }, { "annotation": { @@ -3605,30 +3526,9 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "elements": [ { "annotation": { - "tag": "Var" - }, - "segment": "f" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "##List.cons", - "tag": "TermReference" - }, - "segment": "+:" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" + "tag": "NumericLiteral" }, - "segment": "fs" + "segment": "1" } ] }, @@ -3652,12 +3552,11 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha ] }, { - "diffTag": "both", + "diffTag": "old", "elements": [ { "annotation": { - "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", - "tag": "TypeReference" + "tag": "Parenthesis" }, "segment": ")" } @@ -3672,94 +3571,12 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "tag": "TypeReference" }, "segment": ")" - }, - { - "annotation": { - "tag": "Parenthesis" - }, - "segment": ")" - } - ] - }, - { - "diffTag": "both", - "elements": [ - { - "annotation": null, - "segment": "\n" - }, - { - "annotation": null, - "segment": " " - } - ] - }, - { - "diffTag": "annotationChange", - "fromAnnotation": { - "contents": "#bcar3v5qe5466tnl5vc1crcpo13mv0pbspfmtm0g9d9i66pp3og6f75bmk6bhv7ah09igb3un5pmdjdo5ghm0n6krnbne7u2ngi770g", - "tag": "TermReference" - }, - "segment": "foreach", - "toAnnotation": { - "contents": "#jb1dd16mkieu352mk4ijml6ksvobs3e31b6q0mt219rrnk9dt6o7rgs87b3kglpfo27nsqmu8ts4q8e55t44e6v894kg9d4361gj4po", - "tag": "TermReference" - } - }, - { - "diffTag": "both", - "elements": [ - { - "annotation": null, - "segment": " " } ] }, { "diffTag": "new", "elements": [ - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" - }, - { - "annotation": null, - "segment": " " - } - ] - }, - { - "diffTag": "both", - "elements": [ - { - "annotation": { - "tag": "Parenthesis" - }, - "segment": "(" - }, - { - "annotation": null, - "segment": "f" - }, - { - "annotation": { - "tag": "ControlKeyword" - }, - "segment": " ->" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", - "tag": "TypeReference" - }, - "segment": "(" - }, { "annotation": { "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", @@ -3774,21 +3591,6 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "segment": ")" } ] - }, - { - "diffTag": "old", - "elements": [ - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" - } - ] } ], "tag": "UserObject" @@ -3796,26 +3598,69 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "diffKind": "diff", "newBranchRef": "new", "newTerm": { - "bestTermName": "handleRequest", + "bestTermName": "unitCase", "defnTermTag": "Plain", "signature": [ { - "annotation": null, - "segment": "(" + "annotation": { + "tag": "Var" + }, + "segment": "x" }, { "annotation": null, - "segment": ")" - } - ], - "termDefinition": { - "contents": [ - { + "segment": " " + }, + { + "annotation": { + "tag": "TypeOperator" + }, + "segment": "->" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": "(" + }, + { + "annotation": { + "contents": "##Nat", + "tag": "TypeReference" + }, + "segment": "Nat" + }, + { + "annotation": null, + "segment": "," + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": "(" + }, + { + "annotation": null, + "segment": ")" + }, + { + "annotation": null, + "segment": ")" + } + ], + "termDefinition": { + "contents": [ + { "annotation": { - "contents": "handleRequest", + "contents": "unitCase", "tag": "HashQualifier" }, - "segment": "handleRequest" + "segment": "unitCase" }, { "annotation": { @@ -3827,126 +3672,67 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "annotation": null, "segment": " " }, - { - "annotation": null, - "segment": "(" - }, - { - "annotation": null, - "segment": ")" - }, - { - "annotation": null, - "segment": "\n" - }, - { - "annotation": { - "contents": "handleRequest", - "tag": "HashQualifier" - }, - "segment": "handleRequest" - }, { "annotation": { - "tag": "BindingEquals" + "tag": "Var" }, - "segment": " =" + "segment": "x" }, { "annotation": null, - "segment": "\n" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "finalizers", - "tag": "HashQualifier" - }, - "segment": "finalizers" + "segment": " " }, { "annotation": { - "tag": "BindingEquals" + "tag": "TypeOperator" }, - "segment": " =" + "segment": "->" }, { "annotation": null, "segment": " " }, { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": "[" - }, - { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "1" - }, - { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": ", " - }, - { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "2" + "annotation": null, + "segment": "(" }, { "annotation": { - "contents": "##Sequence", + "contents": "##Nat", "tag": "TypeReference" }, - "segment": ", " + "segment": "Nat" }, { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "3" + "annotation": null, + "segment": "," }, { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": "]" + "annotation": null, + "segment": " " }, { "annotation": null, - "segment": "\n" + "segment": "(" }, { "annotation": null, - "segment": " " + "segment": ")" }, { - "annotation": { - "contents": "addFinalizer", - "tag": "HashQualifier" - }, - "segment": "addFinalizer" + "annotation": null, + "segment": ")" }, { "annotation": null, - "segment": " " + "segment": "\n" }, { "annotation": { - "tag": "Var" + "contents": "unitCase", + "tag": "HashQualifier" }, - "segment": "f" + "segment": "unitCase" }, { "annotation": { @@ -3960,20 +3746,10 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": { - "contents": "#a85req9b0u8gkt82fgebosrcu3ba5g1aoqgt1vu5ohd93vpbdlo184e9pf9hgc4nml73aeohru6enhnnpch5oqilutaf0h40uv8dfvg", + "contents": "#ttjui80dbufvf3vgaddmcr065dpgl0rtp68i5cdht6tq4t2vk3i2vg60hi77rug368qijgijf8oui27te7o5oq0t0osm6dg65c080i0", "tag": "TermReference" }, - "segment": "fakeRefModify" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" + "segment": "id" }, { "annotation": null, @@ -3987,7 +3763,7 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": null, - "segment": "fs" + "segment": "x" }, { "annotation": { @@ -4008,30 +3784,9 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": { - "tag": "Var" - }, - "segment": "f" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "##List.cons", - "tag": "TermReference" - }, - "segment": "+:" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" + "tag": "NumericLiteral" }, - "segment": "fs" + "segment": "1" }, { "annotation": { @@ -4061,75 +3816,6 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, "segment": ")" }, - { - "annotation": { - "tag": "Parenthesis" - }, - "segment": ")" - }, - { - "annotation": null, - "segment": "\n" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "#jb1dd16mkieu352mk4ijml6ksvobs3e31b6q0mt219rrnk9dt6o7rgs87b3kglpfo27nsqmu8ts4q8e55t44e6v894kg9d4361gj4po", - "tag": "TermReference" - }, - "segment": "foreach" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Parenthesis" - }, - "segment": "(" - }, - { - "annotation": null, - "segment": "f" - }, - { - "annotation": { - "tag": "ControlKeyword" - }, - "segment": " ->" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", - "tag": "TypeReference" - }, - "segment": "(" - }, - { - "annotation": { - "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", - "tag": "TypeReference" - }, - "segment": ")" - }, { "annotation": { "tag": "Parenthesis" @@ -4141,31 +3827,50 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, "termDocs": [], "termNames": [ - "handleRequest" + "unitCase" ] }, "oldBranchRef": "main", "oldTerm": { - "bestTermName": "handleRequest", + "bestTermName": "unitCase", "defnTermTag": "Plain", "signature": [ + { + "annotation": { + "tag": "Var" + }, + "segment": "x" + }, { "annotation": null, - "segment": "(" + "segment": " " + }, + { + "annotation": { + "tag": "TypeOperator" + }, + "segment": "->" }, { "annotation": null, - "segment": ")" + "segment": " " + }, + { + "annotation": { + "contents": "##Nat", + "tag": "TypeReference" + }, + "segment": "Nat" } ], "termDefinition": { "contents": [ { "annotation": { - "contents": "handleRequest", + "contents": "unitCase", "tag": "HashQualifier" }, - "segment": "handleRequest" + "segment": "unitCase" }, { "annotation": { @@ -4177,51 +3882,21 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha "annotation": null, "segment": " " }, - { - "annotation": null, - "segment": "(" - }, - { - "annotation": null, - "segment": ")" - }, - { - "annotation": null, - "segment": "\n" - }, { "annotation": { - "contents": "handleRequest", - "tag": "HashQualifier" - }, - "segment": "handleRequest" - }, - { - "annotation": { - "tag": "BindingEquals" + "tag": "Var" }, - "segment": " =" + "segment": "x" }, { "annotation": null, - "segment": "\n" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "finalizers", - "tag": "HashQualifier" - }, - "segment": "finalizers" + "segment": " " }, { "annotation": { - "tag": "BindingEquals" + "tag": "TypeOperator" }, - "segment": " =" + "segment": "->" }, { "annotation": null, @@ -4229,74 +3904,21 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": "[" - }, - { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "1" - }, - { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": ", " - }, - { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "2" - }, - { - "annotation": { - "contents": "##Sequence", - "tag": "TypeReference" - }, - "segment": ", " - }, - { - "annotation": { - "tag": "NumericLiteral" - }, - "segment": "3" - }, - { - "annotation": { - "contents": "##Sequence", + "contents": "##Nat", "tag": "TypeReference" }, - "segment": "]" + "segment": "Nat" }, { "annotation": null, "segment": "\n" }, - { - "annotation": null, - "segment": " " - }, { "annotation": { - "contents": "addFinalizer", + "contents": "unitCase", "tag": "HashQualifier" }, - "segment": "addFinalizer" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "f" + "segment": "unitCase" }, { "annotation": { @@ -4310,92 +3932,10 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": { - "contents": "#a85req9b0u8gkt82fgebosrcu3ba5g1aoqgt1vu5ohd93vpbdlo184e9pf9hgc4nml73aeohru6enhnnpch5oqilutaf0h40uv8dfvg", - "tag": "TermReference" - }, - "segment": "fakeRefModify" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Parenthesis" - }, - "segment": "(" - }, - { - "annotation": null, - "segment": "fs" - }, - { - "annotation": { - "tag": "ControlKeyword" - }, - "segment": " ->" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "f" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "##List.cons", + "contents": "#ttjui80dbufvf3vgaddmcr065dpgl0rtp68i5cdht6tq4t2vk3i2vg60hi77rug368qijgijf8oui27te7o5oq0t0osm6dg65c080i0", "tag": "TermReference" }, - "segment": "+:" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "fs" - }, - { - "annotation": { - "tag": "Parenthesis" - }, - "segment": ")" - }, - { - "annotation": null, - "segment": "\n" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "contents": "#bcar3v5qe5466tnl5vc1crcpo13mv0pbspfmtm0g9d9i66pp3og6f75bmk6bhv7ah09igb3un5pmdjdo5ghm0n6krnbne7u2ngi770g", - "tag": "TermReference" - }, - "segment": "foreach" + "segment": "id" }, { "annotation": null, @@ -4409,7 +3949,7 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": null, - "segment": "f" + "segment": "x" }, { "annotation": { @@ -4423,40 +3963,22 @@ GET /api/projects/diffs/diff/terms?oldBranchRef=main&newBranchRef=new&oldTerm=ha }, { "annotation": { - "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", - "tag": "TypeReference" - }, - "segment": "(" - }, - { - "annotation": { - "contents": "#2lg4ah6ir6t129m33d7gssnigacral39qdamo20mn6r2vefliubpeqnjhejai9ekjckv0qnu9mlu3k9nbpfhl2schec4dohn7rjhjt8", - "tag": "TypeReference" + "tag": "NumericLiteral" }, - "segment": ")" + "segment": "1" }, { "annotation": { "tag": "Parenthesis" }, "segment": ")" - }, - { - "annotation": null, - "segment": " " - }, - { - "annotation": { - "tag": "Var" - }, - "segment": "finalizers" } ], "tag": "UserObject" }, "termDocs": [], "termNames": [ - "handleRequest" + "unitCase" ] }, "project": "diffs" From 4332f42f28531e68218ec8f773570d691104b60c Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 21 Nov 2024 13:52:43 -0800 Subject: [PATCH 109/113] Remove stray HasCallStack in Machine --- unison-runtime/src/Unison/Runtime/Machine.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 795d7a9d29..22b4add374 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1209,7 +1209,7 @@ uprim1 !stk COMI !i = do pure stk {-# INLINE uprim1 #-} -uprim2 :: (HasCallStack) => Stack -> UPrim2 -> Int -> Int -> IO Stack +uprim2 :: Stack -> UPrim2 -> Int -> Int -> IO Stack uprim2 !stk ADDI !i !j = do m <- upeekOff stk i n <- upeekOff stk j From 9b92ea27c5e820328c59cd365ce75da909cac407 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 21 Nov 2024 14:57:56 -0800 Subject: [PATCH 110/113] Gitignore more profiling files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 94b29b69e8..9af3e43c04 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ dist-newstyle *.hie *.prof *.prof.html +*.hp +*.ps /.direnv/ /.envrc From 547fdbf45eaad210766435ae5185c0226fa338e8 Mon Sep 17 00:00:00 2001 From: aryairani Date: Mon, 25 Nov 2024 15:23:42 +0000 Subject: [PATCH 111/113] rerun transcripts (reminder to rerun CI!) --- unison-src/transcripts/help.output.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unison-src/transcripts/help.output.md b/unison-src/transcripts/help.output.md index 510fe617cc..1b176f97b3 100644 --- a/unison-src/transcripts/help.output.md +++ b/unison-src/transcripts/help.output.md @@ -810,6 +810,9 @@ scratch/main> help undo `undo` reverts the most recent change to the codebase. + unsafe.force-push (or push.unsafe-force) + Like `push`, but forcibly overwrites the remote namespace. + update Adds everything in the most recently typechecked file to the namespace, replacing existing definitions having the same From c08c30906993c0c6376f15b5dc4620e62afa22d0 Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Mon, 25 Nov 2024 13:56:41 -0500 Subject: [PATCH 112/113] add failing transcript --- unison-src/transcripts/fix-5464.md | 37 ++++++++ unison-src/transcripts/fix-5464.output.md | 107 ++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 unison-src/transcripts/fix-5464.md create mode 100644 unison-src/transcripts/fix-5464.output.md diff --git a/unison-src/transcripts/fix-5464.md b/unison-src/transcripts/fix-5464.md new file mode 100644 index 0000000000..61bb5f3297 --- /dev/null +++ b/unison-src/transcripts/fix-5464.md @@ -0,0 +1,37 @@ +```ucm +scratch/main> builtins.merge lib.builtin +``` + +```unison +foo : Nat +foo = + baz = bar.baz + bar.baz + 19 + +bar.baz : Nat +bar.baz = 20 + +qux : Nat +qux = foo + foo +``` + +```ucm +scratch/main> add +``` + +```unison +foo : Nat +foo = + baz = bar.baz + bar.baz + 20 + +bar.baz : Nat +bar.baz = 20 +``` + +This update should succeed, but it fails because `foo` is incorrectly printed with a `use bar baz` statement, which +causes references to `bar.baz` to be captured by its locally-bound `baz`. + +```ucm:error +scratch/main> update +``` diff --git a/unison-src/transcripts/fix-5464.output.md b/unison-src/transcripts/fix-5464.output.md new file mode 100644 index 0000000000..76755a8147 --- /dev/null +++ b/unison-src/transcripts/fix-5464.output.md @@ -0,0 +1,107 @@ +``` ucm +scratch/main> builtins.merge lib.builtin + + Done. + +``` +``` unison +foo : Nat +foo = + baz = bar.baz + bar.baz + 19 + +bar.baz : Nat +bar.baz = 20 + +qux : Nat +qux = foo + foo +``` + +``` ucm + + Loading changes detected in scratch.u. + + I found and typechecked these definitions in scratch.u. If you + do an `add` or `update`, here's how your codebase would + change: + + ⍟ These new definitions are ok to `add`: + + bar.baz : Nat + foo : Nat + qux : Nat + +``` +``` ucm +scratch/main> add + + ⍟ I've added these definitions: + + bar.baz : Nat + foo : Nat + qux : Nat + +``` +``` unison +foo : Nat +foo = + baz = bar.baz + bar.baz + 20 + +bar.baz : Nat +bar.baz = 20 +``` + +``` 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: + + ⊡ Previously added definitions will be ignored: bar.baz + + ⍟ These names already exist. You can `update` them to your + new definition: + + foo : Nat + +``` +This update should succeed, but it fails because `foo` is incorrectly printed with a `use bar baz` statement, which +causes references to `bar.baz` to be captured by its locally-bound `baz`. + +``` ucm +scratch/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 +foo : Nat +foo = + use Nat + + use bar baz + baz = baz + baz + 20 + +bar.baz : Nat +bar.baz = 20 + +-- The definitions below no longer typecheck with the changes above. +-- Please fix the errors and try `update` again. + +qux : Nat +qux = + use Nat + + foo + foo + +``` + From f37d8449a503284f1345702c9315aae34325d745 Mon Sep 17 00:00:00 2001 From: Mitchell Dalvi Rosen Date: Mon, 25 Nov 2024 14:44:58 -0500 Subject: [PATCH 113/113] bugfix: don't consider shortening variables with use statements --- .../src/Unison/Syntax/TermPrinter.hs | 1 - unison-src/transcripts/fix-5464.md | 6 ++-- unison-src/transcripts/fix-5464.output.md | 29 +++---------------- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/parser-typechecker/src/Unison/Syntax/TermPrinter.hs b/parser-typechecker/src/Unison/Syntax/TermPrinter.hs index f506467a39..e516fb404a 100644 --- a/parser-typechecker/src/Unison/Syntax/TermPrinter.hs +++ b/parser-typechecker/src/Unison/Syntax/TermPrinter.hs @@ -1285,7 +1285,6 @@ instance Monoid PrintAnnotation where suffixCounterTerm :: (Var v) => PrettyPrintEnv -> Set Name -> Set Name -> Term2 v at ap v a -> PrintAnnotation suffixCounterTerm n usedTm usedTy = \case - Var' v -> countHQ mempty $ HQ.unsafeFromVar v Ref' r -> countHQ usedTm $ PrettyPrintEnv.termName n (Referent.Ref r) Constructor' r | noImportRefs (r ^. ConstructorReference.reference_) -> mempty Constructor' r -> countHQ usedTm $ PrettyPrintEnv.termName n (Referent.Con r CT.Data) diff --git a/unison-src/transcripts/fix-5464.md b/unison-src/transcripts/fix-5464.md index 61bb5f3297..2bec8ec9e3 100644 --- a/unison-src/transcripts/fix-5464.md +++ b/unison-src/transcripts/fix-5464.md @@ -29,9 +29,9 @@ bar.baz : Nat bar.baz = 20 ``` -This update should succeed, but it fails because `foo` is incorrectly printed with a `use bar baz` statement, which -causes references to `bar.baz` to be captured by its locally-bound `baz`. +This update used to fail because `foo` would incorrectly print with a `use bar baz` statement, which caused references +to `bar.baz` to be captured by its locally-bound `baz`. -```ucm:error +```ucm scratch/main> update ``` diff --git a/unison-src/transcripts/fix-5464.output.md b/unison-src/transcripts/fix-5464.output.md index 76755a8147..aa1c7aa6ea 100644 --- a/unison-src/transcripts/fix-5464.output.md +++ b/unison-src/transcripts/fix-5464.output.md @@ -68,8 +68,8 @@ bar.baz = 20 foo : Nat ``` -This update should succeed, but it fails because `foo` is incorrectly printed with a `use bar baz` statement, which -causes references to `bar.baz` to be captured by its locally-bound `baz`. +This update used to fail because `foo` would incorrectly print with a `use bar baz` statement, which caused references +to `bar.baz` to be captured by its locally-bound `baz`. ``` ucm scratch/main> update @@ -79,29 +79,8 @@ scratch/main> update 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. + Everything typechecks, so I'm saving the results... -``` -``` unison :added-by-ucm scratch.u -foo : Nat -foo = - use Nat + - use bar baz - baz = baz + baz - 20 - -bar.baz : Nat -bar.baz = 20 - --- The definitions below no longer typecheck with the changes above. --- Please fix the errors and try `update` again. - -qux : Nat -qux = - use Nat + - foo + foo + Done. ``` -