@greenpandastudios/aug-cli 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/THIRD_PARTY_NOTICES.md +4 -0
- package/bin/aug.mjs +12 -2
- package/docs/about.md +27 -0
- package/docs/api/crypto.md +103 -69
- package/docs/api/io.md +35 -33
- package/docs/api/json.md +3 -3
- package/docs/api/memory.md +23 -19
- package/docs/api/time.md +10 -9
- package/docs/api/web.md +33 -38
- package/docs/assets/benchmarks/execution.svg +774 -637
- package/docs/assets/benchmarks/http.svg +278 -249
- package/docs/assets/benchmarks/improvements.svg +66 -66
- package/docs/assets/benchmarks/kernels-mobile.svg +1 -0
- package/docs/assets/benchmarks/kernels.svg +1 -0
- package/docs/assets/benchmarks/memory.svg +153 -153
- package/docs/benchmark-results.json +227089 -90363
- package/docs/compatibility.md +8 -8
- package/docs/contributing-benchmarks.md +68 -0
- package/docs/dev-containers.md +88 -0
- package/docs/dgx-consumers.json +122 -0
- package/docs/dgx-gyms.json +784 -0
- package/docs/dgx-kernels.json +1170 -0
- package/docs/dgx-performance.json +227849 -0
- package/docs/dgx-spark.md +64 -0
- package/docs/diagnostics.md +15 -5
- package/docs/docker.md +173 -12
- package/docs/editor.md +35 -0
- package/docs/example-projects.json +238 -24
- package/docs/examples/approved-design/counters.md +34 -126
- package/docs/examples/approved-design/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/approved-design/domain/app.md +13 -77
- package/docs/examples/approved-design/domain/export.md +5 -19
- package/docs/examples/approved-design/domain/models.md +4 -23
- package/docs/examples/approved-design/domain/numbers.md +24 -114
- package/docs/examples/approved-design/index.md +16 -7
- package/docs/examples/approved-design/main.md +19 -96
- package/docs/examples/benchmark/index.md +6 -5
- package/docs/examples/benchmark/main.md +7 -35
- package/docs/examples/calls-benchmark/index.md +36 -0
- package/docs/examples/calls-benchmark/main.md +78 -0
- package/docs/examples/calls-benchmark/operations.md +60 -0
- package/docs/examples/cli-args/index.md +6 -5
- package/docs/examples/cli-args/main.md +6 -31
- package/docs/examples/collections/index.md +6 -5
- package/docs/examples/collections/main.md +7 -35
- package/docs/examples/collections-benchmark/index.md +6 -5
- package/docs/examples/collections-benchmark/main.md +7 -35
- package/docs/examples/cpu-benchmark/index.md +6 -5
- package/docs/examples/cpu-benchmark/main.md +5 -24
- package/docs/examples/developer-workflow/calculator.md +39 -186
- package/docs/examples/developer-workflow/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/developer-workflow/index.md +16 -7
- package/docs/examples/developer-workflow/logging/console.md +10 -56
- package/docs/examples/developer-workflow/logging/export.md +4 -14
- package/docs/examples/developer-workflow/logging/logger.md +7 -43
- package/docs/examples/developer-workflow/main.md +17 -69
- package/docs/examples/drop/index.md +6 -5
- package/docs/examples/drop/main.md +7 -27
- package/docs/examples/drop/resource.md +7 -30
- package/docs/examples/errors/errors.md +7 -27
- package/docs/examples/errors/index.md +6 -5
- package/docs/examples/errors/main.md +7 -28
- package/docs/examples/errors-benchmark/index.md +36 -0
- package/docs/examples/errors-benchmark/main.md +92 -0
- package/docs/examples/errors-benchmark/operations.md +65 -0
- package/docs/examples/ffi/index.md +6 -5
- package/docs/examples/ffi/main.md +6 -20
- package/docs/examples/ffi/native.md +8 -34
- package/docs/examples/float-benchmark/index.md +35 -0
- package/docs/examples/float-benchmark/main.md +75 -0
- package/docs/examples/generic-di/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/generic-di/index.md +6 -5
- package/docs/examples/generic-di/main.md +9 -39
- package/docs/examples/generic-di/types.md +23 -92
- package/docs/examples/generics/index.md +6 -5
- package/docs/examples/generics/main.md +10 -47
- package/docs/examples/generics/types.md +25 -100
- package/docs/examples/hello/app/export.md +4 -12
- package/docs/examples/hello/app/greeter.md +13 -91
- package/docs/examples/hello/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/hello/index.md +17 -6
- package/docs/examples/hello/logging/console.md +10 -54
- package/docs/examples/hello/logging/export.md +4 -14
- package/docs/examples/hello/logging/logger.md +7 -45
- package/docs/examples/hello/main.md +9 -39
- package/docs/examples/http-benchmark/index.md +6 -5
- package/docs/examples/http-benchmark/main.md +6 -20
- package/docs/examples/http-benchmark/routes.md +9 -31
- package/docs/examples/index.md +63 -29
- package/docs/examples/interceptors/app.md +20 -139
- package/docs/examples/interceptors/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/interceptors/index.md +6 -5
- package/docs/examples/interceptors/interceptors.md +24 -148
- package/docs/examples/interceptors/logging.md +13 -76
- package/docs/examples/interceptors/main.md +10 -65
- package/docs/examples/json-benchmark/data.md +4 -20
- package/docs/examples/json-benchmark/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
- package/docs/examples/json-benchmark/index.md +7 -5
- package/docs/examples/json-benchmark/main-yaml.md +20 -0
- package/docs/examples/json-benchmark/main.md +10 -49
- package/docs/examples/list-benchmark/index.md +35 -0
- package/docs/examples/list-benchmark/main.md +78 -0
- package/docs/examples/map-churn-benchmark/index.md +35 -0
- package/docs/examples/map-churn-benchmark/main.md +106 -0
- package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/api.md +104 -0
- package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.md +54 -0
- package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi-json.md +48 -0
- package/docs/examples/native-blake3/hashing.md +93 -0
- package/docs/examples/native-blake3/index.md +38 -0
- package/docs/examples/native-blake3/main.md +73 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/api.md +406 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.md +51 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.md +63 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi-json.md +161 -0
- package/docs/examples/native-pytorch/index.md +38 -0
- package/docs/examples/native-pytorch/main.md +73 -0
- package/docs/examples/native-pytorch/tensors.md +123 -0
- package/docs/examples/native-sqlite/database.md +116 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/api.md +284 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.md +51 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.md +75 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi-json.md +119 -0
- package/docs/examples/native-sqlite/index.md +38 -0
- package/docs/examples/native-sqlite/main.md +73 -0
- package/docs/examples/native-zlib/compression.md +99 -0
- package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/api.md +153 -0
- package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.md +54 -0
- package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi-json.md +76 -0
- package/docs/examples/native-zlib/index.md +38 -0
- package/docs/examples/native-zlib/main.md +78 -0
- package/docs/examples/new-syntax/console.md +10 -52
- package/docs/examples/new-syntax/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/new-syntax/greeter.md +13 -71
- package/docs/examples/new-syntax/index.md +6 -5
- package/docs/examples/new-syntax/logger.md +7 -43
- package/docs/examples/new-syntax/main.md +10 -53
- package/docs/examples/new-syntax/math.md +6 -24
- package/docs/examples/oidc-login/client/contracts.md +10 -61
- package/docs/examples/oidc-login/client/endpoints.md +32 -154
- package/docs/examples/oidc-login/client/export.md +5 -23
- package/docs/examples/oidc-login/client/login.md +234 -344
- package/docs/examples/oidc-login/client/logout.md +38 -143
- package/docs/examples/oidc-login/client/protocol.md +183 -304
- package/docs/examples/oidc-login/client/session.md +41 -149
- package/docs/examples/oidc-login/client/views.md +13 -58
- package/docs/examples/oidc-login/common/export.md +6 -26
- package/docs/examples/oidc-login/common/headers.md +42 -72
- package/docs/examples/oidc-login/common/keys.md +40 -164
- package/docs/examples/oidc-login/common/settings.md +24 -40
- package/docs/examples/oidc-login/common/views.md +7 -28
- package/docs/examples/oidc-login/dependencies/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md +205 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +267 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md +415 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.md +271 -0
- package/docs/examples/oidc-login/dependencies/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +89 -0
- package/docs/examples/oidc-login/index.md +8 -7
- package/docs/examples/oidc-login/main-yaml.md +7 -0
- package/docs/examples/oidc-login/main.md +26 -153
- package/docs/examples/oidc-login/provider/authorization.md +232 -275
- package/docs/examples/oidc-login/provider/contracts.md +24 -146
- package/docs/examples/oidc-login/provider/credentials.md +24 -57
- package/docs/examples/oidc-login/provider/discovery.md +48 -122
- package/docs/examples/oidc-login/provider/export.md +11 -37
- package/docs/examples/oidc-login/provider/token.md +159 -237
- package/docs/examples/oidc-login/provider/userinfo.md +47 -102
- package/docs/examples/oidc-login/provider/views.md +13 -53
- package/docs/examples/ownership/counter.md +17 -63
- package/docs/examples/ownership/index.md +6 -5
- package/docs/examples/ownership/main.md +7 -30
- package/docs/examples/ownership-transfer/dependencies/august/0.21.0/io/contracts.md +178 -0
- package/docs/examples/ownership-transfer/index.md +6 -5
- package/docs/examples/ownership-transfer/main.md +10 -52
- package/docs/examples/ownership-transfer/resource.md +15 -67
- package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +12 -50
- package/docs/examples/packages-app/index.md +7 -6
- package/docs/examples/packages-app/main.md +7 -25
- package/docs/examples/packages-math/aug-package-json.md +1 -1
- package/docs/examples/packages-math/index.md +7 -6
- package/docs/examples/packages-math/src/arithmetic.md +12 -50
- package/docs/examples/packages-math/src/export.md +4 -12
- package/docs/examples/records-benchmark/data.md +55 -0
- package/docs/examples/records-benchmark/index.md +36 -0
- package/docs/examples/records-benchmark/main.md +85 -0
- package/docs/examples/startup-benchmark/index.md +6 -5
- package/docs/examples/startup-benchmark/main.md +5 -17
- package/docs/examples/strings-benchmark/index.md +35 -0
- package/docs/examples/strings-benchmark/main.md +76 -0
- package/docs/examples/tasks-benchmark/index.md +36 -0
- package/docs/examples/tasks-benchmark/main.md +89 -0
- package/docs/examples/tasks-benchmark/operations.md +58 -0
- package/docs/examples/visibility/counter.md +19 -67
- package/docs/examples/visibility/index.md +6 -5
- package/docs/examples/visibility/main.md +7 -31
- package/docs/examples/weather-api/forecasts.md +168 -0
- package/docs/examples/weather-api/index.md +42 -0
- package/docs/examples/weather-api/main-yaml.md +21 -0
- package/docs/examples/weather-api/main.md +65 -0
- package/docs/examples.json +10 -0
- package/docs/getting-started.md +105 -2
- package/docs/grammar.md +7 -5
- package/docs/guides/change-a-module.md +64 -0
- package/docs/guides/index.md +27 -0
- package/docs/gym-results.json +784 -0
- package/docs/implementation-map.md +6 -0
- package/docs/index.md +51 -29
- package/docs/kernel-results.json +1170 -0
- package/docs/language-conformance.md +7 -1
- package/docs/language-constructs.md +30 -22
- package/docs/language-design-audit.md +1 -1
- package/docs/learn/data-and-errors.md +77 -0
- package/docs/learn/index.md +30 -0
- package/docs/learn/modules-and-dependencies.md +73 -0
- package/docs/learn/state-and-tests.md +71 -0
- package/docs/learn/values-and-functions.md +62 -0
- package/docs/lesson-failures.json +8 -0
- package/docs/maintaining-docs.md +16 -4
- package/docs/native-implementation.md +276 -0
- package/docs/native-interop-llvm-plan.md +342 -0
- package/docs/native-package-examples.md +684 -0
- package/docs/native-packages.md +179 -0
- package/docs/packages.md +72 -126
- package/docs/performance.md +61 -68
- package/docs/production-readiness.md +16 -5
- package/docs/public/downloads/approved-design.zip +0 -0
- package/docs/public/downloads/benchmark.zip +0 -0
- package/docs/public/downloads/calls-benchmark.zip +0 -0
- package/docs/public/downloads/cli-args.zip +0 -0
- package/docs/public/downloads/collections-benchmark.zip +0 -0
- package/docs/public/downloads/collections.zip +0 -0
- package/docs/public/downloads/cpu-benchmark.zip +0 -0
- package/docs/public/downloads/developer-workflow.zip +0 -0
- package/docs/public/downloads/drop.zip +0 -0
- package/docs/public/downloads/errors-benchmark.zip +0 -0
- package/docs/public/downloads/errors.zip +0 -0
- package/docs/public/downloads/ffi.zip +0 -0
- package/docs/public/downloads/float-benchmark.zip +0 -0
- package/docs/public/downloads/generic-di.zip +0 -0
- package/docs/public/downloads/generics.zip +0 -0
- package/docs/public/downloads/hello.zip +0 -0
- package/docs/public/downloads/http-benchmark.zip +0 -0
- package/docs/public/downloads/interceptors.zip +0 -0
- package/docs/public/downloads/json-benchmark.zip +0 -0
- package/docs/public/downloads/list-benchmark.zip +0 -0
- package/docs/public/downloads/map-churn-benchmark.zip +0 -0
- package/docs/public/downloads/native-blake3.zip +0 -0
- package/docs/public/downloads/native-pytorch.zip +0 -0
- package/docs/public/downloads/native-sqlite.zip +0 -0
- package/docs/public/downloads/native-zlib.zip +0 -0
- package/docs/public/downloads/new-syntax.zip +0 -0
- package/docs/public/downloads/oidc-login.zip +0 -0
- package/docs/public/downloads/ownership-transfer.zip +0 -0
- package/docs/public/downloads/ownership.zip +0 -0
- package/docs/public/downloads/packages-app.zip +0 -0
- package/docs/public/downloads/packages-math.zip +0 -0
- package/docs/public/downloads/records-benchmark.zip +0 -0
- package/docs/public/downloads/startup-benchmark.zip +0 -0
- package/docs/public/downloads/strings-benchmark.zip +0 -0
- package/docs/public/downloads/tasks-benchmark.zip +0 -0
- package/docs/public/downloads/visibility.zip +0 -0
- package/docs/public/downloads/weather-api.zip +0 -0
- package/docs/qualification-results.md +66 -0
- package/docs/reference.md +47 -17
- package/docs/releasing.md +105 -16
- package/docs/research/code-to-natural-language.md +108 -0
- package/docs/research/ecosystem-workflow.md +41 -0
- package/docs/research/libtorch-native-qualification.md +115 -0
- package/docs/research/native-interop-llvm.md +197 -0
- package/docs/research/qualification-methods.md +15 -0
- package/docs/research/wiki-editorial-design.md +71 -0
- package/docs/roadmap.md +2 -1
- package/docs/safety-gyms.md +41 -0
- package/docs/specifications.md +27 -11
- package/docs/testing.md +19 -5
- package/docs/tooling.md +36 -22
- package/docs/weather-api.md +65 -0
- package/docs/web-library-gaps.md +1 -1
- package/docs/web.md +54 -18
- package/docs/writing-docs.md +49 -0
- package/examples/{hello/.aug-spec/august/0.19.0 → approved-design/.aug-spec/august/0.21.0}/io/contracts.aug +4 -3
- package/examples/approved-design/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/approved-design/.aug-spec/manifest.json +3 -3
- package/examples/approved-design/counters.aug +5 -4
- package/examples/approved-design/counters.aug.md +25 -132
- package/examples/approved-design/domain/app.aug +2 -1
- package/examples/approved-design/domain/app.aug.md +10 -80
- package/examples/approved-design/domain/export.aug +1 -0
- package/examples/approved-design/domain/export.aug.md +4 -20
- package/examples/approved-design/domain/models.aug +1 -0
- package/examples/approved-design/domain/models.aug.md +3 -25
- package/examples/approved-design/domain/numbers.aug +3 -2
- package/examples/approved-design/domain/numbers.aug.md +19 -116
- package/examples/approved-design/main.aug +1 -0
- package/examples/approved-design/main.aug.md +12 -95
- package/examples/benchmark/.aug-spec/manifest.json +1 -1
- package/examples/benchmark/main.aug +1 -0
- package/examples/benchmark/main.aug.md +6 -36
- package/examples/cli-args/.aug-spec/manifest.json +1 -1
- package/examples/cli-args/main.aug +1 -0
- package/examples/cli-args/main.aug.md +5 -32
- package/examples/collections/.aug-spec/manifest.json +1 -1
- package/examples/collections/main.aug +1 -0
- package/examples/collections/main.aug.md +6 -36
- package/examples/{generic-di/.aug-spec/august/0.19.0 → developer-workflow/.aug-spec/august/0.21.0}/io/contracts.aug +4 -3
- package/examples/developer-workflow/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
- package/examples/developer-workflow/calculator.aug +3 -2
- package/examples/developer-workflow/calculator.aug.md +28 -189
- package/examples/developer-workflow/logging/console.aug +2 -1
- package/examples/developer-workflow/logging/console.aug.md +7 -57
- package/examples/developer-workflow/logging/export.aug +1 -0
- package/examples/developer-workflow/logging/export.aug.md +3 -15
- package/examples/developer-workflow/logging/logger.aug +1 -0
- package/examples/developer-workflow/logging/logger.aug.md +6 -46
- package/examples/developer-workflow/main.aug +1 -0
- package/examples/developer-workflow/main.aug.md +10 -68
- package/examples/drop/.aug-spec/manifest.json +1 -1
- package/examples/drop/main.aug +1 -0
- package/examples/drop/main.aug.md +6 -28
- package/examples/drop/resource.aug +1 -0
- package/examples/drop/resource.aug.md +6 -34
- package/examples/errors/.aug-spec/manifest.json +1 -1
- package/examples/errors/errors.aug +2 -1
- package/examples/errors/errors.aug.md +4 -27
- package/examples/errors/main.aug +1 -0
- package/examples/errors/main.aug.md +6 -29
- package/examples/ffi/.aug-spec/manifest.json +1 -1
- package/examples/ffi/main.aug +1 -0
- package/examples/ffi/main.aug.md +5 -21
- package/examples/ffi/native.aug +2 -1
- package/examples/ffi/native.aug.md +5 -35
- package/examples/{approved-design/.aug-spec/august/0.19.0 → generic-di/.aug-spec/august/0.21.0}/io/contracts.aug +4 -3
- package/examples/generic-di/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/generic-di/.aug-spec/manifest.json +3 -3
- package/examples/generic-di/main.aug +1 -0
- package/examples/generic-di/main.aug.md +8 -40
- package/examples/generic-di/types.aug +3 -2
- package/examples/generic-di/types.aug.md +18 -97
- package/examples/generics/.aug-spec/manifest.json +1 -1
- package/examples/generics/main.aug +1 -0
- package/examples/generics/main.aug.md +9 -48
- package/examples/generics/types.aug +4 -3
- package/examples/generics/types.aug.md +18 -104
- package/examples/{developer-workflow/.aug-spec/august/0.19.0 → hello/.aug-spec/august/0.21.0}/io/contracts.aug +4 -3
- package/examples/hello/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/hello/.aug-spec/manifest.json +3 -3
- package/examples/hello/app/export.aug +1 -0
- package/examples/hello/app/export.aug.md +3 -13
- package/examples/hello/app/greeter.aug +2 -1
- package/examples/hello/app/greeter.aug.md +10 -94
- package/examples/hello/logging/console.aug +2 -1
- package/examples/hello/logging/console.aug.md +7 -55
- package/examples/hello/logging/export.aug +1 -0
- package/examples/hello/logging/export.aug.md +3 -15
- package/examples/hello/logging/logger.aug +1 -0
- package/examples/hello/logging/logger.aug.md +6 -48
- package/examples/hello/main.aug +1 -0
- package/examples/hello/main.aug.md +8 -40
- package/examples/interceptors/.aug-spec/august/0.21.0/io/contracts.aug +37 -0
- package/examples/interceptors/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/interceptors/.aug-spec/manifest.json +3 -3
- package/examples/interceptors/app.aug +3 -2
- package/examples/interceptors/app.aug.md +15 -141
- package/examples/interceptors/interceptors.aug +3 -2
- package/examples/interceptors/interceptors.aug.md +19 -152
- package/examples/interceptors/logging.aug +2 -1
- package/examples/interceptors/logging.aug.md +10 -79
- package/examples/interceptors/main.aug +1 -0
- package/examples/interceptors/main.aug.md +9 -66
- package/examples/native-blake3/.aug-spec/manifest.json +16 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.1/native.abi.json +29 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug +14 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug.md +34 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug +4 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug.md +8 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi.json +29 -0
- package/examples/native-blake3/AGENTS.md +5 -0
- package/examples/native-blake3/aug.lock.json +253 -0
- package/examples/native-blake3/hashing.aug +11 -0
- package/examples/native-blake3/hashing.aug.md +25 -0
- package/examples/native-blake3/main.aug +8 -0
- package/examples/native-blake3/main.aug.md +13 -0
- package/examples/native-pytorch/.aug-spec/manifest.json +18 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.1/native.abi.json +142 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.3/native.abi.json +142 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug +101 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug.md +160 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug +3 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug.md +8 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug +6 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug.md +13 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi.json +142 -0
- package/examples/native-pytorch/AGENTS.md +5 -0
- package/examples/native-pytorch/aug.lock.json +309 -0
- package/examples/native-pytorch/main.aug +8 -0
- package/examples/native-pytorch/main.aug.md +13 -0
- package/examples/native-pytorch/tensors.aug +23 -0
- package/examples/native-pytorch/tensors.aug.md +35 -0
- package/examples/native-sqlite/.aug-spec/manifest.json +18 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.2/native.abi.json +100 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug +48 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug.md +91 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug +3 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug.md +8 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug +8 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug.md +22 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi.json +100 -0
- package/examples/native-sqlite/AGENTS.md +5 -0
- package/examples/native-sqlite/aug.lock.json +236 -0
- package/examples/native-sqlite/database.aug +15 -0
- package/examples/native-sqlite/database.aug.md +27 -0
- package/examples/native-sqlite/main.aug +8 -0
- package/examples/native-sqlite/main.aug.md +13 -0
- package/examples/native-zlib/.aug-spec/manifest.json +16 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.1/native.abi.json +57 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug +29 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug.md +54 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug +4 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug.md +8 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi.json +57 -0
- package/examples/native-zlib/AGENTS.md +5 -0
- package/examples/native-zlib/aug.lock.json +236 -0
- package/examples/native-zlib/compression.aug +15 -0
- package/examples/native-zlib/compression.aug.md +27 -0
- package/examples/native-zlib/main.aug +10 -0
- package/examples/native-zlib/main.aug.md +13 -0
- package/examples/new-syntax/.aug-spec/august/0.21.0/io/contracts.aug +37 -0
- package/examples/new-syntax/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/new-syntax/.aug-spec/manifest.json +3 -3
- package/examples/new-syntax/console.aug +2 -1
- package/examples/new-syntax/console.aug.md +7 -53
- package/examples/new-syntax/greeter.aug +2 -1
- package/examples/new-syntax/greeter.aug.md +10 -74
- package/examples/new-syntax/logger.aug +1 -0
- package/examples/new-syntax/logger.aug.md +6 -46
- package/examples/new-syntax/main.aug +1 -0
- package/examples/new-syntax/main.aug.md +9 -54
- package/examples/new-syntax/math.aug +2 -1
- package/examples/new-syntax/math.aug.md +3 -24
- package/examples/oidc-login/.aug-spec/manifest.json +13 -13
- package/examples/oidc-login/.aug-spec/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.aug.md +71 -0
- package/examples/oidc-login/.aug-spec/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +17 -0
- package/examples/oidc-login/.aug-spec/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +125 -0
- package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/contracts.aug +12 -11
- package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.aug.md +244 -0
- package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/jose.aug +6 -5
- package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.aug.md +71 -0
- package/examples/oidc-login/.aug-spec/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +30 -0
- package/examples/oidc-login/aug.lock.json +100 -0
- package/examples/oidc-login/client/contracts.aug +1 -0
- package/examples/oidc-login/client/contracts.aug.md +9 -66
- package/examples/oidc-login/client/endpoints.aug +6 -5
- package/examples/oidc-login/client/endpoints.aug.md +13 -145
- package/examples/oidc-login/client/export.aug +1 -0
- package/examples/oidc-login/client/export.aug.md +4 -24
- package/examples/oidc-login/client/login.aug +7 -6
- package/examples/oidc-login/client/login.aug.md +25 -303
- package/examples/oidc-login/client/logout.aug +5 -4
- package/examples/oidc-login/client/logout.aug.md +13 -135
- package/examples/oidc-login/client/protocol.aug +7 -6
- package/examples/oidc-login/client/protocol.aug.md +36 -283
- package/examples/oidc-login/client/session.aug +5 -4
- package/examples/oidc-login/client/session.aug.md +12 -139
- package/examples/oidc-login/client/views.aug +3 -2
- package/examples/oidc-login/client/views.aug.md +8 -57
- package/examples/oidc-login/common/export.aug +1 -0
- package/examples/oidc-login/common/export.aug.md +5 -27
- package/examples/oidc-login/common/headers.aug +4 -3
- package/examples/oidc-login/common/headers.aug.md +9 -67
- package/examples/oidc-login/common/keys.aug +6 -5
- package/examples/oidc-login/common/keys.aug.md +29 -165
- package/examples/oidc-login/common/settings.aug +2 -1
- package/examples/oidc-login/common/settings.aug.md +5 -39
- package/examples/oidc-login/common/views.aug +2 -1
- package/examples/oidc-login/common/views.aug.md +4 -28
- package/examples/oidc-login/main.aug +6 -16
- package/examples/oidc-login/main.aug.md +17 -146
- package/examples/oidc-login/main.yaml +7 -0
- package/examples/oidc-login/provider/authorization.aug +7 -6
- package/examples/oidc-login/provider/authorization.aug.md +23 -238
- package/examples/oidc-login/provider/contracts.aug +1 -0
- package/examples/oidc-login/provider/contracts.aug.md +23 -158
- package/examples/oidc-login/provider/credentials.aug +3 -2
- package/examples/oidc-login/provider/credentials.aug.md +9 -53
- package/examples/oidc-login/provider/discovery.aug +4 -3
- package/examples/oidc-login/provider/discovery.aug.md +11 -118
- package/examples/oidc-login/provider/export.aug +1 -0
- package/examples/oidc-login/provider/export.aug.md +6 -34
- package/examples/oidc-login/provider/token.aug +6 -5
- package/examples/oidc-login/provider/token.aug.md +16 -204
- package/examples/oidc-login/provider/userinfo.aug +4 -3
- package/examples/oidc-login/provider/userinfo.aug.md +10 -92
- package/examples/oidc-login/provider/views.aug +3 -2
- package/examples/oidc-login/provider/views.aug.md +8 -52
- package/examples/ownership/.aug-spec/manifest.json +1 -1
- package/examples/ownership/counter.aug +3 -2
- package/examples/ownership/counter.aug.md +12 -66
- package/examples/ownership/main.aug +1 -0
- package/examples/ownership/main.aug.md +6 -31
- package/examples/ownership-transfer/.aug-spec/august/0.21.0/io/contracts.aug +37 -0
- package/examples/ownership-transfer/.aug-spec/august/0.21.0/io/contracts.aug.md +82 -0
- package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
- package/examples/ownership-transfer/main.aug +1 -0
- package/examples/ownership-transfer/main.aug.md +9 -53
- package/examples/ownership-transfer/resource.aug +2 -1
- package/examples/ownership-transfer/resource.aug.md +12 -71
- package/examples/packages/app/.aug-spec/manifest.json +1 -1
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +2 -1
- package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +9 -51
- package/examples/packages/app/main.aug +1 -0
- package/examples/packages/app/main.aug.md +6 -26
- package/examples/packages/math/.aug-spec/manifest.json +1 -1
- package/examples/packages/math/aug-package.json +1 -1
- package/examples/packages/math/src/arithmetic.aug +2 -1
- package/examples/packages/math/src/arithmetic.aug.md +9 -51
- package/examples/packages/math/src/export.aug +1 -0
- package/examples/packages/math/src/export.aug.md +3 -13
- package/examples/visibility/.aug-spec/manifest.json +1 -1
- package/examples/visibility/counter.aug +4 -3
- package/examples/visibility/counter.aug.md +12 -68
- package/examples/visibility/main.aug +1 -0
- package/examples/visibility/main.aug.md +6 -32
- package/examples/weather-api/.aug-spec/manifest.json +8 -0
- package/examples/weather-api/AGENTS.md +17 -0
- package/examples/weather-api/README.md +19 -0
- package/examples/weather-api/forecasts.aug +47 -0
- package/examples/weather-api/forecasts.aug.md +32 -0
- package/examples/weather-api/main.aug +4 -0
- package/examples/weather-api/main.aug.md +15 -0
- package/examples/weather-api/main.yaml +5 -0
- package/examples/weather-api/weather.http +5 -0
- package/native/compiler-packs.json +43 -0
- package/package.json +4 -4
- package/runtime/aug_http.c +48 -21
- package/runtime/aug_http_ir.c +30 -0
- package/runtime/aug_http_ir.h +18 -0
- package/runtime/aug_ir.c +209 -0
- package/runtime/aug_ir.h +89 -0
- package/runtime/aug_json.c +6 -1
- package/runtime/aug_runtime.c +82 -16
- package/runtime/aug_runtime.h +16 -2
- package/runtime/aug_tasks.c +38 -7
- package/runtime/aug_values.c +12 -6
- package/scripts/bootstrap-native.mjs +184 -106
- package/scripts/native-setup.mjs +98 -0
- package/scripts/native-toolchain.mjs +28 -0
- package/src/ast.js +1 -1
- package/src/builtins.js +1 -1
- package/src/checker.js +369 -100
- package/src/cli.js +198 -26
- package/src/codegen.js +32 -7
- package/src/compiler-packs.js +66 -0
- package/src/config.js +3 -3
- package/src/contracts.js +10 -0
- package/src/editor.js +86 -22
- package/src/fixes.js +90 -2
- package/src/formatter.js +23 -10
- package/src/git-http.js +137 -0
- package/src/git-packages.js +118 -0
- package/src/help.js +33 -24
- package/src/http-contracts.js +14 -0
- package/src/http-policies.js +5 -5
- package/src/ir-types.js +5 -0
- package/src/ir-verify.js +277 -0
- package/src/ir.js +962 -0
- package/src/libraries.js +1 -1
- package/src/llvm-debug.js +101 -0
- package/src/llvm-native.js +152 -0
- package/src/llvm-platform.js +20 -0
- package/src/llvm.js +781 -0
- package/src/lsp.js +14 -5
- package/src/native-artifacts.js +207 -0
- package/src/native-bindings.js +189 -0
- package/src/native-contracts.js +295 -0
- package/src/native-declarations.js +68 -0
- package/src/native-facts.js +63 -0
- package/src/native.js +19 -13
- package/src/navigation.js +4 -2
- package/src/openapi.js +5 -4
- package/src/package-locking.js +88 -0
- package/src/package-manager.js +267 -68
- package/src/parser.js +32 -6
- package/src/policies.js +3 -3
- package/src/project-init.js +78 -4
- package/src/project.js +11 -9
- package/src/runtime-abi.js +23 -0
- package/src/runtime-adapters.js +18 -0
- package/src/schemas.js +24 -17
- package/src/semantic.js +54 -5
- package/src/snippets.js +60 -0
- package/src/spec-hints.js +56 -0
- package/src/spec-tree.js +241 -0
- package/src/spec.js +669 -305
- package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +0 -103
- package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +0 -925
- package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +0 -434
- package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +0 -103
- package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +0 -374
- package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +0 -150
- package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +0 -532
- package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +0 -395
- package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
- package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
- package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +0 -791
- package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +0 -266
- package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +0 -55
- package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +0 -250
- package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +0 -96
- package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +0 -420
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
- package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/memory → packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/store.aug +0 -0
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/json → packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/web → packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
- /package/examples/oidc-login/.aug-spec/{august/0.19.0/time → packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
package/src/checker.js
CHANGED
|
@@ -10,14 +10,17 @@ import { builtinType as builtin, builtinTypes, builtinProperties, collectionOper
|
|
|
10
10
|
import { orderGraph } from "./di.js";
|
|
11
11
|
import { javadocBefore } from "./javadoc.js";
|
|
12
12
|
import { callableDocumentation } from "./documentation.js";
|
|
13
|
+
import { nativeHttpContracts } from "./http-contracts.js";
|
|
13
14
|
import { jsonDataType } from "./schemas.js";
|
|
14
15
|
import { htmlTags, htmlVoidTags, htmlAttribute, htmlUrlAttributes } from "./html.js";
|
|
15
16
|
import { generateOpenApi } from "./openapi.js";
|
|
16
|
-
import { httpPolicyNames, checkHttpPolicy } from "./http-policies.js";
|
|
17
|
+
import { httpPolicyNames, httpPolicyOptions, checkHttpPolicy } from "./http-policies.js";
|
|
18
|
+
import { nativeDeclarations } from "./native-declarations.js";
|
|
17
19
|
export { tyName } from "./types.js";
|
|
18
20
|
const builtinNames = new Set(Object.keys(builtinTypes));
|
|
19
21
|
const errorTy = { id: 'error', name: '<error>', kind: 'error', args: [], nullable: false };
|
|
20
22
|
const nullTy = { id: 'null', name: 'null', kind: 'null', args: [], nullable: true };
|
|
23
|
+
const unresolved = (type) => type.kind === 'error' || type.args.some(unresolved);
|
|
21
24
|
export function checkProject(project) {
|
|
22
25
|
const checker = new Checker(project);
|
|
23
26
|
const checked = checker.check();
|
|
@@ -34,11 +37,17 @@ class Checker {
|
|
|
34
37
|
bindings = [];
|
|
35
38
|
interceptorPlans = new Map();
|
|
36
39
|
effectContracts = new Map();
|
|
40
|
+
callableContracts = new Map();
|
|
41
|
+
constructorContracts = new Map();
|
|
42
|
+
initializers = new Map();
|
|
43
|
+
inferredChanges = new Map();
|
|
44
|
+
contextualResults = new Set();
|
|
37
45
|
expressionOrigins = new WeakMap();
|
|
38
46
|
scopes = new Map();
|
|
39
47
|
markupCalls = new WeakMap();
|
|
40
48
|
actions = new Map();
|
|
41
49
|
httpPolicies = new Map();
|
|
50
|
+
native;
|
|
42
51
|
bindingByKey = new Map();
|
|
43
52
|
constructorFreshness = new Map();
|
|
44
53
|
constraintStack = new Set();
|
|
@@ -46,13 +55,35 @@ class Checker {
|
|
|
46
55
|
inferring = false;
|
|
47
56
|
inferenceChanged = false;
|
|
48
57
|
changingInference = new Set();
|
|
49
|
-
constructor(project) { this.project = project; this.diagnostics = [...project.diagnostics]; }
|
|
58
|
+
constructor(project) { this.project = project; this.native = nativeDeclarations(project); this.diagnostics = [...project.diagnostics, ...this.native.diagnostics]; }
|
|
50
59
|
check() {
|
|
60
|
+
// Make inherited default bodies visible to forward calls during inference.
|
|
61
|
+
this.inferring = true;
|
|
62
|
+
for (const def of this.project.definitions.values())
|
|
63
|
+
if (def.node.kind === 'class') {
|
|
64
|
+
const methods = new Map();
|
|
65
|
+
const types = this.paramsFor(def.node.typeParams, def.node, def.file);
|
|
66
|
+
for (const ref of def.node.implements)
|
|
67
|
+
for (const [name, entries] of this.interfaceMethods(this.resolveType(ref, def.file, types), new Set()))
|
|
68
|
+
if (!def.node.methods.some(method => method.name === name)) {
|
|
69
|
+
const entry = entries.find(entry => entry.method.body);
|
|
70
|
+
if (entry)
|
|
71
|
+
methods.set(name, entry);
|
|
72
|
+
}
|
|
73
|
+
this.defaults.set(def.id, methods);
|
|
74
|
+
}
|
|
75
|
+
this.inferring = false;
|
|
76
|
+
this.inferImplementationEffects();
|
|
51
77
|
for (const def of this.project.definitions.values())
|
|
52
78
|
if (def.node.kind === 'interceptor')
|
|
53
79
|
this.checkInterceptorShape(def);
|
|
54
80
|
this.planInterceptors();
|
|
55
|
-
this.
|
|
81
|
+
this.constructorFreshness.clear();
|
|
82
|
+
// Layers can add contracts to callers. Recompute after their mappings exist.
|
|
83
|
+
this.inferImplementationEffects(false);
|
|
84
|
+
for (const layers of this.interceptorPlans.values())
|
|
85
|
+
for (const layer of layers)
|
|
86
|
+
layer.errors = this.bodyErrors(layer.around, layer.definition.file, layer.types);
|
|
56
87
|
for (const def of this.project.definitions.values()) {
|
|
57
88
|
if (def.node.kind === 'class')
|
|
58
89
|
this.checkClassShape(def);
|
|
@@ -67,12 +98,9 @@ class Checker {
|
|
|
67
98
|
if (def.node.kind === 'function' && def.node.body)
|
|
68
99
|
this.checkFunctionBody(def.node, def.file);
|
|
69
100
|
if (def.node.kind === 'class') {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
returns: syntheticType('void', def.node.span), returnOwnership: 'managed',
|
|
74
|
-
throws: def.node.validationErrors ?? [], body: initializationOf(def.node), externC: false, span: def.node.span,
|
|
75
|
-
}, def.file, def, true);
|
|
101
|
+
const initializer = this.initializers.get(def.node);
|
|
102
|
+
if (initializer)
|
|
103
|
+
this.checkFunctionBody(initializer, def.file, def, true);
|
|
76
104
|
for (const method of def.node.methods)
|
|
77
105
|
if (method.body)
|
|
78
106
|
this.checkFunctionBody(method, def.file, def);
|
|
@@ -96,15 +124,32 @@ class Checker {
|
|
|
96
124
|
returns: layer.outputType, returnOwnership: layer.around.returnOwnership,
|
|
97
125
|
indices: layer.argumentIndices });
|
|
98
126
|
}
|
|
99
|
-
for (const
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
127
|
+
for (const def of this.project.definitions.values()) {
|
|
128
|
+
if (this.project.files.get(def.file)?.builtin)
|
|
129
|
+
continue;
|
|
130
|
+
const methods = def.node.kind === 'function' ? [def.node] : 'methods' in def.node ? def.node.methods : [];
|
|
131
|
+
for (const method of methods) {
|
|
132
|
+
const source = this.project.files.get(def.file)?.source ?? '';
|
|
133
|
+
const doc = javadocBefore(source, method.annotations?.[0]?.span.start ?? method.span.start);
|
|
134
|
+
const types = new Map([...this.paramsFor(def.node.typeParams, def.node, def.file), ...this.paramsFor(method.typeParams, method, def.file)]);
|
|
135
|
+
const errors = this.effectiveErrors(method, def.file, types);
|
|
136
|
+
for (const tag of doc?.tags ?? []) {
|
|
137
|
+
if (['return', 'returns'].includes(tag.name) && this.returnType(method, def.file, types).name === 'void')
|
|
138
|
+
this.report(method.span, `@${tag.name} requires a value-returning callable`, 'DOC');
|
|
105
139
|
if (['throws', 'exception'].includes(tag.name) && !errors.some(error => tyName(error) === tag.value.split(/\s/)[0]))
|
|
106
|
-
this.report(
|
|
140
|
+
this.report(method.span, `@${tag.name} ${tag.value.split(/\s/)[0]} is absent from ${method.name}'s effective unless contract`, 'DOC');
|
|
141
|
+
}
|
|
107
142
|
}
|
|
143
|
+
if (def.node.kind === 'class' && def.node.record && def.node.validationDeclared === false) {
|
|
144
|
+
const source = this.project.files.get(def.file)?.source ?? '';
|
|
145
|
+
const doc = javadocBefore(source, def.node.span.start);
|
|
146
|
+
const errors = this.effectiveErrors(def.node, def.file, this.paramsFor(def.node.typeParams, def.node, def.file));
|
|
147
|
+
for (const tag of doc?.tags ?? [])
|
|
148
|
+
if (['throws', 'exception'].includes(tag.name) &&
|
|
149
|
+
!errors.some(error => tyName(error) === tag.value.split(/\s/)[0]))
|
|
150
|
+
this.report(def.node.span, `@${tag.name} ${tag.value.split(/\s/)[0]} is absent from ${def.node.name}'s inferred validation errors`, 'DOC');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
108
153
|
if (this.project.main) {
|
|
109
154
|
const context = { file: this.project.main.path, locals: new Map(),
|
|
110
155
|
returns: builtin('void'), returnOwnership: 'managed', allowedErrors: this.project.testMode ? [builtin('Error')] : [],
|
|
@@ -131,10 +176,16 @@ class Checker {
|
|
|
131
176
|
for (const def of this.project.definitions.values())
|
|
132
177
|
if (served.has(def.id) && def.node.kind === 'function' && def.node.endpoint?.path === '/__aug/actions.js')
|
|
133
178
|
this.report(def.node.span, '/__aug/actions.js is reserved for HTTP action transport', 'HTTP');
|
|
179
|
+
for (const [node, layers] of this.interceptorPlans)
|
|
180
|
+
if (node.kind === 'class') {
|
|
181
|
+
for (const [index, layer] of layers.entries())
|
|
182
|
+
layer.constructorResultFresh =
|
|
183
|
+
layers.slice(index + 1).every(inner => this.layerReturnsFresh(inner));
|
|
184
|
+
}
|
|
134
185
|
return { project: this.project, diagnostics: this.diagnostics, bindings: this.bindings,
|
|
135
186
|
expressionTypes: this.expressionTypes, defaults: this.defaults, callPlans: this.callPlans,
|
|
136
|
-
interceptorPlans: this.interceptorPlans, effectContracts: this.effectContracts,
|
|
137
|
-
expressionOrigins: this.expressionOrigins, scopes: this.scopes, markupCalls: this.markupCalls, actions: this.actions, httpPolicies: this.httpPolicies };
|
|
187
|
+
interceptorPlans: this.interceptorPlans, effectContracts: this.effectContracts, callableContracts: this.callableContracts, constructorContracts: this.constructorContracts,
|
|
188
|
+
expressionOrigins: this.expressionOrigins, scopes: this.scopes, markupCalls: this.markupCalls, actions: this.actions, httpPolicies: this.httpPolicies, native: this.native };
|
|
138
189
|
}
|
|
139
190
|
isStatement(item) {
|
|
140
191
|
return ['expr', 'assign', 'return', 'throw', 'if', 'while', 'for', 'destructure', 'match', 'try', 'unsafe', 'borrow', 'scope', 'freeze', 'serve', 'lock', 'yield'].includes(item.kind);
|
|
@@ -144,48 +195,84 @@ class Checker {
|
|
|
144
195
|
return;
|
|
145
196
|
this.diagnostics.push({ file: span.file, line: span.line, column: span.column, message, code });
|
|
146
197
|
}
|
|
147
|
-
/** Infer
|
|
148
|
-
inferImplementationEffects() {
|
|
198
|
+
/** Infer body-derived contracts without changing the cached source AST. */
|
|
199
|
+
inferImplementationEffects(initialize = true) {
|
|
149
200
|
const bodies = [];
|
|
150
201
|
for (const definition of this.project.definitions.values()) {
|
|
151
202
|
const node = definition.node;
|
|
203
|
+
if (node.kind === 'class' && initializationOf(node).length) {
|
|
204
|
+
if (initialize) {
|
|
205
|
+
const initializer = { kind: 'function', name: node.name, typeParams: [], params: [],
|
|
206
|
+
returns: syntheticType('void', node.span), returnOwnership: 'managed', throws: node.validationErrors ?? [],
|
|
207
|
+
body: initializationOf(node), externC: false, span: node.span };
|
|
208
|
+
const errors = (node.validationErrors ?? []).map(ref => this.resolveType(ref, definition.file, this.paramsFor(node.typeParams, node, definition.file)));
|
|
209
|
+
const contract = { result: builtin('void'), errors, inferredResult: false,
|
|
210
|
+
inferredErrors: !!node.record && node.validationDeclared === false };
|
|
211
|
+
this.initializers.set(node, initializer);
|
|
212
|
+
this.callableContracts.set(initializer, contract);
|
|
213
|
+
this.constructorContracts.set(node, contract);
|
|
214
|
+
}
|
|
215
|
+
bodies.push({ method: this.initializers.get(node), definition, owner: definition, initializing: true });
|
|
216
|
+
}
|
|
152
217
|
const methods = node.kind === 'function' ? [node] : 'methods' in node ? node.methods : [];
|
|
218
|
+
const types = this.paramsFor(node.typeParams, node, definition.file);
|
|
153
219
|
for (const method of methods) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
220
|
+
const eligible = !!method.body && !method.externC && method.name !== 'drop';
|
|
221
|
+
if (initialize) {
|
|
222
|
+
const params = new Map([...types, ...this.paramsFor(method.typeParams, method, definition.file)]);
|
|
223
|
+
this.callableContracts.set(method, {
|
|
224
|
+
result: eligible && method.declared?.returns === false ? errorTy : this.resolveType(method.returns, definition.file, params),
|
|
225
|
+
errors: method.throws.map(ref => this.resolveType(ref, definition.file, params)),
|
|
226
|
+
inferredResult: eligible && method.declared?.returns === false,
|
|
227
|
+
inferredErrors: eligible && method.declared?.errors === false,
|
|
228
|
+
});
|
|
229
|
+
if (eligible && !method.uses?.length)
|
|
230
|
+
this.inferredUses.set(method, new Map());
|
|
231
|
+
if (eligible && !method.changes?.length)
|
|
232
|
+
this.inferredChanges.set(method, new Set());
|
|
233
|
+
}
|
|
234
|
+
if (eligible)
|
|
235
|
+
bodies.push({ method, definition, owner: node.kind === 'function' ? undefined : definition });
|
|
162
236
|
}
|
|
163
237
|
}
|
|
164
238
|
this.inferring = true;
|
|
165
239
|
try {
|
|
166
|
-
for (const { method, owner } of bodies)
|
|
167
|
-
if (owner?.node.kind === 'class') {
|
|
240
|
+
for (const { method, owner, initializing } of bodies)
|
|
241
|
+
if (!initializing && owner?.node.kind === 'class') {
|
|
168
242
|
const types = this.paramsFor(owner.node.typeParams, owner.node, owner.file);
|
|
169
243
|
for (const ref of owner.node.implements) {
|
|
170
244
|
const implemented = this.resolveType(ref, owner.file, types);
|
|
171
245
|
for (const entry of this.interfaceMethods(implemented, new Set()).get(method.name) ?? []) {
|
|
172
246
|
const contractOwner = this.project.definitions.get(entry.from);
|
|
247
|
+
if (initialize && this.callableContracts.get(method)?.inferredResult && !entry.method.body) {
|
|
248
|
+
const interfaceTypes = new Map(entry.params);
|
|
249
|
+
entry.method.typeParams.forEach((name, index) => {
|
|
250
|
+
const own = this.paramsFor(method.typeParams, method, owner.file).get(method.typeParams[index]);
|
|
251
|
+
if (own)
|
|
252
|
+
interfaceTypes.set(name, own);
|
|
253
|
+
});
|
|
254
|
+
this.callableContracts.get(method).result = this.returnType(entry.method, entry.file, interfaceTypes);
|
|
255
|
+
this.contextualResults.add(method);
|
|
256
|
+
}
|
|
173
257
|
if (contractOwner?.node.kind !== 'interface' || !contractOwner.node.capability)
|
|
174
258
|
continue;
|
|
175
|
-
// Invoking a capability is
|
|
259
|
+
// Invoking a capability is an effect even for a pure test adapter.
|
|
176
260
|
const contract = this.contractFor(entry.method, entry.file, contractOwner, entry.params);
|
|
177
261
|
for (const [key, effect] of contract.uses)
|
|
178
|
-
this.inferredUses.get(method)
|
|
262
|
+
this.inferredUses.get(method)?.set(key, effect);
|
|
179
263
|
}
|
|
180
264
|
}
|
|
181
265
|
}
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
266
|
+
// Forward references and recursive calls reach the same deterministic fixed point.
|
|
267
|
+
for (let pass = 0; pass <= bodies.length + 1; pass++) {
|
|
268
|
+
this.constructorFreshness.clear();
|
|
185
269
|
this.inferenceChanged = false;
|
|
186
270
|
this.changingInference.clear();
|
|
187
|
-
for (const { method, definition, owner } of bodies)
|
|
188
|
-
this.
|
|
271
|
+
for (const { method, definition, owner, initializing } of bodies) {
|
|
272
|
+
const types = this.paramsFor(owner && 'typeParams' in owner.node ? owner.node.typeParams : [], owner?.node, definition.file);
|
|
273
|
+
const next = owner?.node.kind === 'interceptor' && method.name === 'around' ? this.nextFor(method, definition.file, types) : undefined;
|
|
274
|
+
this.checkFunctionBody(method, definition.file, owner, initializing, undefined, next);
|
|
275
|
+
}
|
|
189
276
|
if (!this.inferenceChanged)
|
|
190
277
|
return;
|
|
191
278
|
}
|
|
@@ -194,7 +281,39 @@ class Checker {
|
|
|
194
281
|
this.inferring = false;
|
|
195
282
|
}
|
|
196
283
|
for (const method of this.changingInference)
|
|
197
|
-
this.report(method.span, `
|
|
284
|
+
this.report(method.span, `Contract inference for ${method.name} did not reach a finite contract; declare returns, uses, or unless on recursive generic helpers`, 'INFERENCE');
|
|
285
|
+
}
|
|
286
|
+
returnType(fn, file, types = new Map()) {
|
|
287
|
+
const contract = this.callableContracts.get(fn);
|
|
288
|
+
return contract ? this.substitute(contract.result, types) : this.resolveType(fn.returns, file, types);
|
|
289
|
+
}
|
|
290
|
+
bodyErrors(fn, file, types = new Map()) {
|
|
291
|
+
const contract = this.callableContracts.get(fn);
|
|
292
|
+
return contract ? contract.errors.map(type => this.substitute(type, types)) : fn.throws.map(ref => this.resolveType(ref, file, types));
|
|
293
|
+
}
|
|
294
|
+
markInference(fn) {
|
|
295
|
+
this.inferenceChanged = true;
|
|
296
|
+
this.changingInference.add(fn);
|
|
297
|
+
}
|
|
298
|
+
inferredReturn(types) {
|
|
299
|
+
const known = types.filter(type => type.kind !== 'error');
|
|
300
|
+
if (!known.length)
|
|
301
|
+
return types.length ? errorTy : builtin('void');
|
|
302
|
+
let result = known[0];
|
|
303
|
+
for (const type of known.slice(1)) {
|
|
304
|
+
if (unresolved(result) && !unresolved(type))
|
|
305
|
+
result = type;
|
|
306
|
+
else if (type.kind === 'null' && result.kind !== 'null')
|
|
307
|
+
result = { ...result, nullable: true, optional: true };
|
|
308
|
+
else if (result.kind === 'null' && type.kind !== 'null')
|
|
309
|
+
result = { ...type, nullable: true, optional: true };
|
|
310
|
+
else if (this.assignable(type, result))
|
|
311
|
+
continue;
|
|
312
|
+
else if (this.assignable(result, type))
|
|
313
|
+
result = type;
|
|
314
|
+
// Keep the first type; the final checking pass diagnoses incompatible returns.
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
198
317
|
}
|
|
199
318
|
checkMemberVisibility(ownerId, ownerName, name, span, context) {
|
|
200
319
|
if (isPrivateName(name) && context.self?.id !== ownerId)
|
|
@@ -212,6 +331,9 @@ class Checker {
|
|
|
212
331
|
const args = ref.args.map(arg => this.resolveType(arg, file, params, validateConstraints));
|
|
213
332
|
if (ref.name !== 'Task' && args.some(arg => arg.id === 'builtin:void'))
|
|
214
333
|
this.report(ref.span, 'Collections cannot contain void', 'COLLECTION');
|
|
334
|
+
const containsResource = (type) => type.kind === 'resource' || type.args.some(containsResource);
|
|
335
|
+
if (args.some(containsResource))
|
|
336
|
+
this.report(ref.span, 'Native resources require individual own bindings; managed collections cannot retain them', 'OWN');
|
|
215
337
|
return { ...builtin(ref.name), args,
|
|
216
338
|
nullable: ref.nullable, optional: ref.optional };
|
|
217
339
|
}
|
|
@@ -289,8 +411,10 @@ class Checker {
|
|
|
289
411
|
iface.extends.forEach(ref => visit(ref, 1));
|
|
290
412
|
iface.methods.forEach(method => {
|
|
291
413
|
method.params.forEach(param => visit(param.type, -1));
|
|
292
|
-
|
|
293
|
-
|
|
414
|
+
const result = this.callableContracts.get(method)?.result;
|
|
415
|
+
const reference = (type) => ({ name: type.name, args: type.args.map(reference), nullable: type.nullable, optional: type.optional, span: method.span });
|
|
416
|
+
visit(result ? reference(result) : method.returns, 1);
|
|
417
|
+
(this.callableContracts.get(method)?.errors.map(reference) ?? method.throws).forEach(ref => visit(ref, 1));
|
|
294
418
|
});
|
|
295
419
|
}
|
|
296
420
|
checkFunctionSignature(fn, file, inheritedParams) {
|
|
@@ -313,7 +437,9 @@ class Checker {
|
|
|
313
437
|
this.report(param.span, 'A resolve parameter cannot also be own or borrow', 'DI');
|
|
314
438
|
this.resolveType(param.type, file, params);
|
|
315
439
|
}
|
|
316
|
-
this.
|
|
440
|
+
this.returnType(fn, file, params);
|
|
441
|
+
if (this.returnType(fn, file, params).kind === 'resource' && fn.returnOwnership !== 'own')
|
|
442
|
+
this.report(fn.span, 'A native resource return must declare returns own', 'OWN');
|
|
317
443
|
if (fn.endpoint) {
|
|
318
444
|
const endpoint = fn.endpoint;
|
|
319
445
|
if (!/^[A-Z]+$/.test(endpoint.method))
|
|
@@ -342,7 +468,7 @@ class Checker {
|
|
|
342
468
|
if (param.source?.kind === 'request' && type.name !== 'HttpRequest')
|
|
343
469
|
this.report(param.span, 'from request provides HttpRequest', 'HTTP');
|
|
344
470
|
}
|
|
345
|
-
const result = this.
|
|
471
|
+
const result = this.returnType(fn, file, params);
|
|
346
472
|
if (endpoint.streams) {
|
|
347
473
|
if (!['ServerEvent', 'Bytes', 'Html'].includes(result.name) || result.optional || result.nullable)
|
|
348
474
|
this.report(fn.span, 'An endpoint streams ServerEvent<T>, Bytes, or Html', 'HTTP');
|
|
@@ -369,22 +495,65 @@ class Checker {
|
|
|
369
495
|
this.report(thrown.span, `Thrown type ${typeName(thrown)} must implement Error`);
|
|
370
496
|
}
|
|
371
497
|
if (fn.externC) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
498
|
+
const native = this.native.functions.get(fn);
|
|
499
|
+
if (native)
|
|
500
|
+
this.checkNativeSignature(fn, file, native);
|
|
501
|
+
else {
|
|
502
|
+
if (fn.nativePure && (fn.uses?.length || fn.changes?.length))
|
|
503
|
+
this.report(fn.span, 'A pure native declaration cannot declare effects', 'FFI');
|
|
504
|
+
if (fn.params.some(param => param.injected))
|
|
505
|
+
this.report(fn.span, 'extern C declarations cannot use resolve parameters', 'FFI');
|
|
506
|
+
if (fn.typeParams.length || fn.throws.length && !fn.valueAbi)
|
|
507
|
+
this.report(fn.span, 'extern C functions cannot be generic or declare unless errors', 'FFI');
|
|
508
|
+
if (fn.returnOwnership === 'own' || fn.params.some(param => param.ownership !== 'managed'))
|
|
509
|
+
this.report(fn.span, 'extern C functions cannot transfer AugScript ownership', 'FFI');
|
|
510
|
+
for (const type of fn.valueAbi ? [] : [...fn.params.map(p => p.type), fn.returns]) {
|
|
511
|
+
if (!['int', 'c_int', 'float', 'bool', 'string', 'void'].includes(type.name) || type.args.length || type.nullable)
|
|
512
|
+
this.report(type.span, `Type ${typeName(type)} is not supported at the C FFI boundary`, 'FFI');
|
|
513
|
+
}
|
|
383
514
|
}
|
|
384
515
|
}
|
|
385
516
|
if (fn.name === 'drop' && (fn.params.length || fn.throws.length || fn.returns.name !== 'void' || fn.uses?.length))
|
|
386
517
|
this.report(fn.span, 'drop must take no inputs, return void, and perform only local cleanup; external effects require an explicit method', 'EFFECT');
|
|
387
518
|
}
|
|
519
|
+
checkNativeSignature(fn, file, binding) {
|
|
520
|
+
const check = (type, view, span) => {
|
|
521
|
+
const name = view.kind === 'i64' ? 'int' : view.kind === 'i32' ? 'c_int' : view.kind === 'f64' ? 'float' : view.kind === 'utf8' ? 'string' : view.kind === 'bytes' ? 'Bytes' : view.kind;
|
|
522
|
+
const valid = view.kind === 'resource' ? type.kind === 'resource' && this.native.resources.get(type.def.node)?.module + '.' + type.name === view.resource && this.native.providers.get(type.def.node) === this.native.providers.get(fn) :
|
|
523
|
+
view.kind === 'f64-list' || view.kind === 'utf8-list' ? type.name === 'List' && type.args.length === 1 && type.args[0].name === (view.kind === 'f64-list' ? 'float' : 'string') : type.name === name;
|
|
524
|
+
if (!valid || type.nullable || type.optional)
|
|
525
|
+
this.report(span, `Native contract expects ${view.resource ?? view.kind}, got ${tyName(type)}`, 'NATIVE_ABI');
|
|
526
|
+
};
|
|
527
|
+
if (fn.body || fn.typeParams.length || fn.params.some(p => p.injected) || fn.annotations?.length)
|
|
528
|
+
this.report(fn.span, 'Native ABI declarations have concrete inputs, no body, no resolve parameters, and no interceptors', 'NATIVE_ABI');
|
|
529
|
+
if (fn.params.length !== binding.params.length)
|
|
530
|
+
this.report(fn.span, 'Native parameter count differs from the binding descriptor', 'NATIVE_ABI');
|
|
531
|
+
fn.params.forEach((p, i) => {
|
|
532
|
+
const view = binding.params[i];
|
|
533
|
+
if (!view)
|
|
534
|
+
return;
|
|
535
|
+
if (p.name !== view.name)
|
|
536
|
+
this.report(p.span, 'Native parameter label differs from the binding descriptor: ' + view.name, 'NATIVE_ABI');
|
|
537
|
+
check(this.resolveType(p.type, file), view, p.span);
|
|
538
|
+
const ownership = view.kind === 'resource' ? view.ownership === 'consume' ? 'own' : view.ownership === 'borrow' ? 'borrow' : 'managed' : 'managed';
|
|
539
|
+
if (p.ownership !== ownership)
|
|
540
|
+
this.report(p.span, 'Native parameter ownership differs from its binding descriptor', 'NATIVE_ABI');
|
|
541
|
+
});
|
|
542
|
+
check(this.returnType(fn, file), binding.result, fn.returns.span);
|
|
543
|
+
if ((binding.result.kind === 'resource') !== (fn.returnOwnership === 'own'))
|
|
544
|
+
this.report(fn.span, 'Native result ownership differs from its binding descriptor', 'NATIVE_ABI');
|
|
545
|
+
const errors = fn.throws.map(t => this.resolveType(t, file));
|
|
546
|
+
if (errors.length !== (binding.error ? 1 : 0) || binding.error && errors[0]?.def?.id !== this.native.errors.get(fn)?.id)
|
|
547
|
+
this.report(fn.span, 'Native checked errors differ from the binding descriptor', 'NATIVE_ABI');
|
|
548
|
+
if (binding.error) {
|
|
549
|
+
const error = errors[0]?.def?.node;
|
|
550
|
+
if (error?.kind !== 'class' || error.typeParams.length || error.fields.length !== 2 || error.fields[0].name !== 'code' || error.fields[0].type.name !== 'int' || error.fields[1].name !== 'message' || error.fields[1].type.name !== 'string' || error.fields.some(p => p.injected || p.ownership !== 'managed' || p.type.nullable || p.type.optional || p.type.args.length) || initializationOf(error).length || error.annotations?.length)
|
|
551
|
+
this.report(fn.span, 'Native status errors require an Error class with int code and string message inputs and no constructor work', 'NATIVE_ABI');
|
|
552
|
+
}
|
|
553
|
+
const uses = (fn.uses ?? []).map(u => u.source + '.' + u.operation).sort(), changes = [...(fn.changes ?? [])].sort();
|
|
554
|
+
if (JSON.stringify(uses) !== JSON.stringify([...binding.uses].sort()) || JSON.stringify(changes) !== JSON.stringify([...binding.changes].sort()))
|
|
555
|
+
this.report(fn.span, 'Native effects or mutation differ from the binding descriptor', 'NATIVE_ABI');
|
|
556
|
+
}
|
|
388
557
|
checkInterceptorShape(def) {
|
|
389
558
|
const node = def.node;
|
|
390
559
|
const types = this.paramsFor(node.typeParams, node, def.file);
|
|
@@ -414,7 +583,7 @@ class Checker {
|
|
|
414
583
|
this.report(method.span, 'Declare generic parameters on the interceptor, rather than around', 'INTERCEPTOR');
|
|
415
584
|
if (method.annotations?.length)
|
|
416
585
|
this.report(method.span, 'Apply interceptor layers to the target declaration; around cannot be annotated', 'INTERCEPTOR');
|
|
417
|
-
if (method.
|
|
586
|
+
if (this.returnType(method, def.file, types).name !== 'void' && canFallThrough(method.body ?? []))
|
|
418
587
|
this.report(method.span, 'around must return its result or throw on every execution path', 'INTERCEPTOR');
|
|
419
588
|
if (canRepeatNext(method.body ?? []))
|
|
420
589
|
this.report(method.span, 'next may be called at most once on each execution path; a loop or catch path can call it again', 'NEXT');
|
|
@@ -424,8 +593,11 @@ class Checker {
|
|
|
424
593
|
this.report(node.span, `${node.name} must define around(...)`, 'INTERCEPTOR');
|
|
425
594
|
}
|
|
426
595
|
nextFor(method, file, types) {
|
|
596
|
+
const result = this.returnType(method, file, types);
|
|
427
597
|
return { params: method.params, types: method.params.map(param => this.resolveType(param.type, file, types)),
|
|
428
|
-
returns:
|
|
598
|
+
returns: result.kind === 'error' && method.declared?.returns === false ?
|
|
599
|
+
{ id: 'continuation:' + file + ':' + method.span.start, name: '<target result>', kind: 'param', args: [], nullable: false } : result,
|
|
600
|
+
returnOwnership: method.returnOwnership };
|
|
429
601
|
}
|
|
430
602
|
inferInterceptorType(ref, actual, names, types, file) {
|
|
431
603
|
inferType(ref, actual, names, types, message => this.report(ref.span, message, 'GENERIC'), (name, value) => {
|
|
@@ -450,6 +622,24 @@ class Checker {
|
|
|
450
622
|
}
|
|
451
623
|
return undefined;
|
|
452
624
|
}
|
|
625
|
+
/** The native policy ABI accepts the published capability shape across source-package identities. */
|
|
626
|
+
nativeWebCapability(type, name) {
|
|
627
|
+
const canonical = nativeHttpContracts.get(name);
|
|
628
|
+
const shape = (value) => {
|
|
629
|
+
if (Array.isArray(value))
|
|
630
|
+
return value.map(shape);
|
|
631
|
+
if (!value || typeof value !== 'object')
|
|
632
|
+
return value;
|
|
633
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => !['span', 'nameSpan', 'headerEnd'].includes(key)).map(([key, child]) => [key, shape(child)]));
|
|
634
|
+
};
|
|
635
|
+
if (!canonical || !type.def || JSON.stringify(shape(type.def.node)) !== JSON.stringify(shape(canonical)))
|
|
636
|
+
return false;
|
|
637
|
+
if (name === 'RequestLogger')
|
|
638
|
+
return true;
|
|
639
|
+
const principal = this.project.scopes.get(type.def.file)?.get('Principal');
|
|
640
|
+
const expected = nativeHttpContracts.get('Principal');
|
|
641
|
+
return !!principal && !!expected && JSON.stringify(shape(principal.node)) === JSON.stringify(shape(expected));
|
|
642
|
+
}
|
|
453
643
|
planInterceptors() {
|
|
454
644
|
const plan = (node, file, ownerTypes, inputs, output, ownership) => {
|
|
455
645
|
const layers = [];
|
|
@@ -465,7 +655,7 @@ class Checker {
|
|
|
465
655
|
const policies = this.httpPolicies.get(node) ?? [];
|
|
466
656
|
if (['Cors', 'Compress'].includes(annotation.name) && policies.some(policy => policy.name === annotation.name))
|
|
467
657
|
this.report(annotation.span, `${annotation.name} may appear only once on an endpoint`, 'HTTP');
|
|
468
|
-
policies.push(checkHttpPolicy(annotation, node, this.diagnostics, (param, name) => this.resolveType(param.type, file, ownerTypes)
|
|
658
|
+
policies.push(checkHttpPolicy(annotation, node, this.diagnostics, (param, name) => this.nativeWebCapability(this.resolveType(param.type, file, ownerTypes), name)));
|
|
469
659
|
this.httpPolicies.set(node, policies);
|
|
470
660
|
}
|
|
471
661
|
continue;
|
|
@@ -511,7 +701,16 @@ class Checker {
|
|
|
511
701
|
types.set(name, this.resolveType(annotation.typeArgs[index], file, ownerTypes));
|
|
512
702
|
});
|
|
513
703
|
const inferredNames = interceptor.typeParams.filter((_, index) => !annotation.typeArgs[index]);
|
|
514
|
-
this.
|
|
704
|
+
const inferredOutput = this.callableContracts.get(around);
|
|
705
|
+
if (inferredOutput?.inferredResult) {
|
|
706
|
+
types.set('<target result>', output);
|
|
707
|
+
if (inferredOutput.result.name !== '<target result>') {
|
|
708
|
+
const reference = (type) => ({ name: type.name, args: type.args.map(reference), nullable: type.nullable, optional: type.optional, span: around.span });
|
|
709
|
+
this.inferInterceptorType(reference(inferredOutput.result), output, inferredNames, types, definition.file);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
else
|
|
713
|
+
this.inferInterceptorType(around.returns, output, inferredNames, types, definition.file);
|
|
515
714
|
const argumentIndices = around.params.map(param => param.injected ? undefined :
|
|
516
715
|
inputs.findIndex(input => input.name === (mapping.get(param.name) ?? param.name)));
|
|
517
716
|
const inputTypes = argumentIndices.map((index, i) => index !== undefined && index >= 0 ?
|
|
@@ -548,7 +747,7 @@ class Checker {
|
|
|
548
747
|
}
|
|
549
748
|
return undefined;
|
|
550
749
|
});
|
|
551
|
-
const result = this.
|
|
750
|
+
const result = this.returnType(around, definition.file, types);
|
|
552
751
|
if (!this.assignable(result, output))
|
|
553
752
|
this.report(annotation.span, `${interceptor.name}.around returns ${tyName(result)}; ${node.name} requires ${tyName(output)}`, 'INTERCEPTOR');
|
|
554
753
|
if (around.returnOwnership !== ownership)
|
|
@@ -566,7 +765,7 @@ class Checker {
|
|
|
566
765
|
const argumentInjectionIndices = around.params.map(param => param.injected ? injectedIndex(param.type) : undefined);
|
|
567
766
|
layers.push({ annotation, definition, around, argumentIndices, argumentBindings, constructorKeys,
|
|
568
767
|
types, inputTypes, outputType: output, constructorInputIndices, argumentInjectionIndices,
|
|
569
|
-
errors:
|
|
768
|
+
errors: this.bodyErrors(around, definition.file, types) });
|
|
570
769
|
}
|
|
571
770
|
};
|
|
572
771
|
for (const def of this.project.definitions.values()) {
|
|
@@ -575,13 +774,13 @@ class Checker {
|
|
|
575
774
|
if (node.kind === 'class')
|
|
576
775
|
plan(node, def.file, types, node.fields, { id: def.id, name: def.name, kind: 'class', def, args: [...types.values()], nullable: false }, 'managed');
|
|
577
776
|
if (node.kind === 'function')
|
|
578
|
-
plan(node, def.file, types, node.params, this.
|
|
777
|
+
plan(node, def.file, types, node.params, this.returnType(node, def.file, types), node.returnOwnership);
|
|
579
778
|
if ('methods' in node)
|
|
580
779
|
for (const method of node.methods) {
|
|
581
780
|
if (node.kind === 'interceptor' && method.name === 'around')
|
|
582
781
|
continue;
|
|
583
782
|
const methodTypes = new Map([...types, ...this.paramsFor(method.typeParams, method, def.file)]);
|
|
584
|
-
plan(method, def.file, methodTypes, method.params, this.
|
|
783
|
+
plan(method, def.file, methodTypes, method.params, this.returnType(method, def.file, methodTypes), method.returnOwnership);
|
|
585
784
|
}
|
|
586
785
|
}
|
|
587
786
|
}
|
|
@@ -594,8 +793,8 @@ class Checker {
|
|
|
594
793
|
}
|
|
595
794
|
effectiveErrors(node, file, types) {
|
|
596
795
|
return [
|
|
597
|
-
...(node.kind === 'function' ? node
|
|
598
|
-
...(this.interceptorPlans.get(node) ?? []).flatMap(layer => layer.
|
|
796
|
+
...(node.kind === 'function' ? this.bodyErrors(node, file, types) : (this.constructorContracts.get(node)?.errors.map(type => this.substitute(type, types)) ?? (node.validationErrors ?? []).map(ref => this.resolveType(ref, file, types)))),
|
|
797
|
+
...(this.interceptorPlans.get(node) ?? []).flatMap(layer => this.bodyErrors(layer.around, layer.definition.file, new Map([...layer.types].map(([name, type]) => [name, this.substitute(type, types)])))),
|
|
599
798
|
];
|
|
600
799
|
}
|
|
601
800
|
checkInterceptorDependencies() {
|
|
@@ -620,6 +819,11 @@ class Checker {
|
|
|
620
819
|
if (!cls.record && cls.implements.length === 0)
|
|
621
820
|
this.report(cls.span, `${cls.name} must implement at least one interface`, 'INTERFACE');
|
|
622
821
|
const params = this.paramsFor(cls.typeParams, cls, def.file);
|
|
822
|
+
for (const error of cls.validationErrors ?? []) {
|
|
823
|
+
const type = this.resolveType(error, def.file, params);
|
|
824
|
+
if (!this.implementsError(type))
|
|
825
|
+
this.report(error.span, `Thrown type ${typeName(error)} must implement Error`);
|
|
826
|
+
}
|
|
623
827
|
this.checkVariance(cls, def.file);
|
|
624
828
|
const names = new Set();
|
|
625
829
|
for (const field of fieldsOf(cls)) {
|
|
@@ -627,6 +831,8 @@ class Checker {
|
|
|
627
831
|
this.report(field.span, `Duplicate field ${field.name}`);
|
|
628
832
|
names.add(field.name);
|
|
629
833
|
this.resolveType(field.type, def.file, params);
|
|
834
|
+
if (this.resolveType(field.type, def.file, params).kind === 'resource' && field.ownership !== 'own')
|
|
835
|
+
this.report(field.span, 'Native resource fields require own ownership', 'OWN');
|
|
630
836
|
if (cls.record && (field.mutable || field.injected || field.ownership !== 'managed'))
|
|
631
837
|
this.report(field.span, 'Record fields are immutable data; dependencies and ownership belong in behavioral classes', 'RECORD');
|
|
632
838
|
if (cls.record && !this.immutableData(this.resolveType(field.type, def.file, params)))
|
|
@@ -745,7 +951,7 @@ class Checker {
|
|
|
745
951
|
param.injected === method.params[i].injected &&
|
|
746
952
|
param.ownership === method.params[i].ownership &&
|
|
747
953
|
equalRef(param.type, method.params[i].type)) &&
|
|
748
|
-
|
|
954
|
+
this.sameType(this.returnType(left, leftFile, leftParams), this.returnType(method, right.file, rightParams)) &&
|
|
749
955
|
left.returnOwnership === method.returnOwnership &&
|
|
750
956
|
this.effectiveErrors(left, leftFile, leftParams).every(thrown => this.effectiveErrors(method, right.file, rightParams).some(allowed => this.assignable(thrown, allowed)));
|
|
751
957
|
}
|
|
@@ -851,6 +1057,8 @@ class Checker {
|
|
|
851
1057
|
continue;
|
|
852
1058
|
}
|
|
853
1059
|
const interfaceDef = this.project.scopes.get(item.span.file)?.get(item.key);
|
|
1060
|
+
if (target.node.validationErrors?.length)
|
|
1061
|
+
this.report(item.span, `${target.name} has a checked constructor failure; construct it explicitly and catch or propagate the error instead of binding it`, 'DI');
|
|
854
1062
|
let exposedType = targetType;
|
|
855
1063
|
if (interfaceDef?.node.kind === 'interface') {
|
|
856
1064
|
exposedType = this.resolveType({ name: item.key, args: item.keyTypeArgs,
|
|
@@ -863,7 +1071,7 @@ class Checker {
|
|
|
863
1071
|
else if (item.keyTypeArgs.length)
|
|
864
1072
|
this.report(item.span, `Named binding ${item.key} cannot take type arguments`, 'DI');
|
|
865
1073
|
const stateful = fieldsOf(target.node).some(field => field.mutable || field.ownership === 'own' || field.type.name === 'Shared') ||
|
|
866
|
-
target.node.methods.some(method => method.changes
|
|
1074
|
+
target.node.methods.some(method => this.effectiveContract(method, target.file, target, new Map(target.node.typeParams.map((name, index) => [name, targetType.args[index] ?? errorTy]))).changes.some(path => path === 'self' || path.startsWith('self.')));
|
|
867
1075
|
const info = { key, target, exposedType, stateful, lifetime: item.lifetime ?? (stateful ? 'fresh' : 'shared'),
|
|
868
1076
|
dependencies: [], constructorKeys: [], declaration: item, requiresScope: item.lifetime === 'scoped' };
|
|
869
1077
|
this.bindings.push(info);
|
|
@@ -921,9 +1129,10 @@ class Checker {
|
|
|
921
1129
|
for (const [name, ty] of this.paramsFor(fn.typeParams, fn, file))
|
|
922
1130
|
params.set(name, ty);
|
|
923
1131
|
this.addBounds(params, fn, file);
|
|
924
|
-
const context = { file, locals: new Map(), returns: this.
|
|
1132
|
+
const context = { file, locals: new Map(), returns: this.returnType(fn, file, params),
|
|
925
1133
|
returnOwnership: fn.returnOwnership,
|
|
926
|
-
allowedErrors:
|
|
1134
|
+
allowedErrors: this.bodyErrors(fn, file, params),
|
|
1135
|
+
inferredReturns: this.inferring && this.callableContracts.get(fn)?.inferredResult && !this.contextualResults.has(fn) ? [] : undefined,
|
|
927
1136
|
unsafe: false, borrowed: new Set(), initializing, types: params, next, callable: fn, owner,
|
|
928
1137
|
flow: new OwnershipFlow() };
|
|
929
1138
|
if (fn.endpoint?.streams) {
|
|
@@ -934,7 +1143,7 @@ class Checker {
|
|
|
934
1143
|
context.self = { id: owner.id, name: owner.name,
|
|
935
1144
|
kind: owner.node.kind === 'class' ? 'class' : owner.node.kind === 'interceptor' ? 'interceptor' : 'interface', def: owner,
|
|
936
1145
|
args: [...params.values()].slice(0, owner.node.typeParams.length), nullable: false };
|
|
937
|
-
context.locals.set('self', { type: context.self, ownership: (fn
|
|
1146
|
+
context.locals.set('self', { type: context.self, ownership: this.contractFor(fn, file, owner, params).changes.some(path => path === 'self' || path.startsWith('self.')) || initializing ? 'borrow' : 'managed', moved: false });
|
|
938
1147
|
if (owner.node.kind === 'class' || owner.node.kind === 'interceptor') {
|
|
939
1148
|
for (const field of fieldsOf(owner.node))
|
|
940
1149
|
context.locals.set(field.name, { type: { ...this.resolveType(field.type, file, params), readonly: !field.mutable }, ownership: field.ownership,
|
|
@@ -966,7 +1175,28 @@ class Checker {
|
|
|
966
1175
|
context.effects = this.contractFor(fn, file, owner, params);
|
|
967
1176
|
if ((fn.changes ?? []).some(path => path.startsWith('self')) && !owner)
|
|
968
1177
|
this.report(fn.span, 'A free function has no self to change', 'EFFECT');
|
|
1178
|
+
for (const policy of this.httpPolicies.get(fn) ?? []) {
|
|
1179
|
+
const operations = Object.values(httpPolicyOptions[policy.name]).filter(spec => spec.startsWith('dependency:'));
|
|
1180
|
+
policy.dependencies.forEach((index, order) => {
|
|
1181
|
+
const param = fn.params[index];
|
|
1182
|
+
if (!param || !operations[order])
|
|
1183
|
+
return;
|
|
1184
|
+
const type = this.resolveType(param.type, file, params);
|
|
1185
|
+
const operation = operations[order].split('.')[1];
|
|
1186
|
+
this.requireUse(capabilityKey(type, operation), `${tyName(type)}.${operation}`, policy.annotation.span, context, { source: tyName(type), operation, span: policy.annotation.span, capability: type });
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
969
1189
|
this.checkStatements(fn.body ?? [], context, fn.span);
|
|
1190
|
+
if (context.inferredReturns) {
|
|
1191
|
+
const contract = this.callableContracts.get(fn);
|
|
1192
|
+
const result = this.inferredReturn(context.inferredReturns);
|
|
1193
|
+
if (!sameType(result, contract.result)) {
|
|
1194
|
+
contract.result = result;
|
|
1195
|
+
this.markInference(fn);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
if (!this.inferring && unresolved(this.returnType(fn, file, params)))
|
|
1199
|
+
this.report(fn.span, `Cannot infer ${fn.name}'s return type; add returns T to anchor recursive or ambiguous results`, 'INFERENCE');
|
|
970
1200
|
if (fn.body && context.returns.id !== 'builtin:void' &&
|
|
971
1201
|
!(owner?.node.kind === 'interceptor' && fn.name === 'around') && canFallThrough(fn.body))
|
|
972
1202
|
this.report(fn.span, `${fn.name} must return a value or throw on every path`, 'TYPE');
|
|
@@ -1046,16 +1276,19 @@ class Checker {
|
|
|
1046
1276
|
report: (span, message) => this.report(span, message, 'EFFECT'),
|
|
1047
1277
|
});
|
|
1048
1278
|
const inferred = this.inferredUses.get(fn);
|
|
1279
|
+
const inferredChanges = this.inferredChanges.get(fn);
|
|
1280
|
+
const changes = inferredChanges ? [...inferredChanges].sort() : result.changes;
|
|
1049
1281
|
if (!inferred) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1282
|
+
const contract = { ...result, changes, inferredChanges: !!inferredChanges };
|
|
1283
|
+
this.effectContracts.set(fn, contract);
|
|
1284
|
+
return contract;
|
|
1052
1285
|
}
|
|
1053
1286
|
const uses = new Map(result.uses);
|
|
1054
1287
|
for (const [key, effect] of inferred) {
|
|
1055
1288
|
const capability = effect.capability && this.substitute(effect.capability, types);
|
|
1056
1289
|
uses.set(capability ? capabilityKey(capability, effect.operation) : key, { ...effect, capability, source: capability ? tyName(capability) : effect.source });
|
|
1057
1290
|
}
|
|
1058
|
-
const contract = { ...result, uses, inferred: true };
|
|
1291
|
+
const contract = { ...result, changes, uses, inferred: true, inferredChanges: !!inferredChanges };
|
|
1059
1292
|
this.effectContracts.set(fn, contract);
|
|
1060
1293
|
return contract;
|
|
1061
1294
|
}
|
|
@@ -1096,7 +1329,7 @@ class Checker {
|
|
|
1096
1329
|
changes.push([fn.params[target].name, ...path].join('.'));
|
|
1097
1330
|
}
|
|
1098
1331
|
}
|
|
1099
|
-
const result = { changes: [...new Set(changes)], uses, inferred: base.inferred };
|
|
1332
|
+
const result = { changes: [...new Set(changes)], uses, inferred: base.inferred, inferredChanges: base.inferredChanges };
|
|
1100
1333
|
this.effectContracts.set(fn, result);
|
|
1101
1334
|
return result;
|
|
1102
1335
|
}
|
|
@@ -1126,8 +1359,16 @@ class Checker {
|
|
|
1126
1359
|
return;
|
|
1127
1360
|
const input = context.callable.params.find(param => param.name === origin);
|
|
1128
1361
|
if (path.startsWith('self') || input && input.ownership !== 'own') {
|
|
1129
|
-
|
|
1130
|
-
|
|
1362
|
+
const inferred = this.inferring && this.inferredChanges.get(context.callable);
|
|
1363
|
+
const change = path.startsWith('self') ? 'self' : origin;
|
|
1364
|
+
if (inferred) {
|
|
1365
|
+
if (!inferred.has(change)) {
|
|
1366
|
+
inferred.add(change);
|
|
1367
|
+
this.markInference(context.callable);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
else if (!coversChange(context.effects?.changes ?? [], path))
|
|
1371
|
+
this.report(span, `${context.callable.name} must declare changes ${change}`, 'EFFECT');
|
|
1131
1372
|
}
|
|
1132
1373
|
}
|
|
1133
1374
|
immutableData(type, seen = new Set()) {
|
|
@@ -1214,8 +1455,9 @@ class Checker {
|
|
|
1214
1455
|
const type = this.checkExpression(stmt.value, context);
|
|
1215
1456
|
if (type.id !== 'builtin:Shared')
|
|
1216
1457
|
this.report(stmt.value.span, 'lock requires Shared<T>', 'CONCURRENCY');
|
|
1217
|
-
|
|
1218
|
-
|
|
1458
|
+
const external = type.readonly || !!context.flow.external(this.rootName(stmt.value) ?? '');
|
|
1459
|
+
if (context.callable && external && !context.effects?.uses.size && !context.effects?.changes.length)
|
|
1460
|
+
this.report(stmt.span, 'A callable that locks external shared state declares its capability operation or changes contract', 'EFFECT');
|
|
1219
1461
|
const inside = this.cloneContext(context);
|
|
1220
1462
|
inside.locked = true;
|
|
1221
1463
|
const origins = allocationOrigin(stmt.span);
|
|
@@ -1377,6 +1619,8 @@ class Checker {
|
|
|
1377
1619
|
const expected = stmt.declaredType ? this.resolveType(stmt.declaredType, context.file, context.types) :
|
|
1378
1620
|
stmt.target.kind === 'name' ? context.locals.get(stmt.target.name)?.declaredType ?? context.locals.get(stmt.target.name)?.type : undefined;
|
|
1379
1621
|
const value = this.checkExpression(stmt.value, context, expected);
|
|
1622
|
+
if (value.kind === 'resource' && stmt.target.kind === 'name' && stmt.ownership !== 'own' && context.locals.get(stmt.target.name)?.origin !== 'field')
|
|
1623
|
+
this.report(stmt.span, 'Native resources must be held by own bindings', 'OWN');
|
|
1380
1624
|
const source = stmt.value.kind === 'name' ? context.locals.get(stmt.value.name) : undefined;
|
|
1381
1625
|
const origins = this.placesOf(stmt.value, context);
|
|
1382
1626
|
const ownedSource = this.ownershipOf(stmt.value, context) === 'own';
|
|
@@ -1408,9 +1652,9 @@ class Checker {
|
|
|
1408
1652
|
context.flow.declare(stmt.target.name, origins, !!value.readonly, { source: sourceName(stmt.value) });
|
|
1409
1653
|
}
|
|
1410
1654
|
else if (existing) {
|
|
1411
|
-
if (existing.ownership === 'own')
|
|
1655
|
+
if (existing.ownership === 'own' && existing.origin !== 'field')
|
|
1412
1656
|
this.report(stmt.target.span, `Reassigning owned value ${stmt.target.name} is not supported; use a new scope`, 'OWN');
|
|
1413
|
-
if (source?.ownership === 'own')
|
|
1657
|
+
if (source?.ownership === 'own' && !(existing.origin === 'field' && existing.ownership === 'own'))
|
|
1414
1658
|
this.report(stmt.value.span, 'Cannot copy an owned value into a managed variable', 'OWN');
|
|
1415
1659
|
if (existing.origin === 'field' && existing.ownership !== 'own' &&
|
|
1416
1660
|
!context.initializing && !context.borrowed.has('self') && context.locals.get('self')?.ownership !== 'borrow')
|
|
@@ -1436,6 +1680,12 @@ class Checker {
|
|
|
1436
1680
|
existing.type = { ...declared, nullable: value.nullable, optional: value.optional, readonly: value.readonly, frozen: value.frozen };
|
|
1437
1681
|
context.flow.rebind(stmt.target.name, origins, !!value.readonly, stmt.span, (span, message) => this.report(span, message, 'BORROW'), sourceName(stmt.value));
|
|
1438
1682
|
existing.moved = false;
|
|
1683
|
+
if (existing.origin === 'field' && existing.ownership === 'own') {
|
|
1684
|
+
if (source?.ownership === 'own' && stmt.value.kind === 'name')
|
|
1685
|
+
this.moveOwnedLocal(stmt.value.name, stmt.value.span, context);
|
|
1686
|
+
else if (!['own', 'fresh'].includes(this.ownershipOf(stmt.value, context)))
|
|
1687
|
+
this.report(stmt.value.span, 'An owned field requires a new object or another owned value', 'OWN');
|
|
1688
|
+
}
|
|
1439
1689
|
}
|
|
1440
1690
|
else {
|
|
1441
1691
|
if (source?.ownership === 'own')
|
|
@@ -1461,6 +1711,8 @@ class Checker {
|
|
|
1461
1711
|
const node = object.def?.node;
|
|
1462
1712
|
const fieldName = stmt.target.name;
|
|
1463
1713
|
const field = node?.kind === 'class' || node?.kind === 'interceptor' ? fieldsOf(node).find(item => item.name === fieldName) : undefined;
|
|
1714
|
+
if (value.kind === 'resource' && field?.ownership !== 'own')
|
|
1715
|
+
this.report(stmt.span, 'Native resources must be held by own fields', 'OWN');
|
|
1464
1716
|
if (!(context.initializing && root === 'self') && !field?.mutable)
|
|
1465
1717
|
this.report(stmt.target.span, `Field ${fieldName} is read-only; declare mutable storage`, 'MUTABILITY');
|
|
1466
1718
|
if (object.readonly && !(context.initializing && root === 'self'))
|
|
@@ -1494,8 +1746,9 @@ class Checker {
|
|
|
1494
1746
|
return;
|
|
1495
1747
|
}
|
|
1496
1748
|
if (stmt.kind === 'return') {
|
|
1497
|
-
const type = stmt.value ? this.checkExpression(stmt.value, context, context.returns) : builtin('void');
|
|
1498
|
-
|
|
1749
|
+
const type = stmt.value ? this.checkExpression(stmt.value, context, context.returns.kind === 'error' ? undefined : context.returns) : builtin('void');
|
|
1750
|
+
context.inferredReturns?.push(type);
|
|
1751
|
+
const declaredErrors = context.callable ? this.bodyErrors(context.callable, context.file, context.types) : [];
|
|
1499
1752
|
for (const error of context.flow.pendingTaskErrors())
|
|
1500
1753
|
this.checkAllowedError(error, stmt.span, { ...context, allowedErrors: declaredErrors, exceptionalFlows: undefined });
|
|
1501
1754
|
if (!this.assignable(type, context.returns))
|
|
@@ -1808,29 +2061,39 @@ class Checker {
|
|
|
1808
2061
|
if (visiting.has(node))
|
|
1809
2062
|
return false;
|
|
1810
2063
|
visiting.add(node);
|
|
1811
|
-
const result = (this.interceptorPlans.get(node) ?? []).every(layer =>
|
|
1812
|
-
const interceptor = layer.definition.node;
|
|
1813
|
-
return returnsFresh(layer.around.body ?? [], new Set(interceptor.fields.map(field => field.name)), expr => {
|
|
1814
|
-
if (expr.kind !== 'call' || expr.callee.kind !== 'name')
|
|
1815
|
-
return false;
|
|
1816
|
-
if (expr.callee.name === 'next')
|
|
1817
|
-
return true;
|
|
1818
|
-
const def = this.project.scopes.get(layer.definition.file)?.get(expr.callee.name);
|
|
1819
|
-
return def?.node.kind === 'class' && this.constructorIsFresh(def.node, visiting);
|
|
1820
|
-
});
|
|
1821
|
-
});
|
|
2064
|
+
const result = (this.interceptorPlans.get(node) ?? []).every(layer => this.layerReturnsFresh(layer, visiting));
|
|
1822
2065
|
visiting.delete(node);
|
|
1823
2066
|
this.constructorFreshness.set(node, result);
|
|
1824
2067
|
return result;
|
|
1825
2068
|
}
|
|
2069
|
+
layerReturnsFresh(layer, visiting = new Set()) {
|
|
2070
|
+
const interceptor = layer.definition.node;
|
|
2071
|
+
return returnsFresh(layer.around.body ?? [], new Set(interceptor.fields.map(field => field.name)), expr => {
|
|
2072
|
+
if (expr.kind !== 'call' || expr.callee.kind !== 'name')
|
|
2073
|
+
return false;
|
|
2074
|
+
if (expr.callee.name === 'next')
|
|
2075
|
+
return true;
|
|
2076
|
+
const def = this.project.scopes.get(layer.definition.file)?.get(expr.callee.name);
|
|
2077
|
+
return def?.node.kind === 'class' && this.constructorIsFresh(def.node, visiting);
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
1826
2080
|
checkAllowedError(type, span, context) {
|
|
1827
2081
|
if (context.deferredErrors) {
|
|
1828
2082
|
context.deferredErrors.push(type);
|
|
1829
2083
|
return;
|
|
1830
2084
|
}
|
|
1831
2085
|
context.exceptionalFlows?.push({ type, flow: context.flow.clone() });
|
|
1832
|
-
if (!context.allowedErrors.some(allowed => this.assignable(type, allowed)))
|
|
1833
|
-
|
|
2086
|
+
if (!context.allowedErrors.some(allowed => this.assignable(type, allowed))) {
|
|
2087
|
+
const contract = context.callable && this.inferring && this.callableContracts.get(context.callable);
|
|
2088
|
+
if (contract && contract.inferredErrors && type.kind !== 'error') {
|
|
2089
|
+
if (!contract.errors.some(error => sameType(error, type))) {
|
|
2090
|
+
contract.errors.push(type);
|
|
2091
|
+
this.markInference(context.callable);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
else
|
|
2095
|
+
this.report(span, `Unhandled ${tyName(type)}; catch it or declare unless ${tyName(type)}`, 'THROWS');
|
|
2096
|
+
}
|
|
1834
2097
|
}
|
|
1835
2098
|
checkCollection(expr, context, expected) {
|
|
1836
2099
|
const name = expr.collection === 'empty' ? expected?.name === 'Set' ? 'Set' : 'Map' : expr.collection;
|
|
@@ -1959,6 +2222,8 @@ class Checker {
|
|
|
1959
2222
|
type = { ...builtin('Task'), args: [result] };
|
|
1960
2223
|
if (expr.call.kind === 'call' && context.scope) {
|
|
1961
2224
|
const plan = this.callPlans.get(expr.call), task = [...allocationOrigin(expr.span)][0], scope = `tasks:${context.scope.file}:${context.scope.start}`;
|
|
2225
|
+
if (plan?.returnOwnership === 'own')
|
|
2226
|
+
this.report(expr.call.span, 'A task cannot return an owned value. Return immutable data, or create and release the owned resource inside the task.', 'CONCURRENCY');
|
|
1962
2227
|
context.flow.registerTask(task, scope, errors);
|
|
1963
2228
|
const captureOrigins = (origins, actual, exclusive, span) => {
|
|
1964
2229
|
if (!this.isReference(actual))
|
|
@@ -2112,6 +2377,9 @@ class Checker {
|
|
|
2112
2377
|
}
|
|
2113
2378
|
else if (expr.kind === 'call') {
|
|
2114
2379
|
type = this.checkCall(expr, context);
|
|
2380
|
+
const plan = this.callPlans.get(expr);
|
|
2381
|
+
if (plan)
|
|
2382
|
+
plan.returnOwnership = this.ownershipOf(expr, context) === 'own' ? 'own' : 'managed';
|
|
2115
2383
|
}
|
|
2116
2384
|
this.expressionTypes.set(expr, type);
|
|
2117
2385
|
this.expressionOrigins.set(expr, this.placesOf(expr, context));
|
|
@@ -2142,14 +2410,14 @@ class Checker {
|
|
|
2142
2410
|
this.defaults.get(def.id)?.get(name)?.method;
|
|
2143
2411
|
if (method) {
|
|
2144
2412
|
this.checkMemberVisibility(def.id, def.name, name, span, context);
|
|
2145
|
-
return this.
|
|
2413
|
+
return this.returnType(method, def.file, new Map(def.node.typeParams.map((param, i) => [param, receiver.args[i] ?? errorTy])));
|
|
2146
2414
|
}
|
|
2147
2415
|
}
|
|
2148
2416
|
if (def?.node.kind === 'interface') {
|
|
2149
2417
|
const entry = this.interfaceMethods(receiver, new Set()).get(name)?.[0];
|
|
2150
2418
|
if (entry) {
|
|
2151
2419
|
this.checkMemberVisibility(entry.from, def.name, name, span, context);
|
|
2152
|
-
return this.
|
|
2420
|
+
return this.returnType(entry.method, entry.file, entry.params);
|
|
2153
2421
|
}
|
|
2154
2422
|
}
|
|
2155
2423
|
this.report(span, `${tyName(receiver)} has no member ${name}`);
|
|
@@ -2424,6 +2692,7 @@ class Checker {
|
|
|
2424
2692
|
}
|
|
2425
2693
|
if (expr.callee.kind === 'name' && expr.callee.name === 'Shared') {
|
|
2426
2694
|
const plan = this.planCall(expr, ['value'], 'Shared'), index = plan.sourceIndices[0];
|
|
2695
|
+
plan.ownerships = ['own'];
|
|
2427
2696
|
const result = index === undefined ? errorTy : argTypes[index];
|
|
2428
2697
|
if (index !== undefined && !['fresh', 'own'].includes(this.ownershipOf(expr.args[index], context)))
|
|
2429
2698
|
this.report(expr.args[index].span, 'Shared takes a fresh value or an owned value; existing mutable aliases cannot survive the transfer', 'OWN');
|
|
@@ -2604,8 +2873,8 @@ class Checker {
|
|
|
2604
2873
|
else if (!jsonDataType(this.project, result))
|
|
2605
2874
|
this.report(expr.span, `${tyName(result)} is not JSON data; use a record or data collection`, 'JSON');
|
|
2606
2875
|
if (result.def?.node.kind === 'class')
|
|
2607
|
-
for (const error of result.def.node.
|
|
2608
|
-
this.checkAllowedError(
|
|
2876
|
+
for (const error of this.effectiveErrors(result.def.node, result.def.file, new Map(result.def.node.typeParams.map((name, index) => [name, result.args[index] ?? errorTy]))))
|
|
2877
|
+
this.checkAllowedError(error, expr.span, context);
|
|
2609
2878
|
}
|
|
2610
2879
|
return this.isReference(result) ? { ...result, readonly: true, frozen: decoding || receiver.name === 'Json' } : result;
|
|
2611
2880
|
}
|
|
@@ -2728,7 +2997,7 @@ class Checker {
|
|
|
2728
2997
|
}
|
|
2729
2998
|
if (fn.externC && !context.unsafe)
|
|
2730
2999
|
this.report(expr.span, `Call to extern C function ${fn.name} requires unsafe { ... }`, 'FFI');
|
|
2731
|
-
if (fn.externC && !fn.nativePure && !(fn.valueAbi && fn.uses?.length)) {
|
|
3000
|
+
if (fn.externC && !fn.nativePure && !this.native.functions.has(fn) && !(fn.valueAbi && fn.uses?.length)) {
|
|
2732
3001
|
const native = this.project.scopes.get(fnFile)?.get(fn.name);
|
|
2733
3002
|
this.requireUse(`C:${native?.id ?? fn.name}`, `C.${fn.name}`, expr.span, context);
|
|
2734
3003
|
}
|
|
@@ -2797,7 +3066,7 @@ class Checker {
|
|
|
2797
3066
|
], (span, message) => this.report(span, message, 'BORROW'));
|
|
2798
3067
|
for (const thrown of this.effectiveErrors(fn, fnFile, params))
|
|
2799
3068
|
this.checkAllowedError(thrown, expr.span, context);
|
|
2800
|
-
const result = this.
|
|
3069
|
+
const result = this.returnType(fn, fnFile, params);
|
|
2801
3070
|
return this.isReference(result) && fn.returnOwnership !== 'own' && !this.functionIsFresh(fn, fnFile, owner && 'fields' in owner.node ? new Set(fieldsOf(owner.node).map(field => field.name)) : new Set()) ?
|
|
2802
3071
|
{ ...result, readonly: true } : result;
|
|
2803
3072
|
}
|
|
@@ -2866,7 +3135,7 @@ class Checker {
|
|
|
2866
3135
|
else if (!['own', 'fresh'].includes(this.ownershipOf(argument, context)))
|
|
2867
3136
|
this.report(argument.span, 'Owned field requires a new object or owned argument', 'OWN');
|
|
2868
3137
|
}
|
|
2869
|
-
else if (this.ownershipOf(argument, context) === 'own' && param.ownership !== 'borrow')
|
|
3138
|
+
else if (this.ownershipOf(argument, context) === 'own' && param.ownership !== 'borrow' && this.expressionTypes.get(argument)?.kind !== 'resource')
|
|
2870
3139
|
this.report(argument.span, 'Cannot copy an owned value into managed storage', 'OWN');
|
|
2871
3140
|
if (param.ownership === 'borrow') {
|
|
2872
3141
|
if (context.flow.hasTaskCapture(this.placesOf(argument, context)))
|