@greenpandastudios/aug-cli 0.19.0 → 0.20.1
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/compatibility.md +3 -3
- package/docs/contributing-benchmarks.md +38 -0
- package/docs/dev-containers.md +95 -0
- package/docs/diagnostics.md +15 -5
- package/docs/docker.md +174 -12
- package/docs/editor.md +35 -0
- package/docs/example-projects.json +206 -24
- package/docs/examples/approved-design/counters.md +34 -126
- package/docs/examples/approved-design/dependencies/august/0.20.1/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/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.20.1/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/ffi/index.md +6 -5
- package/docs/examples/ffi/main.md +6 -20
- package/docs/examples/ffi/native.md +8 -34
- package/docs/examples/generic-di/dependencies/august/0.20.1/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.20.1/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 +46 -29
- package/docs/examples/interceptors/app.md +20 -139
- package/docs/examples/interceptors/dependencies/august/0.20.1/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/new-syntax/console.md +10 -52
- package/docs/examples/new-syntax/dependencies/august/0.20.1/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.20.1/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/startup-benchmark/index.md +6 -5
- package/docs/examples/startup-benchmark/main.md +5 -17
- 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 +6 -4
- package/docs/guides/change-a-module.md +64 -0
- package/docs/guides/index.md +27 -0
- package/docs/index.md +51 -29
- package/docs/language-conformance.md +1 -1
- package/docs/language-constructs.md +22 -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/packages.md +72 -126
- package/docs/performance.md +13 -41
- package/docs/production-readiness.md +5 -4
- package/docs/public/downloads/approved-design.zip +0 -0
- package/docs/public/downloads/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.zip +0 -0
- package/docs/public/downloads/ffi.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/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/startup-benchmark.zip +0 -0
- package/docs/public/downloads/visibility.zip +0 -0
- package/docs/public/downloads/weather-api.zip +0 -0
- package/docs/reference.md +23 -17
- package/docs/releasing.md +29 -15
- package/docs/research/code-to-natural-language.md +108 -0
- package/docs/research/ecosystem-workflow.md +41 -0
- package/docs/research/wiki-editorial-design.md +71 -0
- package/docs/roadmap.md +1 -1
- package/docs/specifications.md +27 -11
- package/docs/testing.md +19 -5
- package/docs/tooling.md +25 -12
- package/docs/weather-api.md +65 -0
- package/docs/web.md +50 -18
- package/docs/writing-docs.md +49 -0
- package/examples/{hello/.aug-spec/august/0.19.0 → approved-design/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
- package/examples/approved-design/.aug-spec/august/0.20.1/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.20.1}/io/contracts.aug +4 -3
- package/examples/developer-workflow/.aug-spec/august/0.20.1/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.20.1}/io/contracts.aug +4 -3
- package/examples/generic-di/.aug-spec/august/0.20.1/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.20.1}/io/contracts.aug +4 -3
- package/examples/hello/.aug-spec/august/0.20.1/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.20.1/io/contracts.aug +37 -0
- package/examples/interceptors/.aug-spec/august/0.20.1/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/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
- package/examples/new-syntax/.aug-spec/august/0.20.1/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.20.1/io/contracts.aug +37 -0
- package/examples/ownership-transfer/.aug-spec/august/0.20.1/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/package.json +3 -4
- package/scripts/bootstrap-native.mjs +181 -106
- package/scripts/native-setup.mjs +98 -0
- package/scripts/native-toolchain.mjs +28 -0
- package/src/builtins.js +1 -1
- package/src/checker.js +259 -72
- package/src/cli.js +114 -20
- package/src/codegen.js +1 -1
- package/src/config.js +1 -1
- package/src/contracts.js +10 -0
- package/src/editor.js +71 -16
- package/src/fixes.js +90 -2
- package/src/formatter.js +19 -8
- package/src/git-packages.js +110 -0
- package/src/help.js +24 -23
- package/src/http-contracts.js +14 -0
- package/src/http-policies.js +5 -5
- package/src/libraries.js +1 -1
- package/src/lsp.js +14 -5
- package/src/native.js +19 -13
- package/src/navigation.js +4 -2
- package/src/openapi.js +5 -4
- package/src/package-locking.js +45 -0
- package/src/package-manager.js +251 -67
- package/src/parser.js +13 -5
- package/src/policies.js +3 -3
- package/src/project-init.js +78 -4
- package/src/project.js +9 -7
- package/src/semantic.js +46 -2
- package/src/snippets.js +59 -0
- package/src/spec-hints.js +56 -0
- package/src/spec-tree.js +241 -0
- package/src/spec.js +626 -303
- 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,16 @@ 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";
|
|
17
18
|
export { tyName } from "./types.js";
|
|
18
19
|
const builtinNames = new Set(Object.keys(builtinTypes));
|
|
19
20
|
const errorTy = { id: 'error', name: '<error>', kind: 'error', args: [], nullable: false };
|
|
20
21
|
const nullTy = { id: 'null', name: 'null', kind: 'null', args: [], nullable: true };
|
|
22
|
+
const unresolved = (type) => type.kind === 'error' || type.args.some(unresolved);
|
|
21
23
|
export function checkProject(project) {
|
|
22
24
|
const checker = new Checker(project);
|
|
23
25
|
const checked = checker.check();
|
|
@@ -34,6 +36,11 @@ class Checker {
|
|
|
34
36
|
bindings = [];
|
|
35
37
|
interceptorPlans = new Map();
|
|
36
38
|
effectContracts = new Map();
|
|
39
|
+
callableContracts = new Map();
|
|
40
|
+
constructorContracts = new Map();
|
|
41
|
+
initializers = new Map();
|
|
42
|
+
inferredChanges = new Map();
|
|
43
|
+
contextualResults = new Set();
|
|
37
44
|
expressionOrigins = new WeakMap();
|
|
38
45
|
scopes = new Map();
|
|
39
46
|
markupCalls = new WeakMap();
|
|
@@ -48,11 +55,33 @@ class Checker {
|
|
|
48
55
|
changingInference = new Set();
|
|
49
56
|
constructor(project) { this.project = project; this.diagnostics = [...project.diagnostics]; }
|
|
50
57
|
check() {
|
|
58
|
+
// Make inherited default bodies visible to forward calls during inference.
|
|
59
|
+
this.inferring = true;
|
|
60
|
+
for (const def of this.project.definitions.values())
|
|
61
|
+
if (def.node.kind === 'class') {
|
|
62
|
+
const methods = new Map();
|
|
63
|
+
const types = this.paramsFor(def.node.typeParams, def.node, def.file);
|
|
64
|
+
for (const ref of def.node.implements)
|
|
65
|
+
for (const [name, entries] of this.interfaceMethods(this.resolveType(ref, def.file, types), new Set()))
|
|
66
|
+
if (!def.node.methods.some(method => method.name === name)) {
|
|
67
|
+
const entry = entries.find(entry => entry.method.body);
|
|
68
|
+
if (entry)
|
|
69
|
+
methods.set(name, entry);
|
|
70
|
+
}
|
|
71
|
+
this.defaults.set(def.id, methods);
|
|
72
|
+
}
|
|
73
|
+
this.inferring = false;
|
|
74
|
+
this.inferImplementationEffects();
|
|
51
75
|
for (const def of this.project.definitions.values())
|
|
52
76
|
if (def.node.kind === 'interceptor')
|
|
53
77
|
this.checkInterceptorShape(def);
|
|
54
78
|
this.planInterceptors();
|
|
55
|
-
this.
|
|
79
|
+
this.constructorFreshness.clear();
|
|
80
|
+
// Layers can add contracts to callers. Recompute after their mappings exist.
|
|
81
|
+
this.inferImplementationEffects(false);
|
|
82
|
+
for (const layers of this.interceptorPlans.values())
|
|
83
|
+
for (const layer of layers)
|
|
84
|
+
layer.errors = this.bodyErrors(layer.around, layer.definition.file, layer.types);
|
|
56
85
|
for (const def of this.project.definitions.values()) {
|
|
57
86
|
if (def.node.kind === 'class')
|
|
58
87
|
this.checkClassShape(def);
|
|
@@ -67,12 +96,9 @@ class Checker {
|
|
|
67
96
|
if (def.node.kind === 'function' && def.node.body)
|
|
68
97
|
this.checkFunctionBody(def.node, def.file);
|
|
69
98
|
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);
|
|
99
|
+
const initializer = this.initializers.get(def.node);
|
|
100
|
+
if (initializer)
|
|
101
|
+
this.checkFunctionBody(initializer, def.file, def, true);
|
|
76
102
|
for (const method of def.node.methods)
|
|
77
103
|
if (method.body)
|
|
78
104
|
this.checkFunctionBody(method, def.file, def);
|
|
@@ -96,15 +122,32 @@ class Checker {
|
|
|
96
122
|
returns: layer.outputType, returnOwnership: layer.around.returnOwnership,
|
|
97
123
|
indices: layer.argumentIndices });
|
|
98
124
|
}
|
|
99
|
-
for (const
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
for (const def of this.project.definitions.values()) {
|
|
126
|
+
if (this.project.files.get(def.file)?.builtin)
|
|
127
|
+
continue;
|
|
128
|
+
const methods = def.node.kind === 'function' ? [def.node] : 'methods' in def.node ? def.node.methods : [];
|
|
129
|
+
for (const method of methods) {
|
|
130
|
+
const source = this.project.files.get(def.file)?.source ?? '';
|
|
131
|
+
const doc = javadocBefore(source, method.annotations?.[0]?.span.start ?? method.span.start);
|
|
132
|
+
const types = new Map([...this.paramsFor(def.node.typeParams, def.node, def.file), ...this.paramsFor(method.typeParams, method, def.file)]);
|
|
133
|
+
const errors = this.effectiveErrors(method, def.file, types);
|
|
134
|
+
for (const tag of doc?.tags ?? []) {
|
|
135
|
+
if (['return', 'returns'].includes(tag.name) && this.returnType(method, def.file, types).name === 'void')
|
|
136
|
+
this.report(method.span, `@${tag.name} requires a value-returning callable`, 'DOC');
|
|
105
137
|
if (['throws', 'exception'].includes(tag.name) && !errors.some(error => tyName(error) === tag.value.split(/\s/)[0]))
|
|
106
|
-
this.report(
|
|
138
|
+
this.report(method.span, `@${tag.name} ${tag.value.split(/\s/)[0]} is absent from ${method.name}'s effective unless contract`, 'DOC');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (def.node.kind === 'class' && def.node.record && def.node.validationDeclared === false) {
|
|
142
|
+
const source = this.project.files.get(def.file)?.source ?? '';
|
|
143
|
+
const doc = javadocBefore(source, def.node.span.start);
|
|
144
|
+
const errors = this.effectiveErrors(def.node, def.file, this.paramsFor(def.node.typeParams, def.node, def.file));
|
|
145
|
+
for (const tag of doc?.tags ?? [])
|
|
146
|
+
if (['throws', 'exception'].includes(tag.name) &&
|
|
147
|
+
!errors.some(error => tyName(error) === tag.value.split(/\s/)[0]))
|
|
148
|
+
this.report(def.node.span, `@${tag.name} ${tag.value.split(/\s/)[0]} is absent from ${def.node.name}'s inferred validation errors`, 'DOC');
|
|
107
149
|
}
|
|
150
|
+
}
|
|
108
151
|
if (this.project.main) {
|
|
109
152
|
const context = { file: this.project.main.path, locals: new Map(),
|
|
110
153
|
returns: builtin('void'), returnOwnership: 'managed', allowedErrors: this.project.testMode ? [builtin('Error')] : [],
|
|
@@ -133,7 +176,7 @@ class Checker {
|
|
|
133
176
|
this.report(def.node.span, '/__aug/actions.js is reserved for HTTP action transport', 'HTTP');
|
|
134
177
|
return { project: this.project, diagnostics: this.diagnostics, bindings: this.bindings,
|
|
135
178
|
expressionTypes: this.expressionTypes, defaults: this.defaults, callPlans: this.callPlans,
|
|
136
|
-
interceptorPlans: this.interceptorPlans, effectContracts: this.effectContracts,
|
|
179
|
+
interceptorPlans: this.interceptorPlans, effectContracts: this.effectContracts, callableContracts: this.callableContracts, constructorContracts: this.constructorContracts,
|
|
137
180
|
expressionOrigins: this.expressionOrigins, scopes: this.scopes, markupCalls: this.markupCalls, actions: this.actions, httpPolicies: this.httpPolicies };
|
|
138
181
|
}
|
|
139
182
|
isStatement(item) {
|
|
@@ -144,48 +187,84 @@ class Checker {
|
|
|
144
187
|
return;
|
|
145
188
|
this.diagnostics.push({ file: span.file, line: span.line, column: span.column, message, code });
|
|
146
189
|
}
|
|
147
|
-
/** Infer
|
|
148
|
-
inferImplementationEffects() {
|
|
190
|
+
/** Infer body-derived contracts without changing the cached source AST. */
|
|
191
|
+
inferImplementationEffects(initialize = true) {
|
|
149
192
|
const bodies = [];
|
|
150
193
|
for (const definition of this.project.definitions.values()) {
|
|
151
194
|
const node = definition.node;
|
|
195
|
+
if (node.kind === 'class' && initializationOf(node).length) {
|
|
196
|
+
if (initialize) {
|
|
197
|
+
const initializer = { kind: 'function', name: node.name, typeParams: [], params: [],
|
|
198
|
+
returns: syntheticType('void', node.span), returnOwnership: 'managed', throws: node.validationErrors ?? [],
|
|
199
|
+
body: initializationOf(node), externC: false, span: node.span };
|
|
200
|
+
const errors = (node.validationErrors ?? []).map(ref => this.resolveType(ref, definition.file, this.paramsFor(node.typeParams, node, definition.file)));
|
|
201
|
+
const contract = { result: builtin('void'), errors, inferredResult: false,
|
|
202
|
+
inferredErrors: !!node.record && node.validationDeclared === false };
|
|
203
|
+
this.initializers.set(node, initializer);
|
|
204
|
+
this.callableContracts.set(initializer, contract);
|
|
205
|
+
this.constructorContracts.set(node, contract);
|
|
206
|
+
}
|
|
207
|
+
bodies.push({ method: this.initializers.get(node), definition, owner: definition, initializing: true });
|
|
208
|
+
}
|
|
152
209
|
const methods = node.kind === 'function' ? [node] : 'methods' in node ? node.methods : [];
|
|
210
|
+
const types = this.paramsFor(node.typeParams, node, definition.file);
|
|
153
211
|
for (const method of methods) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
212
|
+
const eligible = !!method.body && !method.externC && method.name !== 'drop';
|
|
213
|
+
if (initialize) {
|
|
214
|
+
const params = new Map([...types, ...this.paramsFor(method.typeParams, method, definition.file)]);
|
|
215
|
+
this.callableContracts.set(method, {
|
|
216
|
+
result: eligible && method.declared?.returns === false ? errorTy : this.resolveType(method.returns, definition.file, params),
|
|
217
|
+
errors: method.throws.map(ref => this.resolveType(ref, definition.file, params)),
|
|
218
|
+
inferredResult: eligible && method.declared?.returns === false,
|
|
219
|
+
inferredErrors: eligible && method.declared?.errors === false,
|
|
220
|
+
});
|
|
221
|
+
if (eligible && !method.uses?.length)
|
|
222
|
+
this.inferredUses.set(method, new Map());
|
|
223
|
+
if (eligible && !method.changes?.length)
|
|
224
|
+
this.inferredChanges.set(method, new Set());
|
|
225
|
+
}
|
|
226
|
+
if (eligible)
|
|
227
|
+
bodies.push({ method, definition, owner: node.kind === 'function' ? undefined : definition });
|
|
162
228
|
}
|
|
163
229
|
}
|
|
164
230
|
this.inferring = true;
|
|
165
231
|
try {
|
|
166
|
-
for (const { method, owner } of bodies)
|
|
167
|
-
if (owner?.node.kind === 'class') {
|
|
232
|
+
for (const { method, owner, initializing } of bodies)
|
|
233
|
+
if (!initializing && owner?.node.kind === 'class') {
|
|
168
234
|
const types = this.paramsFor(owner.node.typeParams, owner.node, owner.file);
|
|
169
235
|
for (const ref of owner.node.implements) {
|
|
170
236
|
const implemented = this.resolveType(ref, owner.file, types);
|
|
171
237
|
for (const entry of this.interfaceMethods(implemented, new Set()).get(method.name) ?? []) {
|
|
172
238
|
const contractOwner = this.project.definitions.get(entry.from);
|
|
239
|
+
if (initialize && this.callableContracts.get(method)?.inferredResult && !entry.method.body) {
|
|
240
|
+
const interfaceTypes = new Map(entry.params);
|
|
241
|
+
entry.method.typeParams.forEach((name, index) => {
|
|
242
|
+
const own = this.paramsFor(method.typeParams, method, owner.file).get(method.typeParams[index]);
|
|
243
|
+
if (own)
|
|
244
|
+
interfaceTypes.set(name, own);
|
|
245
|
+
});
|
|
246
|
+
this.callableContracts.get(method).result = this.returnType(entry.method, entry.file, interfaceTypes);
|
|
247
|
+
this.contextualResults.add(method);
|
|
248
|
+
}
|
|
173
249
|
if (contractOwner?.node.kind !== 'interface' || !contractOwner.node.capability)
|
|
174
250
|
continue;
|
|
175
|
-
// Invoking a capability is
|
|
251
|
+
// Invoking a capability is an effect even for a pure test adapter.
|
|
176
252
|
const contract = this.contractFor(entry.method, entry.file, contractOwner, entry.params);
|
|
177
253
|
for (const [key, effect] of contract.uses)
|
|
178
|
-
this.inferredUses.get(method)
|
|
254
|
+
this.inferredUses.get(method)?.set(key, effect);
|
|
179
255
|
}
|
|
180
256
|
}
|
|
181
257
|
}
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
258
|
+
// Forward references and recursive calls reach the same deterministic fixed point.
|
|
259
|
+
for (let pass = 0; pass <= bodies.length + 1; pass++) {
|
|
260
|
+
this.constructorFreshness.clear();
|
|
185
261
|
this.inferenceChanged = false;
|
|
186
262
|
this.changingInference.clear();
|
|
187
|
-
for (const { method, definition, owner } of bodies)
|
|
188
|
-
this.
|
|
263
|
+
for (const { method, definition, owner, initializing } of bodies) {
|
|
264
|
+
const types = this.paramsFor(owner && 'typeParams' in owner.node ? owner.node.typeParams : [], owner?.node, definition.file);
|
|
265
|
+
const next = owner?.node.kind === 'interceptor' && method.name === 'around' ? this.nextFor(method, definition.file, types) : undefined;
|
|
266
|
+
this.checkFunctionBody(method, definition.file, owner, initializing, undefined, next);
|
|
267
|
+
}
|
|
189
268
|
if (!this.inferenceChanged)
|
|
190
269
|
return;
|
|
191
270
|
}
|
|
@@ -194,7 +273,39 @@ class Checker {
|
|
|
194
273
|
this.inferring = false;
|
|
195
274
|
}
|
|
196
275
|
for (const method of this.changingInference)
|
|
197
|
-
this.report(method.span, `
|
|
276
|
+
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');
|
|
277
|
+
}
|
|
278
|
+
returnType(fn, file, types = new Map()) {
|
|
279
|
+
const contract = this.callableContracts.get(fn);
|
|
280
|
+
return contract ? this.substitute(contract.result, types) : this.resolveType(fn.returns, file, types);
|
|
281
|
+
}
|
|
282
|
+
bodyErrors(fn, file, types = new Map()) {
|
|
283
|
+
const contract = this.callableContracts.get(fn);
|
|
284
|
+
return contract ? contract.errors.map(type => this.substitute(type, types)) : fn.throws.map(ref => this.resolveType(ref, file, types));
|
|
285
|
+
}
|
|
286
|
+
markInference(fn) {
|
|
287
|
+
this.inferenceChanged = true;
|
|
288
|
+
this.changingInference.add(fn);
|
|
289
|
+
}
|
|
290
|
+
inferredReturn(types) {
|
|
291
|
+
const known = types.filter(type => type.kind !== 'error');
|
|
292
|
+
if (!known.length)
|
|
293
|
+
return types.length ? errorTy : builtin('void');
|
|
294
|
+
let result = known[0];
|
|
295
|
+
for (const type of known.slice(1)) {
|
|
296
|
+
if (unresolved(result) && !unresolved(type))
|
|
297
|
+
result = type;
|
|
298
|
+
else if (type.kind === 'null' && result.kind !== 'null')
|
|
299
|
+
result = { ...result, nullable: true, optional: true };
|
|
300
|
+
else if (result.kind === 'null' && type.kind !== 'null')
|
|
301
|
+
result = { ...type, nullable: true, optional: true };
|
|
302
|
+
else if (this.assignable(type, result))
|
|
303
|
+
continue;
|
|
304
|
+
else if (this.assignable(result, type))
|
|
305
|
+
result = type;
|
|
306
|
+
// Keep the first type; the final checking pass diagnoses incompatible returns.
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
198
309
|
}
|
|
199
310
|
checkMemberVisibility(ownerId, ownerName, name, span, context) {
|
|
200
311
|
if (isPrivateName(name) && context.self?.id !== ownerId)
|
|
@@ -289,8 +400,10 @@ class Checker {
|
|
|
289
400
|
iface.extends.forEach(ref => visit(ref, 1));
|
|
290
401
|
iface.methods.forEach(method => {
|
|
291
402
|
method.params.forEach(param => visit(param.type, -1));
|
|
292
|
-
|
|
293
|
-
|
|
403
|
+
const result = this.callableContracts.get(method)?.result;
|
|
404
|
+
const reference = (type) => ({ name: type.name, args: type.args.map(reference), nullable: type.nullable, optional: type.optional, span: method.span });
|
|
405
|
+
visit(result ? reference(result) : method.returns, 1);
|
|
406
|
+
(this.callableContracts.get(method)?.errors.map(reference) ?? method.throws).forEach(ref => visit(ref, 1));
|
|
294
407
|
});
|
|
295
408
|
}
|
|
296
409
|
checkFunctionSignature(fn, file, inheritedParams) {
|
|
@@ -313,7 +426,7 @@ class Checker {
|
|
|
313
426
|
this.report(param.span, 'A resolve parameter cannot also be own or borrow', 'DI');
|
|
314
427
|
this.resolveType(param.type, file, params);
|
|
315
428
|
}
|
|
316
|
-
this.
|
|
429
|
+
this.returnType(fn, file, params);
|
|
317
430
|
if (fn.endpoint) {
|
|
318
431
|
const endpoint = fn.endpoint;
|
|
319
432
|
if (!/^[A-Z]+$/.test(endpoint.method))
|
|
@@ -342,7 +455,7 @@ class Checker {
|
|
|
342
455
|
if (param.source?.kind === 'request' && type.name !== 'HttpRequest')
|
|
343
456
|
this.report(param.span, 'from request provides HttpRequest', 'HTTP');
|
|
344
457
|
}
|
|
345
|
-
const result = this.
|
|
458
|
+
const result = this.returnType(fn, file, params);
|
|
346
459
|
if (endpoint.streams) {
|
|
347
460
|
if (!['ServerEvent', 'Bytes', 'Html'].includes(result.name) || result.optional || result.nullable)
|
|
348
461
|
this.report(fn.span, 'An endpoint streams ServerEvent<T>, Bytes, or Html', 'HTTP');
|
|
@@ -414,7 +527,7 @@ class Checker {
|
|
|
414
527
|
this.report(method.span, 'Declare generic parameters on the interceptor, rather than around', 'INTERCEPTOR');
|
|
415
528
|
if (method.annotations?.length)
|
|
416
529
|
this.report(method.span, 'Apply interceptor layers to the target declaration; around cannot be annotated', 'INTERCEPTOR');
|
|
417
|
-
if (method.
|
|
530
|
+
if (this.returnType(method, def.file, types).name !== 'void' && canFallThrough(method.body ?? []))
|
|
418
531
|
this.report(method.span, 'around must return its result or throw on every execution path', 'INTERCEPTOR');
|
|
419
532
|
if (canRepeatNext(method.body ?? []))
|
|
420
533
|
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 +537,11 @@ class Checker {
|
|
|
424
537
|
this.report(node.span, `${node.name} must define around(...)`, 'INTERCEPTOR');
|
|
425
538
|
}
|
|
426
539
|
nextFor(method, file, types) {
|
|
540
|
+
const result = this.returnType(method, file, types);
|
|
427
541
|
return { params: method.params, types: method.params.map(param => this.resolveType(param.type, file, types)),
|
|
428
|
-
returns:
|
|
542
|
+
returns: result.kind === 'error' && method.declared?.returns === false ?
|
|
543
|
+
{ id: 'continuation:' + file + ':' + method.span.start, name: '<target result>', kind: 'param', args: [], nullable: false } : result,
|
|
544
|
+
returnOwnership: method.returnOwnership };
|
|
429
545
|
}
|
|
430
546
|
inferInterceptorType(ref, actual, names, types, file) {
|
|
431
547
|
inferType(ref, actual, names, types, message => this.report(ref.span, message, 'GENERIC'), (name, value) => {
|
|
@@ -450,6 +566,24 @@ class Checker {
|
|
|
450
566
|
}
|
|
451
567
|
return undefined;
|
|
452
568
|
}
|
|
569
|
+
/** The native policy ABI accepts the published capability shape across source-package identities. */
|
|
570
|
+
nativeWebCapability(type, name) {
|
|
571
|
+
const canonical = nativeHttpContracts.get(name);
|
|
572
|
+
const shape = (value) => {
|
|
573
|
+
if (Array.isArray(value))
|
|
574
|
+
return value.map(shape);
|
|
575
|
+
if (!value || typeof value !== 'object')
|
|
576
|
+
return value;
|
|
577
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => !['span', 'nameSpan', 'headerEnd'].includes(key)).map(([key, child]) => [key, shape(child)]));
|
|
578
|
+
};
|
|
579
|
+
if (!canonical || !type.def || JSON.stringify(shape(type.def.node)) !== JSON.stringify(shape(canonical)))
|
|
580
|
+
return false;
|
|
581
|
+
if (name === 'RequestLogger')
|
|
582
|
+
return true;
|
|
583
|
+
const principal = this.project.scopes.get(type.def.file)?.get('Principal');
|
|
584
|
+
const expected = nativeHttpContracts.get('Principal');
|
|
585
|
+
return !!principal && !!expected && JSON.stringify(shape(principal.node)) === JSON.stringify(shape(expected));
|
|
586
|
+
}
|
|
453
587
|
planInterceptors() {
|
|
454
588
|
const plan = (node, file, ownerTypes, inputs, output, ownership) => {
|
|
455
589
|
const layers = [];
|
|
@@ -465,7 +599,7 @@ class Checker {
|
|
|
465
599
|
const policies = this.httpPolicies.get(node) ?? [];
|
|
466
600
|
if (['Cors', 'Compress'].includes(annotation.name) && policies.some(policy => policy.name === annotation.name))
|
|
467
601
|
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)
|
|
602
|
+
policies.push(checkHttpPolicy(annotation, node, this.diagnostics, (param, name) => this.nativeWebCapability(this.resolveType(param.type, file, ownerTypes), name)));
|
|
469
603
|
this.httpPolicies.set(node, policies);
|
|
470
604
|
}
|
|
471
605
|
continue;
|
|
@@ -511,7 +645,16 @@ class Checker {
|
|
|
511
645
|
types.set(name, this.resolveType(annotation.typeArgs[index], file, ownerTypes));
|
|
512
646
|
});
|
|
513
647
|
const inferredNames = interceptor.typeParams.filter((_, index) => !annotation.typeArgs[index]);
|
|
514
|
-
this.
|
|
648
|
+
const inferredOutput = this.callableContracts.get(around);
|
|
649
|
+
if (inferredOutput?.inferredResult) {
|
|
650
|
+
types.set('<target result>', output);
|
|
651
|
+
if (inferredOutput.result.name !== '<target result>') {
|
|
652
|
+
const reference = (type) => ({ name: type.name, args: type.args.map(reference), nullable: type.nullable, optional: type.optional, span: around.span });
|
|
653
|
+
this.inferInterceptorType(reference(inferredOutput.result), output, inferredNames, types, definition.file);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
else
|
|
657
|
+
this.inferInterceptorType(around.returns, output, inferredNames, types, definition.file);
|
|
515
658
|
const argumentIndices = around.params.map(param => param.injected ? undefined :
|
|
516
659
|
inputs.findIndex(input => input.name === (mapping.get(param.name) ?? param.name)));
|
|
517
660
|
const inputTypes = argumentIndices.map((index, i) => index !== undefined && index >= 0 ?
|
|
@@ -548,7 +691,7 @@ class Checker {
|
|
|
548
691
|
}
|
|
549
692
|
return undefined;
|
|
550
693
|
});
|
|
551
|
-
const result = this.
|
|
694
|
+
const result = this.returnType(around, definition.file, types);
|
|
552
695
|
if (!this.assignable(result, output))
|
|
553
696
|
this.report(annotation.span, `${interceptor.name}.around returns ${tyName(result)}; ${node.name} requires ${tyName(output)}`, 'INTERCEPTOR');
|
|
554
697
|
if (around.returnOwnership !== ownership)
|
|
@@ -566,7 +709,7 @@ class Checker {
|
|
|
566
709
|
const argumentInjectionIndices = around.params.map(param => param.injected ? injectedIndex(param.type) : undefined);
|
|
567
710
|
layers.push({ annotation, definition, around, argumentIndices, argumentBindings, constructorKeys,
|
|
568
711
|
types, inputTypes, outputType: output, constructorInputIndices, argumentInjectionIndices,
|
|
569
|
-
errors:
|
|
712
|
+
errors: this.bodyErrors(around, definition.file, types) });
|
|
570
713
|
}
|
|
571
714
|
};
|
|
572
715
|
for (const def of this.project.definitions.values()) {
|
|
@@ -575,13 +718,13 @@ class Checker {
|
|
|
575
718
|
if (node.kind === 'class')
|
|
576
719
|
plan(node, def.file, types, node.fields, { id: def.id, name: def.name, kind: 'class', def, args: [...types.values()], nullable: false }, 'managed');
|
|
577
720
|
if (node.kind === 'function')
|
|
578
|
-
plan(node, def.file, types, node.params, this.
|
|
721
|
+
plan(node, def.file, types, node.params, this.returnType(node, def.file, types), node.returnOwnership);
|
|
579
722
|
if ('methods' in node)
|
|
580
723
|
for (const method of node.methods) {
|
|
581
724
|
if (node.kind === 'interceptor' && method.name === 'around')
|
|
582
725
|
continue;
|
|
583
726
|
const methodTypes = new Map([...types, ...this.paramsFor(method.typeParams, method, def.file)]);
|
|
584
|
-
plan(method, def.file, methodTypes, method.params, this.
|
|
727
|
+
plan(method, def.file, methodTypes, method.params, this.returnType(method, def.file, methodTypes), method.returnOwnership);
|
|
585
728
|
}
|
|
586
729
|
}
|
|
587
730
|
}
|
|
@@ -594,8 +737,8 @@ class Checker {
|
|
|
594
737
|
}
|
|
595
738
|
effectiveErrors(node, file, types) {
|
|
596
739
|
return [
|
|
597
|
-
...(node.kind === 'function' ? node
|
|
598
|
-
...(this.interceptorPlans.get(node) ?? []).flatMap(layer => layer.
|
|
740
|
+
...(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)))),
|
|
741
|
+
...(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
742
|
];
|
|
600
743
|
}
|
|
601
744
|
checkInterceptorDependencies() {
|
|
@@ -745,7 +888,7 @@ class Checker {
|
|
|
745
888
|
param.injected === method.params[i].injected &&
|
|
746
889
|
param.ownership === method.params[i].ownership &&
|
|
747
890
|
equalRef(param.type, method.params[i].type)) &&
|
|
748
|
-
|
|
891
|
+
this.sameType(this.returnType(left, leftFile, leftParams), this.returnType(method, right.file, rightParams)) &&
|
|
749
892
|
left.returnOwnership === method.returnOwnership &&
|
|
750
893
|
this.effectiveErrors(left, leftFile, leftParams).every(thrown => this.effectiveErrors(method, right.file, rightParams).some(allowed => this.assignable(thrown, allowed)));
|
|
751
894
|
}
|
|
@@ -863,7 +1006,7 @@ class Checker {
|
|
|
863
1006
|
else if (item.keyTypeArgs.length)
|
|
864
1007
|
this.report(item.span, `Named binding ${item.key} cannot take type arguments`, 'DI');
|
|
865
1008
|
const stateful = fieldsOf(target.node).some(field => field.mutable || field.ownership === 'own' || field.type.name === 'Shared') ||
|
|
866
|
-
target.node.methods.some(method => method.changes
|
|
1009
|
+
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
1010
|
const info = { key, target, exposedType, stateful, lifetime: item.lifetime ?? (stateful ? 'fresh' : 'shared'),
|
|
868
1011
|
dependencies: [], constructorKeys: [], declaration: item, requiresScope: item.lifetime === 'scoped' };
|
|
869
1012
|
this.bindings.push(info);
|
|
@@ -921,9 +1064,10 @@ class Checker {
|
|
|
921
1064
|
for (const [name, ty] of this.paramsFor(fn.typeParams, fn, file))
|
|
922
1065
|
params.set(name, ty);
|
|
923
1066
|
this.addBounds(params, fn, file);
|
|
924
|
-
const context = { file, locals: new Map(), returns: this.
|
|
1067
|
+
const context = { file, locals: new Map(), returns: this.returnType(fn, file, params),
|
|
925
1068
|
returnOwnership: fn.returnOwnership,
|
|
926
|
-
allowedErrors:
|
|
1069
|
+
allowedErrors: this.bodyErrors(fn, file, params),
|
|
1070
|
+
inferredReturns: this.inferring && this.callableContracts.get(fn)?.inferredResult && !this.contextualResults.has(fn) ? [] : undefined,
|
|
927
1071
|
unsafe: false, borrowed: new Set(), initializing, types: params, next, callable: fn, owner,
|
|
928
1072
|
flow: new OwnershipFlow() };
|
|
929
1073
|
if (fn.endpoint?.streams) {
|
|
@@ -934,7 +1078,7 @@ class Checker {
|
|
|
934
1078
|
context.self = { id: owner.id, name: owner.name,
|
|
935
1079
|
kind: owner.node.kind === 'class' ? 'class' : owner.node.kind === 'interceptor' ? 'interceptor' : 'interface', def: owner,
|
|
936
1080
|
args: [...params.values()].slice(0, owner.node.typeParams.length), nullable: false };
|
|
937
|
-
context.locals.set('self', { type: context.self, ownership: (fn
|
|
1081
|
+
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
1082
|
if (owner.node.kind === 'class' || owner.node.kind === 'interceptor') {
|
|
939
1083
|
for (const field of fieldsOf(owner.node))
|
|
940
1084
|
context.locals.set(field.name, { type: { ...this.resolveType(field.type, file, params), readonly: !field.mutable }, ownership: field.ownership,
|
|
@@ -966,7 +1110,28 @@ class Checker {
|
|
|
966
1110
|
context.effects = this.contractFor(fn, file, owner, params);
|
|
967
1111
|
if ((fn.changes ?? []).some(path => path.startsWith('self')) && !owner)
|
|
968
1112
|
this.report(fn.span, 'A free function has no self to change', 'EFFECT');
|
|
1113
|
+
for (const policy of this.httpPolicies.get(fn) ?? []) {
|
|
1114
|
+
const operations = Object.values(httpPolicyOptions[policy.name]).filter(spec => spec.startsWith('dependency:'));
|
|
1115
|
+
policy.dependencies.forEach((index, order) => {
|
|
1116
|
+
const param = fn.params[index];
|
|
1117
|
+
if (!param || !operations[order])
|
|
1118
|
+
return;
|
|
1119
|
+
const type = this.resolveType(param.type, file, params);
|
|
1120
|
+
const operation = operations[order].split('.')[1];
|
|
1121
|
+
this.requireUse(capabilityKey(type, operation), `${tyName(type)}.${operation}`, policy.annotation.span, context, { source: tyName(type), operation, span: policy.annotation.span, capability: type });
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
969
1124
|
this.checkStatements(fn.body ?? [], context, fn.span);
|
|
1125
|
+
if (context.inferredReturns) {
|
|
1126
|
+
const contract = this.callableContracts.get(fn);
|
|
1127
|
+
const result = this.inferredReturn(context.inferredReturns);
|
|
1128
|
+
if (!sameType(result, contract.result)) {
|
|
1129
|
+
contract.result = result;
|
|
1130
|
+
this.markInference(fn);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
if (!this.inferring && unresolved(this.returnType(fn, file, params)))
|
|
1134
|
+
this.report(fn.span, `Cannot infer ${fn.name}'s return type; add returns T to anchor recursive or ambiguous results`, 'INFERENCE');
|
|
970
1135
|
if (fn.body && context.returns.id !== 'builtin:void' &&
|
|
971
1136
|
!(owner?.node.kind === 'interceptor' && fn.name === 'around') && canFallThrough(fn.body))
|
|
972
1137
|
this.report(fn.span, `${fn.name} must return a value or throw on every path`, 'TYPE');
|
|
@@ -1046,16 +1211,19 @@ class Checker {
|
|
|
1046
1211
|
report: (span, message) => this.report(span, message, 'EFFECT'),
|
|
1047
1212
|
});
|
|
1048
1213
|
const inferred = this.inferredUses.get(fn);
|
|
1214
|
+
const inferredChanges = this.inferredChanges.get(fn);
|
|
1215
|
+
const changes = inferredChanges ? [...inferredChanges].sort() : result.changes;
|
|
1049
1216
|
if (!inferred) {
|
|
1050
|
-
|
|
1051
|
-
|
|
1217
|
+
const contract = { ...result, changes, inferredChanges: !!inferredChanges };
|
|
1218
|
+
this.effectContracts.set(fn, contract);
|
|
1219
|
+
return contract;
|
|
1052
1220
|
}
|
|
1053
1221
|
const uses = new Map(result.uses);
|
|
1054
1222
|
for (const [key, effect] of inferred) {
|
|
1055
1223
|
const capability = effect.capability && this.substitute(effect.capability, types);
|
|
1056
1224
|
uses.set(capability ? capabilityKey(capability, effect.operation) : key, { ...effect, capability, source: capability ? tyName(capability) : effect.source });
|
|
1057
1225
|
}
|
|
1058
|
-
const contract = { ...result, uses, inferred: true };
|
|
1226
|
+
const contract = { ...result, changes, uses, inferred: true, inferredChanges: !!inferredChanges };
|
|
1059
1227
|
this.effectContracts.set(fn, contract);
|
|
1060
1228
|
return contract;
|
|
1061
1229
|
}
|
|
@@ -1096,7 +1264,7 @@ class Checker {
|
|
|
1096
1264
|
changes.push([fn.params[target].name, ...path].join('.'));
|
|
1097
1265
|
}
|
|
1098
1266
|
}
|
|
1099
|
-
const result = { changes: [...new Set(changes)], uses, inferred: base.inferred };
|
|
1267
|
+
const result = { changes: [...new Set(changes)], uses, inferred: base.inferred, inferredChanges: base.inferredChanges };
|
|
1100
1268
|
this.effectContracts.set(fn, result);
|
|
1101
1269
|
return result;
|
|
1102
1270
|
}
|
|
@@ -1126,8 +1294,16 @@ class Checker {
|
|
|
1126
1294
|
return;
|
|
1127
1295
|
const input = context.callable.params.find(param => param.name === origin);
|
|
1128
1296
|
if (path.startsWith('self') || input && input.ownership !== 'own') {
|
|
1129
|
-
|
|
1130
|
-
|
|
1297
|
+
const inferred = this.inferring && this.inferredChanges.get(context.callable);
|
|
1298
|
+
const change = path.startsWith('self') ? 'self' : origin;
|
|
1299
|
+
if (inferred) {
|
|
1300
|
+
if (!inferred.has(change)) {
|
|
1301
|
+
inferred.add(change);
|
|
1302
|
+
this.markInference(context.callable);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
else if (!coversChange(context.effects?.changes ?? [], path))
|
|
1306
|
+
this.report(span, `${context.callable.name} must declare changes ${change}`, 'EFFECT');
|
|
1131
1307
|
}
|
|
1132
1308
|
}
|
|
1133
1309
|
immutableData(type, seen = new Set()) {
|
|
@@ -1214,8 +1390,9 @@ class Checker {
|
|
|
1214
1390
|
const type = this.checkExpression(stmt.value, context);
|
|
1215
1391
|
if (type.id !== 'builtin:Shared')
|
|
1216
1392
|
this.report(stmt.value.span, 'lock requires Shared<T>', 'CONCURRENCY');
|
|
1217
|
-
|
|
1218
|
-
|
|
1393
|
+
const external = type.readonly || !!context.flow.external(this.rootName(stmt.value) ?? '');
|
|
1394
|
+
if (context.callable && external && !context.effects?.uses.size && !context.effects?.changes.length)
|
|
1395
|
+
this.report(stmt.span, 'A callable that locks external shared state declares its capability operation or changes contract', 'EFFECT');
|
|
1219
1396
|
const inside = this.cloneContext(context);
|
|
1220
1397
|
inside.locked = true;
|
|
1221
1398
|
const origins = allocationOrigin(stmt.span);
|
|
@@ -1494,8 +1671,9 @@ class Checker {
|
|
|
1494
1671
|
return;
|
|
1495
1672
|
}
|
|
1496
1673
|
if (stmt.kind === 'return') {
|
|
1497
|
-
const type = stmt.value ? this.checkExpression(stmt.value, context, context.returns) : builtin('void');
|
|
1498
|
-
|
|
1674
|
+
const type = stmt.value ? this.checkExpression(stmt.value, context, context.returns.kind === 'error' ? undefined : context.returns) : builtin('void');
|
|
1675
|
+
context.inferredReturns?.push(type);
|
|
1676
|
+
const declaredErrors = context.callable ? this.bodyErrors(context.callable, context.file, context.types) : [];
|
|
1499
1677
|
for (const error of context.flow.pendingTaskErrors())
|
|
1500
1678
|
this.checkAllowedError(error, stmt.span, { ...context, allowedErrors: declaredErrors, exceptionalFlows: undefined });
|
|
1501
1679
|
if (!this.assignable(type, context.returns))
|
|
@@ -1829,8 +2007,17 @@ class Checker {
|
|
|
1829
2007
|
return;
|
|
1830
2008
|
}
|
|
1831
2009
|
context.exceptionalFlows?.push({ type, flow: context.flow.clone() });
|
|
1832
|
-
if (!context.allowedErrors.some(allowed => this.assignable(type, allowed)))
|
|
1833
|
-
|
|
2010
|
+
if (!context.allowedErrors.some(allowed => this.assignable(type, allowed))) {
|
|
2011
|
+
const contract = context.callable && this.inferring && this.callableContracts.get(context.callable);
|
|
2012
|
+
if (contract && contract.inferredErrors && type.kind !== 'error') {
|
|
2013
|
+
if (!contract.errors.some(error => sameType(error, type))) {
|
|
2014
|
+
contract.errors.push(type);
|
|
2015
|
+
this.markInference(context.callable);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
else
|
|
2019
|
+
this.report(span, `Unhandled ${tyName(type)}; catch it or declare unless ${tyName(type)}`, 'THROWS');
|
|
2020
|
+
}
|
|
1834
2021
|
}
|
|
1835
2022
|
checkCollection(expr, context, expected) {
|
|
1836
2023
|
const name = expr.collection === 'empty' ? expected?.name === 'Set' ? 'Set' : 'Map' : expr.collection;
|
|
@@ -2142,14 +2329,14 @@ class Checker {
|
|
|
2142
2329
|
this.defaults.get(def.id)?.get(name)?.method;
|
|
2143
2330
|
if (method) {
|
|
2144
2331
|
this.checkMemberVisibility(def.id, def.name, name, span, context);
|
|
2145
|
-
return this.
|
|
2332
|
+
return this.returnType(method, def.file, new Map(def.node.typeParams.map((param, i) => [param, receiver.args[i] ?? errorTy])));
|
|
2146
2333
|
}
|
|
2147
2334
|
}
|
|
2148
2335
|
if (def?.node.kind === 'interface') {
|
|
2149
2336
|
const entry = this.interfaceMethods(receiver, new Set()).get(name)?.[0];
|
|
2150
2337
|
if (entry) {
|
|
2151
2338
|
this.checkMemberVisibility(entry.from, def.name, name, span, context);
|
|
2152
|
-
return this.
|
|
2339
|
+
return this.returnType(entry.method, entry.file, entry.params);
|
|
2153
2340
|
}
|
|
2154
2341
|
}
|
|
2155
2342
|
this.report(span, `${tyName(receiver)} has no member ${name}`);
|
|
@@ -2604,8 +2791,8 @@ class Checker {
|
|
|
2604
2791
|
else if (!jsonDataType(this.project, result))
|
|
2605
2792
|
this.report(expr.span, `${tyName(result)} is not JSON data; use a record or data collection`, 'JSON');
|
|
2606
2793
|
if (result.def?.node.kind === 'class')
|
|
2607
|
-
for (const error of result.def.node.
|
|
2608
|
-
this.checkAllowedError(
|
|
2794
|
+
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]))))
|
|
2795
|
+
this.checkAllowedError(error, expr.span, context);
|
|
2609
2796
|
}
|
|
2610
2797
|
return this.isReference(result) ? { ...result, readonly: true, frozen: decoding || receiver.name === 'Json' } : result;
|
|
2611
2798
|
}
|
|
@@ -2797,7 +2984,7 @@ class Checker {
|
|
|
2797
2984
|
], (span, message) => this.report(span, message, 'BORROW'));
|
|
2798
2985
|
for (const thrown of this.effectiveErrors(fn, fnFile, params))
|
|
2799
2986
|
this.checkAllowedError(thrown, expr.span, context);
|
|
2800
|
-
const result = this.
|
|
2987
|
+
const result = this.returnType(fn, fnFile, params);
|
|
2801
2988
|
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
2989
|
{ ...result, readonly: true } : result;
|
|
2803
2990
|
}
|