diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6b251402bc..5f1199a3d8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,42 @@ env: NIGHTLY_RUST_VERSION: nightly-2024-10-21 jobs: + verifications-complete: + needs: + - build-sway-lib-core + - build-sway-lib-std + - build-sway-examples + - build-reference-examples + - forc-fmt-check-sway-lib-core + - forc-fmt-check-sway-lib-std + - forc-fmt-check-sway-examples + - forc-fmt-check-panic + - check-sdk-harness-test-suite-compatibility + - build-mdbook + - build-forc-doc-sway-lib-std + - build-forc-test-project + - cargo-build-workspace + - cargo-clippy + - cargo-toml-fmt-check + - cargo-fmt-check + - cargo-run-e2e-test-evm + - cargo-test-lib-std + - forc-run-benchmarks + - forc-unit-tests + - forc-pkg-fuels-deps-check + - cargo-test-sway-lsp + - cargo-test-forc + - cargo-test-workspace + - cargo-unused-deps-check + - pre-publish-check + - cargo-run-e2e-test + - cargo-run-e2e-test-release + - cargo-test-forc-debug + - cargo-test-forc-client + - notify-slack-on-failure + runs-on: ubuntu-latest + steps: + - run: echo "pass" get-fuel-core-version: runs-on: buildjet-4vcpu-ubuntu-2204 outputs: @@ -251,7 +287,7 @@ jobs: run: | cargo install --locked --debug --path ./forc-plugins/forc-doc - name: Build sway-lib-std docs - run: forc doc --manifest-path ./sway-lib-std + run: forc doc --path ./sway-lib-std build-forc-test-project: runs-on: buildjet-4vcpu-ubuntu-2204 @@ -434,6 +470,10 @@ jobs: run: cargo run --locked --release -p forc -- build --release --locked --path ./test/src/sdk-harness - name: Cargo Test sway-lib-std run: cargo test --locked --release --manifest-path ./test/src/sdk-harness/Cargo.toml -- --nocapture + - name: Build All Tests - Experimental Feature 'storage_domains' + run: cargo run --locked --release -p forc -- build --experimental storage_domains --release --locked --path ./test/src/sdk-harness + - name: Cargo Test sway-lib-std - Experimental Feature 'storage_domains' + run: cargo test --locked --release --manifest-path ./test/src/sdk-harness/Cargo.toml -- --nocapture forc-run-benchmarks: runs-on: buildjet-4vcpu-ubuntu-2204 @@ -489,10 +529,16 @@ jobs: run: cargo install --locked --debug --path ./forc - name: Run Core Unit Tests run: forc build --path sway-lib-core && forc test --path sway-lib-core + - name: Run Core Unit Tests - Experimental feature 'storage_domains' + run: forc build --experimental storage_domains --path sway-lib-core && forc test --experimental storage_domains --path sway-lib-core - name: Run Std Unit Tests run: forc build --path sway-lib-std && forc test --path sway-lib-std + - name: Run Std Unit Tests - Experimental feature 'storage_domains' + run: forc build --experimental storage_domains --path sway-lib-std && forc test --experimental storage_domains --path sway-lib-std - name: Run In Language Unit Tests run: forc build --path test/src/in_language_tests && forc test --path test/src/in_language_tests + - name: Run In Language Unit Tests - Experimental feature 'storage_domains' + run: forc build --experimental storage_domains --path test/src/in_language_tests && forc test --experimental storage_domains --path test/src/in_language_tests forc-pkg-fuels-deps-check: runs-on: buildjet-4vcpu-ubuntu-2204 diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index fa2ac16b866..7e3201451c5 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -50,7 +50,7 @@ jobs: run: mdbook build docs/reference - name: Build Sway std library - run: forc doc --manifest-path ./sway-lib-std + run: forc doc --path ./sway-lib-std - name: Deploy master std uses: peaceiris/actions-gh-pages@v3 diff --git a/Cargo.lock b/Cargo.lock index 95a6bab5a68..d3c21b0d08b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,9 +73,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "alloy-eip2930" @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f35429a652765189c1c5092870d8360ee7b7769b09b06d89ebaefd34676446" +checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425" dependencies = [ "alloy-rlp", "bytes", @@ -112,7 +112,7 @@ dependencies = [ "const-hex", "derive_more 1.0.0", "foldhash", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "hex-literal", "indexmap 2.6.0", "itoa", @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -141,13 +141,13 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -190,11 +190,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "ansiterm" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab587f5395da16dd2e6939adf53dede583221b320cadfb94e02b5b7b9bf24cc" +dependencies = [ + "winapi", +] + [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -207,43 +216,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arc-swap" @@ -423,7 +432,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -441,17 +450,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "aurora-engine-modexp" version = "1.1.0" @@ -470,7 +468,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -481,9 +479,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.8" +version = "1.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6" +checksum = "9b49afaa341e8dd8577e1a2200468f98956d6eda50bcf4a53246cc00174ba924" dependencies = [ "aws-credential-types", "aws-runtime", @@ -548,9 +546,9 @@ dependencies = [ [[package]] name = "aws-sdk-kms" -version = "1.47.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "564a597a3c71a957d60a2e4c62c93d78ee5a0d636531e15b760acad983a5c18e" +checksum = "bfd059dacda4dfd5b57f2bd453fc6555f9acb496cb77508d517da24cf5d73167" dependencies = [ "aws-credential-types", "aws-runtime", @@ -570,9 +568,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.46.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc2faec3205d496c7e57eff685dd944203df7ce16a4116d0281c44021788a7b" +checksum = "09677244a9da92172c8dc60109b4a9658597d4d298b188dd0018b6a66b410ca4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -592,9 +590,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.47.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93c241f52bc5e0476e259c953234dab7e2a35ee207ee202e86c0095ec4951dc" +checksum = "81fea2f3a8bb3bd10932ae7ad59cc59f65f270fc9183a7e91f501dc5efbef7ee" dependencies = [ "aws-credential-types", "aws-runtime", @@ -614,9 +612,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.46.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b259429be94a3459fa1b00c5684faee118d74f9577cc50aebadc36e507c63b5f" +checksum = "6ada54e5f26ac246dc79727def52f7f8ed38915cb47781e2a72213957dc3a7d5" dependencies = [ "aws-credential-types", "aws-runtime", @@ -637,9 +635,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" +checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -710,9 +708,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -737,9 +735,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e086682a53d3aa241192aa110fa8dfce98f2f5ac2ead0de84d41582c7e8fdb96" +checksum = "92165296a47a812b267b4f41032ff8069ab7ff783696d217f0994a0d7ab585cd" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -754,9 +752,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.7" +version = "1.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b" +checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510" dependencies = [ "base64-simd", "bytes", @@ -967,9 +965,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" dependencies = [ "borsh-derive", "cfg_aliases", @@ -977,16 +975,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", - "syn_derive", + "syn 2.0.87", ] [[package]] @@ -1001,12 +998,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "serde", ] @@ -1024,9 +1021,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "byte-unit" -version = "5.1.4" +version = "5.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ac19bdf0b2665407c39d82dbc937e951e7e2001609f0fb32edd0af45a2d63e" +checksum = "e1cd29c3c585209b0cbc7309bfe3ed7efd8c84c21b7af29c8bfae908f8777174" dependencies = [ "rust_decimal", "serde", @@ -1069,9 +1066,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bytes-utils" @@ -1116,9 +1113,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.30" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "jobserver", "libc", @@ -1193,7 +1190,7 @@ checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" dependencies = [ "core2", "multibase", - "multihash 0.19.1", + "multihash 0.19.2", "unsigned-varint 0.8.0", ] @@ -1209,24 +1206,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", -] - -[[package]] -name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -1234,9 +1216,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -1247,11 +1229,11 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.33" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ - "clap 4.5.20", + "clap", ] [[package]] @@ -1260,7 +1242,7 @@ version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d494102c8ff3951810c72baf96910b980fb065ca5d3101243e6a8dc19747c86b" dependencies = [ - "clap 4.5.20", + "clap", "clap_complete", ] @@ -1273,14 +1255,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clipboard-win" @@ -1373,9 +1355,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -1446,7 +1428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c93ab3577cca16b4a1d80a88c2e0cd8b6e969e51696f0bbb0d1dcb0157109832" dependencies = [ "caseless", - "clap 4.5.20", + "clap", "derive_builder", "entities", "memchr", @@ -1568,9 +1550,9 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] @@ -1593,7 +1575,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.20", + "clap", "criterion-plot", "is-terminal", "itertools 0.10.5", @@ -1700,9 +1682,9 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", @@ -1751,7 +1733,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1850,7 +1832,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1872,7 +1854,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1885,7 +1867,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -1899,7 +1881,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -1988,7 +1970,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1998,7 +1980,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2011,7 +1993,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2031,7 +2013,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "unicode-xid", ] @@ -2160,6 +2142,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "dissimilar" version = "1.0.9" @@ -2300,9 +2293,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if 1.0.0", ] @@ -2336,7 +2329,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2349,7 +2342,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2360,7 +2353,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2426,9 +2419,9 @@ checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" [[package]] name = "escargot" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000f23e9d459aef148b7267e02b03b94a0aaacf4ec64c65612f67e02f525fb6" +checksum = "05a3ac187a16b5382fef8c69fd1bad123c67b7cf3932240a2d43dcdd32cded88" dependencies = [ "log", "once_cell", @@ -2525,7 +2518,7 @@ checksum = "dd65f1b59dd22d680c7a626cc4a000c1e03d241c51c3e034d2bc9f1e90734f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -2552,9 +2545,9 @@ checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fastrlp" @@ -2647,9 +2640,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -2669,18 +2662,18 @@ checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "forc" -version = "0.66.4" +version = "0.66.5" dependencies = [ "annotate-snippets", - "ansi_term", + "ansiterm", "anyhow", - "clap 4.5.20", + "clap", "clap_complete", "clap_complete_fig", "completest-pty", "forc-pkg", "forc-test", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "fs_extra", "fuel-asm", @@ -2700,26 +2693,25 @@ dependencies = [ "toml_edit", "tracing", "url", - "uwuify", "walkdir", "whoami", ] [[package]] name = "forc-client" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "async-trait", "aws-config", "aws-sdk-kms", "chrono", - "clap 4.5.20", + "clap", "devault", "dialoguer", "forc", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-tx", "forc-util", "forc-wallet", @@ -2755,13 +2747,13 @@ dependencies = [ [[package]] name = "forc-crypto" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "async-trait", - "clap 4.5.20", + "clap", "criterion", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "fuel-core-types", "fuel-crypto", @@ -2785,15 +2777,15 @@ dependencies = [ [[package]] name = "forc-debug" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "dap", "escargot", "forc-pkg", "forc-test", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "fuel-core-client", "fuel-types", "fuel-vm", @@ -2812,15 +2804,15 @@ dependencies = [ [[package]] name = "forc-doc" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "comrak", "dir_indexer", "expect-test", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "horrorshow", "include_dir", @@ -2838,14 +2830,14 @@ dependencies = [ [[package]] name = "forc-fmt" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", - "prettydiff 0.7.0", + "prettydiff", "sway-core", "sway-utils", "swayfmt", @@ -2855,10 +2847,10 @@ dependencies = [ [[package]] name = "forc-lsp" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "sway-lsp", "tikv-jemallocator", "tokio", @@ -2866,13 +2858,13 @@ dependencies = [ [[package]] name = "forc-pkg" -version = "0.66.4" +version = "0.66.5" dependencies = [ - "ansi_term", + "ansiterm", "anyhow", "byte-unit", "cid", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "fuel-abi-types", "futures", @@ -2882,7 +2874,7 @@ dependencies = [ "ipfs-api-backend-hyper", "petgraph", "regex", - "reqwest 0.12.8", + "reqwest 0.12.9", "semver 1.0.23", "serde", "serde_ignored", @@ -2904,7 +2896,7 @@ dependencies = [ [[package]] name = "forc-test" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "forc-pkg", @@ -2932,9 +2924,9 @@ dependencies = [ [[package]] name = "forc-tracing" -version = "0.66.4" +version = "0.66.5" dependencies = [ - "ansi_term", + "ansiterm", "tracing", "tracing-subscriber", "tracing-test", @@ -2942,10 +2934,10 @@ dependencies = [ [[package]] name = "forc-tx" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "devault", "forc-util", "fuel-tx", @@ -2957,15 +2949,16 @@ dependencies = [ [[package]] name = "forc-util" -version = "0.66.4" +version = "0.66.5" dependencies = [ "annotate-snippets", - "ansi_term", + "ansiterm", "anyhow", - "clap 4.5.20", + "clap", "dirs 5.0.1", "fd-lock", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", + "fuel-asm", "fuel-tx", "hex", "paste", @@ -2973,6 +2966,7 @@ dependencies = [ "serde", "serde_json", "serial_test", + "sha2 0.10.8", "sway-core", "sway-error", "sway-types", @@ -2984,12 +2978,12 @@ dependencies = [ [[package]] name = "forc-wallet" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6ad4498ecab72fa7c5e134ade0137279d1b8f4a6df50963bb3803fdeb69dac" +checksum = "6ed94e0de4d8265fe744704544932bf1285ffa16ee5feb18062194904d299f9f" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "eth-keystore", "forc-tracing 0.47.0", "fuel-crypto", @@ -3060,7 +3054,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.79", + "syn 2.0.87", "thiserror", ] @@ -3128,7 +3122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94a1c3eb92040d95d27f7c658801bb5c04ad4aaf67de380cececbeed5aab6e61" dependencies = [ "once_cell", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "prometheus-client", "regex", @@ -3166,7 +3160,7 @@ dependencies = [ "async-trait", "fuel-core-metrics", "futures", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "tokio", "tracing", @@ -3241,7 +3235,7 @@ checksum = "ab0bc46a3552964bae5169e79b383761a54bd115ea66951a1a7a229edcefa55a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "synstructure 0.13.1", ] @@ -3383,9 +3377,9 @@ dependencies = [ [[package]] name = "fuels" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed08053e72bdb285d5a167c27a7a0d10f1dc4e27d1e6e5296dd2a67813bd13f" +checksum = "25bf359dceffcbab4163bca473a03658b912686c3aa81a223f828260729dd474" dependencies = [ "fuel-core-client", "fuel-crypto", @@ -3399,9 +3393,9 @@ dependencies = [ [[package]] name = "fuels-accounts" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fee90e8f3a4fc9392a6cde3010c561fa50da0f805d66fdb659eaa4d5d8a504" +checksum = "4b0b09d6ce3a12196f6944c74bdd795c39950d32ebaaf56b2943741a5e4308a1" dependencies = [ "async-trait", "chrono", @@ -3425,9 +3419,9 @@ dependencies = [ [[package]] name = "fuels-code-gen" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f857b7ff658400506ca6be57bb84fedda44b566e78f5f0a8d0782242f41615c0" +checksum = "78bf5f7b37ec598514fb3767abdae5372a9fa0919d350703f5d627ec2eb33456" dependencies = [ "Inflector", "fuel-abi-types", @@ -3436,14 +3430,14 @@ dependencies = [ "quote", "regex", "serde_json", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "fuels-core" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baccbdd81e624f57950dcb136b32b853c520dd954badf26b9f58de33f3d71c7e" +checksum = "ab66cdf52fa6ef98dbc9cc7b4ce19c6a340b2a4710c5d5f87eae39ffb868bad7" dependencies = [ "async-trait", "bech32", @@ -3470,22 +3464,22 @@ dependencies = [ [[package]] name = "fuels-macros" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da75294c5e9da312bdc49239736699ee84ea9c5bfbc19a61a8ee588a1247aa1" +checksum = "1471d221453d13d4643c9a698212781f0e8ac40f515a8566538db87409e30752" dependencies = [ "fuels-code-gen", "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "fuels-programs" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32675ed1c08edd28ddb648dfae0c60a1946d4368a69ddfa6434f2316e33f0520" +checksum = "7a854561a68ef4088972119cf31023d2d1afd58584da203bcb7dfbd1e84dd8fc" dependencies = [ "async-trait", "fuel-abi-types", @@ -3502,9 +3496,9 @@ dependencies = [ [[package]] name = "fuels-test-helpers" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02176c0fb1bf8cf58b8a9e5372efb650324740abcd4847b45bd0b041a0f133a2" +checksum = "5a7b428c35a54e4d667343b4051f07a7397e6039bd110411c37647db4478086e" dependencies = [ "fuel-core-chain-config", "fuel-core-client", @@ -3586,7 +3580,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -3700,9 +3694,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.11" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebfc4febd088abdcbc9f1246896e57e37b7a34f6909840045a1767c6dafac7af" +checksum = "c04e5a94fdb56b1e91eb7df2658ad16832428b8eeda24ff1a0f0288de2bce554" dependencies = [ "bstr", "gix-trace", @@ -3713,9 +3707,9 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b" +checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" [[package]] name = "gix-url" @@ -3747,7 +3741,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3804,9 +3798,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" dependencies = [ "atomic-waker", "bytes", @@ -3833,11 +3827,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -3885,9 +3880,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" dependencies = [ "foldhash", ] @@ -3906,15 +3901,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.4.1" @@ -3927,15 +3913,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.9" @@ -4117,14 +4094,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", + "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -4173,9 +4150,9 @@ checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", - "rustls 0.23.15", + "rustls 0.23.17", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -4202,7 +4179,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -4212,16 +4189,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.5.1", "pin-project-lite", "socket2", "tokio", @@ -4252,6 +4229,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -4270,12 +4365,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -4321,26 +4427,26 @@ dependencies = [ [[package]] name = "impl-tools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82c305b1081f1a99fda262883c788e50ab57d36c00830bdd7e0a82894ad965c" +checksum = "8a84bc8d2baf8da56e93b4247067d918e1a44829bbbe3e4b875aaf8d7d3c7bc9" dependencies = [ "autocfg", "impl-tools-lib", - "proc-macro-error", - "syn 2.0.79", + "proc-macro-error2", + "syn 2.0.87", ] [[package]] name = "impl-tools-lib" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85d3946d886eaab0702fa0c6585adcced581513223fa9df7ccfabbd9fa331a88" +checksum = "a795a1e201125947a063b967c79de6ae152143ab522f481d4f493c44835ba37a" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -4397,7 +4503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "rayon", "serde", ] @@ -4439,9 +4545,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" +checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" dependencies = [ "console", "lazy_static", @@ -4451,15 +4557,6 @@ dependencies = [ "similar", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "ipfs-api-backend-hyper" version = "0.6.0" @@ -4564,9 +4661,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "7a73e9fe3c49d7afb2ace819fa181a287ce54a0983eda4e0eb05c22f82ffe534" [[package]] name = "jobserver" @@ -4650,9 +4747,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libdbus-sys" @@ -4680,9 +4777,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p-identity" @@ -4694,7 +4791,7 @@ dependencies = [ "bs58", "hkdf", "libsecp256k1", - "multihash 0.19.1", + "multihash 0.19.2", "quick-protobuf", "sha2 0.10.8", "thiserror", @@ -4792,7 +4889,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc0bda45ed5b3a2904262c1bb91e526127aa70e7ef3758aba2ef93cf896b9b58" dependencies = [ - "clap 4.5.20", + "clap", "escape8259", "termcolor", "threadpool", @@ -4822,6 +4919,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -4885,13 +4988,13 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" dependencies = [ "anyhow", "chrono", - "clap 4.5.20", + "clap", "clap_complete", "env_logger", "handlebars", @@ -4914,7 +5017,7 @@ name = "mdbook-forc-documenter" version = "0.0.0" dependencies = [ "anyhow", - "clap 4.5.20", + "clap", "mdbook", "semver 1.0.23", "serde", @@ -4963,11 +5066,11 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" +checksum = "bd559bbf5d350ac7f2c1cf92ed71a869b847a92bce0c1318b47932a5b5f65cdd" dependencies = [ - "clap 4.5.20", + "clap", ] [[package]] @@ -5046,12 +5149,12 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -5269,6 +5372,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -5318,7 +5436,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5341,7 +5459,7 @@ checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "indexmap 2.6.0", "memchr", "ruzstd", @@ -5422,7 +5540,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5433,9 +5551,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.3.2+3.3.2" +version = "300.4.1+3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" dependencies = [ "cc", ] @@ -5481,12 +5599,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "owo-colors" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" - [[package]] name = "owo-colors" version = "3.5.0" @@ -5516,39 +5628,29 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", + "syn 2.0.87", ] [[package]] @@ -5558,21 +5660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -5677,7 +5765,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5733,7 +5821,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -5747,29 +5835,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -5881,25 +5969,13 @@ dependencies = [ "yansi 1.0.1", ] -[[package]] -name = "prettydiff" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11" -dependencies = [ - "ansi_term", - "pad", - "prettytable-rs", - "structopt", -] - [[package]] name = "prettydiff" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "owo-colors 3.5.0", + "owo-colors", "pad", "prettytable-rs", ] @@ -5983,11 +6059,32 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", +] + [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -6000,7 +6097,7 @@ checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.3", + "parking_lot", "prometheus-client-derive-encode", ] @@ -6012,7 +6109,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -6072,11 +6169,11 @@ dependencies = [ [[package]] name = "publicsuffix" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" dependencies = [ - "idna 0.3.0", + "idna 1.0.3", "psl-types", ] @@ -6226,15 +6323,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -6272,13 +6360,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -6293,9 +6381,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -6374,20 +6462,20 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.4.6", + "h2 0.4.7", "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-tls", "hyper-util", @@ -6721,9 +6809,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -6746,9 +6834,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" dependencies = [ "once_cell", "rustls-pki-types", @@ -6889,18 +6977,18 @@ dependencies = [ [[package]] name = "scc" -version = "2.2.2" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c1f7fc6deb21665a9060dfc7d271be784669295a31babdcd4dd2c79ae8cbfb" +checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" dependencies = [ "sdd", ] [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -7028,9 +7116,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -7056,31 +7144,31 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] [[package]] name = "serde" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7094,9 +7182,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.129" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap 2.6.0", "itoa", @@ -7113,7 +7201,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7164,7 +7252,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7182,27 +7270,27 @@ dependencies = [ [[package]] name = "serial_test" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" dependencies = [ "futures", "log", "once_cell", - "parking_lot 0.12.3", + "parking_lot", "scc", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7448,15 +7536,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "str_indices" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" - -[[package]] -name = "strsim" -version = "0.8.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" [[package]] name = "strsim" @@ -7470,30 +7552,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap 2.34.0", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck 0.3.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "strum" version = "0.24.1" @@ -7541,7 +7599,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7554,7 +7612,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7578,7 +7636,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sway-ast" -version = "0.66.4" +version = "0.66.5" dependencies = [ "extension-trait", "num-bigint", @@ -7590,9 +7648,9 @@ dependencies = [ [[package]] name = "sway-core" -version = "0.66.4" +version = "0.66.5" dependencies = [ - "clap 4.5.20", + "clap", "derivative", "dirs 5.0.1", "either", @@ -7610,7 +7668,8 @@ dependencies = [ "itertools 0.13.0", "lazy_static", "object", - "parking_lot 0.12.3", + "parking_lot", + "paste", "pest", "pest_derive", "petgraph", @@ -7635,7 +7694,7 @@ dependencies = [ [[package]] name = "sway-error" -version = "0.66.4" +version = "0.66.5" dependencies = [ "either", "in_definite", @@ -7644,20 +7703,19 @@ dependencies = [ "strsim 0.11.1", "sway-types", "thiserror", - "uwuify", ] [[package]] name = "sway-features" -version = "0.66.4" +version = "0.66.5" dependencies = [ - "clap 4.5.20", + "clap", "paste", ] [[package]] name = "sway-ir" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "downcast-rs", @@ -7666,8 +7724,9 @@ dependencies = [ "itertools 0.13.0", "once_cell", "peg", - "prettydiff 0.7.0", + "prettydiff", "rustc-hash 1.1.0", + "serde", "slotmap", "sway-features", "sway-ir-macros", @@ -7677,17 +7736,17 @@ dependencies = [ [[package]] name = "sway-ir-macros" -version = "0.66.4" +version = "0.66.5" dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "sway-lsp" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", "assert-json-diff", @@ -7698,14 +7757,14 @@ dependencies = [ "dirs 4.0.0", "fd-lock", "forc-pkg", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "forc-util", "futures", "indexmap 2.6.0", "lsp-types", "notify", "notify-debouncer-mini", - "parking_lot 0.12.3", + "parking_lot", "pretty_assertions", "proc-macro2", "quote", @@ -7724,7 +7783,7 @@ dependencies = [ "sway-types", "sway-utils", "swayfmt", - "syn 2.0.79", + "syn 2.0.87", "tempfile", "thiserror", "tikv-jemallocator", @@ -7738,7 +7797,7 @@ dependencies = [ [[package]] name = "sway-lsp-test-utils" -version = "0.66.4" +version = "0.66.5" dependencies = [ "assert-json-diff", "futures", @@ -7753,7 +7812,7 @@ dependencies = [ [[package]] name = "sway-parse" -version = "0.66.4" +version = "0.66.5" dependencies = [ "assert_matches", "extension-trait", @@ -7771,7 +7830,7 @@ dependencies = [ [[package]] name = "sway-types" -version = "0.66.4" +version = "0.66.5" dependencies = [ "bytecount", "fuel-asm", @@ -7781,7 +7840,7 @@ dependencies = [ "lazy_static", "num-bigint", "num-traits", - "parking_lot 0.12.3", + "parking_lot", "rustc-hash 1.1.0", "serde", "sway-utils", @@ -7790,7 +7849,7 @@ dependencies = [ [[package]] name = "sway-utils" -version = "0.66.4" +version = "0.66.5" dependencies = [ "serde", "walkdir", @@ -7798,19 +7857,18 @@ dependencies = [ [[package]] name = "swayfmt" -version = "0.66.4" +version = "0.66.5" dependencies = [ "anyhow", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "indoc", "paste", - "prettydiff 0.6.4", + "prettydiff", "ropey", "serde", "serde_ignored", "similar", "sway-ast", - "sway-core", "sway-error", "sway-parse", "sway-types", @@ -7833,27 +7891,15 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.79", -] - [[package]] name = "sync_wrapper" version = "0.1.2" @@ -7889,7 +7935,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -7974,9 +8020,9 @@ dependencies = [ [[package]] name = "tai64" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7401421025f4132e6c1f7af5e7f8287383969f36e6628016cd509b8d3da9dc" +checksum = "014639506e4f425c78e823eabf56e71c093f940ae55b43e58f682e7bc2f5887a" dependencies = [ "serde", ] @@ -8010,9 +8056,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" dependencies = [ "filetime", "libc", @@ -8021,9 +8067,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if 1.0.0", "fastrand", @@ -8103,7 +8149,7 @@ version = "0.0.0" dependencies = [ "anyhow", "bytes", - "clap 4.5.20", + "clap", "colored", "duct", "filecheck", @@ -8111,7 +8157,7 @@ dependencies = [ "forc-client", "forc-pkg", "forc-test", - "forc-tracing 0.66.4", + "forc-tracing 0.66.5", "fuel-vm", "futures", "gag", @@ -8120,7 +8166,7 @@ dependencies = [ "insta", "libtest-mimic", "normalize-path", - "prettydiff 0.7.0", + "prettydiff", "rand", "regex", "revm", @@ -8131,7 +8177,7 @@ dependencies = [ "sway-ir", "sway-types", "sway-utils", - "textwrap 0.16.1", + "textwrap", "tokio", "toml 0.8.19", "tracing", @@ -8143,7 +8189,7 @@ name = "test-macros" version = "0.0.0" dependencies = [ "paste", - "prettydiff 0.6.4", + "prettydiff", ] [[package]] @@ -8152,15 +8198,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "textwrap" version = "0.16.1" @@ -8174,22 +8211,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8290,6 +8327,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -8317,15 +8364,15 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", "libc", "mio 1.0.2", - "parking_lot 0.12.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -8351,7 +8398,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8380,7 +8427,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.15", + "rustls 0.23.17", "rustls-pki-types", "tokio", ] @@ -8523,7 +8570,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8551,7 +8598,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8624,7 +8671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -8692,12 +8739,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -8707,9 +8751,9 @@ checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-linebreak" @@ -8785,12 +8829,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -8801,12 +8845,24 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -8829,18 +8885,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -[[package]] -name = "uwuify" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db6840b7adcfd2e866c79157cc890ecdbbc1f739607134039ae64eaa6c07e24" -dependencies = [ - "clap 2.34.0", - "owo-colors 1.3.0", - "parking_lot 0.11.2", - "thiserror", -] - [[package]] name = "valuable" version = "0.1.0" @@ -8859,12 +8903,6 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.5" @@ -8989,7 +9027,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -9023,7 +9061,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -9316,6 +9354,18 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -9369,6 +9419,30 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -9387,7 +9461,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", ] [[package]] @@ -9407,5 +9502,27 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] diff --git a/Cargo.toml b/Cargo.toml index 340bc9d0581..402b7679c42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ exclude = ["examples/*", "swayfmt/test_macros", "forc-test/test_data"] [workspace.package] edition = "2021" -version = "0.66.4" +version = "0.66.5" authors = ["Fuel Labs "] homepage = "https://fuel.network/" license = "Apache-2.0" @@ -42,35 +42,35 @@ repository = "https://github.com/FuelLabs/sway" # Internal dependencies in order to propagate `workspace.version` # -forc = { path = "forc/", version = "0.66.4" } -forc-pkg = { path = "forc-pkg/", version = "0.66.4" } -forc-test = { path = "forc-test/", version = "0.66.4" } -forc-tracing = { path = "forc-tracing/", version = "0.66.4" } -forc-util = { path = "forc-util/", version = "0.66.4" } +forc = { path = "forc/", version = "0.66.5" } +forc-pkg = { path = "forc-pkg/", version = "0.66.5" } +forc-test = { path = "forc-test/", version = "0.66.5" } +forc-tracing = { path = "forc-tracing/", version = "0.66.5" } +forc-util = { path = "forc-util/", version = "0.66.5" } # Forc plugins -forc-plugins = { path = "forc-plugins/", version = "0.66.4" } -forc-client = { path = "forc-plugins/forc-client/", version = "0.66.4" } -forc-crypto = { path = "forc-plugins/forc-crypto/", version = "0.66.4" } -forc-debug = { path = "forc-plugins/forc-debug/", version = "0.66.4" } -forc-doc = { path = "forc-plugins/forc-doc/", version = "0.66.4" } -forc-fmt = { path = "forc-plugins/forc-fmt/", version = "0.66.4" } -forc-lsp = { path = "forc-plugins/forc-lsp/", version = "0.66.4" } -forc-tx = { path = "forc-plugins/forc-tx/", version = "0.66.4" } +forc-plugins = { path = "forc-plugins/", version = "0.66.5" } +forc-client = { path = "forc-plugins/forc-client/", version = "0.66.5" } +forc-crypto = { path = "forc-plugins/forc-crypto/", version = "0.66.5" } +forc-debug = { path = "forc-plugins/forc-debug/", version = "0.66.5" } +forc-doc = { path = "forc-plugins/forc-doc/", version = "0.66.5" } +forc-fmt = { path = "forc-plugins/forc-fmt/", version = "0.66.5" } +forc-lsp = { path = "forc-plugins/forc-lsp/", version = "0.66.5" } +forc-tx = { path = "forc-plugins/forc-tx/", version = "0.66.5" } -sway-ast = { path = "sway-ast/", version = "0.66.4" } -sway-core = { path = "sway-core/", version = "0.66.4" } -sway-error = { path = "sway-error/", version = "0.66.4" } -sway-features = { path = "sway-features/", version = "0.66.4" } -sway-lsp = { path = "sway-lsp/", version = "0.66.4" } -sway-parse = { path = "sway-parse/", version = "0.66.4" } -sway-types = { path = "sway-types/", version = "0.66.4" } -sway-utils = { path = "sway-utils/", version = "0.66.4" } -swayfmt = { path = "swayfmt/", version = "0.66.4" } +sway-ast = { path = "sway-ast/", version = "0.66.5" } +sway-core = { path = "sway-core/", version = "0.66.5" } +sway-error = { path = "sway-error/", version = "0.66.5" } +sway-features = { path = "sway-features/", version = "0.66.5" } +sway-lsp = { path = "sway-lsp/", version = "0.66.5" } +sway-parse = { path = "sway-parse/", version = "0.66.5" } +sway-types = { path = "sway-types/", version = "0.66.5" } +sway-utils = { path = "sway-utils/", version = "0.66.5" } +swayfmt = { path = "swayfmt/", version = "0.66.5" } # Sway IR -sway-ir = { path = "sway-ir/", version = "0.66.4" } -sway-ir-macros = { path = "sway-ir/sway-ir-macros", version = "0.66.4" } +sway-ir = { path = "sway-ir/", version = "0.66.5" } +sway-ir-macros = { path = "sway-ir/sway-ir-macros", version = "0.66.5" } # # External Fuel dependencies @@ -89,9 +89,9 @@ fuel-core-types = { version = "0.40", default-features = false } # Dependencies from the `fuels-rs` repository: -fuels = "0.66.9" -fuels-core = "0.66.9" -fuels-accounts = "0.66.9" +fuels = "0.66.10" +fuels-core = "0.66.10" +fuels-accounts = "0.66.10" # Dependencies from the `fuel-vm` repository: fuel-asm = "0.58" @@ -108,7 +108,7 @@ forc-wallet = "0.11" # annotate-snippets = "0.10" -ansi_term = "0.12" +ansiterm = "0.12" anyhow = "1.0" assert-json-diff = "2.0" async-trait = "0.1" @@ -165,7 +165,7 @@ libtest-mimic = "0.7" lsp-types = "0.94" mdbook = { version = "0.4", default-features = false } minifier = "0.3" -normalize-path = "0.2.1" +normalize-path = "0.2" notify = "6.1" notify-debouncer-mini = "0.4" num-bigint = "0.4" @@ -228,7 +228,6 @@ unicode-bidi = "0.3" unicode-xid = "0.2" url = "2.2" urlencoding = "2.1" -uwuify = "^0.2" vec1 = "1.8" vte = "0.13" walkdir = "2.3" diff --git a/docs/book/spell-check-custom-words.txt b/docs/book/spell-check-custom-words.txt index 6e18232eaf0..3b51147b9ee 100644 --- a/docs/book/spell-check-custom-words.txt +++ b/docs/book/spell-check-custom-words.txt @@ -227,4 +227,8 @@ predicate-root forc-client crypto doc -fmt \ No newline at end of file +fmt +deallocated +deallocate +destructors +destructor \ No newline at end of file diff --git a/docs/book/src/forc/manifest_reference.md b/docs/book/src/forc/manifest_reference.md index e9be681e5c8..0757f13e213 100644 --- a/docs/book/src/forc/manifest_reference.md +++ b/docs/book/src/forc/manifest_reference.md @@ -11,6 +11,7 @@ The `Forc.toml` (the _manifest_ file) is a compulsory file for each package and * For the recommended way of selecting an entry point of large libraries please take a look at: [Libraries](./../sway-program-types/libraries.md) * `implicit-std` - Controls whether provided `std` version (with the current `forc` version) will get added as a dependency _implicitly_. _Unless you know what you are doing, leave this as default._ * `forc-version` - The minimum forc version required for this project to work properly. + * `metadata` - Metadata for the project; can be used by tools which would like to store package configuration in `Forc.toml`. * [`[dependencies]`](#the-dependencies-section) — Defines the dependencies. * `[network]` — Defines a network for forc to interact with. @@ -41,8 +42,85 @@ entry = "main.sw" organization = "Fuel_Labs" license = "Apache-2.0" name = "wallet_contract" + +[project.metadata] +indexing = { namespace = "counter-contract", schema_path = "out/release/counter-contract-abi.json" } +``` + +### Metadata Section in `Forc.toml` + +The `[project.metadata]` section provides a dedicated space for external tools and plugins to store their configuration in `Forc.toml`. The metadata key names are arbitrary and do not need to match the tool's name. + +#### Workspace vs Project Metadata + +Metadata can be defined at two levels: + +Workspace level - defined in the workspace\'s root `Forc.toml`: + +```toml +[workspace.metadata] +my_tool = { shared_setting = "value" } +``` + +Project level - defined in individual project\'s `Forc.toml`: + +```toml +[project.metadata.any_name_here] +option1 = "value" +option2 = "value" + +[project.metadata.my_custom_config] +setting1 = "value" +setting2 = "value" +``` + +Example for an indexing tool: + +```toml +[project.metadata.indexing] +namespace = "counter-contract" +schema_path = "out/release/counter-contract-abi.json" ``` +When both workspace and project metadata exist: + +* Project-level metadata should take precedence over workspace metadata +* Tools can choose to merge workspace and project settings +* Consider documenting your tool's metadata inheritance behavior + +#### Guidelines for Plugin Developers + +Best Practices + +* Choose clear, descriptive metadata key names +* Document the exact metadata key name your tool expects +* Don't require `Forc.toml` if tool can function without it +* Consider using TOML format for dedicated config files +* Specify how your tool handles workspace vs project metadata + +Implementation Notes + +* The metadata section is optional +* Forc does not parse metadata contents +* Plugin developers handle their own configuration parsing +* Choose unique metadata keys to avoid conflicts with other tools + +#### Example Use Cases + +* Documentation generation settings +* Formatter configurations +* Debugger options +* Wallet integration +* Contract indexing +* Testing frameworks + +This allows for a streamlined developer experience while maintaining clear separation between core Forc functionality and third-party tools. + +#### External Tooling Examples + +* [forc-index-ts](https://github.com/FuelLabs/example-forc-plugins/tree/master/forc-index-ts): A TypeScript CLI tool for parsing `Forc.toml` metadata to read contract ABI JSON file. +* [forc-index-rs](https://github.com/FuelLabs/example-forc-plugins/tree/master/forc-index-rs): A Rust CLI tool for parsing `Forc.toml` metadata to read contract ABI JSON file. + ## The `[dependencies]` section The following fields can be provided with a dependency: diff --git a/docs/book/src/reference/rust_differences.md b/docs/book/src/reference/rust_differences.md index c9505814b20..abd7d7b736d 100644 --- a/docs/book/src/reference/rust_differences.md +++ b/docs/book/src/reference/rust_differences.md @@ -34,3 +34,9 @@ struct MyStruct { field_two: bool, } ``` + +## Memory Allocation + +In Rust, the borrow checker implements Rust's [ownership system](https://doc.rust-lang.org/1.8.0/book/ownership.html) + +In Sway, there is no borrow checker. This means there is no concept of ownership, borrowing, or lifetimes. Instead, objects are copied and moved similar to C++. Also Sway does not have any destructors nor `Drop` traits. This means allocated memory lives for the entire transaction and is not deallocated until the end of the transaction. A transaction may allocate up to [64 MB](https://github.com/FuelLabs/fuel-vm/blob/a80f82ed7c793763de6a73ca72d946b311b0fd0b/fuel-vm/src/consts.rs#L26) of memory. diff --git a/docs/reference/src/documentation/language/control-flow/match/single-line.md b/docs/reference/src/documentation/language/control-flow/match/single-line.md index 376b226b387..04b308c883f 100644 --- a/docs/reference/src/documentation/language/control-flow/match/single-line.md +++ b/docs/reference/src/documentation/language/control-flow/match/single-line.md @@ -10,6 +10,6 @@ The left side of the arrow `=>` is the pattern that we are matching on and the r We check each arm starting from `0` and make our way down until we either find a match on our pattern or we reach the `catch_all` case. -The `|` operator can be used to produce a pattern that is a disjuction of other patterns. +The `|` operator can be used to produce a pattern that is a disjunction of other patterns. The `catch_all` case is equivalent to an `else` in [if expressions](../if-expressions.md) and it does not have to be called `catch_all`. Any pattern declared after a `catch_all` case will not be matched because once the compiler sees the first `catch_all` it stop performing further checks. diff --git a/docs/reference/src/documentation/operations/namespace/index.md b/docs/reference/src/documentation/operations/namespace/index.md index 171f78629a2..773caebffa0 100644 --- a/docs/reference/src/documentation/operations/namespace/index.md +++ b/docs/reference/src/documentation/operations/namespace/index.md @@ -1,6 +1,6 @@ # Address Namespace -Sway utilizies namespaces to distinguish between address types. +Sway utilizes namespaces to distinguish between address types. Having multiple address types enforces type-safety and expands the range of values that an address can take because the same value can be used across multiple types. diff --git a/examples/advanced_storage_variables/src/main.sw b/examples/advanced_storage_variables/src/main.sw index 75054ab7149..c1afb9f4790 100644 --- a/examples/advanced_storage_variables/src/main.sw +++ b/examples/advanced_storage_variables/src/main.sw @@ -1,6 +1,6 @@ contract; -use std::{bytes::Bytes, string::String,}; +use std::{bytes::Bytes, string::String}; // ANCHOR: temp_hash_import use std::hash::Hash; diff --git a/examples/converting_types/src/byte_arrays.sw b/examples/converting_types/src/byte_arrays.sw index d98931c163f..41c1ef543ba 100644 --- a/examples/converting_types/src/byte_arrays.sw +++ b/examples/converting_types/src/byte_arrays.sw @@ -1,7 +1,7 @@ library; // ANCHOR: to_byte_array_import -use std::array_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*,}; +use std::array_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*}; // ANCHOR_END: to_byte_array_import pub fn to_byte_array() { diff --git a/examples/converting_types/src/bytes.sw b/examples/converting_types/src/bytes.sw index 5460352b10d..3537eca8a51 100644 --- a/examples/converting_types/src/bytes.sw +++ b/examples/converting_types/src/bytes.sw @@ -1,7 +1,7 @@ library; // ANCHOR: to_bytes_import -use std::{bytes::Bytes, bytes_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*,}}; +use std::{bytes::Bytes, bytes_conversions::{b256::*, u16::*, u256::*, u32::*, u64::*}}; // ANCHOR_END: to_bytes_import pub fn convert_to_bytes() { diff --git a/examples/enums/src/main.sw b/examples/enums/src/main.sw index b6804891143..87dbdf428cb 100644 --- a/examples/enums/src/main.sw +++ b/examples/enums/src/main.sw @@ -2,6 +2,6 @@ library; mod basic_enum; mod enum_of_structs; -mod enum_of_enums; +pub mod enum_of_enums; mod enums_avoid; mod enums_preferred; diff --git a/examples/wallet_smart_contract/src/main.sw b/examples/wallet_smart_contract/src/main.sw index 9343e818bdf..5ab406a6f3c 100644 --- a/examples/wallet_smart_contract/src/main.sw +++ b/examples/wallet_smart_contract/src/main.sw @@ -1,7 +1,7 @@ // ANCHOR: full_wallet contract; -use std::{asset::transfer, call_frames::msg_asset_id, context::msg_amount,}; +use std::{asset::transfer, call_frames::msg_asset_id, context::msg_amount}; // ANCHOR: abi_import use wallet_abi::Wallet; diff --git a/forc-pkg/Cargo.toml b/forc-pkg/Cargo.toml index 7b1bc68587b..6e0e6431fac 100644 --- a/forc-pkg/Cargo.toml +++ b/forc-pkg/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true repository.workspace = true [dependencies] -ansi_term.workspace = true +ansiterm.workspace = true anyhow.workspace = true byte-unit.workspace = true cid.workspace = true @@ -45,3 +45,4 @@ regex = "^1.10.2" [target.'cfg(not(target_os = "macos"))'.dependencies] sysinfo = "0.29" + diff --git a/forc-pkg/src/lock.rs b/forc-pkg/src/lock.rs index 594c107bc09..f5db529cc7b 100644 --- a/forc-pkg/src/lock.rs +++ b/forc-pkg/src/lock.rs @@ -354,7 +354,7 @@ where }; println_action_red( "Removing", - &format!("{}{src}", ansi_term::Style::new().bold().paint(&pkg.name)), + &format!("{}{src}", ansiterm::Style::new().bold().paint(&pkg.name)), ); } } @@ -372,7 +372,7 @@ where }; println_action_green( "Adding", - &format!("{}{src}", ansi_term::Style::new().bold().paint(&pkg.name)), + &format!("{}{src}", ansiterm::Style::new().bold().paint(&pkg.name)), ); } } diff --git a/forc-pkg/src/manifest/build_profile.rs b/forc-pkg/src/manifest/build_profile.rs index af5822ec693..a196cd51068 100644 --- a/forc-pkg/src/manifest/build_profile.rs +++ b/forc-pkg/src/manifest/build_profile.rs @@ -24,6 +24,8 @@ pub struct BuildProfile { #[serde(default)] pub time_phases: bool, #[serde(default)] + pub profile: bool, + #[serde(default)] pub metrics_outfile: Option, #[serde(default)] pub include_tests: bool, @@ -52,6 +54,7 @@ impl BuildProfile { print_bytecode_spans: false, terse: false, time_phases: false, + profile: false, metrics_outfile: None, include_tests: false, error_on_warnings: false, @@ -72,6 +75,7 @@ impl BuildProfile { print_bytecode_spans: false, terse: false, time_phases: false, + profile: false, metrics_outfile: None, include_tests: false, error_on_warnings: false, @@ -140,6 +144,7 @@ mod tests { print_bytecode_spans: false, terse: true, time_phases: true, + profile: false, metrics_outfile: Some("metrics_outfile".into()), include_tests: true, error_on_warnings: true, diff --git a/forc-pkg/src/manifest/mod.rs b/forc-pkg/src/manifest/mod.rs index 5ce50d65804..c20effec0fb 100644 --- a/forc-pkg/src/manifest/mod.rs +++ b/forc-pkg/src/manifest/mod.rs @@ -166,7 +166,7 @@ impl TryInto for ManifestFile { type PatchMap = BTreeMap; /// A [PackageManifest] that was deserialized from a file at a particular path. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq)] pub struct PackageManifestFile { /// The deserialized `Forc.toml`. manifest: PackageManifest, @@ -175,7 +175,7 @@ pub struct PackageManifestFile { } /// A direct mapping to a `Forc.toml`. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct PackageManifest { pub project: Project, @@ -189,7 +189,7 @@ pub struct PackageManifest { pub proxy: Option, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct Project { pub authors: Option>, @@ -202,6 +202,7 @@ pub struct Project { pub forc_version: Option, #[serde(default)] pub experimental: HashMap, + pub metadata: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] @@ -850,6 +851,7 @@ pub struct WorkspaceManifest { #[serde(rename_all = "kebab-case")] pub struct Workspace { pub members: Vec, + pub metadata: Option, } impl WorkspaceManifestFile { @@ -1330,4 +1332,287 @@ mod tests { assert!(dependency_details_git_rev.validate().is_ok()); assert!(dependency_details_ipfs.validate().is_ok()); } + + #[test] + fn test_project_with_null_metadata() { + let project = Project { + authors: Some(vec!["Test Author".to_string()]), + name: "test-project".to_string(), + organization: None, + license: "Apache-2.0".to_string(), + entry: "main.sw".to_string(), + implicit_std: None, + forc_version: None, + experimental: HashMap::new(), + metadata: Some(toml::Value::from(toml::value::Table::new())), + }; + + let serialized = toml::to_string(&project).unwrap(); + let deserialized: Project = toml::from_str(&serialized).unwrap(); + + assert_eq!(project.name, deserialized.name); + assert_eq!(project.metadata, deserialized.metadata); + } + + #[test] + fn test_project_without_metadata() { + let project = Project { + authors: Some(vec!["Test Author".to_string()]), + name: "test-project".to_string(), + organization: None, + license: "Apache-2.0".to_string(), + entry: "main.sw".to_string(), + implicit_std: None, + forc_version: None, + experimental: HashMap::new(), + metadata: None, + }; + + let serialized = toml::to_string(&project).unwrap(); + let deserialized: Project = toml::from_str(&serialized).unwrap(); + + assert_eq!(project.name, deserialized.name); + assert_eq!(project.metadata, deserialized.metadata); + assert_eq!(project.metadata, None); + } + + #[test] + fn test_project_metadata_from_toml() { + let toml_str = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + authors = ["Test Author"] + + [metadata] + description = "A test project" + version = "1.0.0" + homepage = "https://example.com" + documentation = "https://docs.example.com" + repository = "https://github.com/example/test-project" + keywords = ["test", "project"] + categories = ["test"] + "#; + + let project: Project = toml::from_str(toml_str).unwrap(); + assert!(project.metadata.is_some()); + + let metadata = project.metadata.unwrap(); + let table = metadata.as_table().unwrap(); + + assert_eq!( + table.get("description").unwrap().as_str().unwrap(), + "A test project" + ); + assert_eq!(table.get("version").unwrap().as_str().unwrap(), "1.0.0"); + assert_eq!( + table.get("homepage").unwrap().as_str().unwrap(), + "https://example.com" + ); + + let keywords = table.get("keywords").unwrap().as_array().unwrap(); + assert_eq!(keywords[0].as_str().unwrap(), "test"); + assert_eq!(keywords[1].as_str().unwrap(), "project"); + } + + #[test] + fn test_project_with_invalid_metadata() { + // Test with invalid TOML syntax - unclosed table + let invalid_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata + description = "Invalid TOML" + "#; + + let result: Result = toml::from_str(invalid_toml); + assert!(result.is_err()); + + // Test with invalid TOML syntax - invalid key + let invalid_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata] + ] = "Invalid key" + "#; + + let result: Result = toml::from_str(invalid_toml); + assert!(result.is_err()); + + // Test with duplicate keys + let invalid_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata] + nested = { key = "value1" } + + [metadata.nested] + key = "value2" + "#; + + let result: Result = toml::from_str(invalid_toml); + assert!(result.is_err()); + assert!(result + .err() + .unwrap() + .to_string() + .contains("duplicate key `nested` in table `metadata`")); + } + + #[test] + fn test_metadata_roundtrip() { + let original_toml = r#" + name = "test-project" + license = "Apache-2.0" + entry = "main.sw" + + [metadata] + boolean = true + integer = 42 + float = 3.12 + string = "value" + array = [1, 2, 3] + mixed_array = [1, "two", true] + + [metadata.nested] + key = "value2" + "#; + + let project: Project = toml::from_str(original_toml).unwrap(); + let serialized = toml::to_string(&project).unwrap(); + let deserialized: Project = toml::from_str(&serialized).unwrap(); + + // Verify that the metadata is preserved + assert_eq!(project.metadata, deserialized.metadata); + + // Verify all types were preserved + let table_val = project.metadata.unwrap(); + let table = table_val.as_table().unwrap(); + assert!(table.get("boolean").unwrap().as_bool().unwrap()); + assert_eq!(table.get("integer").unwrap().as_integer().unwrap(), 42); + assert_eq!(table.get("float").unwrap().as_float().unwrap(), 3.12); + assert_eq!(table.get("string").unwrap().as_str().unwrap(), "value"); + assert_eq!(table.get("array").unwrap().as_array().unwrap().len(), 3); + assert!(table.get("nested").unwrap().as_table().is_some()); + } + + #[test] + fn test_workspace_with_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + + [workspace.metadata] + description = "A test workspace" + version = "1.0.0" + authors = ["Test Author"] + homepage = "https://example.com" + + [workspace.metadata.ci] + workflow = "main" + timeout = 3600 + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + assert!(manifest.workspace.metadata.is_some()); + + let metadata = manifest.workspace.metadata.unwrap(); + let table = metadata.as_table().unwrap(); + + assert_eq!( + table.get("description").unwrap().as_str().unwrap(), + "A test workspace" + ); + assert_eq!(table.get("version").unwrap().as_str().unwrap(), "1.0.0"); + + let ci = table.get("ci").unwrap().as_table().unwrap(); + assert_eq!(ci.get("workflow").unwrap().as_str().unwrap(), "main"); + assert_eq!(ci.get("timeout").unwrap().as_integer().unwrap(), 3600); + } + + #[test] + fn test_workspace_without_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + assert!(manifest.workspace.metadata.is_none()); + } + + #[test] + fn test_workspace_empty_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + + [workspace.metadata] + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + assert!(manifest.workspace.metadata.is_some()); + let metadata = manifest.workspace.metadata.unwrap(); + assert!(metadata.as_table().unwrap().is_empty()); + } + + #[test] + fn test_workspace_complex_metadata() { + let toml_str = r#" + [workspace] + members = ["package1", "package2"] + + [workspace.metadata] + numbers = [1, 2, 3] + strings = ["a", "b", "c"] + mixed = [1, "two", true] + + [workspace.metadata.nested] + key = "value" + + [workspace.metadata.nested.deep] + another = "value" + "#; + + let manifest: WorkspaceManifest = toml::from_str(toml_str).unwrap(); + let metadata = manifest.workspace.metadata.unwrap(); + let table = metadata.as_table().unwrap(); + + assert!(table.get("numbers").unwrap().as_array().is_some()); + assert!(table.get("strings").unwrap().as_array().is_some()); + assert!(table.get("mixed").unwrap().as_array().is_some()); + + let nested = table.get("nested").unwrap().as_table().unwrap(); + assert_eq!(nested.get("key").unwrap().as_str().unwrap(), "value"); + + let deep = nested.get("deep").unwrap().as_table().unwrap(); + assert_eq!(deep.get("another").unwrap().as_str().unwrap(), "value"); + } + + #[test] + fn test_workspace_metadata_roundtrip() { + let original = WorkspaceManifest { + workspace: Workspace { + members: vec![PathBuf::from("package1"), PathBuf::from("package2")], + metadata: Some(toml::Value::Table({ + let mut table = toml::value::Table::new(); + table.insert("key".to_string(), toml::Value::String("value".to_string())); + table + })), + }, + patch: None, + }; + + let serialized = toml::to_string(&original).unwrap(); + let deserialized: WorkspaceManifest = toml::from_str(&serialized).unwrap(); + + assert_eq!(original.workspace.members, deserialized.workspace.members); + assert_eq!(original.workspace.metadata, deserialized.workspace.metadata); + } } diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 19291e0d0ce..49829a2a321 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -46,7 +46,7 @@ use sway_core::{ transform::AttributeKind, write_dwarf, BuildTarget, Engines, FinalizedEntry, LspConfig, }; -use sway_core::{PrintAsm, PrintIr}; +use sway_core::{set_bytecode_configurables_offset, PrintAsm, PrintIr}; use sway_error::{error::CompileError, handler::Handler, warning::CompileWarning}; use sway_features::ExperimentalFeatures; use sway_types::constants::{CORE, PRELUDE, STD}; @@ -300,6 +300,8 @@ pub struct BuildOpts { pub release: bool, /// Output the time elapsed over each part of the compilation process. pub time_phases: bool, + /// Profile the build process. + pub profile: bool, /// If set, outputs compilation metrics info in JSON format. pub metrics_outfile: Option, /// Warnings must be treated as compiler errors. @@ -1561,6 +1563,7 @@ pub fn sway_build_config( .with_print_ir(build_profile.print_ir.clone()) .with_include_tests(build_profile.include_tests) .with_time_phases(build_profile.time_phases) + .with_profile(build_profile.profile) .with_metrics(build_profile.metrics_outfile.clone()) .with_optimization_level(build_profile.optimization_level); Ok(build_config) @@ -1780,6 +1783,7 @@ pub fn compile( // First, compile to an AST. We'll update the namespace and check for JSON ABI output. let ast_res = time_expr!( + pkg.name, "compile to ast", "compile_to_ast", sway_core::compile_to_ast( @@ -1819,6 +1823,7 @@ pub fn compile( } let asm_res = time_expr!( + pkg.name, "compile ast to asm", "compile_ast_to_asm", sway_core::ast_to_asm( @@ -1839,6 +1844,7 @@ pub fn compile( let mut program_abi = match pkg.target { BuildTarget::Fuel => { let program_abi_res = time_expr!( + pkg.name, "generate JSON ABI program", "generate_json_abi", fuel_abi::generate_program_abi( @@ -1877,6 +1883,7 @@ pub fn compile( }; let abi = time_expr!( + pkg.name, "generate JSON ABI program", "generate_json_abi", evm_abi::generate_abi_program(typed_program, engines), @@ -1899,22 +1906,29 @@ pub fn compile( .map(|finalized_entry| PkgEntry::from_finalized_entry(finalized_entry, engines)) .collect::>()?; - let asm = match asm_res { + let mut asm = match asm_res { Err(_) => return fail(handler), Ok(asm) => asm, }; let bc_res = time_expr!( + pkg.name, "compile asm to bytecode", "compile_asm_to_bytecode", - sway_core::asm_to_bytecode(&handler, asm, source_map, engines.se(), &sway_build_config), + sway_core::asm_to_bytecode( + &handler, + &mut asm, + source_map, + engines.se(), + &sway_build_config + ), Some(sway_build_config.clone()), metrics ); let errored = handler.has_errors() || (handler.has_warnings() && profile.error_on_warnings); - let compiled = match bc_res { + let mut compiled = match bc_res { Ok(compiled) if !errored => compiled, _ => return fail(handler), }; @@ -1923,9 +1937,12 @@ pub fn compile( print_warnings(engines.se(), terse_mode, &pkg.name, &warnings, &tree_type); + // Metadata to be placed into the binary. + let mut md = [0u8, 0, 0, 0, 0, 0, 0, 0]; // TODO: This should probably be in `fuel_abi_json::generate_json_abi_program`? // If ABI requires knowing config offsets, they should be inputs to ABI gen. if let ProgramABI::Fuel(ref mut program_abi) = program_abi { + let mut configurables_offset = compiled.bytecode.len() as u64; if let Some(ref mut configurables) = program_abi.configurables { // Filter out all dead configurables (i.e. ones without offsets in the bytecode) configurables.retain(|c| { @@ -1934,12 +1951,22 @@ pub fn compile( .contains_key(&c.name) }); // Set the actual offsets in the JSON object - for (config, offset) in compiled.named_data_section_entries_offsets { - if let Some(idx) = configurables.iter().position(|c| c.name == config) { - configurables[idx].offset = offset; + for (config, offset) in &compiled.named_data_section_entries_offsets { + if *offset < configurables_offset { + configurables_offset = *offset; + } + if let Some(idx) = configurables.iter().position(|c| &c.name == config) { + configurables[idx].offset = *offset; } } } + + md = configurables_offset.to_be_bytes(); + } + + // We know to set the metadata only for fuelvm right now. + if let BuildTarget::Fuel = pkg.target { + set_bytecode_configurables_offset(&mut compiled, &md); } metrics.bytecode_size = compiled.bytecode.len(); @@ -1957,9 +1984,83 @@ pub fn compile( warnings, metrics, }; + if sway_build_config.profile { + report_assembly_information(&asm, &compiled_package); + } + Ok(compiled_package) } +/// Reports assembly information for a compiled package to an external `dyno` process through `stdout`. +fn report_assembly_information( + compiled_asm: &sway_core::CompiledAsm, + compiled_package: &CompiledPackage, +) { + // Get the bytes of the compiled package. + let mut bytes = compiled_package.bytecode.bytes.clone(); + + // Attempt to get the data section offset out of the compiled package bytes. + let data_offset = u64::from_be_bytes( + bytes + .iter() + .skip(8) + .take(8) + .cloned() + .collect::>() + .try_into() + .unwrap(), + ); + let data_section_size = bytes.len() as u64 - data_offset; + + // Remove the data section from the compiled package bytes. + bytes.truncate(data_offset as usize); + + // Calculate the unpadded size of each data section section. + // Implementation based directly on `sway_core::asm_generation::Entry::to_bytes`, referenced here: + // https://github.com/FuelLabs/sway/blob/afd6a6709e7cb11c676059a5004012cc466e653b/sway-core/src/asm_generation/fuel/data_section.rs#L147 + fn calculate_entry_size(entry: &sway_core::asm_generation::Entry) -> u64 { + match &entry.value { + sway_core::asm_generation::Datum::Byte(value) => std::mem::size_of_val(value) as u64, + + sway_core::asm_generation::Datum::Word(value) => std::mem::size_of_val(value) as u64, + + sway_core::asm_generation::Datum::ByteArray(bytes) + | sway_core::asm_generation::Datum::Slice(bytes) => { + if bytes.len() % 8 == 0 { + bytes.len() as u64 + } else { + ((bytes.len() + 7) & 0xfffffff8_usize) as u64 + } + } + + sway_core::asm_generation::Datum::Collection(items) => { + items.iter().map(calculate_entry_size).sum() + } + } + } + + // Compute the assembly information to be reported. + let asm_information = sway_core::asm_generation::AsmInformation { + bytecode_size: bytes.len() as _, + data_section: sway_core::asm_generation::DataSectionInformation { + size: data_section_size, + used: compiled_asm + .0 + .data_section + .iter_all_entries() + .map(|entry| calculate_entry_size(&entry)) + .sum(), + value_pairs: compiled_asm.0.data_section.iter_all_entries().collect(), + }, + }; + + // Report the assembly information to the `dyno` process through `stdout`. + println!( + "/dyno info {}", + serde_json::to_string(&asm_information).unwrap() + ); +} + impl PkgEntry { /// Returns whether this `PkgEntry` corresponds to a test. pub fn is_test(&self) -> bool { @@ -2062,6 +2163,7 @@ fn build_profile_from_opts( pkg, print, time_phases, + profile: profile_opt, build_profile, release, metrics_outfile, @@ -2102,6 +2204,7 @@ fn build_profile_from_opts( profile.print_bytecode_spans |= print.bytecode_spans; profile.terse |= pkg.terse; profile.time_phases |= time_phases; + profile.profile |= profile_opt; if profile.metrics_outfile.is_none() { profile.metrics_outfile.clone_from(metrics_outfile); } @@ -2244,13 +2347,13 @@ pub fn build_with_options(build_options: &BuildOpts) -> Result { fn print_pkg_summary_header(built_pkg: &BuiltPackage) { let prog_ty_str = forc_util::program_type_str(&built_pkg.tree_type); - // The ansi_term formatters ignore the `std::fmt` right-align + // The ansiterm formatters ignore the `std::fmt` right-align // formatter, so we manually calculate the padding to align the program // type and name around the 10th column ourselves. let padded_ty_str = format!("{prog_ty_str:>10}"); let padding = &padded_ty_str[..padded_ty_str.len() - prog_ty_str.len()]; - let ty_ansi = ansi_term::Colour::Green.bold().paint(prog_ty_str); - let name_ansi = ansi_term::Style::new() + let ty_ansi = ansiterm::Colour::Green.bold().paint(prog_ty_str); + let name_ansi = ansiterm::Style::new() .bold() .paint(&built_pkg.descriptor.name); debug!("{padding}{ty_ansi} {name_ansi}"); diff --git a/forc-pkg/src/source/git/mod.rs b/forc-pkg/src/source/git/mod.rs index a89e77f3128..d1a74c13f34 100644 --- a/forc-pkg/src/source/git/mod.rs +++ b/forc-pkg/src/source/git/mod.rs @@ -206,11 +206,7 @@ impl source::Fetch for Pinned { if !repo_path.exists() { println_action_green( "Fetching", - &format!( - "{} {}", - ansi_term::Style::new().bold().paint(ctx.name), - self - ), + &format!("{} {}", ansiterm::Style::new().bold().paint(ctx.name), self), ); fetch(ctx.fetch_id(), ctx.name(), self)?; } diff --git a/forc-pkg/src/source/ipfs.rs b/forc-pkg/src/source/ipfs.rs index 1391348834c..4d465ff23f6 100644 --- a/forc-pkg/src/source/ipfs.rs +++ b/forc-pkg/src/source/ipfs.rs @@ -69,11 +69,7 @@ impl source::Fetch for Pinned { if !repo_path.exists() { println_action_green( "Fetching", - &format!( - "{} {}", - ansi_term::Style::new().bold().paint(ctx.name), - self - ), + &format!("{} {}", ansiterm::Style::new().bold().paint(ctx.name), self), ); let cid = &self.0; let ipfs_client = ipfs_client(); diff --git a/forc-plugins/forc-client/src/op/deploy.rs b/forc-plugins/forc-client/src/op/deploy.rs index f489409cc50..078b6ee7377 100644 --- a/forc-plugins/forc-client/src/op/deploy.rs +++ b/forc-plugins/forc-client/src/op/deploy.rs @@ -7,8 +7,8 @@ use crate::{ pkg::{built_pkgs, create_proxy_contract, update_proxy_address_in_manifest}, target::Target, tx::{ - prompt_forc_wallet_password, select_account, update_proxy_contract_target, - SignerSelectionMode, + check_and_create_wallet_at_default_path, prompt_forc_wallet_password, select_account, + update_proxy_contract_target, SignerSelectionMode, }, }, }; @@ -810,6 +810,7 @@ fn build_opts_from_cmd(cmd: &cmd::Deploy, member_filter: pkg::MemberFilter) -> p reverse_order: cmd.print.reverse_order, }, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile.clone(), minify: pkg::MinifyOpts { json_abi: cmd.minify.json_abi, @@ -899,6 +900,11 @@ async fn setup_deployment_account( } else if let Some(arn) = &command.aws_kms_signer { SignerSelectionMode::AwsSigner(arn.clone()) } else { + // Check if we have a wallet in the default path + // If there is one we will ask for the password + // If not we will ask the user to either create a new one or import one + let wallet_path = default_wallet_path(); + check_and_create_wallet_at_default_path(&wallet_path)?; println_action_green("", &format!("Wallet: {}", default_wallet_path().display())); let password = prompt_forc_wallet_password()?; SignerSelectionMode::ForcWallet(password) diff --git a/forc-plugins/forc-client/src/op/run/mod.rs b/forc-plugins/forc-client/src/op/run/mod.rs index debf0579c19..7d21d439e8c 100644 --- a/forc-plugins/forc-client/src/op/run/mod.rs +++ b/forc-plugins/forc-client/src/op/run/mod.rs @@ -267,6 +267,7 @@ fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts { release: cmd.build_profile.release, error_on_warnings: cmd.build_profile.error_on_warnings, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile.clone(), binary_outfile: cmd.build_output.bin_file.clone(), debug_outfile: cmd.build_output.debug_file.clone(), diff --git a/forc-plugins/forc-client/src/util/tx.rs b/forc-plugins/forc-client/src/util/tx.rs index e9f8b220121..a1dad6a3fcd 100644 --- a/forc-plugins/forc-client/src/util/tx.rs +++ b/forc-plugins/forc-client/src/util/tx.rs @@ -10,6 +10,7 @@ use forc_wallet::{ balance::{ collect_accounts_with_verification, AccountBalances, AccountVerification, AccountsMap, }, + import::{import_wallet_cli, Import}, new::{new_wallet_cli, New}, utils::default_wallet_path, }; @@ -45,6 +46,15 @@ fn ask_user_yes_no_question(question: &str) -> Result { Ok(answer) } +fn ask_user_with_options(question: &str, options: &[&str], default: usize) -> Result { + let selection = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(question) + .items(options) + .default(default) + .interact()?; + Ok(selection) +} + fn collect_user_accounts( wallet_path: &Path, password: &str, @@ -71,21 +81,27 @@ pub(crate) fn prompt_forc_wallet_password() -> Result { pub(crate) fn check_and_create_wallet_at_default_path(wallet_path: &Path) -> Result<()> { if !wallet_path.exists() { - let question = format!("Could not find a wallet at {wallet_path:?}, would you like to create a new one? [y/N]: "); - let accepted = ask_user_yes_no_question(&question)?; - let new_options = New { - force: false, - cache_accounts: None, - }; - if accepted { - new_wallet_cli(wallet_path, new_options)?; - println!("Wallet created successfully."); - // Derive first account for the fresh wallet we created. - new_at_index_cli(wallet_path, 0)?; - println!("Account derived successfully."); - } else { - anyhow::bail!("Refused to create a new wallet. If you don't want to use forc-wallet, you can sign this transaction manually with --manual-signing flag.") + let question = + format!("Could not find a wallet at {wallet_path:?}, please select an option: "); + let wallet_options = ask_user_with_options( + &question, + &["Create new wallet", "Import existing wallet"], + 0, + )?; + match wallet_options { + 0 => { + new_wallet_cli(wallet_path, New { force: false, cache_accounts: None })?; + println!("Wallet created successfully."); + } + 1 => { + import_wallet_cli(wallet_path, Import { force: false, cache_accounts: None })?; + println!("Wallet imported successfully."); + }, + _ => anyhow::bail!("Refused to create or import a new wallet. If you don't want to use forc-wallet, you can sign this transaction manually with --manual-signing flag."), } + // Derive first account for the fresh wallet we created. + new_at_index_cli(wallet_path, 0)?; + println!("Account derived successfully."); } Ok(()) } @@ -170,9 +186,6 @@ pub(crate) async fn select_account( match wallet_mode { SignerSelectionMode::ForcWallet(password) => { let wallet_path = default_wallet_path(); - check_and_create_wallet_at_default_path(&wallet_path)?; - // TODO: This is a very simple TUI, we should consider adding a nice TUI - // capabilities for selections and answer collection. let accounts = collect_user_accounts(&wallet_path, password)?; let account_balances = collect_account_balances(&accounts, provider).await?; let base_asset_id = provider.base_asset_id(); diff --git a/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json b/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json index 81b65c43cd7..c51c80ae2e9 100644 --- a/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json +++ b/forc-plugins/forc-client/test/data/deployed_script/deployed_script-loader-abi.json @@ -251,62 +251,62 @@ { "name": "BOOL", "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", - "offset": 136 + "offset": 240 }, { "name": "U8", "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", - "offset": 248 + "offset": 352 }, { "name": "U16", "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", - "offset": 192 + "offset": 296 }, { "name": "U32", "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", - "offset": 232 + "offset": 336 }, { "name": "U64", "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", - "offset": 240 + "offset": 344 }, { "name": "U256", "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", - "offset": 200 + "offset": 304 }, { "name": "B256", "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", - "offset": 104 + "offset": 208 }, { "name": "STR_4", "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", - "offset": 176 + "offset": 280 }, { "name": "TUPLE", "concreteTypeId": "e0128f7be9902d1fe16326cafe703b52038064a7997b03ebfc1c9dd607e1536c", - "offset": 184 + "offset": 288 }, { "name": "ARRAY", "concreteTypeId": "d9fac01ab38fe10950758ae9604da330d6406a71fda3ef1ea818121261132d56", - "offset": 88 + "offset": 192 }, { "name": "STRUCT", "concreteTypeId": "563310524b4f4447a10d0e50556310253dfb3b5eb4b29c3773222b737c8b7075", - "offset": 160 + "offset": 264 }, { "name": "ENUM", "concreteTypeId": "37cd1cba311039a851ac8bfa614cc41359b4ad95c8656fcef2e8f504fe7a1272", - "offset": 144 + "offset": 248 } ] } \ No newline at end of file diff --git a/forc-plugins/forc-client/tests/deploy.rs b/forc-plugins/forc-client/tests/deploy.rs index afabb238e82..7f881bb15d9 100644 --- a/forc-plugins/forc-client/tests/deploy.rs +++ b/forc-plugins/forc-client/tests/deploy.rs @@ -373,7 +373,7 @@ async fn test_simple_deploy() { node.kill().unwrap(); let expected = vec![DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3", + "02a7e78ef0514b80ab56b409f06f895d8939640b6f6d746fcbb15d3e0c6a1a3b", ) .unwrap(), proxy: None, @@ -416,7 +416,7 @@ async fn test_deploy_submit_only() { node.kill().unwrap(); let expected = vec![DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3", + "02a7e78ef0514b80ab56b409f06f895d8939640b6f6d746fcbb15d3e0c6a1a3b", ) .unwrap(), proxy: None, @@ -462,12 +462,12 @@ async fn test_deploy_fresh_proxy() { node.kill().unwrap(); let impl_contract = DeployedPackage::Contract(DeployedContract { id: ContractId::from_str( - "5a4d19b92e784817f3e4f7d7c9961c5cba3069e53dcee2a93e8cd723e555c5f3", + "02a7e78ef0514b80ab56b409f06f895d8939640b6f6d746fcbb15d3e0c6a1a3b", ) .unwrap(), proxy: Some( ContractId::from_str( - "f0641246d72044059de56248becf345bd8553c7892df8c12d7df23f461a7f95b", + "6eb0db0e120222a4ac3ced8dfbf15ae56753b852aa7989849fa20e5aca47af44", ) .unwrap(), ), @@ -693,7 +693,7 @@ async fn test_non_owner_fails_to_set_target() { // It would also require overriding `default_wallet_path` function for tests, so as not to interfere with the user's wallet. #[test] -fn test_deploy_interactive_wrong_password() -> Result<(), rexpect::error::Error> { +fn test_deploy_interactive_missing_wallet() -> Result<(), rexpect::error::Error> { let (mut node, port) = run_node(); let node_url = format!("http://127.0.0.1:{}/v1/graphql", port); @@ -711,9 +711,8 @@ fn test_deploy_interactive_wrong_password() -> Result<(), rexpect::error::Error> process .exp_string("\u{1b}[1;32mConfirming\u{1b}[0m transactions [deploy standalone_contract]")?; process.exp_string(&format!("Network: {node_url}"))?; - process.exp_string("Wallet: ")?; - process.exp_string("Wallet password")?; - process.send_line("mock_password")?; + process.exp_regex("Could not find a wallet at")?; + process.send_line("n")?; process.process.exit()?; node.kill().unwrap(); @@ -1304,7 +1303,7 @@ async fn offset_shifted_abi_works() { let loader_with_configs_from_sdk = call_with_sdk_generated_overrides(&node_url, contract_id).await; - // Genearating the forc-deploy loader bytecode and loader abi. + // Generating the forc-deploy loader bytecode and loader abi. let loader_with_configs_from_forc = call_with_forc_generated_overrides(&node_url, contract_id).await; pretty_assertions::assert_eq!(loader_with_configs_from_forc, loader_with_configs_from_sdk); diff --git a/forc-plugins/forc-debug/src/cli.rs b/forc-plugins/forc-debug/src/cli.rs new file mode 100644 index 00000000000..6705c5b8b8f --- /dev/null +++ b/forc-plugins/forc-debug/src/cli.rs @@ -0,0 +1,332 @@ +use crate::{ + error::{ArgumentError, Error, Result}, + names::{register_index, register_name}, + ContractId, FuelClient, RunResult, Transaction, +}; +use fuel_vm::consts::{VM_MAX_RAM, VM_REGISTER_COUNT, WORD_SIZE}; +use shellfish::{handler::DefaultAsyncHandler, input_handler::IO, Command as ShCommand, Shell}; + +pub struct State { + client: FuelClient, + session_id: String, +} + +/// Start the CLI debug interface +pub async fn start_cli(api_url: &str) -> Result<()> { + let mut shell = Shell::new_async( + State { + client: FuelClient::new(api_url).map_err(|e| Error::FuelClientError(e.to_string()))?, + session_id: String::new(), // Placeholder + }, + ">> ", + ); + + register_commands(&mut shell); + + let session_id = shell + .state + .client + .start_session() + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + shell.state.session_id.clone_from(&session_id); + + shell + .run_async() + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + shell + .state + .client + .end_session(&session_id) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +fn register_commands(shell: &mut Shell<'_, State, &str, DefaultAsyncHandler, IO>) { + // Registers an async command by wrapping the handler function `$f`, + // converting its error type into `Box`, and + // associating it with the provided command names. + macro_rules! command { + ($f:ident, $help:literal, $names:expr) => { + for c in $names { + shell.commands.insert( + c, + ShCommand::new_async($help.to_string(), |state, args| { + Box::pin(async move { + $f(state, args) + .await + .map_err(|e| Box::new(e) as Box) + }) + }), + ); + } + }; + } + + command!( + cmd_start_tx, + "path/to/tx.json -- start a new transaction", + ["n", "tx", "new_tx", "start_tx"] + ); + command!( + cmd_reset, + "-- reset, removing breakpoints and other state", + ["reset"] + ); + command!( + cmd_continue, + "-- run until next breakpoint or termination", + ["c", "continue"] + ); + command!( + cmd_step, + "[on|off] -- turn single-stepping on or off", + ["s", "step"] + ); + command!( + cmd_breakpoint, + "[contract_id] offset -- set a breakpoint", + ["b", "breakpoint"] + ); + command!( + cmd_registers, + "[regname ...] -- dump registers", + ["r", "reg", "register", "registers"] + ); + command!(cmd_memory, "[offset] limit -- dump memory", ["m", "memory"]); +} + +async fn cmd_start_tx(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 1, 1)?; // Ensure exactly one argument + + let path_to_tx_json = args.pop().unwrap(); // Safe due to arg count check + + // Read and parse the transaction JSON + let tx_json = std::fs::read(&path_to_tx_json).map_err(Error::IoError)?; + let tx: Transaction = serde_json::from_slice(&tx_json).map_err(Error::JsonError)?; + + // Start the transaction + let status = state + .client + .start_tx(&state.session_id, &tx) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + pretty_print_run_result(&status); + Ok(()) +} + +async fn cmd_reset(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 0, 0)?; // Ensure no extra arguments + + // Reset the session + state + .client + .reset(&state.session_id) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +async fn cmd_continue(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 0, 0)?; // Ensure no extra arguments + + // Continue the transaction + let status = state + .client + .continue_tx(&state.session_id) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + pretty_print_run_result(&status); + Ok(()) +} + +async fn cmd_step(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + ArgumentError::ensure_arg_count(&args, 0, 1)?; // Ensure the argument count is at most 1 + + // Determine whether to enable or disable single stepping + let enable = args + .first() + .map_or(true, |v| !["off", "no", "disable"].contains(&v.as_str())); + + // Call the client + state + .client + .set_single_stepping(&state.session_id, enable) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +async fn cmd_breakpoint(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove command name + ArgumentError::ensure_arg_count(&args, 1, 2)?; + + let offset_str = args.pop().unwrap(); // Safe due to arg count check + let offset = parse_int(&offset_str).ok_or(ArgumentError::InvalidNumber(offset_str))?; + + let contract = if let Some(contract_id) = args.pop() { + contract_id + .parse::() + .map_err(|_| ArgumentError::Invalid(format!("Invalid contract ID: {}", contract_id)))? + } else { + ContractId::zeroed() + }; + + // Call client + state + .client + .set_breakpoint(&state.session_id, contract, offset as u64) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + Ok(()) +} + +async fn cmd_registers(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + + if args.is_empty() { + // Print all registers + for r in 0..VM_REGISTER_COUNT { + let value = state + .client + .register(&state.session_id, r as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + println!("reg[{:#x}] = {:<8} # {}", r, value, register_name(r)); + } + } else { + // Process specific registers provided as arguments + for arg in &args { + if let Some(v) = parse_int(arg) { + if v < VM_REGISTER_COUNT { + let value = state + .client + .register(&state.session_id, v as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + println!("reg[{:#02x}] = {:<8} # {}", v, value, register_name(v)); + } else { + return Err(ArgumentError::InvalidNumber(format!( + "Register index too large: {v}" + )) + .into()); + } + } else if let Some(index) = register_index(arg) { + let value = state + .client + .register(&state.session_id, index as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + println!("reg[{index:#02x}] = {value:<8} # {arg}"); + } else { + return Err(ArgumentError::Invalid(format!("Unknown register name: {arg}")).into()); + } + } + } + Ok(()) +} + +async fn cmd_memory(state: &mut State, mut args: Vec) -> Result<()> { + args.remove(0); // Remove the command name + + // Parse limit argument or use the default + let limit = args + .pop() + .map(|a| parse_int(&a).ok_or(ArgumentError::InvalidNumber(a))) + .transpose()? + .unwrap_or(WORD_SIZE * (VM_MAX_RAM as usize)); + + // Parse offset argument or use the default + let offset = args + .pop() + .map(|a| parse_int(&a).ok_or(ArgumentError::InvalidNumber(a))) + .transpose()? + .unwrap_or(0); + + // Ensure no extra arguments + ArgumentError::ensure_arg_count(&args, 0, 0)?; + + // Fetch memory from the client + let mem = state + .client + .memory(&state.session_id, offset as u32, limit as u32) + .await + .map_err(|e| Error::FuelClientError(e.to_string()))?; + + // Print memory contents + for (i, chunk) in mem.chunks(WORD_SIZE).enumerate() { + print!(" {:06x}:", offset + i * WORD_SIZE); + for byte in chunk { + print!(" {byte:02x}"); + } + println!(); + } + Ok(()) +} + +/// Pretty-prints the result of a run, including receipts and breakpoint information. +/// +/// Outputs each receipt in the `RunResult` and details about the breakpoint if present. +/// If the execution terminated without hitting a breakpoint, it prints "Terminated". +fn pretty_print_run_result(rr: &RunResult) { + for receipt in rr.receipts() { + println!("Receipt: {receipt:?}"); + } + if let Some(bp) = &rr.breakpoint { + println!( + "Stopped on breakpoint at address {} of contract {}", + bp.pc.0, bp.contract + ); + } else { + println!("Terminated"); + } +} + +/// Parses a string representing a number and returns it as a `usize`. +/// +/// The input string can be in decimal or hexadecimal format: +/// - Decimal numbers are parsed normally (e.g., `"123"`). +/// - Hexadecimal numbers must be prefixed with `"0x"` (e.g., `"0x7B"`). +/// - Underscores can be used as visual separators (e.g., `"1_000"` or `"0x1_F4"`). +/// +/// If the input string is not a valid number in the specified format, `None` is returned. +/// +/// # Examples +/// +/// ``` +/// use forc_debug::cli::parse_int; +/// /// Use underscores as separators in decimal and hexadecimal numbers +/// assert_eq!(parse_int("123"), Some(123)); +/// assert_eq!(parse_int("1_000"), Some(1000)); +/// +/// /// Parse hexadecimal numbers with "0x" prefix +/// assert_eq!(parse_int("0x7B"), Some(123)); +/// assert_eq!(parse_int("0x1_F4"), Some(500)); +/// +/// /// Handle invalid inputs gracefully +/// assert_eq!(parse_int("abc"), None); +/// assert_eq!(parse_int("0xZZZ"), None); +/// assert_eq!(parse_int(""), None); +/// ``` +/// +/// # Errors +/// +/// Returns `None` if the input string contains invalid characters, +/// is not properly formatted, or cannot be parsed into a `usize`. +pub fn parse_int(s: &str) -> Option { + let (s, radix) = s.strip_prefix("0x").map_or((s, 10), |s| (s, 16)); + usize::from_str_radix(&s.replace('_', ""), radix).ok() +} diff --git a/forc-plugins/forc-debug/src/error.rs b/forc-plugins/forc-debug/src/error.rs new file mode 100644 index 00000000000..8f9f76fe114 --- /dev/null +++ b/forc-plugins/forc-debug/src/error.rs @@ -0,0 +1,106 @@ +use crate::types::Instruction; +use dap::requests::Command; + +pub type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + ArgumentError(#[from] ArgumentError), + + #[error(transparent)] + AdapterError(#[from] AdapterError), + + #[error("VM error: {0}")] + VMError(String), + + #[error("Fuel Client error: {0}")] + FuelClientError(String), + + #[error("Session error: {0}")] + SessionError(String), + + #[error("I/O error")] + IoError(std::io::Error), + + #[error("Json error")] + JsonError(#[from] serde_json::Error), + + #[error("Server error: {0}")] + DapServerError(#[from] dap::errors::ServerError), +} + +#[derive(Debug, thiserror::Error)] +pub enum ArgumentError { + #[error("Invalid argument: {0}")] + Invalid(String), + + #[error("Not enough arguments, expected {expected} but got {got}")] + NotEnough { expected: usize, got: usize }, + + #[error("Too many arguments, expected {expected} but got {got}")] + TooMany { expected: usize, got: usize }, + + #[error("Invalid number format: {0}")] + InvalidNumber(String), +} + +#[derive(Debug, thiserror::Error)] +pub enum AdapterError { + #[error("Unhandled command")] + UnhandledCommand { command: Command }, + + #[error("Missing command")] + MissingCommand, + + #[error("Missing configuration")] + MissingConfiguration, + + #[error("Missing source path argument")] + MissingSourcePathArgument, + + #[error("Missing breakpoint location")] + MissingBreakpointLocation, + + #[error("Missing source map")] + MissingSourceMap { pc: Instruction }, + + #[error("Unknown breakpoint")] + UnknownBreakpoint { pc: Instruction }, + + #[error("Build failed")] + BuildFailed { reason: String }, + + #[error("No active test executor")] + NoActiveTestExecutor, + + #[error("Test execution failed")] + TestExecutionFailed { + #[from] + source: anyhow::Error, + }, +} + +impl ArgumentError { + /// Ensures argument count falls within [min, max] range. + pub fn ensure_arg_count( + args: &[String], + min: usize, + max: usize, + ) -> std::result::Result<(), ArgumentError> { + let count = args.len(); + if count < min { + Err(ArgumentError::NotEnough { + expected: min, + got: count, + }) + } else if count > max { + Err(ArgumentError::TooMany { + expected: max, + got: count, + }) + } else { + Ok(()) + } + } +} diff --git a/forc-plugins/forc-debug/src/lib.rs b/forc-plugins/forc-debug/src/lib.rs index e611ae3052c..a98036d815e 100644 --- a/forc-plugins/forc-debug/src/lib.rs +++ b/forc-plugins/forc-debug/src/lib.rs @@ -1,3 +1,5 @@ +pub mod cli; +pub mod error; pub mod names; pub mod server; pub mod types; diff --git a/forc-plugins/forc-debug/src/main.rs b/forc-plugins/forc-debug/src/main.rs index 7bf6a13b81a..da60d35a70b 100644 --- a/forc-plugins/forc-debug/src/main.rs +++ b/forc-plugins/forc-debug/src/main.rs @@ -1,13 +1,5 @@ use clap::Parser; -use forc_debug::{ - names::{register_index, register_name}, - server::DapServer, - ContractId, FuelClient, RunResult, Transaction, -}; -use forc_tracing::{init_tracing_subscriber, println_error}; -use fuel_vm::consts::{VM_MAX_RAM, VM_REGISTER_COUNT, WORD_SIZE}; -use shellfish::{async_fn, Command as ShCommand, Shell}; -use std::error::Error; +use forc_tracing::{init_tracing_subscriber, println_error, TracingSubscriberOptions}; #[derive(Parser, Debug)] #[clap(name = "forc-debug", version)] @@ -23,273 +15,17 @@ pub struct Opt { #[tokio::main] async fn main() { - init_tracing_subscriber(Default::default()); + init_tracing_subscriber(TracingSubscriberOptions::default()); let config = Opt::parse(); - if let Err(err) = run(&config).await { - println_error(&format!("{}", err)); - std::process::exit(1); - } -} - -async fn run(config: &Opt) -> Result<(), Box> { - if config.serve { - return DapServer::default().start(); - } - - let mut shell = Shell::new_async( - State { - client: FuelClient::new(&config.api_url)?, - session_id: String::new(), // Placeholder - }, - ">> ", - ); - - macro_rules! command { - ($f:ident, $help:literal, $names:expr) => { - for c in $names { - shell.commands.insert( - c, - ShCommand::new_async($help.to_string(), async_fn!(State, $f)), - ); - } - }; - } - - command!( - cmd_start_tx, - "path/to/tx.json -- start a new transaction", - ["n", "tx", "new_tx", "start_tx"] - ); - command!( - cmd_reset, - "-- reset, removing breakpoints and other state", - ["reset"] - ); - command!( - cmd_continue, - "-- run until next breakpoint or termination", - ["c", "continue"] - ); - command!( - cmd_step, - "[on|off] -- turn single-stepping on or off", - ["s", "step"] - ); - command!( - cmd_breakpoint, - "[contract_id] offset -- set a breakpoint", - ["b", "breakpoint"] - ); - command!( - cmd_registers, - "[regname ...] -- dump registers", - ["r", "reg", "register", "registers"] - ); - command!(cmd_memory, "[offset] limit -- dump memory", ["m", "memory"]); - - let session_id = shell.state.client.start_session().await?; - shell.state.session_id.clone_from(&session_id); - shell.run_async().await?; - shell.state.client.end_session(&session_id).await?; - Ok(()) -} - -struct State { - client: FuelClient, - session_id: String, -} - -#[derive(Debug, thiserror::Error)] -enum ArgError { - #[error("Invalid argument")] - Invalid, - #[error("Not enough arguments")] - NotEnough, - #[error("Too many arguments")] - TooMany, -} - -fn pretty_print_run_result(rr: &RunResult) { - for receipt in rr.receipts() { - println!("Receipt: {:?}", receipt); - } - if let Some(bp) = &rr.breakpoint { - println!( - "Stopped on breakpoint at address {} of contract {}", - bp.pc.0, bp.contract - ); + let result = if config.serve { + forc_debug::server::DapServer::default().start() } else { - println!("Terminated"); - } -} - -async fn cmd_start_tx(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - let path_to_tx_json = args.pop().ok_or_else(|| Box::new(ArgError::NotEnough))?; - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let tx_json = std::fs::read(path_to_tx_json)?; - let tx: Transaction = serde_json::from_slice(&tx_json)?; - let status = state.client.start_tx(&state.session_id, &tx).await?; - pretty_print_run_result(&status); - - Ok(()) -} - -async fn cmd_reset(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let _ = state.client.reset(&state.session_id).await?; - - Ok(()) -} - -async fn cmd_continue(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let status = state.client.continue_tx(&state.session_id).await?; - pretty_print_run_result(&status); - - Ok(()) -} - -async fn cmd_step(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - if args.len() > 1 { - return Err(Box::new(ArgError::TooMany)); - } - - state - .client - .set_single_stepping( - &state.session_id, - args.first() - .map(|v| !["off", "no", "disable"].contains(&v.as_str())) - .unwrap_or(true), - ) - .await?; - Ok(()) -} - -async fn cmd_breakpoint(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - let offset = args.pop().ok_or_else(|| Box::new(ArgError::NotEnough))?; - let contract_id = args.pop(); - - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let offset = if let Some(offset) = parse_int(&offset) { - offset as u64 - } else { - return Err(Box::new(ArgError::Invalid)); + forc_debug::cli::start_cli(&config.api_url).await }; - let contract = if let Some(contract_id) = contract_id { - if let Ok(contract_id) = contract_id.parse::() { - contract_id - } else { - return Err(Box::new(ArgError::Invalid)); - } - } else { - ContractId::zeroed() // Current script - }; - - state - .client - .set_breakpoint(&state.session_id, contract, offset) - .await?; - - Ok(()) -} - -async fn cmd_registers(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - - if args.is_empty() { - for r in 0..VM_REGISTER_COUNT { - let value = state.client.register(&state.session_id, r as u32).await?; - println!("reg[{:#x}] = {:<8} # {}", r, value, register_name(r)); - } - } else { - for arg in &args { - if let Some(v) = parse_int(arg) { - if v < VM_REGISTER_COUNT { - let value = state.client.register(&state.session_id, v as u32).await?; - println!("reg[{:#02x}] = {:<8} # {}", v, value, register_name(v)); - } else { - println!("Register index too large {}", v); - return Ok(()); - } - } else if let Some(index) = register_index(arg) { - let value = state - .client - .register(&state.session_id, index as u32) - .await?; - println!("reg[{:#02x}] = {:<8} # {}", index, value, arg); - } else { - println!("Unknown register name {}", arg); - return Ok(()); - } - } - } - - Ok(()) -} - -async fn cmd_memory(state: &mut State, mut args: Vec) -> Result<(), Box> { - args.remove(0); - - let limit = args - .pop() - .map(|a| parse_int(&a).ok_or(ArgError::Invalid)) - .transpose()? - .unwrap_or(WORD_SIZE * (VM_MAX_RAM as usize)); - - let offset = args - .pop() - .map(|a| parse_int(&a).ok_or(ArgError::Invalid)) - .transpose()? - .unwrap_or(0); - - if !args.is_empty() { - return Err(Box::new(ArgError::TooMany)); - } - - let mem = state - .client - .memory(&state.session_id, offset as u32, limit as u32) - .await?; - - for (i, chunk) in mem.chunks(WORD_SIZE).enumerate() { - print!(" {:06x}:", offset + i * WORD_SIZE); - for byte in chunk { - print!(" {:02x}", byte); - } - println!(); + if let Err(err) = result { + println_error(&format!("{err}")); + std::process::exit(1); } - - Ok(()) -} - -fn parse_int(s: &str) -> Option { - let (s, radix) = if let Some(stripped) = s.strip_prefix("0x") { - (stripped, 16) - } else { - (s, 10) - }; - - let s = s.replace('_', ""); - - usize::from_str_radix(&s, radix).ok() } diff --git a/forc-plugins/forc-debug/src/names.rs b/forc-plugins/forc-debug/src/names.rs index 91e8833cbf4..548305e9ba9 100644 --- a/forc-plugins/forc-debug/src/names.rs +++ b/forc-plugins/forc-debug/src/names.rs @@ -1,8 +1,22 @@ +/// A list of predefined register names mapped to their corresponding indices. pub const REGISTERS: [&str; 16] = [ "zero", "one", "of", "pc", "ssp", "sp", "fp", "hp", "err", "ggas", "cgas", "bal", "is", "ret", "retl", "flag", ]; +/// Returns the name of a register given its index. +/// +/// If the index corresponds to a predefined register, the corresponding name +/// from `REGISTERS` is returned. Otherwise, it returns a formatted name +/// like `"reg{index}"`. +/// +/// # Examples +/// +/// ``` +/// use forc_debug::names::register_name; +/// assert_eq!(register_name(0), "zero".to_string()); +/// assert_eq!(register_name(15), "flag".to_string()); +/// ``` pub fn register_name(index: usize) -> String { if index < REGISTERS.len() { REGISTERS[index].to_owned() @@ -11,6 +25,19 @@ pub fn register_name(index: usize) -> String { } } +/// Returns the index of a register given its name. +/// +/// If the name matches a predefined register in `REGISTERS`, the corresponding +/// index is returned. Otherwise, returns `None`. +/// +/// # Examples +/// +/// ``` +/// use forc_debug::names::register_index; +/// assert_eq!(register_index("zero"), Some(0)); +/// assert_eq!(register_index("flag"), Some(15)); +/// assert_eq!(register_index("unknown"), None); +/// ``` pub fn register_index(name: &str) -> Option { REGISTERS.iter().position(|&n| n == name) } diff --git a/forc-plugins/forc-debug/src/server/error.rs b/forc-plugins/forc-debug/src/server/error.rs deleted file mode 100644 index 1307e57bdd1..00000000000 --- a/forc-plugins/forc-debug/src/server/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::types::Instruction; -use dap::requests::Command; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum AdapterError { - #[error("Unhandled command")] - UnhandledCommand { command: Command }, - - #[error("Missing command")] - MissingCommand, - - #[error("Missing configuration")] - MissingConfiguration, - - #[error("Missing source path argument")] - MissingSourcePathArgument, - - #[error("Missing breakpoint location")] - MissingBreakpointLocation, - - #[error("Missing source map")] - MissingSourceMap { pc: Instruction }, - - #[error("Unknown breakpoint")] - UnknownBreakpoint { pc: Instruction }, - - #[error("Build failed")] - BuildFailed { reason: String }, - - #[error("No active test executor")] - NoActiveTestExecutor, - - #[error("Test execution failed")] - TestExecutionFailed { - #[from] - source: anyhow::Error, - }, -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs b/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs index 8d7e37259ab..4d41dd32604 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_breakpoint_locations.rs @@ -1,13 +1,28 @@ -use crate::server::AdapterError; -use crate::server::DapServer; -use dap::requests::BreakpointLocationsArguments; -use dap::types::BreakpointLocation; +use crate::server::{AdapterError, DapServer, HandlerResult}; +use dap::{ + requests::BreakpointLocationsArguments, responses::ResponseBody, types::BreakpointLocation, +}; use std::path::PathBuf; impl DapServer { /// Handles a `breakpoint_locations` request. Returns the list of [BreakpointLocation]s. - pub(crate) fn handle_breakpoint_locations( - &mut self, + pub(crate) fn handle_breakpoint_locations_command( + &self, + args: &BreakpointLocationsArguments, + ) -> HandlerResult { + let result = self.breakpoint_locations(args).map(|breakpoints| { + ResponseBody::BreakpointLocations(dap::responses::BreakpointLocationsResponse { + breakpoints, + }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + fn breakpoint_locations( + &self, args: &BreakpointLocationsArguments, ) -> Result, AdapterError> { let source_path = args @@ -62,7 +77,7 @@ mod tests { }, ..Default::default() }; - let result = server.handle_breakpoint_locations(&args).expect("success"); + let result = server.breakpoint_locations(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, MOCK_LINE); } @@ -70,15 +85,15 @@ mod tests { #[test] #[should_panic(expected = "MissingSourcePathArgument")] fn test_handle_breakpoint_locations_missing_argument() { - let mut server = DapServer::default(); + let server = DapServer::default(); let args = BreakpointLocationsArguments::default(); - server.handle_breakpoint_locations(&args).unwrap(); + server.breakpoint_locations(&args).unwrap(); } #[test] #[should_panic(expected = "MissingBreakpointLocation")] fn test_handle_breakpoint_locations_missing_breakpoint() { - let mut server = DapServer::default(); + let server = DapServer::default(); let args = BreakpointLocationsArguments { source: dap::types::Source { path: Some(MOCK_SOURCE_PATH.into()), @@ -86,6 +101,6 @@ mod tests { }, ..Default::default() }; - server.handle_breakpoint_locations(&args).unwrap(); + server.breakpoint_locations(&args).unwrap(); } } diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_continue.rs b/forc-plugins/forc-debug/src/server/handlers/handle_continue.rs deleted file mode 100644 index 200c7091a9a..00000000000 --- a/forc-plugins/forc-debug/src/server/handlers/handle_continue.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::server::AdapterError; -use crate::server::DapServer; - -impl DapServer { - /// Handles a `continue` request. Returns true if the server should continue running. - pub(crate) fn handle_continue(&mut self) -> Result { - self.continue_debugging_tests(false) - } -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs b/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs deleted file mode 100644 index 3ae3c2f3539..00000000000 --- a/forc-plugins/forc-debug/src/server/handlers/handle_launch.rs +++ /dev/null @@ -1,183 +0,0 @@ -use crate::server::{AdapterError, DapServer}; -use crate::types::Instruction; -use forc_pkg::manifest::GenericManifestFile; -use forc_pkg::{self, BuildProfile, Built, BuiltPackage, PackageManifestFile}; -use forc_test::execute::TestExecutor; -use forc_test::setup::TestSetup; -use forc_test::BuiltTests; -use std::{collections::HashMap, sync::Arc}; -use sway_types::LineCol; - -impl DapServer { - /// Handles a `launch` request. Returns true if the server should continue running. - pub fn handle_launch(&mut self) -> Result { - // Build tests for the given path. - let (pkg_to_debug, test_setup) = self.build_tests()?; - let entries = pkg_to_debug.bytecode.entries.iter().filter_map(|entry| { - if let Some(test_entry) = entry.kind.test() { - return Some((entry, test_entry)); - } - None - }); - - // Construct a TestExecutor for each test and store it - let executors: Vec = entries - .filter_map(|(entry, test_entry)| { - let offset = u32::try_from(entry.finalized.imm) - .expect("test instruction offset out of range"); - let name = entry.finalized.fn_name.clone(); - if test_entry.file_path.as_path() != self.state.program_path.as_path() { - return None; - } - - TestExecutor::build( - &pkg_to_debug.bytecode.bytes, - offset, - test_setup.clone(), - test_entry, - name.clone(), - ) - .ok() - }) - .collect(); - self.state.init_executors(executors); - - // Start debugging - self.start_debugging_tests(false) - } - - /// Builds the tests at the given [PathBuf] and stores the source maps. - pub(crate) fn build_tests(&mut self) -> Result<(BuiltPackage, TestSetup), AdapterError> { - if let Some(pkg) = &self.state.built_package { - if let Some(setup) = &self.state.test_setup { - return Ok((pkg.clone(), setup.clone())); - } - } - - // 1. Build the packages - let manifest_file = forc_pkg::manifest::ManifestFile::from_dir(&self.state.program_path) - .map_err(|err| AdapterError::BuildFailed { - reason: format!("read manifest file: {:?}", err), - })?; - let pkg_manifest: PackageManifestFile = - manifest_file - .clone() - .try_into() - .map_err(|err: anyhow::Error| AdapterError::BuildFailed { - reason: format!("package manifest: {:?}", err), - })?; - let member_manifests = - manifest_file - .member_manifests() - .map_err(|err| AdapterError::BuildFailed { - reason: format!("member manifests: {:?}", err), - })?; - let lock_path = manifest_file - .lock_path() - .map_err(|err| AdapterError::BuildFailed { - reason: format!("lock path: {:?}", err), - })?; - let build_plan = forc_pkg::BuildPlan::from_lock_and_manifests( - &lock_path, - &member_manifests, - false, - false, - &Default::default(), - ) - .map_err(|err| AdapterError::BuildFailed { - reason: format!("build plan: {:?}", err), - })?; - - let project_name = pkg_manifest.project_name(); - - let outputs = std::iter::once(build_plan.find_member_index(project_name).ok_or( - AdapterError::BuildFailed { - reason: format!("find built project: {}", project_name), - }, - )?) - .collect(); - - let built_packages = forc_pkg::build( - &build_plan, - Default::default(), - &BuildProfile { - optimization_level: sway_core::OptLevel::Opt0, - include_tests: true, - ..Default::default() - }, - &outputs, - &[], - &[], - ) - .map_err(|err| AdapterError::BuildFailed { - reason: format!("build packages: {:?}", err), - })?; - - // 2. Store the source maps - let mut pkg_to_debug: Option<&BuiltPackage> = None; - built_packages.iter().for_each(|(_, built_pkg)| { - if built_pkg.descriptor.manifest_file == pkg_manifest { - pkg_to_debug = Some(built_pkg); - } - let source_map = &built_pkg.source_map; - - let paths = &source_map.paths; - source_map.map.iter().for_each(|(instruction, sm_span)| { - if let Some(path_buf) = paths.get(sm_span.path.0) { - let LineCol { line, .. } = sm_span.range.start; - let (line, instruction) = (line as i64, *instruction as Instruction); - - self.state - .source_map - .entry(path_buf.clone()) - .and_modify(|new_map| { - new_map - .entry(line) - .and_modify(|val| { - // Store the instructions in ascending order - match val.binary_search(&instruction) { - Ok(_) => {} // Ignore duplicates - Err(pos) => val.insert(pos, instruction), - } - }) - .or_insert(vec![instruction]); - }) - .or_insert(HashMap::from([(line, vec![instruction])])); - } else { - self.error(format!( - "Path missing from source map: {:?}", - sm_span.path.0 - )); - } - }); - }); - - // 3. Build the tests - let built_package = pkg_to_debug.ok_or(AdapterError::BuildFailed { - reason: format!("find package: {}", project_name), - })?; - - let built = Built::Package(Arc::from(built_package.clone())); - - let built_tests = BuiltTests::from_built(built, &build_plan).map_err(|err| { - AdapterError::BuildFailed { - reason: format!("build tests: {:?}", err), - } - })?; - - let pkg_tests = match built_tests { - BuiltTests::Package(pkg_tests) => pkg_tests, - BuiltTests::Workspace(_) => { - return Err(AdapterError::BuildFailed { - reason: "package tests: workspace tests not supported".into(), - }) - } - }; - let test_setup = pkg_tests.setup().map_err(|err| AdapterError::BuildFailed { - reason: format!("test setup: {:?}", err), - })?; - self.state.built_package = Some(built_package.clone()); - self.state.test_setup = Some(test_setup.clone()); - Ok((built_package.clone(), test_setup)) - } -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_next.rs b/forc-plugins/forc-debug/src/server/handlers/handle_next.rs deleted file mode 100644 index 484228494e6..00000000000 --- a/forc-plugins/forc-debug/src/server/handlers/handle_next.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::server::AdapterError; -use crate::server::DapServer; - -impl DapServer { - /// Handles a `next` request. Returns true if the server should continue running. - pub(crate) fn handle_next(&mut self) -> Result { - self.continue_debugging_tests(true) - } -} diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs b/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs index 63390fb458e..d1b62c269cd 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_set_breakpoints.rs @@ -1,12 +1,27 @@ -use crate::server::AdapterError; -use crate::server::DapServer; -use dap::requests::SetBreakpointsArguments; -use dap::types::{Breakpoint, StartDebuggingRequestKind}; +use crate::server::{AdapterError, DapServer, HandlerResult}; +use dap::{ + requests::SetBreakpointsArguments, + responses::ResponseBody, + types::{Breakpoint, StartDebuggingRequestKind}, +}; use std::path::PathBuf; impl DapServer { /// Handles a `set_breakpoints` request. Returns the list of [Breakpoint]s for the path provided in `args`. - pub(crate) fn handle_set_breakpoints( + pub(crate) fn handle_set_breakpoints_command( + &mut self, + args: &SetBreakpointsArguments, + ) -> HandlerResult { + let result = self.set_breakpoints(args).map(|breakpoints| { + ResponseBody::SetBreakpoints(dap::responses::SetBreakpointsResponse { breakpoints }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + fn set_breakpoints( &mut self, args: &SetBreakpointsArguments, ) -> Result, AdapterError> { @@ -44,24 +59,22 @@ impl DapServer { .iter() .map(|source_bp| { let verified = source_map.contains_key(&source_bp.line); - - match existing_breakpoints.iter().find(|bp| match bp.line { - Some(line) => line == source_bp.line, - None => false, - }) { - Some(existing_bp) => Breakpoint { + if let Some(existing_bp) = existing_breakpoints + .iter() + .find(|bp| bp.line.map_or(false, |line| line == source_bp.line)) + { + Breakpoint { verified, ..existing_bp.clone() - }, - None => { - let id = Some(self.breakpoint_id_gen.next()); - Breakpoint { - id, - verified, - line: Some(source_bp.line), - source: Some(args.source.clone()), - ..Default::default() - } + } + } else { + let id = Some(self.breakpoint_id_gen.next()); + Breakpoint { + id, + verified, + line: Some(source_bp.line), + source: Some(args.source.clone()), + ..Default::default() } } }) @@ -131,7 +144,7 @@ mod tests { fn test_handle_set_breakpoints_existing_verified() { let mut server = get_test_server(true, true); let args = get_test_args(); - let result = server.handle_set_breakpoints(&args).expect("success"); + let result = server.set_breakpoints(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, Some(MOCK_LINE)); assert_eq!(result[0].id, Some(MOCK_BP_ID)); @@ -146,7 +159,7 @@ mod tests { fn test_handle_set_breakpoints_existing_unverified() { let mut server = get_test_server(false, true); let args = get_test_args(); - let result = server.handle_set_breakpoints(&args).expect("success"); + let result = server.set_breakpoints(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, Some(MOCK_LINE)); assert_eq!(result[0].id, Some(MOCK_BP_ID)); @@ -161,7 +174,7 @@ mod tests { fn test_handle_set_breakpoints_new() { let mut server = get_test_server(true, false); let args = get_test_args(); - let result = server.handle_set_breakpoints(&args).expect("success"); + let result = server.set_breakpoints(&args).expect("success"); assert_eq!(result.len(), 1); assert_eq!(result[0].line, Some(MOCK_LINE)); assert_eq!( @@ -176,6 +189,6 @@ mod tests { fn test_handle_breakpoint_locations_missing_argument() { let mut server = get_test_server(true, true); let args = SetBreakpointsArguments::default(); - server.handle_set_breakpoints(&args).unwrap(); + server.set_breakpoints(&args).unwrap(); } } diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs b/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs index fd26ff067af..0ee70988626 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_stack_trace.rs @@ -1,12 +1,25 @@ -use crate::server::util; -use crate::server::AdapterError; -use crate::server::DapServer; -use dap::types::StackFrame; -use dap::types::StackFramePresentationhint; +use crate::server::{util, AdapterError, DapServer, HandlerResult}; +use dap::{ + responses::ResponseBody, + types::{StackFrame, StackFramePresentationhint}, +}; impl DapServer { /// Handles a `stack_trace` request. Returns the list of [StackFrame]s for the current execution state. - pub(crate) fn handle_stack_trace(&self) -> Result, AdapterError> { + pub(crate) fn handle_stack_trace_command(&self) -> HandlerResult { + let result = self.stack_trace().map(|stack_frames| { + ResponseBody::StackTrace(dap::responses::StackTraceResponse { + stack_frames, + total_frames: None, + }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + fn stack_trace(&self) -> Result, AdapterError> { let executor = self .state .executors diff --git a/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs b/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs index 1b4db95eab6..498413a0a80 100644 --- a/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs +++ b/forc-plugins/forc-debug/src/server/handlers/handle_variables.rs @@ -1,21 +1,26 @@ -use crate::names::register_name; -use crate::server::AdapterError; -use crate::server::DapServer; -use crate::server::INSTRUCTIONS_VARIABLE_REF; -use crate::server::REGISTERS_VARIABLE_REF; -use dap::requests::VariablesArguments; -use dap::types::Variable; -use fuel_vm::fuel_asm::Imm06; -use fuel_vm::fuel_asm::Imm12; -use fuel_vm::fuel_asm::Imm18; -use fuel_vm::fuel_asm::Imm24; -use fuel_vm::fuel_asm::Instruction; -use fuel_vm::fuel_asm::RawInstruction; -use fuel_vm::fuel_asm::RegId; +use crate::{ + names::register_name, + server::{ + AdapterError, DapServer, HandlerResult, INSTRUCTIONS_VARIABLE_REF, REGISTERS_VARIABLE_REF, + }, +}; +use dap::{requests::VariablesArguments, responses::ResponseBody, types::Variable}; +use fuel_vm::fuel_asm::{Imm06, Imm12, Imm18, Imm24, Instruction, RawInstruction, RegId}; impl DapServer { - /// Handles a `variables` request. Returns the list of [Variable]s for the current execution state. - pub(crate) fn handle_variables( + /// Processes a variables request, returning all variables and their current values. + pub(crate) fn handle_variables_command(&self, args: &VariablesArguments) -> HandlerResult { + let result = self.get_variables(args).map(|variables| { + ResponseBody::Variables(dap::responses::VariablesResponse { variables }) + }); + match result { + Ok(result) => HandlerResult::ok(result), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + /// Returns the list of [Variable]s for the current execution state. + pub(crate) fn get_variables( &self, args: &VariablesArguments, ) -> Result, AdapterError> { @@ -32,7 +37,7 @@ impl DapServer { .enumerate() .map(|(index, value)| Variable { name: register_name(index), - value: format!("0x{:X?}", value), + value: format!("0x{value:X?}"), ..Default::default() }) .collect::>(); @@ -56,7 +61,7 @@ impl DapServer { .iter() .filter_map(|(name, value)| { value.as_ref().map(|value| Variable { - name: name.to_string(), + name: (*name).to_string(), value: value.to_string(), ..Default::default() }) diff --git a/forc-plugins/forc-debug/src/server/handlers/mod.rs b/forc-plugins/forc-debug/src/server/handlers/mod.rs index 66ef3f3aebb..601844a343f 100644 --- a/forc-plugins/forc-debug/src/server/handlers/mod.rs +++ b/forc-plugins/forc-debug/src/server/handlers/mod.rs @@ -1,7 +1,130 @@ +use crate::{ + error::AdapterError, + server::{ + AdditionalData, DapServer, HandlerResult, INSTRUCTIONS_VARIABLE_REF, + REGISTERS_VARIABLE_REF, THREAD_ID, + }, +}; +use dap::{ + prelude::*, + types::{Scope, StartDebuggingRequestKind}, +}; +use requests::{EvaluateArguments, LaunchRequestArguments}; +use std::path::PathBuf; + pub(crate) mod handle_breakpoint_locations; -pub(crate) mod handle_continue; -pub(crate) mod handle_launch; -pub(crate) mod handle_next; pub(crate) mod handle_set_breakpoints; pub(crate) mod handle_stack_trace; pub(crate) mod handle_variables; + +impl DapServer { + pub(crate) fn handle_attach(&mut self) -> HandlerResult { + self.state.mode = Some(StartDebuggingRequestKind::Attach); + self.error("This feature is not currently supported.".into()); + HandlerResult::ok_with_exit(ResponseBody::Attach, 0) + } + + pub(crate) fn handle_initialize(&mut self) -> HandlerResult { + HandlerResult::ok(ResponseBody::Initialize(types::Capabilities { + supports_breakpoint_locations_request: Some(true), + supports_configuration_done_request: Some(true), + ..Default::default() + })) + } + + pub(crate) fn handle_configuration_done(&mut self) -> HandlerResult { + self.state.configuration_done = true; + HandlerResult::ok(ResponseBody::ConfigurationDone) + } + + pub(crate) fn handle_launch(&mut self, args: &LaunchRequestArguments) -> HandlerResult { + self.state.mode = Some(StartDebuggingRequestKind::Launch); + if let Some(additional_data) = &args.additional_data { + if let Ok(data) = serde_json::from_value::(additional_data.clone()) { + self.state.program_path = PathBuf::from(data.program); + return HandlerResult::ok(ResponseBody::Launch); + } + } + HandlerResult::err_with_exit(AdapterError::MissingConfiguration, 1) + } + + /// Handles a `next` request. Returns true if the server should continue running. + pub(crate) fn handle_next(&mut self) -> HandlerResult { + match self.continue_debugging_tests(true) { + Ok(true) => HandlerResult::ok(ResponseBody::Next), + Ok(false) => { + // The tests finished executing + HandlerResult::ok_with_exit(ResponseBody::Next, 0) + } + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + /// Handles a `continue` request. Returns true if the server should continue running. + pub(crate) fn handle_continue(&mut self) -> HandlerResult { + match self.continue_debugging_tests(false) { + Ok(true) => HandlerResult::ok(ResponseBody::Continue(responses::ContinueResponse { + all_threads_continued: Some(true), + })), + Ok(false) => HandlerResult::ok_with_exit( + ResponseBody::Continue(responses::ContinueResponse { + all_threads_continued: Some(true), + }), + 0, + ), + Err(e) => HandlerResult::err_with_exit(e, 1), + } + } + + pub(crate) fn handle_evaluate(&mut self, args: &EvaluateArguments) -> HandlerResult { + let result = match args.context { + Some(types::EvaluateArgumentsContext::Variables) => args.expression.clone(), + _ => "Evaluate expressions not supported in this context".into(), + }; + HandlerResult::ok(ResponseBody::Evaluate(responses::EvaluateResponse { + result, + ..Default::default() + })) + } + + pub(crate) fn handle_pause(&mut self) -> HandlerResult { + // TODO: interpreter pause function + if let Some(executor) = self.state.executor() { + executor.interpreter.set_single_stepping(true); + } + HandlerResult::ok(ResponseBody::Pause) + } + + pub(crate) fn handle_restart(&mut self) -> HandlerResult { + self.state.reset(); + HandlerResult::ok(ResponseBody::Restart) + } + + pub(crate) fn handle_scopes(&mut self) -> HandlerResult { + HandlerResult::ok(ResponseBody::Scopes(responses::ScopesResponse { + scopes: vec![ + Scope { + name: "Current VM Instruction".into(), + presentation_hint: Some(types::ScopePresentationhint::Registers), + variables_reference: INSTRUCTIONS_VARIABLE_REF, + ..Default::default() + }, + Scope { + name: "Registers".into(), + presentation_hint: Some(types::ScopePresentationhint::Registers), + variables_reference: REGISTERS_VARIABLE_REF, + ..Default::default() + }, + ], + })) + } + + pub(crate) fn handle_threads(&mut self) -> HandlerResult { + HandlerResult::ok(ResponseBody::Threads(responses::ThreadsResponse { + threads: vec![types::Thread { + id: THREAD_ID, + name: "main".into(), + }], + })) + } +} diff --git a/forc-plugins/forc-debug/src/server/mod.rs b/forc-plugins/forc-debug/src/server/mod.rs index 968b1cf4ec1..e06959c5e7b 100644 --- a/forc-plugins/forc-debug/src/server/mod.rs +++ b/forc-plugins/forc-debug/src/server/mod.rs @@ -1,25 +1,36 @@ -mod error; mod handlers; mod state; mod util; -use self::error::AdapterError; -use self::state::ServerState; -use self::util::IdGenerator; -use crate::types::DynResult; -use crate::types::Instruction; -use dap::events::OutputEventBody; -use dap::events::{ExitedEventBody, StoppedEventBody}; -use dap::prelude::*; -use dap::types::{Scope, StartDebuggingRequestKind}; -use forc_test::execute::DebugResult; +use crate::{ + error::{self, AdapterError, Error}, + server::{state::ServerState, util::IdGenerator}, + types::{ExitCode, Instruction}, +}; +use dap::{ + events::{ExitedEventBody, OutputEventBody, StoppedEventBody}, + prelude::*, + types::StartDebuggingRequestKind, +}; +use forc_pkg::{ + manifest::GenericManifestFile, + source::IPFSNode, + {self, BuildProfile, Built, BuiltPackage, PackageManifestFile}, +}; +use forc_test::{ + execute::{DebugResult, TestExecutor}, + setup::TestSetup, + BuiltTests, +}; use serde::{Deserialize, Serialize}; -use std::io::{Read, Write}; use std::{ - io::{BufReader, BufWriter}, - path::PathBuf, + collections::HashMap, + io::{BufReader, BufWriter, Read, Write}, process, + sync::Arc, }; +use sway_core::BuildTarget; +use sway_types::LineCol; pub const THREAD_ID: i64 = 0; pub const REGISTERS_VARIABLE_REF: i64 = 1; @@ -52,230 +63,115 @@ impl Default for DapServer { } impl DapServer { + /// Creates a new DAP server with custom input and output streams. + /// + /// # Arguments + /// * `input` - Source of DAP protocol messages (usually stdin) + /// * `output` - Destination for DAP protocol messages (usually stdout) pub fn new(input: Box, output: Box) -> Self { let server = Server::new(BufReader::new(input), BufWriter::new(output)); DapServer { server, - state: Default::default(), - breakpoint_id_gen: Default::default(), + state: ServerState::default(), + breakpoint_id_gen: IdGenerator::default(), } } - pub fn start(&mut self) -> DynResult<()> { + /// Runs the debug server event loop, handling client requests until completion or error. + pub fn start(&mut self) -> error::Result<()> { loop { - match self.server.poll_request()? { - Some(req) => { - let rsp = self.handle_request(req)?; - self.server.respond(rsp)?; - - if !self.state.initialized_event_sent { - let _ = self.server.send_event(Event::Initialized); - self.state.initialized_event_sent = true; - } - if self.state.configuration_done && !self.state.started_debugging { - if let Some(StartDebuggingRequestKind::Launch) = self.state.mode { - self.state.started_debugging = true; - match self.handle_launch() { - Ok(true) => {} - Ok(false) => { - // The tests finished executing - self.exit(0); - } - Err(e) => { - self.error(format!("Launch error: {:?}", e)); - self.exit(1); - } - } - } + let req = match self.server.poll_request()? { + Some(req) => req, + None => return Err(Error::AdapterError(AdapterError::MissingCommand)), + }; + + // Handle the request and send response + let response = self.handle_request(req)?; + self.server.respond(response)?; + + // Handle one-time initialization + if !self.state.initialized_event_sent { + let _ = self.server.send_event(Event::Initialized); + self.state.initialized_event_sent = true; + } + + // Handle launch after configuration is complete + if self.should_launch() { + self.state.started_debugging = true; + match self.launch() { + Ok(true) => continue, + Ok(false) => self.exit(0), // The tests finished executing + Err(e) => { + self.error(format!("Launch error: {e:?}")); + self.exit(1); } } - None => return Err(Box::new(AdapterError::MissingCommand)), - }; + } } } - fn handle_request(&mut self, req: Request) -> DynResult { - let command = req.command.clone(); - let (result, exit_code) = self.handle_command(command); + /// Processes a debug adapter request and generates appropriate response. + fn handle_request(&mut self, req: Request) -> error::Result { + let (result, exit_code) = self.handle_command(&req.command).into_tuple(); let response = match result { Ok(rsp) => Ok(req.success(rsp)), Err(e) => { - self.error(format!("{:?}", e)); - Ok(req.error(&format!("{:?}", e))) + self.error(format!("{e:?}")); + Ok(req.error(&format!("{e:?}"))) } }; if let Some(exit_code) = exit_code { - self.exit(exit_code) + self.exit(exit_code); } response } /// Handles a command and returns the result and exit code, if any. - pub fn handle_command( - &mut self, - command: Command, - ) -> (Result, Option) { + pub fn handle_command(&mut self, command: &Command) -> HandlerResult { match command { - Command::Attach(_) => { - self.state.mode = Some(StartDebuggingRequestKind::Attach); - self.error("This feature is not currently supported.".into()); - (Ok(ResponseBody::Attach), Some(0)) - } + Command::Attach(_) => self.handle_attach(), Command::BreakpointLocations(ref args) => { - match self.handle_breakpoint_locations(args) { - Ok(breakpoints) => ( - Ok(ResponseBody::BreakpointLocations( - responses::BreakpointLocationsResponse { breakpoints }, - )), - None, - ), - Err(e) => (Err(e), None), - } - } - Command::ConfigurationDone => { - self.state.configuration_done = true; - (Ok(ResponseBody::ConfigurationDone), None) - } - Command::Continue(_) => match self.handle_continue() { - Ok(true) => ( - Ok(ResponseBody::Continue(responses::ContinueResponse { - all_threads_continued: Some(true), - })), - None, - ), - Ok(false) => ( - Ok(ResponseBody::Continue(responses::ContinueResponse { - all_threads_continued: Some(true), - })), - Some(0), - ), - Err(e) => (Err(e), Some(1)), - }, - Command::Disconnect(_) => (Ok(ResponseBody::Disconnect), Some(0)), - Command::Evaluate(args) => { - let result = match args.context { - Some(types::EvaluateArgumentsContext::Variables) => args.expression.clone(), - _ => "Evaluate expressions not supported in this context".into(), - }; - ( - Ok(ResponseBody::Evaluate(responses::EvaluateResponse { - result, - ..Default::default() - })), - None, - ) - } - Command::Initialize(_) => ( - Ok(ResponseBody::Initialize(types::Capabilities { - supports_breakpoint_locations_request: Some(true), - supports_configuration_done_request: Some(true), - ..Default::default() - })), - None, - ), - Command::Launch(ref args) => { - self.state.mode = Some(StartDebuggingRequestKind::Launch); - if let Some(additional_data) = &args.additional_data { - if let Ok(data) = - serde_json::from_value::(additional_data.clone()) - { - self.state.program_path = PathBuf::from(data.program); - return (Ok(ResponseBody::Launch), None); - } - } - (Err(AdapterError::MissingConfiguration), Some(1)) - } - Command::Next(_) => { - match self.handle_next() { - Ok(true) => (Ok(ResponseBody::Next), None), - Ok(false) => { - // The tests finished executing - (Ok(ResponseBody::Next), Some(0)) - } - Err(e) => (Err(e), Some(1)), - } - } - Command::Pause(_) => { - // TODO: interpreter pause function - if let Some(executor) = self.state.executor() { - executor.interpreter.set_single_stepping(true); - } - (Ok(ResponseBody::Pause), None) + self.handle_breakpoint_locations_command(args) } - Command::Restart(_) => { - self.state.reset(); - (Ok(ResponseBody::Restart), None) - } - Command::Scopes(_) => ( - Ok(ResponseBody::Scopes(responses::ScopesResponse { - scopes: vec![ - Scope { - name: "Current VM Instruction".into(), - presentation_hint: Some(types::ScopePresentationhint::Registers), - variables_reference: INSTRUCTIONS_VARIABLE_REF, - ..Default::default() - }, - Scope { - name: "Registers".into(), - presentation_hint: Some(types::ScopePresentationhint::Registers), - variables_reference: REGISTERS_VARIABLE_REF, - ..Default::default() - }, - ], - })), - None, - ), - Command::SetBreakpoints(ref args) => match self.handle_set_breakpoints(args) { - Ok(breakpoints) => ( - Ok(ResponseBody::SetBreakpoints( - responses::SetBreakpointsResponse { breakpoints }, - )), - None, - ), - Err(e) => (Err(e), None), - }, - Command::StackTrace(_) => match self.handle_stack_trace() { - Ok(stack_frames) => ( - Ok(ResponseBody::StackTrace(responses::StackTraceResponse { - stack_frames, - total_frames: None, - })), - None, - ), - Err(e) => (Err(e), None), - }, + Command::ConfigurationDone => self.handle_configuration_done(), + Command::Continue(_) => self.handle_continue(), + Command::Disconnect(_) => HandlerResult::ok_with_exit(ResponseBody::Disconnect, 0), + Command::Evaluate(args) => self.handle_evaluate(args), + Command::Initialize(_) => self.handle_initialize(), + Command::Launch(ref args) => self.handle_launch(args), + Command::Next(_) => self.handle_next(), + Command::Pause(_) => self.handle_pause(), + Command::Restart(_) => self.handle_restart(), + Command::Scopes(_) => self.handle_scopes(), + Command::SetBreakpoints(ref args) => self.handle_set_breakpoints_command(args), + Command::StackTrace(_) => self.handle_stack_trace_command(), Command::StepIn(_) => { self.error("This feature is not currently supported.".into()); - (Ok(ResponseBody::StepIn), None) + HandlerResult::ok(ResponseBody::StepIn) } Command::StepOut(_) => { self.error("This feature is not currently supported.".into()); - (Ok(ResponseBody::StepOut), None) + HandlerResult::ok(ResponseBody::StepOut) } - Command::Terminate(_) => (Ok(ResponseBody::Terminate), Some(0)), - Command::TerminateThreads(_) => (Ok(ResponseBody::TerminateThreads), Some(0)), - Command::Threads => ( - Ok(ResponseBody::Threads(responses::ThreadsResponse { - threads: vec![types::Thread { - id: THREAD_ID, - name: "main".into(), - }], - })), - None, - ), - Command::Variables(ref args) => match self.handle_variables(args) { - Ok(variables) => ( - Ok(ResponseBody::Variables(responses::VariablesResponse { - variables, - })), - None, - ), - Err(e) => (Err(e), None), - }, - _ => (Err(AdapterError::UnhandledCommand { command }), None), + Command::Terminate(_) => HandlerResult::ok_with_exit(ResponseBody::Terminate, 0), + Command::TerminateThreads(_) => { + HandlerResult::ok_with_exit(ResponseBody::TerminateThreads, 0) + } + Command::Threads => self.handle_threads(), + Command::Variables(ref args) => self.handle_variables_command(args), + _ => HandlerResult::err(AdapterError::UnhandledCommand { + command: command.clone(), + }), } } + /// Checks whether debug session is ready to begin launching tests. + fn should_launch(&self) -> bool { + self.state.configuration_done + && !self.state.started_debugging + && matches!(self.state.mode, Some(StartDebuggingRequestKind::Launch)) + } + /// Logs a message to the client's debugger console output. fn log(&mut self, output: String) { let _ = self.server.send_event(Event::Output(OutputEventBody { @@ -293,53 +189,212 @@ impl DapServer { })); } + /// Logs test execution results in a cargo-test-like format, showing duration and gas usage for each test. fn log_test_results(&mut self) { if !self.state.executors.is_empty() { return; } - - let results = self - .state - .test_results + let test_results = &self.state.test_results; + let test_lines = test_results .iter() - .map(|result| { - let outcome = match result.passed() { - true => "ok", - false => "failed", - }; - + .map(|r| { + let outcome = if r.passed() { "ok" } else { "failed" }; format!( "test {} ... {} ({}ms, {} gas)", - result.name, + r.name, outcome, - result.duration.as_millis(), - result.gas_used + r.duration.as_millis(), + r.gas_used ) }) .collect::>() .join("\n"); - let final_outcome = match self.state.test_results.iter().any(|r| !r.passed()) { - true => "FAILED", - false => "OK", + + let passed = test_results.iter().filter(|r| r.passed()).count(); + let final_outcome = if passed == test_results.len() { + "OK" + } else { + "FAILED" }; - let passed = self - .state - .test_results - .iter() - .filter(|r| r.passed()) - .count(); - let failed = self - .state - .test_results - .iter() - .filter(|r| !r.passed()) - .count(); + self.log(format!( - "{}\nResult: {}. {} passed. {} failed.\n", - results, final_outcome, passed, failed + "{test_lines}\nResult: {final_outcome}. {passed} passed. {} failed.\n", + test_results.len() - passed )); } + /// Handles a `launch` request. Returns true if the server should continue running. + pub fn launch(&mut self) -> Result { + // Build tests for the given path. + let (pkg_to_debug, test_setup) = self.build_tests()?; + let entries = pkg_to_debug.bytecode.entries.iter().filter_map(|entry| { + if let Some(test_entry) = entry.kind.test() { + return Some((entry, test_entry)); + } + None + }); + + // Construct a TestExecutor for each test and store it + let executors: Vec = entries + .filter_map(|(entry, test_entry)| { + let offset = u32::try_from(entry.finalized.imm) + .expect("test instruction offset out of range"); + let name = entry.finalized.fn_name.clone(); + if test_entry.file_path.as_path() != self.state.program_path.as_path() { + return None; + } + + TestExecutor::build( + &pkg_to_debug.bytecode.bytes, + offset, + test_setup.clone(), + test_entry, + name.clone(), + ) + .ok() + }) + .collect(); + self.state.init_executors(executors); + + // Start debugging + self.start_debugging_tests(false) + } + + /// Builds the tests at the given [PathBuf] and stores the source maps. + pub(crate) fn build_tests(&mut self) -> Result<(BuiltPackage, TestSetup), AdapterError> { + if let Some(pkg) = &self.state.built_package { + if let Some(setup) = &self.state.test_setup { + return Ok((pkg.clone(), setup.clone())); + } + } + + // 1. Build the packages + let manifest_file = forc_pkg::manifest::ManifestFile::from_dir(&self.state.program_path) + .map_err(|err| AdapterError::BuildFailed { + reason: format!("read manifest file: {err:?}"), + })?; + let pkg_manifest: PackageManifestFile = + manifest_file + .clone() + .try_into() + .map_err(|err: anyhow::Error| AdapterError::BuildFailed { + reason: format!("package manifest: {err:?}"), + })?; + let member_manifests = + manifest_file + .member_manifests() + .map_err(|err| AdapterError::BuildFailed { + reason: format!("member manifests: {err:?}"), + })?; + let lock_path = manifest_file + .lock_path() + .map_err(|err| AdapterError::BuildFailed { + reason: format!("lock path: {err:?}"), + })?; + let build_plan = forc_pkg::BuildPlan::from_lock_and_manifests( + &lock_path, + &member_manifests, + false, + false, + &IPFSNode::default(), + ) + .map_err(|err| AdapterError::BuildFailed { + reason: format!("build plan: {err:?}"), + })?; + + let project_name = pkg_manifest.project_name(); + + let outputs = std::iter::once(build_plan.find_member_index(project_name).ok_or( + AdapterError::BuildFailed { + reason: format!("find built project: {project_name}"), + }, + )?) + .collect(); + + let built_packages = forc_pkg::build( + &build_plan, + BuildTarget::default(), + &BuildProfile { + optimization_level: sway_core::OptLevel::Opt0, + include_tests: true, + ..Default::default() + }, + &outputs, + &[], + &[], + ) + .map_err(|err| AdapterError::BuildFailed { + reason: format!("build packages: {err:?}"), + })?; + + // 2. Store the source maps + let mut pkg_to_debug: Option<&BuiltPackage> = None; + for (_, built_pkg) in &built_packages { + if built_pkg.descriptor.manifest_file == pkg_manifest { + pkg_to_debug = Some(built_pkg); + } + let source_map = &built_pkg.source_map; + + let paths = &source_map.paths; + source_map.map.iter().for_each(|(instruction, sm_span)| { + if let Some(path_buf) = paths.get(sm_span.path.0) { + let LineCol { line, .. } = sm_span.range.start; + let (line, instruction) = (line as i64, *instruction as Instruction); + + self.state + .source_map + .entry(path_buf.clone()) + .and_modify(|new_map| { + new_map + .entry(line) + .and_modify(|val| { + // Store the instructions in ascending order + match val.binary_search(&instruction) { + Ok(_) => {} // Ignore duplicates + Err(pos) => val.insert(pos, instruction), + } + }) + .or_insert(vec![instruction]); + }) + .or_insert(HashMap::from([(line, vec![instruction])])); + } else { + self.error(format!( + "Path missing from source map: {:?}", + sm_span.path.0 + )); + } + }); + } + + // 3. Build the tests + let built_package = pkg_to_debug.ok_or(AdapterError::BuildFailed { + reason: format!("find package: {project_name}"), + })?; + + let built = Built::Package(Arc::from(built_package.clone())); + + let built_tests = BuiltTests::from_built(built, &build_plan).map_err(|err| { + AdapterError::BuildFailed { + reason: format!("build tests: {err:?}"), + } + })?; + + let pkg_tests = match built_tests { + BuiltTests::Package(pkg_tests) => pkg_tests, + BuiltTests::Workspace(_) => { + return Err(AdapterError::BuildFailed { + reason: "package tests: workspace tests not supported".into(), + }) + } + }; + let test_setup = pkg_tests.setup().map_err(|err| AdapterError::BuildFailed { + reason: format!("test setup: {err:?}"), + })?; + self.state.built_package = Some(built_package.clone()); + self.state.test_setup = Some(test_setup.clone()); + Ok((built_package.clone(), test_setup)) + } + /// Sends the 'exited' event to the client and kills the server process. fn exit(&mut self, exit_code: i64) { let _ = self @@ -422,3 +477,49 @@ impl DapServer { Ok(false) } } + +/// Represents the result of a DAP handler operation, combining the response/error and an optional exit code +#[derive(Debug)] +pub struct HandlerResult { + response: Result, + exit_code: Option, +} + +impl HandlerResult { + /// Creates a new successful result with no exit code + pub fn ok(response: ResponseBody) -> Self { + Self { + response: Ok(response), + exit_code: None, + } + } + + /// Creates a new successful result with an exit code + pub fn ok_with_exit(response: ResponseBody, code: ExitCode) -> Self { + Self { + response: Ok(response), + exit_code: Some(code), + } + } + + /// Creates a new error result with an exit code + pub fn err_with_exit(error: AdapterError, code: ExitCode) -> Self { + Self { + response: Err(error), + exit_code: Some(code), + } + } + + /// Creates a new error result with no exit code + pub fn err(error: AdapterError) -> Self { + Self { + response: Err(error), + exit_code: None, + } + } + + /// Deconstructs the result into its original tuple form + pub fn into_tuple(self) -> (Result, Option) { + (self.response, self.exit_code) + } +} diff --git a/forc-plugins/forc-debug/src/server/state.rs b/forc-plugins/forc-debug/src/server/state.rs index 948869ead23..a99d5898791 100644 --- a/forc-plugins/forc-debug/src/server/state.rs +++ b/forc-plugins/forc-debug/src/server/state.rs @@ -1,12 +1,10 @@ -use super::AdapterError; -use crate::types::Breakpoints; -use crate::types::Instruction; -use crate::types::SourceMap; +use crate::{ + error::AdapterError, + types::{Breakpoints, Instruction, SourceMap}, +}; use dap::types::StartDebuggingRequestKind; use forc_pkg::BuiltPackage; -use forc_test::execute::TestExecutor; -use forc_test::setup::TestSetup; -use forc_test::TestResult; +use forc_test::{execute::TestExecutor, setup::TestSetup, TestResult}; use std::path::PathBuf; #[derive(Default, Debug, Clone)] @@ -65,7 +63,7 @@ impl ServerState { self.source_map .iter() .find_map(|(source_path, source_map)| { - for (&line, instructions) in source_map.iter() { + for (&line, instructions) in source_map { // Divide by 4 to get the opcode offset rather than the program counter offset. let instruction_offset = pc / 4; if instructions @@ -75,7 +73,6 @@ impl ServerState { return Some((source_path, line)); } } - None }) .ok_or(AdapterError::MissingSourceMap { pc }) diff --git a/forc-plugins/forc-debug/src/server/util.rs b/forc-plugins/forc-debug/src/server/util.rs index ed24363c17b..513b071e192 100644 --- a/forc-plugins/forc-debug/src/server/util.rs +++ b/forc-plugins/forc-debug/src/server/util.rs @@ -27,6 +27,9 @@ impl IdGenerator { } } +/// Converts a filesystem path into a DAP Source object, which is used by the debug adapter +/// to identify source locations. Only sets the path field, leaving other Source fields at +/// their default values. pub(crate) fn path_into_source(path: &Path) -> Source { Source { path: Some(path.to_string_lossy().into_owned()), diff --git a/forc-plugins/forc-debug/src/types.rs b/forc-plugins/forc-debug/src/types.rs index a7f9828ddc5..4eb9b194eea 100644 --- a/forc-plugins/forc-debug/src/types.rs +++ b/forc-plugins/forc-debug/src/types.rs @@ -1,9 +1,8 @@ use dap::types::Breakpoint; -use std::collections::HashMap; -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; -pub type DynResult = std::result::Result>; pub type Line = i64; +pub type ExitCode = i64; pub type Instruction = u64; pub type FileSourceMap = HashMap>; pub type SourceMap = HashMap; diff --git a/forc-plugins/forc-debug/tests/server_integration.rs b/forc-plugins/forc-debug/tests/server_integration.rs index 5f33e658b3f..5bd291b63a4 100644 --- a/forc-plugins/forc-debug/tests/server_integration.rs +++ b/forc-plugins/forc-debug/tests/server_integration.rs @@ -7,8 +7,12 @@ use dap::{ use forc_debug::server::{ AdditionalData, DapServer, INSTRUCTIONS_VARIABLE_REF, REGISTERS_VARIABLE_REF, }; -use std::sync::Mutex; -use std::{env, io::Write, path::PathBuf, sync::Arc}; +use std::{ + env, + io::Write, + path::PathBuf, + sync::{Arc, Mutex}, +}; pub fn sway_workspace_dir() -> PathBuf { env::current_dir().unwrap().parent().unwrap().to_path_buf() @@ -59,12 +63,16 @@ fn test_server_attach_mode() { let mut server = DapServer::new(input, output); // Initialize request - let (result, exit_code) = server.handle_command(Command::Initialize(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Initialize(Default::default())) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Initialize(_)))); assert!(exit_code.is_none()); // Attach request - let (result, exit_code) = server.handle_command(Command::Attach(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Attach(Default::default())) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Attach))); assert_eq!(exit_code, Some(0)); assert_not_supported_event(output_capture.take_event()); @@ -81,7 +89,9 @@ fn test_server_launch_mode() { let source_str = program_path.to_string_lossy().to_string(); // Initialize request - let (result, exit_code) = server.handle_command(Command::Initialize(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Initialize(Default::default())) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Initialize(_)))); assert!(exit_code.is_none()); @@ -90,16 +100,18 @@ fn test_server_launch_mode() { program: source_str.clone(), }) .unwrap(); - let (result, exit_code) = server.handle_command(Command::Launch(LaunchRequestArguments { - additional_data: Some(additional_data), - ..Default::default() - })); + let (result, exit_code) = server + .handle_command(&Command::Launch(LaunchRequestArguments { + additional_data: Some(additional_data), + ..Default::default() + })) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::Launch))); assert!(exit_code.is_none()); // Set Breakpoints - let (result, exit_code) = - server.handle_command(Command::SetBreakpoints(SetBreakpointsArguments { + let (result, exit_code) = server + .handle_command(&Command::SetBreakpoints(SetBreakpointsArguments { source: Source { path: Some(source_str.clone()), ..Default::default() @@ -119,7 +131,8 @@ fn test_server_launch_mode() { }, ]), ..Default::default() - })); + })) + .into_tuple(); match result.expect("set breakpoints result") { ResponseBody::SetBreakpoints(res) => { assert!(res.breakpoints.len() == 3); @@ -129,17 +142,19 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Configuration Done request - let (result, exit_code) = server.handle_command(Command::ConfigurationDone); + let (result, exit_code) = server + .handle_command(&Command::ConfigurationDone) + .into_tuple(); assert!(matches!(result, Ok(ResponseBody::ConfigurationDone))); assert!(exit_code.is_none()); // Launch, should hit first breakpoint - let keep_running = server.handle_launch().expect("launched without error"); + let keep_running = server.launch().expect("launched without error"); assert!(keep_running); assert_stopped_breakpoint_event(output_capture.take_event(), 0); // Threads request - let (result, exit_code) = server.handle_command(Command::Threads); + let (result, exit_code) = server.handle_command(&Command::Threads).into_tuple(); match result.expect("threads result") { ResponseBody::Threads(res) => { assert_eq!(res.threads.len(), 1); @@ -149,7 +164,9 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Stack Trace request - let (result, exit_code) = server.handle_command(Command::StackTrace(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::StackTrace(Default::default())) + .into_tuple(); match result.expect("stack trace result") { ResponseBody::StackTrace(res) => { assert_eq!(res.stack_frames.len(), 1); @@ -159,7 +176,9 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Scopes request - let (result, exit_code) = server.handle_command(Command::Scopes(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Scopes(Default::default())) + .into_tuple(); match result.expect("scopes result") { ResponseBody::Scopes(res) => { assert_eq!(res.scopes.len(), 2); @@ -169,10 +188,12 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Variables request - registers - let (result, exit_code) = server.handle_command(Command::Variables(VariablesArguments { - variables_reference: REGISTERS_VARIABLE_REF, - ..Default::default() - })); + let (result, exit_code) = server + .handle_command(&Command::Variables(VariablesArguments { + variables_reference: REGISTERS_VARIABLE_REF, + ..Default::default() + })) + .into_tuple(); match result.expect("registers variables result") { ResponseBody::Variables(res) => { assert_eq!(res.variables.len(), 64); @@ -182,10 +203,12 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Variables request - VM instructions - let (result, exit_code) = server.handle_command(Command::Variables(VariablesArguments { - variables_reference: INSTRUCTIONS_VARIABLE_REF, - ..Default::default() - })); + let (result, exit_code) = server + .handle_command(&Command::Variables(VariablesArguments { + variables_reference: INSTRUCTIONS_VARIABLE_REF, + ..Default::default() + })) + .into_tuple(); match result.expect("instructions variables result") { ResponseBody::Variables(res) => { let expected = vec![ @@ -201,37 +224,49 @@ fn test_server_launch_mode() { assert!(exit_code.is_none()); // Next request - let (result, exit_code) = server.handle_command(Command::Next(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Next(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_stopped_next_event(output_capture.take_event()); // Step In request - let (result, exit_code) = server.handle_command(Command::StepIn(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::StepIn(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_not_supported_event(output_capture.take_event()); // Step Out request - let (result, exit_code) = server.handle_command(Command::StepOut(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::StepOut(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_not_supported_event(output_capture.take_event()); // Continue request, should hit 2nd breakpoint - let (result, exit_code) = server.handle_command(Command::Continue(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Continue(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_stopped_breakpoint_event(output_capture.take_event(), 1); // Continue request, should hit 3rd breakpoint - let (result, exit_code) = server.handle_command(Command::Continue(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Continue(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert!(exit_code.is_none()); assert_stopped_breakpoint_event(output_capture.take_event(), 2); // Continue request, should exit cleanly - let (result, exit_code) = server.handle_command(Command::Continue(Default::default())); + let (result, exit_code) = server + .handle_command(&Command::Continue(Default::default())) + .into_tuple(); assert!(result.is_ok()); assert_eq!(exit_code, Some(0)); diff --git a/forc-plugins/forc-doc/README.md b/forc-plugins/forc-doc/README.md index 90531e248cd..c82602aa225 100644 --- a/forc-plugins/forc-doc/README.md +++ b/forc-plugins/forc-doc/README.md @@ -78,7 +78,7 @@ $ cargo install --path forc-plugins/forc-doc Great! Let's check everything is working as intended. Try running `forc doc` on one of the test directories: ```sh -$ forc doc --manifest-path src/tests/data/impl_traits --open +$ forc doc --path src/tests/data/impl_traits --open ``` If it succeeded, you should be seeing the test docs in your browser. @@ -274,10 +274,10 @@ Now we can call this function anytime we need to generate a searchbar for our we Once you've made some changes, run the `forc doc` binary, passing it a path containing a `Forc.toml`: ```sh -cargo run -- --manifest-path path/to/manifest --open +cargo run -- --path path/to/manifest --open ``` -> **Tip:** VS Code user? Try the Live Server plugin to make viewing changes even easier. It will reload a webpage on updates, so you only need to rebuild the docs (`cargo run -- --manifest-path path/to/manifest`). Just right click the index file of docs produced by `forc doc` which can be found in the `out/doc` directory, and choose the option "open with Live Server". Voila! +> **Tip:** VS Code user? Try the Live Server plugin to make viewing changes even easier. It will reload a webpage on updates, so you only need to rebuild the docs (`cargo run -- --path path/to/manifest`). Just right click the index file of docs produced by `forc doc` which can be found in the `out/doc` directory, and choose the option "open with Live Server". Voila! [forc-reference]: https://fuellabs.github.io/sway/master/book/forc/index.html "forc reference" [manifest-reference]: https://fuellabs.github.io/sway/master/book/forc/manifest_reference.html "manifest reference" diff --git a/forc-plugins/forc-doc/src/cli.rs b/forc-plugins/forc-doc/src/cli.rs index 309bfb880d6..dff10298122 100644 --- a/forc-plugins/forc-doc/src/cli.rs +++ b/forc-plugins/forc-doc/src/cli.rs @@ -6,7 +6,7 @@ forc_util::cli_examples! { crate::cli::Command { [ Build the docs for a project in the current path => "forc doc"] [ Build the docs for a project in the current path and open it in the browser => "forc doc --open" ] - [ Build the docs for a project located in another path => "forc doc --manifest-path {path}" ] + [ Build the docs for a project located in another path => "forc doc --path {path}" ] [ Build the docs for the current project exporting private types => "forc doc --document-private-items" ] [ Build the docs offline without downloading any dependency from the network => "forc doc --offline" ] } @@ -20,10 +20,11 @@ forc_util::cli_examples! { version )] pub struct Command { - /// Path to the Forc.toml file. By default, forc-doc searches for the Forc.toml - /// file in the current directory or any parent directory. - #[clap(long)] - pub manifest_path: Option, + /// Path to the project. + /// + /// If not specified, current working directory will be used. + #[clap(short, long, alias = "manifest-path")] + pub path: Option, /// Include non-public items in the documentation. #[clap(long)] pub document_private_items: bool, diff --git a/forc-plugins/forc-doc/src/lib.rs b/forc-plugins/forc-doc/src/lib.rs index 4043cfde1f2..ffaf5a5dbe8 100644 --- a/forc-plugins/forc-doc/src/lib.rs +++ b/forc-plugins/forc-doc/src/lib.rs @@ -57,7 +57,7 @@ pub fn compile_html( get_doc_dir: &dyn Fn(&Command) -> String, ) -> Result<(PathBuf, Box)> { // get manifest directory - let dir = if let Some(ref path) = build_instructions.manifest_path { + let dir = if let Some(ref path) = build_instructions.path { PathBuf::from(path) } else { std::env::current_dir()? diff --git a/forc-plugins/forc-doc/src/render/search.rs b/forc-plugins/forc-doc/src/render/search.rs index 9213c17210d..584256189e6 100644 --- a/forc-plugins/forc-doc/src/render/search.rs +++ b/forc-plugins/forc-doc/src/render/search.rs @@ -47,7 +47,9 @@ pub(crate) fn generate_searchbar(module_info: &ModuleInfo) -> Box if (results.length > 0) {{ const resultList = results.map(item => {{ const formattedName = `${{item.name}}`; - const name = [...item.module_info, formattedName].join("::"); + const name = item.type_name === "module" + ? [...item.module_info.slice(0, -1), formattedName].join("::") + : [...item.module_info, formattedName].join("::"); const path = ["{}", ...item.module_info, item.html_filename].join("/"); const left = `${{name}}`; const right = `

${{item.preview}}

`; diff --git a/forc-plugins/forc-doc/src/search.rs b/forc-plugins/forc-doc/src/search.rs index 2506292a21e..2073fc750a6 100644 --- a/forc-plugins/forc-doc/src/search.rs +++ b/forc-plugins/forc-doc/src/search.rs @@ -1,13 +1,17 @@ -use crate::doc::{Document, Documentation}; +use crate::doc::{module::ModuleInfo, Document, Documentation}; use anyhow::Result; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, fs, path::Path}; +use std::{ + collections::{BTreeMap, HashMap}, + fs, + path::Path, +}; const JS_SEARCH_FILE_NAME: &str = "search.js"; /// Creates the search index javascript file for the search bar. pub fn write_search_index(doc_path: &Path, docs: &Documentation) -> Result<()> { - let json_data = docs.to_json_value()?; + let json_data = docs.to_search_index_json_value()?; let module_export = "\"object\"==typeof exports&&\"undefined\"!=typeof module&&(module.exports=SEARCH_INDEX);"; let js_data = format!("var SEARCH_INDEX={json_data};\n{module_export}"); @@ -17,14 +21,28 @@ pub fn write_search_index(doc_path: &Path, docs: &Documentation) -> Result<()> { impl Documentation { /// Generates a mapping of program name to a vector of documentable items within the program /// and returns the map as a `serde_json::Value`. - fn to_json_value(&self) -> Result { + fn to_search_index_json_value(&self) -> Result { let mut map = HashMap::with_capacity(self.len()); + let mut modules = BTreeMap::new(); for doc in self.iter() { let project_name = doc.module_info.project_name().to_string(); map.entry(project_name) .or_insert_with(Vec::new) .push(JsonSearchItem::from(doc)); + modules.insert( + doc.module_info.module_prefixes.join("::"), + doc.module_info.clone(), + ); } + + // Insert the modules themselves into the map. + for (_, module) in modules.iter() { + let project_name = module.project_name().to_string(); + map.entry(project_name) + .or_insert_with(Vec::new) + .push(JsonSearchItem::from(module)); + } + serde_json::to_value(map) } } @@ -57,3 +75,24 @@ impl<'a> From<&'a Document> for JsonSearchItem { } } } + +impl<'a> From<&'a ModuleInfo> for JsonSearchItem { + fn from(value: &'a ModuleInfo) -> Self { + Self { + name: value + .module_prefixes + .last() + .unwrap_or(&String::new()) + .to_string(), + html_filename: "index.html".into(), + module_info: value.module_prefixes.clone(), + preview: value + .preview_opt() + .unwrap_or_default() + .replace("
", "") + .replace("

", "") + .replace("

", ""), + type_name: "module".into(), + } + } +} diff --git a/forc-plugins/forc-doc/src/static.files/swaydoc.css b/forc-plugins/forc-doc/src/static.files/swaydoc.css index 9ed50926ad1..193f3e77586 100644 --- a/forc-plugins/forc-doc/src/static.files/swaydoc.css +++ b/forc-plugins/forc-doc/src/static.files/swaydoc.css @@ -952,6 +952,7 @@ table, .search-results .type.trait { color: #B78CF2; } +.search-results .type.module, .search-results .type.constant { color: #D2991D; } diff --git a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs index 9ead7b2f1dc..555954ce244 100644 --- a/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs +++ b/forc-plugins/forc-doc/src/tests/expects/impl_trait/mod.rs @@ -21,7 +21,7 @@ fn test_impl_traits_default() { let doc_dir_name: &str = "impl_traits_default"; let project_name = "impl_traits"; let command = Command { - manifest_path: Some(format!("{}/{}", DATA_DIR, project_name)), + path: Some(format!("{}/{}", DATA_DIR, project_name)), doc_path: Some(doc_dir_name.into()), ..Default::default() }; @@ -30,137 +30,138 @@ fn test_impl_traits_default() { &doc_path, project_name, &expect![[r##" - Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

+ Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

fn add(self, other: Self) -> Self

fn subtract(self, other: Self) -> Self

"##]], ); assert_search_js( &doc_path, &expect![[r#" - var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"trait.TotalOrd.html","module_info":["core","ops"],"name":"TotalOrd","preview":"Trait to compare values of the same type.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode_in_place.html","module_info":["core","codec"],"name":"abi_decode_in_place","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data.html","module_info":["core","codec"],"name":"decode_predicate_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data_by_index.html","module_info":["core","codec"],"name":"decode_predicate_data_by_index","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"},{"html_filename":"primitive.u256.html","module_info":["core"],"name":"u256","preview":"256-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u64.html","module_info":["core"],"name":"u64","preview":"64-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u32.html","module_info":["core"],"name":"u32","preview":"32-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u16.html","module_info":["core"],"name":"u16","preview":"16-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u8.html","module_info":["core"],"name":"u8","preview":"8-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.b256.html","module_info":["core"],"name":"b256","preview":"256 bits (32 bytes), i.e. a hash","type_name":"primitive"},{"html_filename":"primitive.str.html","module_info":["core"],"name":"str","preview":"string slice","type_name":"primitive"},{"html_filename":"primitive.bool.html","module_info":["core"],"name":"bool","preview":"Boolean true or false","type_name":"primitive"},{"html_filename":"primitive.str[0].html","module_info":["core"],"name":"str[0]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[1].html","module_info":["core"],"name":"str[1]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[2].html","module_info":["core"],"name":"str[2]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[3].html","module_info":["core"],"name":"str[3]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[4].html","module_info":["core"],"name":"str[4]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[5].html","module_info":["core"],"name":"str[5]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[6].html","module_info":["core"],"name":"str[6]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[7].html","module_info":["core"],"name":"str[7]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[8].html","module_info":["core"],"name":"str[8]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[9].html","module_info":["core"],"name":"str[9]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[10].html","module_info":["core"],"name":"str[10]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[11].html","module_info":["core"],"name":"str[11]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[12].html","module_info":["core"],"name":"str[12]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[13].html","module_info":["core"],"name":"str[13]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[14].html","module_info":["core"],"name":"str[14]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[15].html","module_info":["core"],"name":"str[15]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[16].html","module_info":["core"],"name":"str[16]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[17].html","module_info":["core"],"name":"str[17]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[18].html","module_info":["core"],"name":"str[18]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[19].html","module_info":["core"],"name":"str[19]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[20].html","module_info":["core"],"name":"str[20]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[21].html","module_info":["core"],"name":"str[21]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[22].html","module_info":["core"],"name":"str[22]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[23].html","module_info":["core"],"name":"str[23]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[24].html","module_info":["core"],"name":"str[24]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[25].html","module_info":["core"],"name":"str[25]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[26].html","module_info":["core"],"name":"str[26]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[27].html","module_info":["core"],"name":"str[27]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[28].html","module_info":["core"],"name":"str[28]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[29].html","module_info":["core"],"name":"str[29]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[30].html","module_info":["core"],"name":"str[30]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[31].html","module_info":["core"],"name":"str[31]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[32].html","module_info":["core"],"name":"str[32]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[33].html","module_info":["core"],"name":"str[33]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[34].html","module_info":["core"],"name":"str[34]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[35].html","module_info":["core"],"name":"str[35]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[36].html","module_info":["core"],"name":"str[36]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[37].html","module_info":["core"],"name":"str[37]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[38].html","module_info":["core"],"name":"str[38]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[39].html","module_info":["core"],"name":"str[39]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[40].html","module_info":["core"],"name":"str[40]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[41].html","module_info":["core"],"name":"str[41]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[42].html","module_info":["core"],"name":"str[42]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[43].html","module_info":["core"],"name":"str[43]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[44].html","module_info":["core"],"name":"str[44]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[45].html","module_info":["core"],"name":"str[45]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[46].html","module_info":["core"],"name":"str[46]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[47].html","module_info":["core"],"name":"str[47]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[48].html","module_info":["core"],"name":"str[48]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[49].html","module_info":["core"],"name":"str[49]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[50].html","module_info":["core"],"name":"str[50]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[51].html","module_info":["core"],"name":"str[51]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[52].html","module_info":["core"],"name":"str[52]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[53].html","module_info":["core"],"name":"str[53]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[54].html","module_info":["core"],"name":"str[54]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[55].html","module_info":["core"],"name":"str[55]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[56].html","module_info":["core"],"name":"str[56]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[57].html","module_info":["core"],"name":"str[57]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[58].html","module_info":["core"],"name":"str[58]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[59].html","module_info":["core"],"name":"str[59]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[60].html","module_info":["core"],"name":"str[60]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[61].html","module_info":["core"],"name":"str[61]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[62].html","module_info":["core"],"name":"str[62]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[63].html","module_info":["core"],"name":"str[63]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[64].html","module_info":["core"],"name":"str[64]","preview":"fixed-length string","type_name":"primitive"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"}]}; + var SEARCH_INDEX={"core":[{"html_filename":"trait.AsRawSlice.html","module_info":["core","raw_slice"],"name":"AsRawSlice","preview":"Trait to return a type as a raw_slice.\n","type_name":"trait"},{"html_filename":"fn.from_str_array.html","module_info":["core","str"],"name":"from_str_array","preview":"","type_name":"function"},{"html_filename":"trait.Add.html","module_info":["core","ops"],"name":"Add","preview":"Trait for the addition of two values.\n","type_name":"trait"},{"html_filename":"trait.Subtract.html","module_info":["core","ops"],"name":"Subtract","preview":"Trait for the subtraction of two values.\n","type_name":"trait"},{"html_filename":"trait.Multiply.html","module_info":["core","ops"],"name":"Multiply","preview":"Trait for the multiplication of two values.\n","type_name":"trait"},{"html_filename":"trait.Divide.html","module_info":["core","ops"],"name":"Divide","preview":"Trait for the division of two values.\n","type_name":"trait"},{"html_filename":"trait.Mod.html","module_info":["core","ops"],"name":"Mod","preview":"Trait for the modulo of two values.\n","type_name":"trait"},{"html_filename":"trait.Not.html","module_info":["core","ops"],"name":"Not","preview":"Trait to invert a type.\n","type_name":"trait"},{"html_filename":"trait.Eq.html","module_info":["core","ops"],"name":"Eq","preview":"Trait to evaluate if two types are equal.\n","type_name":"trait"},{"html_filename":"trait.Ord.html","module_info":["core","ops"],"name":"Ord","preview":"Trait to evaluate if one value is greater or less than another of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseAnd.html","module_info":["core","ops"],"name":"BitwiseAnd","preview":"Trait to bitwise AND two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseOr.html","module_info":["core","ops"],"name":"BitwiseOr","preview":"Trait to bitwise OR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.BitwiseXor.html","module_info":["core","ops"],"name":"BitwiseXor","preview":"Trait to bitwise XOR two values of the same type.\n","type_name":"trait"},{"html_filename":"trait.OrdEq.html","module_info":["core","ops"],"name":"OrdEq","preview":"Trait to evaluate if one value is greater than or equal, or less than or equal to another of the same type.","type_name":"trait"},{"html_filename":"trait.Shift.html","module_info":["core","ops"],"name":"Shift","preview":"Trait to bit shift a value.\n","type_name":"trait"},{"html_filename":"trait.TotalOrd.html","module_info":["core","ops"],"name":"TotalOrd","preview":"Trait to compare values of the same type.\n","type_name":"trait"},{"html_filename":"fn.ok_str_eq.html","module_info":["core","ops"],"name":"ok_str_eq","preview":"","type_name":"function"},{"html_filename":"struct.StorageKey.html","module_info":["core","storage"],"name":"StorageKey","preview":"Describes a location in storage.\n","type_name":"struct"},{"html_filename":"struct.Buffer.html","module_info":["core","codec"],"name":"Buffer","preview":"","type_name":"struct"},{"html_filename":"struct.BufferReader.html","module_info":["core","codec"],"name":"BufferReader","preview":"","type_name":"struct"},{"html_filename":"trait.AbiDecode.html","module_info":["core","codec"],"name":"AbiDecode","preview":"","type_name":"trait"},{"html_filename":"trait.AbiEncode.html","module_info":["core","codec"],"name":"AbiEncode","preview":"","type_name":"trait"},{"html_filename":"fn.encode.html","module_info":["core","codec"],"name":"encode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode.html","module_info":["core","codec"],"name":"abi_decode","preview":"","type_name":"function"},{"html_filename":"fn.abi_decode_in_place.html","module_info":["core","codec"],"name":"abi_decode_in_place","preview":"","type_name":"function"},{"html_filename":"fn.contract_call.html","module_info":["core","codec"],"name":"contract_call","preview":"","type_name":"function"},{"html_filename":"fn.decode_script_data.html","module_info":["core","codec"],"name":"decode_script_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data.html","module_info":["core","codec"],"name":"decode_predicate_data","preview":"","type_name":"function"},{"html_filename":"fn.decode_predicate_data_by_index.html","module_info":["core","codec"],"name":"decode_predicate_data_by_index","preview":"","type_name":"function"},{"html_filename":"fn.decode_first_param.html","module_info":["core","codec"],"name":"decode_first_param","preview":"","type_name":"function"},{"html_filename":"fn.decode_second_param.html","module_info":["core","codec"],"name":"decode_second_param","preview":"","type_name":"function"},{"html_filename":"primitive.u256.html","module_info":["core"],"name":"u256","preview":"256-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u64.html","module_info":["core"],"name":"u64","preview":"64-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u32.html","module_info":["core"],"name":"u32","preview":"32-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u16.html","module_info":["core"],"name":"u16","preview":"16-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.u8.html","module_info":["core"],"name":"u8","preview":"8-bit unsigned integer","type_name":"primitive"},{"html_filename":"primitive.b256.html","module_info":["core"],"name":"b256","preview":"256 bits (32 bytes), i.e. a hash","type_name":"primitive"},{"html_filename":"primitive.str.html","module_info":["core"],"name":"str","preview":"string slice","type_name":"primitive"},{"html_filename":"primitive.bool.html","module_info":["core"],"name":"bool","preview":"Boolean true or false","type_name":"primitive"},{"html_filename":"primitive.str[0].html","module_info":["core"],"name":"str[0]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[1].html","module_info":["core"],"name":"str[1]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[2].html","module_info":["core"],"name":"str[2]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[3].html","module_info":["core"],"name":"str[3]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[4].html","module_info":["core"],"name":"str[4]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[5].html","module_info":["core"],"name":"str[5]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[6].html","module_info":["core"],"name":"str[6]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[7].html","module_info":["core"],"name":"str[7]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[8].html","module_info":["core"],"name":"str[8]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[9].html","module_info":["core"],"name":"str[9]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[10].html","module_info":["core"],"name":"str[10]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[11].html","module_info":["core"],"name":"str[11]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[12].html","module_info":["core"],"name":"str[12]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[13].html","module_info":["core"],"name":"str[13]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[14].html","module_info":["core"],"name":"str[14]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[15].html","module_info":["core"],"name":"str[15]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[16].html","module_info":["core"],"name":"str[16]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[17].html","module_info":["core"],"name":"str[17]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[18].html","module_info":["core"],"name":"str[18]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[19].html","module_info":["core"],"name":"str[19]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[20].html","module_info":["core"],"name":"str[20]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[21].html","module_info":["core"],"name":"str[21]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[22].html","module_info":["core"],"name":"str[22]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[23].html","module_info":["core"],"name":"str[23]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[24].html","module_info":["core"],"name":"str[24]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[25].html","module_info":["core"],"name":"str[25]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[26].html","module_info":["core"],"name":"str[26]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[27].html","module_info":["core"],"name":"str[27]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[28].html","module_info":["core"],"name":"str[28]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[29].html","module_info":["core"],"name":"str[29]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[30].html","module_info":["core"],"name":"str[30]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[31].html","module_info":["core"],"name":"str[31]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[32].html","module_info":["core"],"name":"str[32]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[33].html","module_info":["core"],"name":"str[33]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[34].html","module_info":["core"],"name":"str[34]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[35].html","module_info":["core"],"name":"str[35]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[36].html","module_info":["core"],"name":"str[36]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[37].html","module_info":["core"],"name":"str[37]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[38].html","module_info":["core"],"name":"str[38]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[39].html","module_info":["core"],"name":"str[39]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[40].html","module_info":["core"],"name":"str[40]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[41].html","module_info":["core"],"name":"str[41]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[42].html","module_info":["core"],"name":"str[42]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[43].html","module_info":["core"],"name":"str[43]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[44].html","module_info":["core"],"name":"str[44]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[45].html","module_info":["core"],"name":"str[45]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[46].html","module_info":["core"],"name":"str[46]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[47].html","module_info":["core"],"name":"str[47]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[48].html","module_info":["core"],"name":"str[48]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[49].html","module_info":["core"],"name":"str[49]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[50].html","module_info":["core"],"name":"str[50]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[51].html","module_info":["core"],"name":"str[51]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[52].html","module_info":["core"],"name":"str[52]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[53].html","module_info":["core"],"name":"str[53]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[54].html","module_info":["core"],"name":"str[54]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[55].html","module_info":["core"],"name":"str[55]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[56].html","module_info":["core"],"name":"str[56]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[57].html","module_info":["core"],"name":"str[57]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[58].html","module_info":["core"],"name":"str[58]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[59].html","module_info":["core"],"name":"str[59]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[60].html","module_info":["core"],"name":"str[60]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[61].html","module_info":["core"],"name":"str[61]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[62].html","module_info":["core"],"name":"str[62]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[63].html","module_info":["core"],"name":"str[63]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"primitive.str[64].html","module_info":["core"],"name":"str[64]","preview":"fixed-length string","type_name":"primitive"},{"html_filename":"index.html","module_info":["core"],"name":"core","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","codec"],"name":"codec","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","ops"],"name":"ops","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","raw_slice"],"name":"raw_slice","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","storage"],"name":"storage","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["core","str"],"name":"str","preview":"","type_name":"module"}],"impl_traits":[{"html_filename":"trait.Foo.html","module_info":["impl_traits","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits","foo"],"name":"foo","preview":"","type_name":"module"}]}; "object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"#]], ); assert_file_tree( doc_dir_name, project_name, vec![ - "core/primitive.str[26].html", - "core/primitive.str[54].html", - "core/primitive.u256.html", - "core/primitive.str[2].html", - "core/primitive.u8.html", + "core/ops/trait.TotalOrd.html", + "core/ops/trait.Mod.html", + "impl_traits/bar/index.html", + "impl_traits/all.html", "core/primitive.str[17].html", - "core/primitive.str[49].html", + "core/primitive.str[51].html", + "core/codec/fn.abi_decode.html", + "core/codec/struct.Buffer.html", + "core/codec/trait.AbiDecode.html", + "core/ops/trait.Divide.html", + "core/codec/fn.abi_decode_in_place.html", "core/primitive.str[34].html", - "core/primitive.str[46].html", - "core/primitive.str[15].html", - "core/primitive.str[21].html", - "core/primitive.str.html", - "core/primitive.str[24].html", - "core/primitive.str[38].html", - "core/primitive.str[47].html", - "core/primitive.str[31].html", - "core/primitive.bool.html", - "core/primitive.str[14].html", - "core/primitive.str[48].html", - "core/primitive.str[1].html", - "core/primitive.str[42].html", - "core/primitive.str[6].html", - "core/primitive.b256.html", - "core/primitive.str[5].html", - "core/primitive.str[43].html", + "core/codec/fn.decode_first_param.html", + "core/primitive.str[20].html", "core/primitive.str[4].html", - "core/primitive.str[19].html", - "core/primitive.str[25].html", - "core/primitive.str[57].html", - "core/primitive.str[56].html", + "core/primitive.str[42].html", "core/primitive.str[10].html", - "core/primitive.str[44].html", + "core/ops/trait.Subtract.html", + "core/primitive.str[28].html", + "core/primitive.u8.html", + "core/primitive.u256.html", + "core/str/fn.from_str_array.html", + "core/primitive.str[62].html", + "core/primitive.str[64].html", + "core/codec/trait.AbiEncode.html", + "core/primitive.str[8].html", + "core/primitive.str[43].html", + "core/codec/fn.decode_predicate_data_by_index.html", "core/primitive.str[37].html", - "core/primitive.str[0].html", - "core/primitive.str[53].html", - "core/primitive.str[59].html", - "core/primitive.str[22].html", - "core/primitive.str[33].html", - "core/primitive.str[27].html", - "core/primitive.str[13].html", + "core/primitive.b256.html", + "core/ops/trait.Eq.html", + "core/storage/index.html", + "core/primitive.str[58].html", + "core/primitive.str[44].html", + "core/raw_slice/index.html", "core/primitive.u16.html", - "core/primitive.str[3].html", "core/primitive.str[35].html", - "core/primitive.str[7].html", - "core/primitive.str[51].html", - "core/primitive.str[40].html", - "core/primitive.str[28].html", - "core/primitive.str[41].html", - "core/primitive.str[58].html", - "core/primitive.str[45].html", - "core/primitive.str[62].html", - "core/primitive.str[63].html", "core/primitive.str[60].html", - "core/primitive.str[50].html", - "core/primitive.str[55].html", - "core/primitive.str[8].html", - "core/primitive.str[32].html", - "core/primitive.str[23].html", - "core/primitive.str[30].html", - "core/primitive.str[61].html", - "core/primitive.str[18].html", - "core/primitive.u32.html", - "core/primitive.str[64].html", + "core/primitive.str[59].html", "core/primitive.str[39].html", - "core/primitive.str[29].html", - "core/primitive.str[11].html", - "core/primitive.str[20].html", - "core/primitive.str[9].html", - "core/primitive.str[12].html", + "core/primitive.str[49].html", + "core/primitive.str[40].html", + "core/index.html", + "search.js", + "core/ops/trait.OrdEq.html", + "core/primitive.bool.html", + "impl_traits/foo/trait.Baz.html", + "core/primitive.str.html", + "core/primitive.str[13].html", "core/primitive.u64.html", "core/primitive.str[16].html", - "core/primitive.str[36].html", - "core/primitive.str[52].html", - "core/all.html", - "core/codec/fn.abi_decode.html", - "core/codec/fn.abi_decode_in_place.html", - "core/codec/fn.contract_call.html", - "core/codec/fn.decode_predicate_data.html", - "core/codec/fn.decode_predicate_data_by_index.html", - "core/codec/fn.decode_first_param.html", - "core/codec/fn.decode_script_data.html", - "core/codec/fn.decode_second_param.html", - "core/codec/fn.encode.html", "core/codec/index.html", - "core/codec/struct.Buffer.html", - "core/codec/struct.BufferReader.html", - "core/codec/trait.AbiDecode.html", - "core/codec/trait.AbiEncode.html", - "core/index.html", - "core/ops/fn.ok_str_eq.html", + "core/primitive.str[47].html", + "core/primitive.str[57].html", + "core/ops/trait.Not.html", + "core/primitive.str[50].html", + "core/raw_slice/trait.AsRawSlice.html", + "core/primitive.str[24].html", + "core/primitive.str[56].html", "core/ops/index.html", - "core/ops/trait.Add.html", + "core/primitive.str[3].html", + "core/primitive.str[36].html", + "core/primitive.str[27].html", + "core/codec/fn.decode_script_data.html", + "impl_traits/index.html", + "core/primitive.str[12].html", + "impl_traits/foo/trait.Foo.html", + "core/primitive.str[15].html", + "core/primitive.str[29].html", + "core/primitive.str[22].html", "core/ops/trait.BitwiseAnd.html", - "core/ops/trait.BitwiseOr.html", - "core/ops/trait.BitwiseXor.html", - "core/ops/trait.Divide.html", - "core/ops/trait.Eq.html", - "core/ops/trait.Mod.html", - "core/ops/trait.Multiply.html", - "core/ops/trait.Not.html", + "core/all.html", + "core/primitive.str[11].html", "core/ops/trait.Ord.html", - "core/ops/trait.Shift.html", - "core/ops/trait.Subtract.html", - "core/ops/trait.TotalOrd.html", - "core/raw_slice/index.html", - "core/raw_slice/trait.AsRawSlice.html", - "core/storage/index.html", - "core/storage/struct.StorageKey.html", - "core/str/fn.from_str_array.html", "core/str/index.html", - "impl_traits/all.html", - "impl_traits/bar/index.html", - "impl_traits/bar/struct.Bar.html", + "core/primitive.str[31].html", "impl_traits/foo/index.html", - "impl_traits/foo/trait.Baz.html", - "impl_traits/foo/trait.Foo.html", - "impl_traits/index.html", - "search.js", + "core/primitive.str[55].html", + "core/primitive.str[38].html", + "core/codec/struct.BufferReader.html", + "core/primitive.str[54].html", + "core/primitive.str[53].html", + "core/primitive.str[19].html", + "core/storage/struct.StorageKey.html", + "core/primitive.str[25].html", + "core/primitive.str[30].html", + "core/codec/fn.encode.html", + "core/primitive.str[26].html", + "core/primitive.str[41].html", + "core/codec/fn.decode_second_param.html", + "core/primitive.u32.html", + "core/ops/fn.ok_str_eq.html", + "core/primitive.str[1].html", + "core/primitive.str[18].html", + "core/primitive.str[33].html", + "core/primitive.str[0].html", + "core/codec/fn.decode_predicate_data.html", + "core/primitive.str[9].html", + "core/ops/trait.Shift.html", + "core/ops/trait.Multiply.html", + "core/primitive.str[32].html", + "core/primitive.str[46].html", + "core/primitive.str[7].html", + "core/primitive.str[14].html", + "core/ops/trait.Add.html", + "core/primitive.str[23].html", + "core/primitive.str[52].html", + "core/primitive.str[48].html", + "core/primitive.str[2].html", + "core/primitive.str[5].html", + "impl_traits/bar/struct.Bar.html", + "core/primitive.str[63].html", + "core/primitive.str[21].html", + "core/codec/fn.contract_call.html", + "core/ops/trait.BitwiseXor.html", + "core/primitive.str[61].html", + "core/primitive.str[45].html", + "core/ops/trait.BitwiseOr.html", + "core/primitive.str[6].html", ], ); } @@ -170,7 +171,7 @@ fn test_impl_traits_no_deps() { let doc_dir_name: &str = "impl_traits_no_deps"; let project_name: &str = "impl_traits_clone"; let command = Command { - manifest_path: Some(format!("{}/{}", DATA_DIR, project_name)), + path: Some(format!("{}/{}", DATA_DIR, project_name)), doc_path: Some(doc_dir_name.into()), no_deps: true, ..Default::default() @@ -180,13 +181,13 @@ fn test_impl_traits_no_deps() { &doc_path, project_name, &expect![[r##" - Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

+ Bar in bar - Sway
pub struct Bar {}

Implementations

fn foo_bar()

Trait Implementations

fn abi_encode(self, buffer: Buffer) -> Buffer

fn abi_decode(refmut _buffer: BufferReader) -> Self

fn foo()

something more about foo();

fn add(self, other: Self) -> Self

fn subtract(self, other: Self) -> Self

"##]], ); assert_search_js( &doc_path, &expect![[ - r#"var SEARCH_INDEX={"impl_traits_clone":[{"html_filename":"trait.Foo.html","module_info":["impl_traits_clone","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits_clone","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits_clone","bar"],"name":"Bar","preview":"","type_name":"struct"}]}; + r#"var SEARCH_INDEX={"impl_traits_clone":[{"html_filename":"trait.Foo.html","module_info":["impl_traits_clone","foo"],"name":"Foo","preview":"","type_name":"trait"},{"html_filename":"trait.Baz.html","module_info":["impl_traits_clone","foo"],"name":"Baz","preview":"","type_name":"trait"},{"html_filename":"struct.Bar.html","module_info":["impl_traits_clone","bar"],"name":"Bar","preview":"","type_name":"struct"},{"html_filename":"index.html","module_info":["impl_traits_clone","bar"],"name":"bar","preview":"","type_name":"module"},{"html_filename":"index.html","module_info":["impl_traits_clone","foo"],"name":"foo","preview":"","type_name":"module"}]}; "object"==typeof exports&&"undefined"!=typeof module&&(module.exports=SEARCH_INDEX);"# ]], ); diff --git a/forc-plugins/forc-doc/tests/lib.rs b/forc-plugins/forc-doc/tests/lib.rs index 9624b656a4f..996e095645b 100644 --- a/forc-plugins/forc-doc/tests/lib.rs +++ b/forc-plugins/forc-doc/tests/lib.rs @@ -5,10 +5,10 @@ use std::path::Path; fn builds_lib_std_docs() { let path = Path::new("./../../sway-lib-std"); let build_instructions = Command { - manifest_path: Some(path.to_str().unwrap().to_string()), + path: Some(path.to_str().unwrap().to_string()), ..Default::default() }; - println!("Building docs for {:?}", build_instructions.manifest_path); + println!("Building docs for {:?}", build_instructions.path); let res = compile_html(&build_instructions, &get_doc_dir); assert!(res.is_ok()); } diff --git a/forc-plugins/forc-fmt/src/main.rs b/forc-plugins/forc-fmt/src/main.rs index 6a818ff245a..331c3e51373 100644 --- a/forc-plugins/forc-fmt/src/main.rs +++ b/forc-plugins/forc-fmt/src/main.rs @@ -15,7 +15,6 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use sway_core::{BuildConfig, BuildTarget}; use sway_utils::{constants, find_parent_manifest_dir, get_sway_files, is_sway_file}; use swayfmt::Formatter; use taplo::formatter as taplo_fmt; @@ -46,7 +45,9 @@ pub struct App { /// - Exits with `1` and prints a diff if formatting is required. #[clap(short, long)] pub check: bool, - /// Path to the project, if not specified, current working directory will be used. + /// Path to the project. + /// + /// If not specified, current working directory will be used. #[clap(short, long)] pub path: Option, #[clap(short, long)] @@ -77,13 +78,8 @@ fn run() -> Result<()> { if let Some(f) = app.file.as_ref() { let file_path = &PathBuf::from(f); - // If we're formatting a single file, find the nearest manifest if within a project. - // Otherwise, we simply provide 'None' to format_file(). - let manifest_file = find_parent_manifest_dir(file_path) - .map(|path| path.join(constants::MANIFEST_FILE_NAME)); - if is_sway_file(file_path) { - format_file(&app, file_path.to_path_buf(), manifest_file, &mut formatter)?; + format_file(&app, file_path.to_path_buf(), &mut formatter)?; return Ok(()); } @@ -142,12 +138,7 @@ fn get_sway_dirs(workspace_dir: PathBuf) -> Vec { /// - Ok(true) if executed successfully and formatted, /// - Ok(false) if executed successfully and not formatted, /// - Err if it fails to execute at all. -fn format_file( - app: &App, - file: PathBuf, - manifest_file: Option, - formatter: &mut Formatter, -) -> Result { +fn format_file(app: &App, file: PathBuf, formatter: &mut Formatter) -> Result { let file = file.canonicalize()?; if is_file_dirty(&file) { bail!( @@ -160,14 +151,7 @@ fn format_file( if let Ok(file_content) = fs::read_to_string(&file) { let mut edited = false; let file_content: Arc = Arc::from(file_content); - let build_config = manifest_file.map(|f| { - BuildConfig::root_from_file_name_and_manifest_path( - file.clone(), - f, - BuildTarget::default(), - ) - }); - match Formatter::format(formatter, file_content.clone(), build_config.as_ref()) { + match Formatter::format(formatter, file_content.clone()) { Ok(formatted_content) => { if app.check { if *file_content != formatted_content { @@ -213,12 +197,7 @@ fn format_workspace_at_dir(app: &App, workspace: &WorkspaceManifestFile, dir: &P for entry in read_dir.filter_map(|res| res.ok()) { let path = entry.path(); if is_sway_file(&path) { - format_file( - app, - path, - Some(workspace.dir().to_path_buf()), - &mut formatter, - )?; + format_file(app, path, &mut formatter)?; } } } @@ -295,7 +274,7 @@ fn format_pkg_at_dir(app: &App, dir: &Path, formatter: &mut Formatter) -> Result let mut contains_edits = false; for file in files { - contains_edits |= format_file(app, file, Some(manifest_file.clone()), formatter)?; + contains_edits |= format_file(app, file, formatter)?; } // format manifest using taplo formatter contains_edits |= format_manifest(app, manifest_file)?; diff --git a/forc-test/src/execute.rs b/forc-test/src/execute.rs index 3436261af94..a0423caba12 100644 --- a/forc-test/src/execute.rs +++ b/forc-test/src/execute.rs @@ -5,11 +5,14 @@ use crate::TEST_METADATA_SEED; use forc_pkg::PkgTestEntry; use fuel_tx::{self as tx, output::contract::Contract, Chargeable, Finalizable}; use fuel_vm::error::InterpreterError; +use fuel_vm::fuel_asm; +use fuel_vm::prelude::Instruction; +use fuel_vm::prelude::RegId; use fuel_vm::{ self as vm, checked_transaction::builder::TransactionBuilderExt, interpreter::{Interpreter, NotSupportedEcal}, - prelude::{Instruction, SecretKey}, + prelude::SecretKey, storage::MemoryStorage, }; use rand::{Rng, SeedableRng}; @@ -27,6 +30,8 @@ pub struct TestExecutor { pub tx: vm::checked_transaction::Ready, pub test_entry: PkgTestEntry, pub name: String, + pub jump_instruction_index: usize, + pub relative_jump_in_bytes: u32, } /// The result of executing a test with breakpoints enabled. @@ -41,15 +46,16 @@ pub enum DebugResult { impl TestExecutor { pub fn build( bytecode: &[u8], - test_offset: u32, + test_instruction_index: u32, test_setup: TestSetup, test_entry: &PkgTestEntry, name: String, ) -> anyhow::Result { let storage = test_setup.storage().clone(); - // Patch the bytecode to jump to the relevant test. - let bytecode = patch_test_bytecode(bytecode, test_offset).into_owned(); + // Find the instruction which we will jump into the + // specified test + let jump_instruction_index = find_jump_instruction_index(bytecode); // Create a transaction to execute the test function. let script_input_data = vec![]; @@ -68,7 +74,7 @@ impl TestExecutor { let block_height = (u32::MAX >> 1).into(); let gas_price = 0; - let mut tx_builder = tx::TransactionBuilder::script(bytecode, script_input_data); + let mut tx_builder = tx::TransactionBuilder::script(bytecode.to_vec(), script_input_data); let params = maxed_consensus_params(); @@ -126,23 +132,72 @@ impl TestExecutor { tx, test_entry: test_entry.clone(), name, + jump_instruction_index, + relative_jump_in_bytes: (test_instruction_index - jump_instruction_index as u32) + * Instruction::SIZE as u32, }) } + // single-step until the jump-to-test instruction, then + // jump into the first instruction of the test + fn single_step_until_test(&mut self) -> ProgramState { + let jump_pc = (self.jump_instruction_index * Instruction::SIZE) as u64; + + let old_single_stepping = self.interpreter.single_stepping(); + self.interpreter.set_single_stepping(true); + let mut state = { + let transition = self.interpreter.transact(self.tx.clone()); + Ok(*transition.unwrap().state()) + }; + + loop { + match state { + // if the VM fails, we interpret as a revert + Err(_) => { + break ProgramState::Revert(0); + } + Ok( + state @ ProgramState::Return(_) + | state @ ProgramState::ReturnData(_) + | state @ ProgramState::Revert(_), + ) => break state, + Ok( + s @ ProgramState::RunProgram(eval) | s @ ProgramState::VerifyPredicate(eval), + ) => { + // time to jump into the specified test + if let Some(b) = eval.breakpoint() { + if b.pc() == jump_pc { + self.interpreter.registers_mut()[RegId::PC] += + self.relative_jump_in_bytes as u64; + self.interpreter.set_single_stepping(old_single_stepping); + break s; + } + } + + state = self.interpreter.resume(); + } + } + } + } + /// Execute the test with breakpoints enabled. pub fn start_debugging(&mut self) -> anyhow::Result { let start = std::time::Instant::now(); - let transition = self + + let _ = self.single_step_until_test(); + let state = self .interpreter - .transact(self.tx.clone()) - .map_err(|err: InterpreterError<_>| anyhow::anyhow!(err))?; - let state = *transition.state(); + .resume() + .map_err(|err: InterpreterError<_>| { + anyhow::anyhow!("VM failed to resume. {:?}", err) + })?; if let ProgramState::RunProgram(DebugEval::Breakpoint(breakpoint)) = state { // A breakpoint was hit, so we tell the client to stop. return Ok(DebugResult::Breakpoint(breakpoint.pc())); } + let duration = start.elapsed(); - let (gas_used, logs) = Self::get_gas_and_receipts(transition.receipts().to_vec())?; + let (gas_used, logs) = Self::get_gas_and_receipts(self.interpreter.receipts().to_vec())?; let span = self.test_entry.span.clone(); let file_path = self.test_entry.file_path.clone(); let condition = self.test_entry.pass_condition.clone(); @@ -192,14 +247,27 @@ impl TestExecutor { pub fn execute(&mut self) -> anyhow::Result { let start = std::time::Instant::now(); - let transition = self - .interpreter - .transact(self.tx.clone()) - .map_err(|err: InterpreterError<_>| anyhow::anyhow!(err))?; - let state = *transition.state(); + + let mut state = Ok(self.single_step_until_test()); + + // Run test until its end + loop { + match state { + Err(_) => { + state = Ok(ProgramState::Revert(0)); + break; + } + Ok( + ProgramState::Return(_) | ProgramState::ReturnData(_) | ProgramState::Revert(_), + ) => break, + Ok(ProgramState::RunProgram(_) | ProgramState::VerifyPredicate(_)) => { + state = self.interpreter.resume(); + } + } + } let duration = start.elapsed(); - let (gas_used, logs) = Self::get_gas_and_receipts(transition.receipts().to_vec())?; + let (gas_used, logs) = Self::get_gas_and_receipts(self.interpreter.receipts().to_vec())?; let span = self.test_entry.span.clone(); let file_path = self.test_entry.file_path.clone(); let condition = self.test_entry.pass_condition.clone(); @@ -209,7 +277,7 @@ impl TestExecutor { file_path, duration, span, - state, + state: state.unwrap(), condition, logs, gas_used, @@ -237,39 +305,25 @@ impl TestExecutor { } } -/// Given some bytecode and an instruction offset for some test's desired entry point, patch the -/// bytecode with a `JI` (jump) instruction to jump to the desired test. -/// -/// We want to splice in the `JI` only after the initial data section setup is complete, and only -/// if the entry point doesn't begin exactly after the data section setup. -/// -/// The following is how the beginning of the bytecode is laid out: -/// -/// ```ignore -/// [0] ji i4 ; Jumps to the data section setup. -/// [1] noop -/// [2] DATA_SECTION_OFFSET[0..32] -/// [3] DATA_SECTION_OFFSET[32..64] -/// [4] lw $ds $is 1 ; The data section setup, i.e. where the first ji lands. -/// [5] add $$ds $$ds $is -/// [6] ; This is where we want to jump from to our test code! -/// ``` -fn patch_test_bytecode(bytecode: &[u8], test_offset: u32) -> std::borrow::Cow<[u8]> { - // TODO: Standardize this or add metadata to bytecode. - const PROGRAM_START_INST_OFFSET: u32 = 6; - const PROGRAM_START_BYTE_OFFSET: usize = PROGRAM_START_INST_OFFSET as usize * Instruction::SIZE; - - // If our desired entry point is the program start, no need to jump. - if test_offset == PROGRAM_START_INST_OFFSET { - return std::borrow::Cow::Borrowed(bytecode); - } +fn find_jump_instruction_index(bytecode: &[u8]) -> usize { + // Search first `move $$locbase $sp` + // This will be `__entry` for script/predicate/contract using encoding v1; + // `main` for script/predicate using encoding v0; + // or the first function for libraries + // MOVE R59 $sp ;; [26, 236, 80, 0] + let a = vm::fuel_asm::op::move_(59, fuel_asm::RegId::SP).to_bytes(); - // Create the jump instruction and splice it into the bytecode. - let ji = vm::fuel_asm::op::ji(test_offset); - let ji_bytes = ji.to_bytes(); - let start = PROGRAM_START_BYTE_OFFSET; - let end = start + ji_bytes.len(); - let mut patched = bytecode.to_vec(); - patched.splice(start..end, ji_bytes); - std::borrow::Cow::Owned(patched) + // for contracts using encoding v0 + // search the first `lw $r0 $fp i73` + // which is the start of the fn selector + // LW $writable $fp 0x49 ;; [93, 64, 96, 73] + let b = vm::fuel_asm::op::lw(fuel_asm::RegId::WRITABLE, fuel_asm::RegId::FP, 73).to_bytes(); + + bytecode + .chunks(Instruction::SIZE) + .position(|instruction| { + let instruction: [u8; 4] = instruction.try_into().unwrap(); + instruction == a || instruction == b + }) + .unwrap() } diff --git a/forc-test/src/lib.rs b/forc-test/src/lib.rs index c7bd19e95fd..bccc4cc0209 100644 --- a/forc-test/src/lib.rs +++ b/forc-test/src/lib.rs @@ -151,6 +151,8 @@ pub struct TestOpts { pub error_on_warnings: bool, /// Output the time elapsed over each part of the compilation process. pub time_phases: bool, + /// Profile the compilation process. + pub profile: bool, /// Output compilation metrics into file. pub metrics_outfile: Option, /// Set of enabled experimental flags @@ -453,6 +455,7 @@ impl From for pkg::BuildOpts { release: val.release, error_on_warnings: val.error_on_warnings, time_phases: val.time_phases, + profile: val.profile, metrics_outfile: val.metrics_outfile, tests: true, member_filter: Default::default(), @@ -476,6 +479,7 @@ impl TestOpts { release: self.release, error_on_warnings: self.error_on_warnings, time_phases: self.time_phases, + profile: self.profile, metrics_outfile: self.metrics_outfile, tests: true, member_filter: Default::default(), diff --git a/forc-tracing/Cargo.toml b/forc-tracing/Cargo.toml index 85240eec345..871e04df5a0 100644 --- a/forc-tracing/Cargo.toml +++ b/forc-tracing/Cargo.toml @@ -9,9 +9,9 @@ license.workspace = true repository.workspace = true [dependencies] -ansi_term.workspace = true +ansiterm.workspace = true tracing.workspace = true tracing-subscriber = { workspace = true, features = ["ansi", "env-filter", "json"] } [dev-dependencies] -tracing-test = "0.2" \ No newline at end of file +tracing-test = "0.2" diff --git a/forc-tracing/src/lib.rs b/forc-tracing/src/lib.rs index 656cb14ca14..c331b0a8a71 100644 --- a/forc-tracing/src/lib.rs +++ b/forc-tracing/src/lib.rs @@ -1,6 +1,6 @@ //! Utility items shared between forc crates. -use ansi_term::Colour; +use ansiterm::Colour; use std::str; use std::{env, io}; use tracing::{Level, Metadata}; diff --git a/forc-util/Cargo.toml b/forc-util/Cargo.toml index f224c3028cb..a7bd7364a7f 100644 --- a/forc-util/Cargo.toml +++ b/forc-util/Cargo.toml @@ -10,12 +10,13 @@ repository.workspace = true [dependencies] annotate-snippets.workspace = true -ansi_term.workspace = true +ansiterm.workspace = true anyhow.workspace = true clap = { workspace = true, features = ["cargo", "derive", "env"] } dirs.workspace = true fd-lock.workspace = true forc-tracing.workspace = true +fuel-asm.workspace = true fuel-tx = { workspace = true, optional = true } hex.workspace = true paste.workspace = true @@ -23,6 +24,7 @@ regex.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true serial_test.workspace = true +sha2.workspace = true sway-core.workspace = true sway-error.workspace = true sway-types.workspace = true diff --git a/forc-util/src/bytecode.rs b/forc-util/src/bytecode.rs new file mode 100644 index 00000000000..7f73f39969e --- /dev/null +++ b/forc-util/src/bytecode.rs @@ -0,0 +1,174 @@ +use anyhow::anyhow; +use sha2::{Digest, Sha256}; +use std::fs::File; +use std::io::{BufReader, Read}; +use std::path::Path; + +// The index of the beginning of the half-word (4 bytes) that contains the configurables section offset. +const CONFIGURABLES_OFFSET_INSTR_LO: usize = 4; +// The index of the end of the half-word (4 bytes) that contains the configurables section offset. +const CONFIGURABLES_OFFSET_INSTR_HI: usize = 5; +// The count of the beginning half-words that contain the configurables section offset. +const CONFIGURABLES_OFFSET_PREAMBLE: usize = CONFIGURABLES_OFFSET_INSTR_HI + 1; + +/// A tuple of an instruction and its corresponding bytes. Useful when needing to access the raw bytes +/// of an instruction that is parsed as [fuel_asm::InvalidOpcode], such as metadata in the preamble. +pub type InstructionWithBytes = ( + Result, + Vec, +); + +/// An iterator over each [fuel_asm::Instruction] or [fuel_asm::InvalidOpcode] with its corresponding bytes. +pub struct InstructionWithBytesIterator { + buf_reader: BufReader, +} + +impl InstructionWithBytesIterator { + /// Return a new iterator for each instruction parsed from raw bytes. + pub fn new(buf_reader: BufReader) -> Self { + InstructionWithBytesIterator { buf_reader } + } +} + +impl Iterator for InstructionWithBytesIterator { + type Item = InstructionWithBytes; + + fn next(&mut self) -> Option { + let mut buffer = [0; fuel_asm::Instruction::SIZE]; + // Read the next instruction into the buffer + match self.buf_reader.read_exact(&mut buffer) { + Ok(_) => fuel_asm::from_bytes(buffer) + .next() + .map(|inst| (inst, buffer.to_vec())), + Err(_) => None, + } + } +} + +/// Parses a bytecode file into an iterator of instructions and their corresponding bytes. +pub fn parse_bytecode_to_instructions

(path: P) -> anyhow::Result +where + P: AsRef + Clone, +{ + let f = File::open(path.clone()) + .map_err(|_| anyhow!("{}: file not found", path.as_ref().to_string_lossy()))?; + let buf_reader = BufReader::new(f); + + Ok(InstructionWithBytesIterator::new(buf_reader)) +} + +/// Gets the bytecode ID from a bytecode file. The bytecode ID is the hash of the bytecode after removing the +/// condigurables section, if any. +pub fn get_bytecode_id

(path: P) -> anyhow::Result +where + P: AsRef + Clone, +{ + let mut instructions = parse_bytecode_to_instructions(path.clone())?; + + // Collect the first six instructions into a temporary vector + let mut first_six_instructions = Vec::with_capacity(CONFIGURABLES_OFFSET_PREAMBLE); + for _ in 0..CONFIGURABLES_OFFSET_PREAMBLE { + if let Some(instruction) = instructions.next() { + first_six_instructions.push(instruction); + } else { + return Err(anyhow!("Incomplete bytecode")); + } + } + + let (lo_instr, low_raw) = &first_six_instructions[CONFIGURABLES_OFFSET_INSTR_LO]; + let (hi_instr, hi_raw) = &first_six_instructions[CONFIGURABLES_OFFSET_INSTR_HI]; + + if let Err(fuel_asm::InvalidOpcode) = lo_instr { + if let Err(fuel_asm::InvalidOpcode) = hi_instr { + // Now assemble the configurables offset. + let configurables_offset = usize::from_be_bytes([ + low_raw[0], low_raw[1], low_raw[2], low_raw[3], hi_raw[0], hi_raw[1], hi_raw[2], + hi_raw[3], + ]); + + // Hash the first six instructions + let mut hasher = Sha256::new(); + for (_, raw) in first_six_instructions { + hasher.update(raw); + } + + // Continue hashing the remaining instructions up to the configurables section offset. + instructions + .take( + configurables_offset / fuel_asm::Instruction::SIZE + - CONFIGURABLES_OFFSET_PREAMBLE, + ) // Minus 6 because we already hashed the first six + .for_each(|(_, raw)| { + hasher.update(raw); + }); + + let hash_result = hasher.finalize(); + let bytecode_id = format!("{:x}", hash_result); + return Ok(bytecode_id); + } + } + + Err(anyhow!("Configurables section offset not found")) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_get_bytecode_id_happy() { + // These binary files were generated from `examples/configurable_constants` and `examples/counter` + // using `forc build` and `forc build --release` respectively. + let bytecode_id: String = + get_bytecode_id("tests/fixtures/bytecode/debug-counter.bin").expect("bytecode id"); + assert_eq!( + bytecode_id, + "e65aa988cae1041b64dc2d85e496eed0e8a1d8105133bd313c17645a1859d53b".to_string() + ); + + let bytecode_id = + get_bytecode_id("tests/fixtures/bytecode/release-counter.bin").expect("bytecode id"); + assert_eq!( + bytecode_id, + "42ae8352cbc892d7c7621f1d6fb42b072a08ba5968508d49f54991668d4ea141".to_string() + ); + + let bytecode_id = + get_bytecode_id("tests/fixtures/bytecode/debug-configurable_constants.bin") + .expect("bytecode id"); + assert_eq!( + bytecode_id, + "babc3d9dcac8d48dee1e5aeb3340ff098d3c1ab8b0a28341d9291d8ff757199e".to_string() + ); + + let bytecode_id = + get_bytecode_id("tests/fixtures/bytecode/release-configurable_constants.bin") + .expect("bytecode id"); + assert_eq!( + bytecode_id, + "2adfb515b66763fd29391bdba012921d045a0be83d89be5492bcaacc429695e9".to_string() + ); + } + + #[test] + fn test_get_bytecode_id_missing_configurable_offset() { + // This bytecode file was generated from `examples/configurable_constants` using an older version of the + // compiler that did not include the configurables section offset in the preamble. + let result = get_bytecode_id( + "tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin", + ); + assert_eq!( + result.unwrap_err().to_string().as_str(), + "Configurables section offset not found" + ); + } + + #[test] + fn test_get_bytecode_id_bad_path() { + let result = get_bytecode_id("tests/fixtures/bytecode/blahblahblahblah.bin"); + assert_eq!( + result.unwrap_err().to_string().as_str(), + "tests/fixtures/bytecode/blahblahblahblah.bin: file not found" + ); + } +} diff --git a/forc-util/src/cli.rs b/forc-util/src/cli.rs index f8f6ed5662e..d5dc863ddcd 100644 --- a/forc-util/src/cli.rs +++ b/forc-util/src/cli.rs @@ -103,7 +103,7 @@ macro_rules! cli_examples { fn help() -> &'static str { - Box::leak(format!("{}\n{}", forc_util::ansi_term::Colour::Yellow.paint("EXAMPLES:"), examples()).into_boxed_str()) + Box::leak(format!("{}\n{}", forc_util::ansiterm::Colour::Yellow.paint("EXAMPLES:"), examples()).into_boxed_str()) } pub fn examples() -> &'static str { diff --git a/forc-util/src/lib.rs b/forc-util/src/lib.rs index 7cf7f45b2b4..03775dcf8f1 100644 --- a/forc-util/src/lib.rs +++ b/forc-util/src/lib.rs @@ -23,13 +23,14 @@ use sway_error::{ use sway_types::{LineCol, LineColRange, SourceEngine, Span}; use sway_utils::constants; +pub mod bytecode; pub mod fs_locking; pub mod restricted; #[macro_use] pub mod cli; -pub use ansi_term; +pub use ansiterm; pub use paste; pub use regex::Regex; pub use serial_test; @@ -347,7 +348,7 @@ pub fn print_compiling(ty: Option<&TreeType>, name: &str, src: &dyn std::fmt::Di }; println_action_green( "Compiling", - &format!("{ty}{} ({src})", ansi_term::Style::new().bold().paint(name)), + &format!("{ty}{} ({src})", ansiterm::Style::new().bold().paint(name)), ); } @@ -510,7 +511,7 @@ fn format_diagnostic(diagnostic: &Diagnostic) { label: if issue.is_in_source() { None } else { - Some(issue.friendly_text()) + Some(issue.text()) }, id: None, annotation_type, @@ -532,7 +533,7 @@ fn format_diagnostic(diagnostic: &Diagnostic) { origin: Some(issue.source_path().unwrap().as_str()), fold: false, annotations: vec![SourceAnnotation { - label: issue.friendly_text(), + label: issue.text(), annotation_type, range: (start_pos, end_pos), }], @@ -594,7 +595,7 @@ fn construct_slice(labels: Vec<&Label>) -> Slice { for message in labels { annotations.push(SourceAnnotation { - label: message.friendly_text(), + label: message.text(), annotation_type: label_type_to_annotation_type(message.label_type()), range: get_annotation_range(message.span(), source_code, shift_in_bytes), }); diff --git a/forc-util/tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin b/forc-util/tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin new file mode 100644 index 00000000000..cedfa0b99ae Binary files /dev/null and b/forc-util/tests/fixtures/bytecode/debug-configurable_constants-missing-offset.bin differ diff --git a/forc-util/tests/fixtures/bytecode/debug-configurable_constants.bin b/forc-util/tests/fixtures/bytecode/debug-configurable_constants.bin new file mode 100644 index 00000000000..4490555350d Binary files /dev/null and b/forc-util/tests/fixtures/bytecode/debug-configurable_constants.bin differ diff --git a/forc-util/tests/fixtures/bytecode/debug-counter.bin b/forc-util/tests/fixtures/bytecode/debug-counter.bin new file mode 100644 index 00000000000..b19a04b03b6 Binary files /dev/null and b/forc-util/tests/fixtures/bytecode/debug-counter.bin differ diff --git a/forc-util/tests/fixtures/bytecode/release-configurable_constants.bin b/forc-util/tests/fixtures/bytecode/release-configurable_constants.bin new file mode 100644 index 00000000000..2538c021e48 Binary files /dev/null and b/forc-util/tests/fixtures/bytecode/release-configurable_constants.bin differ diff --git a/forc-util/tests/fixtures/bytecode/release-counter.bin b/forc-util/tests/fixtures/bytecode/release-counter.bin new file mode 100644 index 00000000000..9f504b1c687 Binary files /dev/null and b/forc-util/tests/fixtures/bytecode/release-counter.bin differ diff --git a/forc/Cargo.toml b/forc/Cargo.toml index 578e427cee8..b3257f1ad1f 100644 --- a/forc/Cargo.toml +++ b/forc/Cargo.toml @@ -18,7 +18,7 @@ path = "src/main.rs" [dependencies] annotate-snippets.workspace = true -ansi_term.workspace = true +ansiterm.workspace = true anyhow.workspace = true clap = { workspace = true, features = ["cargo", "derive", "env"] } clap_complete.workspace = true @@ -44,7 +44,6 @@ toml = { workspace = true, features = ["parse"] } toml_edit.workspace = true tracing.workspace = true url.workspace = true -uwuify = { workspace = true, optional = true } walkdir.workspace = true whoami.workspace = true @@ -52,7 +51,7 @@ whoami.workspace = true default = [] test = [] util = [] -uwu = ["uwuify"] +profile = [] [dev-dependencies] completest-pty = "0.5.0" diff --git a/forc/src/cli/commands/parse_bytecode.rs b/forc/src/cli/commands/parse_bytecode.rs index f4a30c82d6d..0ffa6f0ba4a 100644 --- a/forc/src/cli/commands/parse_bytecode.rs +++ b/forc/src/cli/commands/parse_bytecode.rs @@ -1,8 +1,6 @@ -use anyhow::anyhow; use clap::Parser; +use forc_util::bytecode::parse_bytecode_to_instructions; use forc_util::ForcResult; -use std::fs::{self, File}; -use std::io::Read; use term_table::row::Row; use term_table::table_cell::{Alignment, TableCell}; use tracing::info; @@ -21,15 +19,7 @@ pub(crate) struct Command { } pub(crate) fn exec(command: Command) -> ForcResult<()> { - let mut f = File::open(&command.file_path) - .map_err(|_| anyhow!("{}: file not found", command.file_path))?; - let metadata = fs::metadata(&command.file_path) - .map_err(|_| anyhow!("{}: file not found", command.file_path))?; - let mut buffer = vec![0; metadata.len() as usize]; - f.read_exact(&mut buffer).expect("buffer overflow"); - - let instructions = fuel_asm::from_bytes(buffer.iter().cloned()) - .zip(buffer.chunks(fuel_asm::Instruction::SIZE)); + let instructions = parse_bytecode_to_instructions(&command.file_path)?; let mut table = term_table::Table::new(); table.separate_rows = false; @@ -59,6 +49,14 @@ pub(crate) fn exec(command: Command) -> ForcResult<()> { parsed_raw ) } + Err(fuel_asm::InvalidOpcode) if word_ix == 4 || word_ix == 5 => { + let parsed_raw = u32::from_be_bytes([raw[0], raw[1], raw[2], raw[3]]); + format!( + "configurables offset {} ({})", + if word_ix == 4 { "lo" } else { "hi" }, + parsed_raw + ) + } Ok(_) | Err(fuel_asm::InvalidOpcode) => "".into(), }; table.add_row(Row::new(vec![ diff --git a/forc/src/cli/commands/test.rs b/forc/src/cli/commands/test.rs index d556af6b790..685a7d4e9bb 100644 --- a/forc/src/cli/commands/test.rs +++ b/forc/src/cli/commands/test.rs @@ -1,5 +1,5 @@ use crate::cli; -use ansi_term::Colour; +use ansiterm::Colour; use clap::Parser; use forc_pkg as pkg; use forc_test::{decode_log_data, TestFilter, TestRunnerCount, TestedPackage}; @@ -243,6 +243,7 @@ fn opts_from_cmd(cmd: Command) -> forc_test::TestOpts { reverse_order: cmd.build.print.reverse_order, }, time_phases: cmd.build.print.time_phases, + profile: cmd.build.print.profile, metrics_outfile: cmd.build.print.metrics_outfile, minify: pkg::MinifyOpts { json_abi: cmd.build.minify.json_abi, diff --git a/forc/src/cli/shared.rs b/forc/src/cli/shared.rs index 28b38465df3..23ccdd59cb9 100644 --- a/forc/src/cli/shared.rs +++ b/forc/src/cli/shared.rs @@ -99,6 +99,9 @@ pub struct Print { /// Output the time elapsed over each part of the compilation process. #[clap(long)] pub time_phases: bool, + /// Profile the compilation process. + #[clap(long)] + pub profile: bool, /// Output build errors and warnings in reverse order. #[clap(long)] pub reverse_order: bool, diff --git a/forc/src/ops/forc_build.rs b/forc/src/ops/forc_build.rs index 1118bdb5d54..2ec40cca931 100644 --- a/forc/src/ops/forc_build.rs +++ b/forc/src/ops/forc_build.rs @@ -30,6 +30,7 @@ fn opts_from_cmd(cmd: BuildCommand) -> pkg::BuildOpts { reverse_order: cmd.build.print.reverse_order, }, time_phases: cmd.build.print.time_phases, + profile: cmd.build.print.profile, metrics_outfile: cmd.build.print.metrics_outfile, minify: pkg::MinifyOpts { json_abi: cmd.build.minify.json_abi, diff --git a/forc/src/ops/forc_contract_id.rs b/forc/src/ops/forc_contract_id.rs index f80f4f5262f..9cc18edcfeb 100644 --- a/forc/src/ops/forc_contract_id.rs +++ b/forc/src/ops/forc_contract_id.rs @@ -64,6 +64,7 @@ fn build_opts_from_cmd(cmd: &ContractIdCommand) -> pkg::BuildOpts { reverse_order: cmd.print.reverse_order, }, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile.clone(), minify: pkg::MinifyOpts { json_abi: cmd.minify.json_abi, diff --git a/forc/src/ops/forc_predicate_root.rs b/forc/src/ops/forc_predicate_root.rs index 34be42c4117..41b7c5020a8 100644 --- a/forc/src/ops/forc_predicate_root.rs +++ b/forc/src/ops/forc_predicate_root.rs @@ -33,6 +33,7 @@ fn build_opts_from_cmd(cmd: PredicateRootCommand) -> pkg::BuildOpts { reverse_order: cmd.print.reverse_order, }, time_phases: cmd.print.time_phases, + profile: cmd.print.profile, metrics_outfile: cmd.print.metrics_outfile, minify: pkg::MinifyOpts { json_abi: cmd.minify.json_abi, diff --git a/forc/tests/cli_integration.rs b/forc/tests/cli_integration.rs index 1f1248a2205..422e9f18f9c 100644 --- a/forc/tests/cli_integration.rs +++ b/forc/tests/cli_integration.rs @@ -49,10 +49,10 @@ fn test_forc_test_raw_logs() -> Result<(), rexpect::error::Error> { // Assert that the output is correct process.exp_string(" test test_log_4")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.exp_string(" test test_log_2")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.process.exit()?; Ok(()) @@ -74,11 +74,11 @@ fn test_forc_test_both_logs() -> Result<(), rexpect::error::Error> { process.exp_string(" test test_log_4")?; process.exp_string("Decoded log value: 4, log rb: 1515152261580153489")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000004","digest":"8005f02d43fa06e7d0585fb64c961d57e318b27a145c857bcd3a6bdb413ff7fc","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.exp_string(" test test_log_2")?; process.exp_string("Decoded log value: 2, log rb: 1515152261580153489")?; process.exp_string("Raw logs:")?; - process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12664,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; + process.exp_string(r#"[{"LogData":{"data":"0000000000000002","digest":"cd04a4754498e06db5a13c5f371f1f04ff6d2470f24aa9bd886540e5dce77f70","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":8,"pc":12672,"ptr":67107840,"ra":0,"rb":1515152261580153489}}]"#)?; process.process.exit()?; Ok(()) } diff --git a/sway-ast/src/expr/mod.rs b/sway-ast/src/expr/mod.rs index f27798c2d7f..52999a63dcf 100644 --- a/sway-ast/src/expr/mod.rs +++ b/sway-ast/src/expr/mod.rs @@ -306,6 +306,18 @@ impl ReassignmentOpVariant { ReassignmentOpVariant::ShrEquals => "rsh", } } + + pub fn as_str(&self) -> &'static str { + match self { + ReassignmentOpVariant::Equals => EqToken::AS_STR, + ReassignmentOpVariant::AddEquals => AddEqToken::AS_STR, + ReassignmentOpVariant::SubEquals => SubEqToken::AS_STR, + ReassignmentOpVariant::MulEquals => StarEqToken::AS_STR, + ReassignmentOpVariant::DivEquals => DivEqToken::AS_STR, + ReassignmentOpVariant::ShlEquals => ShlEqToken::AS_STR, + ReassignmentOpVariant::ShrEquals => ShrEqToken::AS_STR, + } + } } #[derive(Clone, Debug, Serialize)] diff --git a/sway-ast/src/expr/op_code.rs b/sway-ast/src/expr/op_code.rs index acfc54411eb..83c6d319743 100644 --- a/sway-ast/src/expr/op_code.rs +++ b/sway-ast/src/expr/op_code.rs @@ -123,6 +123,14 @@ macro_rules! define_op_codes ( } } + pub fn op_code_as_str(&self) -> &'static str { + match self { + $(Instruction::$op_name { .. } => { + $s + },)* + } + } + #[allow(clippy::vec_init_then_push)] pub fn register_arg_idents(&self) -> Vec { match self { diff --git a/sway-ast/src/intrinsics.rs b/sway-ast/src/intrinsics.rs index 182d47fa3d9..d14c4e1b85a 100644 --- a/sway-ast/src/intrinsics.rs +++ b/sway-ast/src/intrinsics.rs @@ -1,6 +1,7 @@ +use serde::{Deserialize, Serialize}; use std::fmt; -#[derive(Eq, PartialEq, Debug, Clone, Hash)] +#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize)] pub enum Intrinsic { IsReferenceType, SizeOfType, @@ -43,6 +44,7 @@ pub enum Intrinsic { EncodeBufferAsRawSlice, // let slice: raw_slice = __encode_buffer_as_raw_slice(buffer) Slice, // let ref_to_slice = __slice::(item: T, inclusive_start_index, exclusive_end_index) ElemAt, // let elem: &T = __elem_at::(item: T, index) + Transmute, // let dst: B = __transmute::(src) } impl fmt::Display for Intrinsic { @@ -89,6 +91,7 @@ impl fmt::Display for Intrinsic { Intrinsic::EncodeBufferAsRawSlice => "encode_buffer_as_raw_slice", Intrinsic::Slice => "slice", Intrinsic::ElemAt => "elem_at", + Intrinsic::Transmute => "transmute", }; write!(f, "{s}") } @@ -139,6 +142,7 @@ impl Intrinsic { "__encode_buffer_as_raw_slice" => EncodeBufferAsRawSlice, "__slice" => Slice, "__elem_at" => ElemAt, + "__transmute" => Transmute, _ => return None, }) } diff --git a/sway-ast/src/keywords.rs b/sway-ast/src/keywords.rs index 0e3ea802da0..236b07cb8aa 100644 --- a/sway-ast/src/keywords.rs +++ b/sway-ast/src/keywords.rs @@ -98,10 +98,13 @@ pub trait Token: Spanned + Sized { /// Punctuations that will not follow the token. const NOT_FOLLOWED_BY: &'static [PunctKind]; + + /// What the string representation of the token is when lexing. + const AS_STR: &'static str; } macro_rules! define_token ( - ($ty_name:ident, $description:literal, [$($punct_kinds:ident),*], [$($not_followed_by:ident),*]) => { + ($ty_name:ident, $description:literal, $as_str:literal, [$($punct_kinds:ident),*], [$($not_followed_by:ident),*]) => { #[derive(Clone, Debug, Serialize)] pub struct $ty_name { span: Span, @@ -132,6 +135,7 @@ macro_rules! define_token ( const PUNCT_KINDS: &'static [PunctKind] = &[$(PunctKind::$punct_kinds,)*]; const NOT_FOLLOWED_BY: &'static [PunctKind] = &[$(PunctKind::$not_followed_by,)*]; + const AS_STR: &'static str = $as_str; } impl From<$ty_name> for Ident { @@ -142,93 +146,121 @@ macro_rules! define_token ( }; ); -define_token!(SemicolonToken, "a semicolon", [Semicolon], []); +define_token!(SemicolonToken, "a semicolon", ";", [Semicolon], []); define_token!( ForwardSlashToken, "a forward slash", + "/", [ForwardSlash], [Equals] ); define_token!( DoubleColonToken, "a double colon (::)", + "::", [Colon, Colon], [Colon] ); -define_token!(StarToken, "an asterisk (*)", [Star], [Equals]); -define_token!(DoubleStarToken, "`**`", [Star, Star], []); -define_token!(CommaToken, "a comma", [Comma], []); -define_token!(ColonToken, "a colon", [Colon], [Colon]); +define_token!(StarToken, "an asterisk (*)", "*", [Star], [Equals]); +define_token!(DoubleStarToken, "`**`", "**", [Star, Star], []); +define_token!(CommaToken, "a comma", ",", [Comma], []); +define_token!(ColonToken, "a colon", ":", [Colon], [Colon]); define_token!( RightArrowToken, "`->`", + "->", [Sub, GreaterThan], [GreaterThan, Equals] ); -define_token!(LessThanToken, "`<`", [LessThan], [LessThan, Equals]); +define_token!(LessThanToken, "`<`", "<", [LessThan], [LessThan, Equals]); define_token!( GreaterThanToken, "`>`", + ">", [GreaterThan], [GreaterThan, Equals] ); -define_token!(OpenAngleBracketToken, "`<`", [LessThan], []); -define_token!(CloseAngleBracketToken, "`>`", [GreaterThan], []); -define_token!(EqToken, "`=`", [Equals], [GreaterThan, Equals]); -define_token!(AddEqToken, "`+=`", [Add, Equals], []); -define_token!(SubEqToken, "`-=`", [Sub, Equals], []); -define_token!(StarEqToken, "`*=`", [Star, Equals], []); -define_token!(DivEqToken, "`/=`", [ForwardSlash, Equals], []); -define_token!(ShlEqToken, "`<<=`", [LessThan, LessThan, Equals], []); -define_token!(ShrEqToken, "`>>=`", [GreaterThan, GreaterThan, Equals], []); +define_token!(OpenAngleBracketToken, "`<`", "<", [LessThan], []); +define_token!(CloseAngleBracketToken, "`>`", ">", [GreaterThan], []); +define_token!(EqToken, "`=`", "=", [Equals], [GreaterThan, Equals]); +define_token!(AddEqToken, "`+=`", "+=", [Add, Equals], []); +define_token!(SubEqToken, "`-=`", "-=", [Sub, Equals], []); +define_token!(StarEqToken, "`*=`", "*=", [Star, Equals], []); +define_token!(DivEqToken, "`/=`", "/=", [ForwardSlash, Equals], []); +define_token!(ShlEqToken, "`<<=`", "<<=", [LessThan, LessThan, Equals], []); +define_token!( + ShrEqToken, + "`>>=`", + ">>=", + [GreaterThan, GreaterThan, Equals], + [] +); define_token!( FatRightArrowToken, "`=>`", + "=>", [Equals, GreaterThan], [GreaterThan, Equals] ); -define_token!(DotToken, "`.`", [Dot], []); -define_token!(DoubleDotToken, "`..`", [Dot, Dot], [Dot]); -define_token!(BangToken, "`!`", [Bang], [Equals]); -define_token!(PercentToken, "`%`", [Percent], []); -define_token!(AddToken, "`+`", [Add], [Equals]); -define_token!(SubToken, "`-`", [Sub], [Equals]); +define_token!(DotToken, "`.`", ".", [Dot], []); +define_token!(DoubleDotToken, "`..`", "..", [Dot, Dot], [Dot]); +define_token!(BangToken, "`!`", "!", [Bang], [Equals]); +define_token!(PercentToken, "`%`", "%", [Percent], []); +define_token!(AddToken, "`+`", "+", [Add], [Equals]); +define_token!(SubToken, "`-`", "-", [Sub], [Equals]); define_token!( ShrToken, "`>>`", + ">>", [GreaterThan, GreaterThan], [GreaterThan, Equals] ); -define_token!(ShlToken, "`<<`", [LessThan, LessThan], [LessThan, Equals]); -define_token!(AmpersandToken, "`&`", [Ampersand], [Ampersand]); -define_token!(CaretToken, "`^`", [Caret], []); -define_token!(PipeToken, "`|`", [Pipe], [Pipe]); +define_token!( + ShlToken, + "`<<`", + "<<", + [LessThan, LessThan], + [LessThan, Equals] +); +define_token!(AmpersandToken, "`&`", "&", [Ampersand], [Ampersand]); +define_token!(CaretToken, "`^`", "^", [Caret], []); +define_token!(PipeToken, "`|`", "|", [Pipe], [Pipe]); define_token!( DoubleEqToken, "`==`", + "==", [Equals, Equals], [Equals, GreaterThan] ); -define_token!(BangEqToken, "`!=`", [Bang, Equals], [Equals, GreaterThan]); +define_token!( + BangEqToken, + "`!=`", + "!=", + [Bang, Equals], + [Equals, GreaterThan] +); define_token!( GreaterThanEqToken, "`>=`", + ">=", [GreaterThan, Equals], [Equals, GreaterThan] ); define_token!( LessThanEqToken, "`<=`", + "<=", [LessThan, Equals], [Equals, GreaterThan] ); define_token!( DoubleAmpersandToken, "`&&`", + "&&", [Ampersand, Ampersand], [Ampersand] ); -define_token!(DoublePipeToken, "`||`", [Pipe, Pipe], [Pipe]); -define_token!(UnderscoreToken, "`_`", [Underscore], [Underscore]); -define_token!(HashToken, "`#`", [Sharp], []); -define_token!(HashBangToken, "`#!`", [Sharp, Bang], []); +define_token!(DoublePipeToken, "`||`", "||", [Pipe, Pipe], [Pipe]); +define_token!(UnderscoreToken, "`_`", "_", [Underscore], [Underscore]); +define_token!(HashToken, "`#`", "#", [Sharp], []); +define_token!(HashBangToken, "`#!`", "#!", [Sharp, Bang], []); diff --git a/sway-ast/src/literal.rs b/sway-ast/src/literal.rs index 1cede566e18..0b175235506 100644 --- a/sway-ast/src/literal.rs +++ b/sway-ast/src/literal.rs @@ -1,25 +1,25 @@ use crate::priv_prelude::*; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitString { pub span: Span, pub parsed: String, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitChar { pub span: Span, pub parsed: char, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitInt { pub span: Span, pub parsed: BigUint, pub ty_opt: Option<(LitIntType, Span)>, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub enum LitIntType { U8, U16, @@ -32,13 +32,13 @@ pub enum LitIntType { I64, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub struct LitBool { pub span: Span, pub kind: LitBoolType, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub enum LitBoolType { True, False, @@ -53,7 +53,7 @@ impl From for bool { } } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] pub enum Literal { String(LitString), Char(LitChar), diff --git a/sway-ast/src/path.rs b/sway-ast/src/path.rs index b472426c8d9..c7be1225e87 100644 --- a/sway-ast/src/path.rs +++ b/sway-ast/src/path.rs @@ -110,5 +110,5 @@ impl Spanned for PathTypeSegment { #[derive(Clone, Debug, Serialize)] pub struct QualifiedPathRoot { pub ty: Box, - pub as_trait: Option<(AsToken, Box)>, + pub as_trait: (AsToken, Box), } diff --git a/sway-ast/src/priv_prelude.rs b/sway-ast/src/priv_prelude.rs index b799d69f37d..9da93d80994 100644 --- a/sway-ast/src/priv_prelude.rs +++ b/sway-ast/src/priv_prelude.rs @@ -35,7 +35,7 @@ pub use { }, extension_trait::extension_trait, num_bigint::BigUint, - serde::Serialize, + serde::{Deserialize, Serialize}, sway_types::{ ast::{Delimiter, PunctKind}, Ident, Span, Spanned, diff --git a/sway-ast/src/punctuated.rs b/sway-ast/src/punctuated.rs index 9aa88c64495..af6cf423f89 100644 --- a/sway-ast/src/punctuated.rs +++ b/sway-ast/src/punctuated.rs @@ -20,6 +20,19 @@ impl Punctuated { final_value_opt: Some(Box::new(value)), } } + + /// Returns true if the [Punctuated] ends with the punctuation token. + /// E.g., `fn fun(x: u64, y: u64,)`. + pub fn has_trailing_punctuation(&self) -> bool { + !self.value_separator_pairs.is_empty() && self.final_value_opt.is_none() + } + + /// Returns true if the [Punctuated] has neither value separator pairs, + /// nor the final value. + /// E.g., `fn fun()`. + pub fn is_empty(&self) -> bool { + self.value_separator_pairs.is_empty() && self.final_value_opt.is_none() + } } impl IntoIterator for Punctuated { diff --git a/sway-core/Cargo.toml b/sway-core/Cargo.toml index 3a351390cbb..71ca263d962 100644 --- a/sway-core/Cargo.toml +++ b/sway-core/Cargo.toml @@ -23,11 +23,12 @@ graph-cycles.workspace = true hashbrown.workspace = true hex = { workspace = true, optional = true } im.workspace = true -indexmap.workspace = true +indexmap = { workspace = true, features = ["serde"] } itertools.workspace = true lazy_static.workspace = true object = { workspace = true, features = ["write"] } parking_lot.workspace = true +paste.workspace = true pest.workspace = true pest_derive.workspace = true petgraph.workspace = true diff --git a/sway-core/src/abi_generation/abi_str.rs b/sway-core/src/abi_generation/abi_str.rs index 254b8a805ad..5794906d7c9 100644 --- a/sway-core/src/abi_generation/abi_str.rs +++ b/sway-core/src/abi_generation/abi_str.rs @@ -179,7 +179,6 @@ impl TypeInfo { length.val() ) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { diff --git a/sway-core/src/abi_generation/evm_abi.rs b/sway-core/src/abi_generation/evm_abi.rs index f723f36d14a..147fa387a6f 100644 --- a/sway-core/src/abi_generation/evm_abi.rs +++ b/sway-core/src/abi_generation/evm_abi.rs @@ -115,7 +115,6 @@ pub fn abi_str(type_info: &TypeInfo, engines: &Engines) -> String { Array(elem_ty, length) => { format!("{}[{}]", abi_str_type_arg(elem_ty, engines), length.val()) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { diff --git a/sway-core/src/asm_generation/finalized_asm.rs b/sway-core/src/asm_generation/finalized_asm.rs index ce3c81e3a56..936127d7554 100644 --- a/sway-core/src/asm_generation/finalized_asm.rs +++ b/sway-core/src/asm_generation/finalized_asm.rs @@ -3,8 +3,8 @@ use super::{ fuel::{checks, data_section::DataSection}, ProgramABI, ProgramKind, }; -use crate::asm_generation::fuel::data_section::{DataId, Datum, Entry}; -use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode}; +use crate::asm_generation::fuel::data_section::{Datum, Entry, EntryName}; +use crate::asm_lang::allocated_ops::{AllocatedOp, AllocatedOpcode, FuelAsmData}; use crate::decl_engine::DeclRefFunction; use crate::source_map::SourceMap; use crate::BuildConfig; @@ -16,9 +16,26 @@ use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::span::Span; use sway_types::SourceEngine; -use either::Either; use std::{collections::BTreeMap, fmt}; +/// Represents an ASM set which has had register allocation, jump elimination, and optimization +/// applied to it +#[derive(Clone, serde::Serialize)] +pub struct AsmInformation { + pub bytecode_size: u64, + pub data_section: DataSectionInformation, +} + +#[derive(Default, Clone, Debug, serde::Serialize)] +pub struct DataSectionInformation { + /// The total size of the data section in bytes + pub size: u64, + /// The used size of the data section in bytes + pub used: u64, + /// The data to be put in the data section of the asm + pub value_pairs: Vec, +} + /// Represents an ASM set which has had register allocation, jump elimination, and optimization /// applied to it #[derive(Clone)] @@ -112,6 +129,8 @@ fn to_bytecode_mut( { 8 } + AllocatedOpcode::AddrDataId(_, _data_id) => 8, + AllocatedOpcode::ConfigurablesOffsetPlaceholder => 8, AllocatedOpcode::DataSectionOffsetPlaceholder => 8, AllocatedOpcode::BLOB(count) => count.value as u64 * 4, AllocatedOpcode::CFEI(i) | AllocatedOpcode::CFSI(i) if i.value == 0 => 0, @@ -141,6 +160,29 @@ fn to_bytecode_mut( &ops_padded }; + let mut offset_from_instr_start = 0; + for op in ops.iter() { + match &op.opcode { + AllocatedOpcode::LoadDataId(_reg, data_label) + if !data_section + .has_copy_type(data_label) + .expect("data label references non existent data -- internal error") => + { + // For non-copy type loads, pre-insert pointers into the data_section so that + // from this point on, the data_section remains immutable. This is necessary + // so that when we take addresses of configurables, that address doesn't change + // later on if a non-configurable is added to the data-section. + let offset_bytes = data_section.data_id_to_offset(data_label) as u64; + // The -4 is because $pc is added in the *next* instruction. + let pointer_offset_from_current_instr = + offset_to_data_section_in_bytes - offset_from_instr_start + offset_bytes - 4; + data_section.append_pointer(pointer_offset_from_current_instr); + } + _ => (), + } + offset_from_instr_start += op_size_in_bytes(data_section, op); + } + let mut bytecode = Vec::with_capacity(offset_to_data_section_in_bytes as usize); if build_config.print_bytecode { @@ -166,7 +208,7 @@ fn to_bytecode_mut( offset_from_instr_start += op_size_in_bytes(data_section, op); match fuel_op { - Either::Right(data) => { + FuelAsmData::DatasectionOffset(data) => { if build_config.print_bytecode { print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len()); println!( @@ -182,7 +224,23 @@ fn to_bytecode_mut( bytecode.extend(data.iter().cloned()); half_word_ix += 2; } - Either::Left(instructions) => { + FuelAsmData::ConfigurablesOffset(data) => { + if build_config.print_bytecode { + print!("{}{:#010x} ", " ".repeat(indentation), bytecode.len()); + println!( + " ;; {:?}", + data + ); + } + + // Static assert to ensure that we're only dealing with ConfigurablesOffsetPlaceholder, + // a 1-word (8 bytes) data within the code. No other uses are known. + let _: [u8; 8] = data; + + bytecode.extend(data.iter().cloned()); + half_word_ix += 2; + } + FuelAsmData::Instructions(instructions) => { for instruction in instructions { // Print original source span only once if build_config.print_bytecode_spans { @@ -295,9 +353,9 @@ fn to_bytecode_mut( }; } - for (i, entry) in data_section.value_pairs.iter().enumerate() { - let entry_offset = data_section.data_id_to_offset(&DataId(i as u32)); - print_entry(indentation, offset + entry_offset, entry); + for (i, entry) in data_section.iter_all_entries().enumerate() { + let entry_offset = data_section.absolute_idx_to_offset(i); + print_entry(indentation, offset + entry_offset, &entry); } println!(";; --- END OF TARGET BYTECODE ---\n"); @@ -306,16 +364,19 @@ fn to_bytecode_mut( assert_eq!(half_word_ix * 4, offset_to_data_section_in_bytes as usize); assert_eq!(bytecode.len(), offset_to_data_section_in_bytes as usize); + let num_nonconfigurables = data_section.non_configurables.len(); let named_data_section_entries_offsets = data_section - .value_pairs + .configurables .iter() .enumerate() - .filter(|entry| entry.1.name.is_some()) .map(|(id, entry)| { + let EntryName::Configurable(name) = &entry.name else { + panic!("Non-configurable in configurables part of datasection"); + }; ( - entry.name.as_ref().unwrap().clone(), + name.clone(), offset_to_data_section_in_bytes - + data_section.raw_data_id_to_offset(id as u32) as u64, + + data_section.absolute_idx_to_offset(id + num_nonconfigurables) as u64, ) }) .collect::>(); diff --git a/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs b/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs index 0865687f5c8..e939ef633a2 100644 --- a/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs +++ b/sway-core/src/asm_generation/fuel/allocated_abstract_instruction_set.rs @@ -1,7 +1,10 @@ -use crate::asm_lang::{ - allocated_ops::{AllocatedOpcode, AllocatedRegister}, - AllocatedAbstractOp, ConstantRegister, ControlFlowOp, Label, RealizedOp, VirtualImmediate12, - VirtualImmediate18, VirtualImmediate24, +use crate::{ + asm_generation::fuel::data_section::EntryName, + asm_lang::{ + allocated_ops::{AllocatedOpcode, AllocatedRegister}, + AllocatedAbstractOp, ConstantRegister, ControlFlowOp, Label, RealizedOp, + VirtualImmediate12, VirtualImmediate18, VirtualImmediate24, + }, }; use super::{ @@ -348,6 +351,13 @@ impl AllocatedAbstractInstructionSet { comment: String::new(), }); } + ControlFlowOp::ConfigurablesOffsetPlaceholder => { + realized_ops.push(RealizedOp { + opcode: AllocatedOpcode::ConfigurablesOffsetPlaceholder, + owning_span: None, + comment: String::new(), + }); + } ControlFlowOp::LoadLabel(r1, ref lab) => { // LoadLabel ops are inserted by `rewrite_far_jumps`. // So the next instruction must be a relative jump. @@ -363,8 +373,11 @@ impl AllocatedAbstractInstructionSet { // We compute the relative offset w.r.t the actual jump. // Sub 1 because the relative jumps add a 1. let offset = rel_offset(curr_offset + 1, lab) - 1; - let data_id = - data_section.insert_data_value(Entry::new_word(offset, None, None)); + let data_id = data_section.insert_data_value(Entry::new_word( + offset, + EntryName::NonConfigurable, + None, + )); realized_ops.push(RealizedOp { opcode: AllocatedOpcode::LoadDataId(r1, data_id), owning_span, @@ -444,6 +457,8 @@ impl AllocatedAbstractInstructionSet { } } + Either::Left(AllocatedOpcode::AddrDataId(_, ref _data_id)) => 2, + // cfei 0 and cfsi 0 are omitted from asm emission, don't count them for offsets Either::Left(AllocatedOpcode::CFEI(ref op)) | Either::Left(AllocatedOpcode::CFSI(ref op)) @@ -473,6 +488,8 @@ impl AllocatedAbstractInstructionSet { 2 } + Either::Right(ConfigurablesOffsetPlaceholder) => 2, + Either::Right(PushAll(_)) | Either::Right(PopAll(_)) => unreachable!( "fix me, pushall and popall don't really belong in control flow ops \ since they're not about control flow" diff --git a/sway-core/src/asm_generation/fuel/data_section.rs b/sway-core/src/asm_generation/fuel/data_section.rs index 3db12443f4f..86cb5a1133a 100644 --- a/sway-core/src/asm_generation/fuel/data_section.rs +++ b/sway-core/src/asm_generation/fuel/data_section.rs @@ -1,19 +1,33 @@ +use rustc_hash::FxHashMap; use sway_ir::{size_bytes_round_up_to_word_alignment, Constant, ConstantValue, Context, Padding}; use std::{fmt, iter::repeat}; +#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)] +pub enum EntryName { + NonConfigurable, + Configurable(String), +} + +impl fmt::Display for EntryName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + EntryName::NonConfigurable => write!(f, "NonConfigurable"), + EntryName::Configurable(name) => write!(f, "", name), + } + } +} + // An entry in the data section. It's important for the size to be correct, especially for unions // where the size could be larger than the represented value. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub struct Entry { pub value: Datum, pub padding: Padding, - // It is assumed, for now, that only configuration-time constants have a name. Otherwise, this - // is `None`. - pub name: Option, + pub name: EntryName, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub enum Datum { Byte(u8), Word(u64), @@ -23,7 +37,7 @@ pub enum Datum { } impl Entry { - pub(crate) fn new_byte(value: u8, name: Option, padding: Option) -> Entry { + pub(crate) fn new_byte(value: u8, name: EntryName, padding: Option) -> Entry { Entry { value: Datum::Byte(value), padding: padding.unwrap_or(Padding::default_for_u8(value)), @@ -31,7 +45,7 @@ impl Entry { } } - pub(crate) fn new_word(value: u64, name: Option, padding: Option) -> Entry { + pub(crate) fn new_word(value: u64, name: EntryName, padding: Option) -> Entry { Entry { value: Datum::Word(value), padding: padding.unwrap_or(Padding::default_for_u64(value)), @@ -41,7 +55,7 @@ impl Entry { pub(crate) fn new_byte_array( bytes: Vec, - name: Option, + name: EntryName, padding: Option, ) -> Entry { Entry { @@ -51,11 +65,7 @@ impl Entry { } } - pub(crate) fn new_slice( - bytes: Vec, - name: Option, - padding: Option, - ) -> Entry { + pub(crate) fn new_slice(bytes: Vec, name: EntryName, padding: Option) -> Entry { Entry { padding: padding.unwrap_or(Padding::default_for_byte_array(&bytes)), value: Datum::Slice(bytes), @@ -65,7 +75,7 @@ impl Entry { pub(crate) fn new_collection( elements: Vec, - name: Option, + name: EntryName, padding: Option, ) -> Entry { Entry { @@ -80,7 +90,7 @@ impl Entry { pub(crate) fn from_constant( context: &Context, constant: &Constant, - name: Option, + name: EntryName, padding: Option, ) -> Entry { // We need a special handling in case of enums. @@ -89,8 +99,9 @@ impl Entry { .enum_tag_and_value_with_paddings(context) .expect("Constant is an enum."); - let tag_entry = Entry::from_constant(context, tag.0, None, tag.1); - let value_entry = Entry::from_constant(context, value.0, None, value.1); + let tag_entry = Entry::from_constant(context, tag.0, EntryName::NonConfigurable, tag.1); + let value_entry = + Entry::from_constant(context, value.0, EntryName::NonConfigurable, value.1); return Entry::new_collection(vec![tag_entry, value_entry], name, padding); } @@ -118,7 +129,9 @@ impl Entry { .array_elements_with_padding(context) .expect("Constant is an array.") .into_iter() - .map(|(elem, padding)| Entry::from_constant(context, elem, None, padding)) + .map(|(elem, padding)| { + Entry::from_constant(context, elem, EntryName::NonConfigurable, padding) + }) .collect(), name, padding, @@ -128,7 +141,9 @@ impl Entry { .struct_fields_with_padding(context) .expect("Constant is a struct.") .into_iter() - .map(|(elem, padding)| Entry::from_constant(context, elem, None, padding)) + .map(|(elem, padding)| { + Entry::from_constant(context, elem, EntryName::NonConfigurable, padding) + }) .collect(), name, padding, @@ -198,45 +213,92 @@ impl Entry { } } +#[derive(Clone, Debug)] +pub enum DataIdEntryKind { + NonConfigurable, + Configurable, +} + +impl fmt::Display for DataIdEntryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DataIdEntryKind::NonConfigurable => write!(f, "NonConfigurable"), + DataIdEntryKind::Configurable => write!(f, "Configurable"), + } + } +} + /// An address which refers to a value in the data section of the asm. #[derive(Clone, Debug)] -pub(crate) struct DataId(pub(crate) u32); +pub(crate) struct DataId { + pub(crate) idx: u32, + pub(crate) kind: DataIdEntryKind, +} impl fmt::Display for DataId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "data_{}", self.0) + write!(f, "data_{}_{}", self.kind, self.idx) } } +/// The data to be put in the data section of the asm #[derive(Default, Clone, Debug)] pub struct DataSection { - /// the data to be put in the data section of the asm - pub value_pairs: Vec, + pub non_configurables: Vec, + pub configurables: Vec, + pub(crate) pointer_id: FxHashMap, } impl DataSection { + /// Get the number of entries + pub fn num_entries(&self) -> usize { + self.non_configurables.len() + self.configurables.len() + } + + /// Iterate over all entries, non-configurables followed by configurables + pub fn iter_all_entries(&self) -> impl Iterator + '_ { + self.non_configurables + .iter() + .chain(self.configurables.iter()) + .cloned() + } + + /// Get the absolute index of an id + fn absolute_idx(&self, id: &DataId) -> usize { + match id.kind { + DataIdEntryKind::NonConfigurable => id.idx as usize, + DataIdEntryKind::Configurable => id.idx as usize + self.non_configurables.len(), + } + } + + /// Get entry at id + fn get(&self, id: &DataId) -> Option<&Entry> { + match id.kind { + DataIdEntryKind::NonConfigurable => self.non_configurables.get(id.idx as usize), + DataIdEntryKind::Configurable => self.configurables.get(id.idx as usize), + } + } + /// Given a [DataId], calculate the offset _from the beginning of the data section_ to the data /// in bytes. pub(crate) fn data_id_to_offset(&self, id: &DataId) -> usize { - self.raw_data_id_to_offset(id.0) + let idx = self.absolute_idx(id); + self.absolute_idx_to_offset(idx) } - /// Given a [DataId], calculate the offset _from the beginning of the data section_ to the data + /// Given an absolute index, calculate the offset _from the beginning of the data section_ to the data /// in bytes. - pub(crate) fn raw_data_id_to_offset(&self, id: u32) -> usize { - self.value_pairs - .iter() - .take(id as usize) - .fold(0, |offset, entry| { - //entries must be word aligned - size_bytes_round_up_to_word_alignment!(offset + entry.to_bytes().len()) - }) + pub(crate) fn absolute_idx_to_offset(&self, idx: usize) -> usize { + self.iter_all_entries().take(idx).fold(0, |offset, entry| { + //entries must be word aligned + size_bytes_round_up_to_word_alignment!(offset + entry.to_bytes().len()) + }) } pub(crate) fn serialize_to_bytes(&self) -> Vec { // not the exact right capacity but serves as a lower bound - let mut buf = Vec::with_capacity(self.value_pairs.len()); - for entry in &self.value_pairs { + let mut buf = Vec::with_capacity(self.num_entries()); + for entry in self.iter_all_entries() { buf.append(&mut entry.to_bytes()); //entries must be word aligned @@ -248,16 +310,12 @@ impl DataSection { /// Returns whether a specific [DataId] value has a copy type (fits in a register). pub(crate) fn has_copy_type(&self, id: &DataId) -> Option { - self.value_pairs - .get(id.0 as usize) - .map(|entry| entry.has_copy_type()) + self.get(id).map(|entry| entry.has_copy_type()) } /// Returns whether a specific [DataId] value is a byte entry. pub(crate) fn is_byte(&self, id: &DataId) -> Option { - self.value_pairs - .get(id.0 as usize) - .map(|entry| entry.is_byte()) + self.get(id).map(|entry| entry.is_byte()) } /// When generating code, sometimes a hard-coded data pointer is needed to reference @@ -268,31 +326,57 @@ impl DataSection { /// relative to the current (load) instruction. pub(crate) fn append_pointer(&mut self, pointer_value: u64) -> DataId { // The 'pointer' is just a literal 64 bit address. - self.insert_data_value(Entry::new_word(pointer_value, None, None)) + let data_id = self.insert_data_value(Entry::new_word( + pointer_value, + EntryName::NonConfigurable, + None, + )); + self.pointer_id.insert(pointer_value, data_id.clone()); + data_id + } + + /// Get the [DataId] for a pointer, if it exists. + /// The pointer must've been inserted with append_pointer. + pub(crate) fn data_id_of_pointer(&self, pointer_value: u64) -> Option { + self.pointer_id.get(&pointer_value).cloned() } /// Given any data in the form of a [Literal] (using this type mainly because it includes type - /// information and debug spans), insert it into the data section and return its offset as a + /// information and debug spans), insert it into the data section and return its handle as /// [DataId]. pub(crate) fn insert_data_value(&mut self, new_entry: Entry) -> DataId { // if there is an identical data value, use the same id - match self - .value_pairs - .iter() - .position(|entry| entry.equiv(&new_entry)) - { - Some(num) => DataId(num as u32), + + let (value_pairs, kind) = match new_entry.name { + EntryName::NonConfigurable => ( + &mut self.non_configurables, + DataIdEntryKind::NonConfigurable, + ), + EntryName::Configurable(_) => (&mut self.configurables, DataIdEntryKind::Configurable), + }; + match value_pairs.iter().position(|entry| entry.equiv(&new_entry)) { + Some(num) => DataId { + idx: num as u32, + kind, + }, None => { - self.value_pairs.push(new_entry); + value_pairs.push(new_entry); // the index of the data section where the value is stored - DataId((self.value_pairs.len() - 1) as u32) + DataId { + idx: (value_pairs.len() - 1) as u32, + kind, + } } } } // If the stored data is Datum::Word, return the inner value. pub(crate) fn get_data_word(&self, data_id: &DataId) -> Option { - self.value_pairs.get(data_id.0 as usize).and_then(|entry| { + let value_pairs = match data_id.kind { + DataIdEntryKind::NonConfigurable => &self.non_configurables, + DataIdEntryKind::Configurable => &self.configurables, + }; + value_pairs.get(data_id.idx as usize).and_then(|entry| { if let Datum::Word(w) = entry.value { Some(w) } else { @@ -322,11 +406,12 @@ impl fmt::Display for DataSection { use std::fmt::Write; let mut data_buf = String::new(); - for (ix, entry) in self.value_pairs.iter().enumerate() { + for (ix, entry) in self.iter_all_entries().enumerate() { writeln!( data_buf, - "{} {}", - DataId(ix as u32), + "data_{}_{} {}", + entry.name, + ix, display_entry(&entry.value) )?; } diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index 0e56e87d33f..5c98c09411e 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -1,4 +1,5 @@ use super::{ + data_section::EntryName, globals_section::GlobalsSection, programs::{AbstractEntry, AbstractProgram}, }; @@ -98,7 +99,12 @@ impl<'ir, 'eng> AsmBuilder for FuelAsmBuilder<'ir, 'eng> { fn compile_configurable(&mut self, config: &ConfigContent) { match config { ConfigContent::V0 { name, constant, .. } => { - let entry = Entry::from_constant(self.context, constant, Some(name.clone()), None); + let entry = Entry::from_constant( + self.context, + constant, + EntryName::Configurable(name.clone()), + None, + ); let dataid = self.data_section.insert_data_value(entry); self.configurable_v0_data_id.insert(name.clone(), dataid); } @@ -117,7 +123,7 @@ impl<'ir, 'eng> AsmBuilder for FuelAsmBuilder<'ir, 'eng> { let (decode_fn_label, _) = self.func_label_map.get(&decode_fn.get()).unwrap(); let dataid = self.data_section.insert_data_value(Entry::new_byte_array( encoded_bytes.clone(), - Some(name.clone()), + EntryName::Configurable(name.clone()), None, )); @@ -2057,6 +2063,11 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { _otherwise => { // Get the constant into the namespace. + let config_name = if let Some(name) = config_name { + EntryName::Configurable(name) + } else { + EntryName::NonConfigurable + }; let entry = Entry::from_constant(self.context, constant, config_name, None); let data_id = self.data_section.insert_data_value(entry); @@ -2177,9 +2188,11 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { } } else { let comment = comment.into(); - let data_id = self - .data_section - .insert_data_value(Entry::new_word(imm, None, None)); + let data_id = self.data_section.insert_data_value(Entry::new_word( + imm, + EntryName::NonConfigurable, + None, + )); self.cur_bytecode.push(Op { opcode: Either::Left(VirtualOp::LoadDataId(reg.clone(), data_id)), owning_span: span.clone(), diff --git a/sway-core/src/asm_generation/fuel/functions.rs b/sway-core/src/asm_generation/fuel/functions.rs index 42577c543d6..f217a4e8396 100644 --- a/sway-core/src/asm_generation/fuel/functions.rs +++ b/sway-core/src/asm_generation/fuel/functions.rs @@ -26,7 +26,7 @@ use sway_error::{ }; use sway_types::{Ident, Span}; -use super::compiler_constants::NUM_ARG_REGISTERS; +use super::{compiler_constants::NUM_ARG_REGISTERS, data_section::EntryName}; /// A summary of the adopted calling convention: /// @@ -830,9 +830,13 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { ); } _ => { - let data_id = self.data_section.insert_data_value( - Entry::from_constant(self.context, constant, None, None), - ); + let data_id = + self.data_section.insert_data_value(Entry::from_constant( + self.context, + constant, + EntryName::NonConfigurable, + None, + )); self.ptr_map.insert(*ptr, Storage::Data(data_id)); } } @@ -858,9 +862,13 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { }); } _ => { - let data_id = self.data_section.insert_data_value( - Entry::from_constant(self.context, constant, None, None), - ); + let data_id = + self.data_section.insert_data_value(Entry::from_constant( + self.context, + constant, + EntryName::NonConfigurable, + None, + )); init_mut_vars.push(InitMutVars { stack_base_words, diff --git a/sway-core/src/asm_generation/fuel/optimizations.rs b/sway-core/src/asm_generation/fuel/optimizations.rs index 4800ba6906f..7fa0da2356c 100644 --- a/sway-core/src/asm_generation/fuel/optimizations.rs +++ b/sway-core/src/asm_generation/fuel/optimizations.rs @@ -27,7 +27,7 @@ impl AbstractInstructionSet { } // What does a register contain? - #[derive(Debug)] + #[derive(Debug, PartialEq, Eq)] enum RegContents { Constant(u64), BaseOffset(VRegDef, u64), @@ -57,145 +57,184 @@ impl AbstractInstructionSet { latest_version.get(reg).cloned().unwrap_or(0) } - for op in &mut self.ops { + fn process_add( + reg_contents: &mut FxHashMap, + latest_version: &mut FxHashMap, + dest: &VirtualRegister, + opd1: &VirtualRegister, + c2: u64, + ) { + match reg_contents.get(opd1) { + Some(RegContents::Constant(c1)) if c1.checked_add(c2).is_some() => { + reg_contents.insert(dest.clone(), RegContents::Constant(c1 + c2)); + record_new_def(latest_version, dest); + } + Some(RegContents::BaseOffset(base_reg, offset)) + if get_def_version(latest_version, &base_reg.reg) == base_reg.ver + && offset.checked_add(c2).is_some() => + { + reg_contents.insert( + dest.clone(), + RegContents::BaseOffset(base_reg.clone(), offset + c2), + ); + record_new_def(latest_version, dest); + } + _ => { + let base = VRegDef { + reg: opd1.clone(), + ver: get_def_version(latest_version, opd1), + }; + reg_contents.insert(dest.clone(), RegContents::BaseOffset(base, c2)); + record_new_def(latest_version, dest); + } + } + } + + self.ops.retain_mut(|op| { + let mut retain = true; + let mut clear_state = false; + // Uncomment to debug what this optimization is doing // let op_before = op.clone(); - fn process_add( - reg_contents: &mut FxHashMap, - latest_version: &mut FxHashMap, - dest: &VirtualRegister, - opd1: &VirtualRegister, - c2: u64, - ) { - match reg_contents.get(opd1) { - Some(RegContents::Constant(c1)) if c1.checked_add(c2).is_some() => { - reg_contents.insert(dest.clone(), RegContents::Constant(c1 + c2)); - record_new_def(latest_version, dest); - } - Some(RegContents::BaseOffset(base_reg, offset)) - if get_def_version(latest_version, &base_reg.reg) == base_reg.ver - && offset.checked_add(c2).is_some() => - { - reg_contents.insert( - dest.clone(), - RegContents::BaseOffset(base_reg.clone(), offset + c2), - ); - record_new_def(latest_version, dest); - } - _ => { - let base = VRegDef { - reg: opd1.clone(), - ver: get_def_version(latest_version, opd1), - }; - reg_contents.insert(dest.clone(), RegContents::BaseOffset(base, c2)); - record_new_def(latest_version, dest); - } - } - } match &mut op.opcode { - either::Either::Left(op) => match op { - VirtualOp::ADD(dest, opd1, opd2) => { - // We don't look for the first operand being a constant and the second - // one a base register. Such patterns must be canonicalised prior. - let Some(&RegContents::Constant(c2)) = reg_contents.get(opd2) else { - reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); - continue; - }; - process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); - } - VirtualOp::ADDI(dest, opd1, opd2) => { - let c2 = opd2.value as u64; - process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); - } - VirtualOp::MUL(dest, opd1, opd2) => { - match (reg_contents.get(opd1), reg_contents.get(opd2)) { - (Some(RegContents::Constant(c1)), Some(RegContents::Constant(c2))) => { - reg_contents.insert(dest.clone(), RegContents::Constant(c1 * c2)); + either::Either::Left(op) => { + match op { + VirtualOp::ADD(dest, opd1, opd2) => { + // We don't look for the first operand being a constant and the second + // one a base register. Such patterns must be canonicalised prior. + if let Some(&RegContents::Constant(c2)) = reg_contents.get(opd2) { + process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); + } else { + reg_contents.remove(dest); record_new_def(&mut latest_version, dest); + }; + } + VirtualOp::ADDI(dest, opd1, opd2) => { + let c2 = opd2.value as u64; + process_add(&mut reg_contents, &mut latest_version, dest, opd1, c2); + } + VirtualOp::MUL(dest, opd1, opd2) => { + match (reg_contents.get(opd1), reg_contents.get(opd2)) { + ( + Some(RegContents::Constant(c1)), + Some(RegContents::Constant(c2)), + ) => { + reg_contents + .insert(dest.clone(), RegContents::Constant(c1 * c2)); + record_new_def(&mut latest_version, dest); + } + _ => { + reg_contents.remove(dest); + record_new_def(&mut latest_version, dest); + } } - _ => { + } + VirtualOp::LoadDataId(dest, data_id) => { + if let Some(c) = data_section.get_data_word(data_id) { + reg_contents.insert(dest.clone(), RegContents::Constant(c)); + } else { reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); } + record_new_def(&mut latest_version, dest); } - } - VirtualOp::LoadDataId(dest, data_id) => { - if let Some(c) = data_section.get_data_word(data_id) { - reg_contents.insert(dest.clone(), RegContents::Constant(c)); - } else { - reg_contents.remove(dest); + VirtualOp::MOVI(dest, imm) => { + reg_contents + .insert(dest.clone(), RegContents::Constant(imm.value as u64)); + record_new_def(&mut latest_version, dest); } - record_new_def(&mut latest_version, dest); - } - VirtualOp::MOVI(dest, imm) => { - reg_contents.insert(dest.clone(), RegContents::Constant(imm.value as u64)); - record_new_def(&mut latest_version, dest); - } - VirtualOp::LW(dest, addr_reg, imm) => match reg_contents.get(addr_reg) { - Some(RegContents::BaseOffset(base_reg, offset)) - if get_def_version(&latest_version, &base_reg.reg) == base_reg.ver - && ((offset / 8) + imm.value as u64) - < compiler_constants::TWELVE_BITS => - { - // bail if LW cannot read where this memory is - if offset % 8 == 0 { + VirtualOp::LW(dest, addr_reg, imm) => match reg_contents.get(addr_reg) { + Some(RegContents::BaseOffset(base_reg, offset)) + if get_def_version(&latest_version, &base_reg.reg) + == base_reg.ver + && ((offset / 8) + imm.value as u64) + < compiler_constants::TWELVE_BITS => + { + // bail if LW cannot read where this memory is + if offset % 8 == 0 { + let new_imm = VirtualImmediate12::new_unchecked( + (offset / 8) + imm.value as u64, + "Immediate offset too big for LW", + ); + let new_lw = + VirtualOp::LW(dest.clone(), base_reg.reg.clone(), new_imm); + // The register defined is no more useful for us. Forget anything from its past. + reg_contents.remove(dest); + record_new_def(&mut latest_version, dest); + // Replace the LW with a new one in-place. + *op = new_lw; + } + } + _ => { + reg_contents.remove(dest); + record_new_def(&mut latest_version, dest); + } + }, + VirtualOp::SW(addr_reg, src, imm) => match reg_contents.get(addr_reg) { + Some(RegContents::BaseOffset(base_reg, offset)) + if get_def_version(&latest_version, &base_reg.reg) + == base_reg.ver + && ((offset / 8) + imm.value as u64) + < compiler_constants::TWELVE_BITS => + { let new_imm = VirtualImmediate12::new_unchecked( (offset / 8) + imm.value as u64, - "Immediate offset too big for LW", + "Immediate offset too big for SW", + ); + let new_sw = + VirtualOp::SW(base_reg.reg.clone(), src.clone(), new_imm); + // Replace the SW with a new one in-place. + *op = new_sw; + } + _ => (), + }, + VirtualOp::MOVE(dest, src) => { + let ver = get_def_version(&latest_version, src); + if let Some(RegContents::BaseOffset(src, 0)) = reg_contents.get(src) { + if dest == &src.reg && src.ver == ver { + retain = false; + } + } else { + reg_contents.insert( + dest.clone(), + RegContents::BaseOffset( + VRegDef { + reg: src.clone(), + ver, + }, + 0, + ), ); - let new_lw = - VirtualOp::LW(dest.clone(), base_reg.reg.clone(), new_imm); - // The register defined is no more useful for us. Forget anything from its past. - reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); - // Replace the LW with a new one in-place. - *op = new_lw; } } _ => { - reg_contents.remove(dest); - record_new_def(&mut latest_version, dest); - } - }, - VirtualOp::SW(addr_reg, src, imm) => match reg_contents.get(addr_reg) { - Some(RegContents::BaseOffset(base_reg, offset)) - if get_def_version(&latest_version, &base_reg.reg) == base_reg.ver - && ((offset / 8) + imm.value as u64) - < compiler_constants::TWELVE_BITS => - { - let new_imm = VirtualImmediate12::new_unchecked( - (offset / 8) + imm.value as u64, - "Immediate offset too big for SW", - ); - let new_sw = VirtualOp::SW(base_reg.reg.clone(), src.clone(), new_imm); - // Replace the SW with a new one in-place. - *op = new_sw; - } - _ => (), - }, - _ => { - // For every Op that we don't know about, - // forget everything we know about its def registers. - for def_reg in op.def_registers() { - reg_contents.remove(def_reg); - record_new_def(&mut latest_version, def_reg); + // For every Op that we don't know about, + // forget everything we know about its def registers. + for def_reg in op.def_registers() { + reg_contents.remove(def_reg); + record_new_def(&mut latest_version, def_reg); + } } } - }, + } + either::Either::Right(ControlFlowOp::SaveRetAddr(..)) => {} either::Either::Right(_) => { - // Reset state. - latest_version.clear(); - reg_contents.clear(); + clear_state = true; } } // Uncomment to debug what this optimization is doing - // let before = op_before.opcode.to_string(); - // let after = op.opcode.to_string(); - + //let before = op_before.opcode.to_string(); + //let after = op.opcode.to_string(); // println!("{}", before); + + if clear_state { + latest_version.clear(); + reg_contents.clear(); + // println!(" state cleared"); + } + + // Uncomment to debug what this optimization is doing // if before != after { // println!(" optimized to"); // println!(" {}", after); @@ -204,7 +243,20 @@ impl AbstractInstructionSet { // println!(" - {:?} -> {:?}", k, v); // } // } - } + // if !retain { + // println!(" removed"); + // for (k, v) in reg_contents.iter() { + // println!(" - {:?} -> {:?}", k, v); + // } + // } + // if forget_def_registers { + // for def_reg in op.def_registers() { + // println!(" forget {}", def_reg.to_string()); + // } + // } + + retain + }); self } diff --git a/sway-core/src/asm_generation/fuel/programs/abstract.rs b/sway-core/src/asm_generation/fuel/programs/abstract.rs index b5a8a12e302..3256da242bb 100644 --- a/sway-core/src/asm_generation/fuel/programs/abstract.rs +++ b/sway-core/src/asm_generation/fuel/programs/abstract.rs @@ -5,7 +5,7 @@ use crate::{ abstract_instruction_set::AbstractInstructionSet, allocated_abstract_instruction_set::AllocatedAbstractInstructionSet, compiler_constants, - data_section::{DataSection, Entry}, + data_section::{DataSection, Entry, EntryName}, globals_section::GlobalsSection, register_sequencer::RegisterSequencer, }, @@ -75,7 +75,7 @@ impl AbstractProgram { pub(crate) fn is_empty(&self) -> bool { self.non_entries.is_empty() && self.entries.is_empty() - && self.data_section.value_pairs.is_empty() + && self.data_section.iter_all_entries().next().is_none() } /// Adds prologue, globals allocation, before entries, contract method switch, and allocates virtual register. @@ -164,14 +164,28 @@ impl AbstractProgram { /// Right now, it looks like this: /// /// WORD OP - /// [1] MOV $scratch $pc - /// [-] JMPF $zero i2 - /// [2] DATA_START (0-32) (in bytes, offset from $is) - /// [-] DATA_START (32-64) - /// [3] LW $ds $scratch 1 - /// [-] ADD $ds $ds $scratch - /// [4] .program_start: + /// 1 MOV $scratch $pc + /// - JMPF $zero i10 + /// 2 DATA_START (0-32) (in bytes, offset from $is) + /// - DATA_START (32-64) + /// 3 CONFIGURABLES_OFFSET (0-32) + /// - CONFIGURABLES_OFFSET (32-64) + /// 4 LW $ds $scratch 1 + /// - ADD $ds $ds $scratch + /// 5 .program_start: fn build_prologue(&mut self) -> AllocatedAbstractInstructionSet { + const _: () = assert!( + crate::PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES == 16, + "Inconsistency in the assumption of prelude organisation" + ); + const _: () = assert!( + crate::PRELUDE_CONFIGURABLES_SIZE_IN_BYTES == 8, + "Inconsistency in the assumption of prelude organisation" + ); + const _: () = assert!( + crate::PRELUDE_SIZE_IN_BYTES == 32, + "Inconsistency in the assumption of prelude organisation" + ); let label = self.reg_seqr.get_label(); AllocatedAbstractInstructionSet { ops: [ @@ -195,12 +209,18 @@ impl AbstractProgram { comment: "data section offset".into(), owning_span: None, }, + // word 3 -- full word u64 placeholder + AllocatedAbstractOp { + opcode: Either::Right(ControlFlowOp::ConfigurablesOffsetPlaceholder), + comment: "configurables offset".into(), + owning_span: None, + }, AllocatedAbstractOp { opcode: Either::Right(ControlFlowOp::Label(label)), - comment: "end of metadata".into(), + comment: "end of configurables offset".into(), owning_span: None, }, - // word 3 -- load the data offset into $ds + // word 4 -- load the data offset into $ds AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::LW( AllocatedRegister::Constant(ConstantRegister::DataSectionStart), @@ -210,7 +230,7 @@ impl AbstractProgram { comment: "".into(), owning_span: None, }, - // word 3.5 -- add $ds $ds $is + // word 4.5 -- add $ds $ds $is AllocatedAbstractOp { opcode: Either::Left(AllocatedOpcode::ADD( AllocatedRegister::Constant(ConstantRegister::DataSectionStart), @@ -281,7 +301,7 @@ impl AbstractProgram { // Put the selector in the data section. let data_label = self.data_section.insert_data_value(Entry::new_word( u32::from_be_bytes(selector) as u64, - None, + EntryName::NonConfigurable, None, )); diff --git a/sway-core/src/asm_generation/mod.rs b/sway-core/src/asm_generation/mod.rs index 2cd0e7d0605..dc7be862366 100644 --- a/sway-core/src/asm_generation/mod.rs +++ b/sway-core/src/asm_generation/mod.rs @@ -8,7 +8,8 @@ pub mod fuel; pub mod instruction_set; mod finalized_asm; -pub use finalized_asm::{CompiledBytecode, FinalizedAsm, FinalizedEntry}; +pub use finalized_asm::*; +pub use fuel::data_section::{Datum, Entry}; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ProgramKind { diff --git a/sway-core/src/asm_lang/allocated_ops.rs b/sway-core/src/asm_lang/allocated_ops.rs index b78ba37b2db..b817afd3c32 100644 --- a/sway-core/src/asm_lang/allocated_ops.rs +++ b/sway-core/src/asm_lang/allocated_ops.rs @@ -17,8 +17,10 @@ use crate::{ }, fuel_prelude::fuel_asm::{self, op}, }; -use either::Either; -use fuel_vm::fuel_asm::{op::ADDI, Imm12}; +use fuel_vm::fuel_asm::{ + op::{ADD, MOVI}, + Imm18, +}; use std::fmt::{self, Write}; use sway_types::span::Span; @@ -273,6 +275,7 @@ pub(crate) enum AllocatedOpcode { /* Non-VM Instructions */ BLOB(VirtualImmediate24), + ConfigurablesOffsetPlaceholder, DataSectionOffsetPlaceholder, LoadDataId(AllocatedRegister, DataId), AddrDataId(AllocatedRegister, DataId), @@ -397,6 +400,7 @@ impl AllocatedOpcode { /* Non-VM Instructions */ BLOB(_imm) => vec![], + ConfigurablesOffsetPlaceholder => vec![], DataSectionOffsetPlaceholder => vec![], LoadDataId(r1, _i) => vec![r1], AddrDataId(r1, _i) => vec![r1], @@ -525,6 +529,10 @@ impl fmt::Display for AllocatedOpcode { /* Non-VM Instructions */ BLOB(a) => write!(fmtr, "blob {a}"), + ConfigurablesOffsetPlaceholder => write!( + fmtr, + "CONFIGURABLES_OFFSET[0..32]\nCONFIGURABLES_OFFSET[32..64]" + ), DataSectionOffsetPlaceholder => { write!( fmtr, @@ -562,17 +570,21 @@ impl fmt::Display for AllocatedOp { } } -type DoubleWideData = [u8; 8]; +pub(crate) enum FuelAsmData { + ConfigurablesOffset([u8; 8]), + DatasectionOffset([u8; 8]), + Instructions(Vec), +} impl AllocatedOp { pub(crate) fn to_fuel_asm( &self, offset_to_data_section: u64, offset_from_instr_start: u64, - data_section: &mut DataSection, - ) -> Either, DoubleWideData> { + data_section: &DataSection, + ) -> FuelAsmData { use AllocatedOpcode::*; - Either::Left(vec![match &self.opcode { + FuelAsmData::Instructions(vec![match &self.opcode { /* Arithmetic/Logic (ALU) Instructions */ ADD(a, b, c) => op::ADD::new(a.to_reg_id(), b.to_reg_id(), c.to_reg_id()).into(), ADDI(a, b, c) => op::ADDI::new(a.to_reg_id(), b.to_reg_id(), c.value.into()).into(), @@ -641,9 +653,9 @@ impl AllocatedOp { /* Memory Instructions */ ALOC(a) => op::ALOC::new(a.to_reg_id()).into(), - CFEI(a) if a.value == 0 => return Either::Left(vec![]), + CFEI(a) if a.value == 0 => return FuelAsmData::Instructions(vec![]), CFEI(a) => op::CFEI::new(a.value.into()).into(), - CFSI(a) if a.value == 0 => return Either::Left(vec![]), + CFSI(a) if a.value == 0 => return FuelAsmData::Instructions(vec![]), CFSI(a) => op::CFSI::new(a.value.into()).into(), CFE(a) => op::CFE::new(a.to_reg_id()).into(), CFS(a) => op::CFS::new(a.to_reg_id()).into(), @@ -727,17 +739,20 @@ impl AllocatedOp { /* Non-VM Instructions */ BLOB(a) => { - return Either::Left( + return FuelAsmData::Instructions( std::iter::repeat(op::NOOP::new().into()) .take(a.value as usize) .collect(), ) } + ConfigurablesOffsetPlaceholder => { + return FuelAsmData::ConfigurablesOffset([0, 0, 0, 0, 0, 0, 0, 0]) + } DataSectionOffsetPlaceholder => { - return Either::Right(offset_to_data_section.to_be_bytes()) + return FuelAsmData::DatasectionOffset(offset_to_data_section.to_be_bytes()) } LoadDataId(a, b) => { - return Either::Left(realize_load( + return FuelAsmData::Instructions(realize_load( a, b, data_section, @@ -745,7 +760,7 @@ impl AllocatedOp { offset_from_instr_start, )) } - AddrDataId(a, b) => return Either::Left(addr_of(a, b, data_section)), + AddrDataId(a, b) => return FuelAsmData::Instructions(addr_of(a, b, data_section)), Undefined => unreachable!("Sway cannot generate undefined ASM opcodes"), }]) } @@ -755,14 +770,20 @@ impl AllocatedOp { fn addr_of( dest: &AllocatedRegister, data_id: &DataId, - data_section: &mut DataSection, + data_section: &DataSection, ) -> Vec { let offset_bytes = data_section.data_id_to_offset(data_id) as u64; - vec![fuel_asm::Instruction::ADDI(ADDI::new( - dest.to_reg_id(), - fuel_asm::RegId::new(DATA_SECTION_REGISTER), - Imm12::new(offset_bytes as u16), - ))] + vec![ + fuel_asm::Instruction::MOVI(MOVI::new( + dest.to_reg_id(), + Imm18::new(offset_bytes.try_into().unwrap()), + )), + fuel_asm::Instruction::ADD(ADD::new( + dest.to_reg_id(), + dest.to_reg_id(), + fuel_asm::RegId::new(DATA_SECTION_REGISTER), + )), + ] } /// Converts a virtual load word instruction which uses data labels into one which uses @@ -772,7 +793,7 @@ fn addr_of( fn realize_load( dest: &AllocatedRegister, data_id: &DataId, - data_section: &mut DataSection, + data_section: &DataSection, offset_to_data_section: u64, offset_from_instr_start: u64, ) -> Vec { @@ -815,7 +836,9 @@ fn realize_load( offset_to_data_section - offset_from_instr_start + offset_bytes - 4; // insert the pointer as bytes as a new data section entry at the end of the data - let data_id_for_pointer = data_section.append_pointer(pointer_offset_from_current_instr); + let data_id_for_pointer = data_section + .data_id_of_pointer(pointer_offset_from_current_instr) + .expect("Pointer offset must be in data_section"); // now load the pointer we just created into the `dest`ination let mut buf = Vec::with_capacity(2); diff --git a/sway-core/src/asm_lang/mod.rs b/sway-core/src/asm_lang/mod.rs index 5e1bcaded52..71e09cc2290 100644 --- a/sway-core/src/asm_lang/mod.rs +++ b/sway-core/src/asm_lang/mod.rs @@ -1248,6 +1248,7 @@ impl fmt::Display for VirtualOp { /* Non-VM Instructions */ BLOB(a) => write!(fmtr, "blob {a}"), DataSectionOffsetPlaceholder => write!(fmtr, "data section offset placeholder"), + ConfigurablesOffsetPlaceholder => write!(fmtr, "configurables offset placeholder"), LoadDataId(a, b) => write!(fmtr, "load {a} {b}"), AddrDataId(a, b) => write!(fmtr, "addr {a} {b}"), Undefined => write!(fmtr, "undefined op"), @@ -1277,6 +1278,8 @@ pub(crate) enum ControlFlowOp { Call(Label), // Save a return label address in a register. SaveRetAddr(Reg, Label), + // Placeholder for the offset into the configurables section. + ConfigurablesOffsetPlaceholder, // placeholder for the DataSection offset DataSectionOffsetPlaceholder, // Placeholder for loading an address from the data section. @@ -1304,6 +1307,8 @@ impl fmt::Display for ControlFlowOp { SaveRetAddr(r1, lab) => format!("mova {r1} {lab}"), DataSectionOffsetPlaceholder => "DATA SECTION OFFSET[0..32]\nDATA SECTION OFFSET[32..64]".into(), + ConfigurablesOffsetPlaceholder => + "CONFIGURABLES_OFFSET[0..32]\nCONFIGURABLES_OFFSET[32..64]".into(), LoadLabel(r1, lab) => format!("lwlab {r1} {lab}"), PushAll(lab) => format!("pusha {lab}"), PopAll(lab) => format!("popa {lab}"), @@ -1321,6 +1326,7 @@ impl ControlFlowOp { | Jump(_) | Call(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | PushAll(_) | PopAll(_) => vec![], @@ -1339,6 +1345,7 @@ impl ControlFlowOp { | Call(_) | SaveRetAddr(..) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | LoadLabel(..) | PushAll(_) | PopAll(_) => vec![], @@ -1360,6 +1367,7 @@ impl ControlFlowOp { | JumpIfNotZero(..) | Call(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | PushAll(_) | PopAll(_) => vec![], }) @@ -1381,6 +1389,7 @@ impl ControlFlowOp { | Jump(_) | Call(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | PushAll(_) | PopAll(_) => self.clone(), @@ -1410,6 +1419,7 @@ impl ControlFlowOp { | Call(_) | SaveRetAddr(..) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | LoadLabel(..) | PushAll(_) | PopAll(_) => (), @@ -1466,6 +1476,7 @@ impl ControlFlowOp { Jump(label) => Jump(*label), Call(label) => Call(*label), DataSectionOffsetPlaceholder => DataSectionOffsetPlaceholder, + ConfigurablesOffsetPlaceholder => ConfigurablesOffsetPlaceholder, PushAll(label) => PushAll(*label), PopAll(label) => PopAll(*label), diff --git a/sway-core/src/asm_lang/virtual_ops.rs b/sway-core/src/asm_lang/virtual_ops.rs index ffe3509b7cd..3d041713a4f 100644 --- a/sway-core/src/asm_lang/virtual_ops.rs +++ b/sway-core/src/asm_lang/virtual_ops.rs @@ -226,6 +226,7 @@ pub(crate) enum VirtualOp { /* Non-VM Instructions */ BLOB(VirtualImmediate24), + ConfigurablesOffsetPlaceholder, DataSectionOffsetPlaceholder, // LoadDataId takes a virtual register and a DataId, which points to a labeled piece // of data in the data section. Note that the ASM op corresponding to a LW is @@ -347,6 +348,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(_imm) => vec![], DataSectionOffsetPlaceholder => vec![], + ConfigurablesOffsetPlaceholder => vec![], LoadDataId(r1, _i) => vec![r1], AddrDataId(r1, _) => vec![r1], @@ -465,6 +467,7 @@ impl VirtualOp { // Virtual OPs | BLOB(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | Undefined => true } } @@ -571,6 +574,7 @@ impl VirtualOp { | GTF(_, _, _) | BLOB(_) | DataSectionOffsetPlaceholder + | ConfigurablesOffsetPlaceholder | LoadDataId(_, _) | AddrDataId(_, _) | Undefined => vec![], @@ -692,6 +696,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(_imm) => vec![], DataSectionOffsetPlaceholder => vec![], + ConfigurablesOffsetPlaceholder => vec![], LoadDataId(_r1, _i) => vec![], AddrDataId(_r1, _i) => vec![], @@ -815,6 +820,7 @@ impl VirtualOp { LoadDataId(r1, _i) => vec![r1], AddrDataId(r1, _i) => vec![r1], DataSectionOffsetPlaceholder => vec![], + ConfigurablesOffsetPlaceholder => vec![], Undefined => vec![], }) .into_iter() @@ -1263,6 +1269,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(i) => Self::BLOB(i.clone()), DataSectionOffsetPlaceholder => Self::DataSectionOffsetPlaceholder, + ConfigurablesOffsetPlaceholder => Self::ConfigurablesOffsetPlaceholder, LoadDataId(r1, i) => Self::LoadDataId(update_reg(reg_to_reg_map, r1), i.clone()), AddrDataId(r1, i) => Self::AddrDataId(update_reg(reg_to_reg_map, r1), i.clone()), Undefined => Self::Undefined, @@ -1743,6 +1750,7 @@ impl VirtualOp { /* Non-VM Instructions */ BLOB(imm) => AllocatedOpcode::BLOB(imm.clone()), DataSectionOffsetPlaceholder => AllocatedOpcode::DataSectionOffsetPlaceholder, + ConfigurablesOffsetPlaceholder => AllocatedOpcode::ConfigurablesOffsetPlaceholder, LoadDataId(reg1, label) => { AllocatedOpcode::LoadDataId(map_reg(&mapping, reg1), label.clone()) } diff --git a/sway-core/src/build_config.rs b/sway-core/src/build_config.rs index 711ceb014d4..4f4ad896662 100644 --- a/sway-core/src/build_config.rs +++ b/sway-core/src/build_config.rs @@ -188,6 +188,7 @@ pub struct BuildConfig { pub(crate) include_tests: bool, pub(crate) optimization_level: OptLevel, pub time_phases: bool, + pub profile: bool, pub metrics_outfile: Option, pub lsp_mode: Option, } @@ -234,6 +235,7 @@ impl BuildConfig { print_ir: PrintIr::default(), include_tests: false, time_phases: false, + profile: false, metrics_outfile: None, optimization_level: OptLevel::Opt0, lsp_mode: None, @@ -280,6 +282,10 @@ impl BuildConfig { } } + pub fn with_profile(self, a: bool) -> Self { + Self { profile: a, ..self } + } + pub fn with_metrics(self, a: Option) -> Self { Self { metrics_outfile: a, diff --git a/sway-core/src/concurrent_slab.rs b/sway-core/src/concurrent_slab.rs index 77aef759e9d..8c3d1eacf2c 100644 --- a/sway-core/src/concurrent_slab.rs +++ b/sway-core/src/concurrent_slab.rs @@ -100,6 +100,13 @@ where Arc::into_inner(old) } + pub fn replace_arc(&self, index: usize, new_value: Arc) -> Option { + let mut inner = self.inner.write(); + let item = inner.items.get_mut(index)?; + let old = item.replace(new_value)?; + Arc::into_inner(old) + } + pub fn get(&self, index: usize) -> Arc { let inner = self.inner.read(); inner.items[index] diff --git a/sway-core/src/decl_engine/id.rs b/sway-core/src/decl_engine/id.rs index 8878b9aaa79..597b716f1c1 100644 --- a/sway-core/src/decl_engine/id.rs +++ b/sway-core/src/decl_engine/id.rs @@ -1,20 +1,20 @@ -use std::collections::hash_map::DefaultHasher; -use std::hash::Hasher; -use std::marker::PhantomData; -use std::{fmt, hash::Hash}; - -use sway_types::{Named, Spanned}; - -use crate::language::ty::{TyDeclParsedType, TyTraitType}; use crate::{ decl_engine::*, engine_threading::*, language::ty::{ - TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStructDecl, TyTraitDecl, TyTraitFn, - TyTypeAliasDecl, + TyDeclParsedType, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStructDecl, TyTraitDecl, + TyTraitFn, TyTraitType, TyTypeAliasDecl, }, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + collections::hash_map::DefaultHasher, + fmt, + hash::{Hash, Hasher}, + marker::PhantomData, +}; +use sway_types::{Named, Spanned}; pub type DeclIdIndexType = usize; @@ -27,7 +27,7 @@ impl fmt::Debug for DeclId { } } -#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)] pub struct DeclUniqueId(pub(crate) u64); impl DeclId { @@ -258,3 +258,22 @@ where } } } + +impl Serialize for DeclId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } +} + +impl<'de, T> Deserialize<'de> for DeclId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let id = DeclIdIndexType::deserialize(deserializer)?; + Ok(DeclId::new(id)) + } +} diff --git a/sway-core/src/decl_engine/interface_decl_id.rs b/sway-core/src/decl_engine/interface_decl_id.rs index 2306622a94a..cba36cfd429 100644 --- a/sway-core/src/decl_engine/interface_decl_id.rs +++ b/sway-core/src/decl_engine/interface_decl_id.rs @@ -1,3 +1,4 @@ +use super::{parsed_engine::ParsedDeclEngineGet, parsed_id::ParsedDeclId}; use crate::{ decl_engine::*, engine_threading::{EqWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext}, @@ -6,8 +7,7 @@ use crate::{ ty, }, }; - -use super::{parsed_engine::ParsedDeclEngineGet, parsed_id::ParsedDeclId}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, PartialEq, Hash, Clone)] pub enum ParsedInterfaceDeclId { @@ -43,7 +43,7 @@ impl From> for ParsedInterfaceDeclId { } } -#[derive(Debug, Eq, PartialEq, Hash, Clone)] +#[derive(Debug, Eq, PartialEq, Hash, Clone, Serialize, Deserialize)] pub enum InterfaceDeclId { Abi(DeclId), Trait(DeclId), diff --git a/sway-core/src/decl_engine/parsed_id.rs b/sway-core/src/decl_engine/parsed_id.rs index 3a97459aa75..1a513a6d5be 100644 --- a/sway-core/src/decl_engine/parsed_id.rs +++ b/sway-core/src/decl_engine/parsed_id.rs @@ -1,16 +1,20 @@ -use std::hash::{DefaultHasher, Hasher}; -use std::marker::PhantomData; -use std::{fmt, hash::Hash}; - -use sway_types::{Named, Spanned}; - -use crate::engine_threading::{ - EqWithEngines, HashWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, +use super::{ + parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet, ParsedDeclEngineIndex}, + DeclUniqueId, }; -use crate::Engines; - -use super::parsed_engine::{ParsedDeclEngine, ParsedDeclEngineGet, ParsedDeclEngineIndex}; -use super::DeclUniqueId; +use crate::{ + engine_threading::{ + EqWithEngines, HashWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext, + }, + Engines, +}; +use serde::{Deserialize, Serialize}; +use std::{ + hash::{DefaultHasher, Hasher}, + marker::PhantomData, + {fmt, hash::Hash}, +}; +use sway_types::{Named, Spanned}; pub type ParsedDeclIdIndexType = usize; @@ -91,6 +95,25 @@ impl Ord for ParsedDeclId { } } +impl Serialize for ParsedDeclId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } +} + +impl<'de, T> Deserialize<'de> for ParsedDeclId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let id = usize::deserialize(deserializer)?; + Ok(ParsedDeclId::new(id)) + } +} + impl ParsedDeclId { pub(crate) fn new(id: usize) -> Self { ParsedDeclId(id, PhantomData) diff --git a/sway-core/src/decl_engine/ref.rs b/sway-core/src/decl_engine/ref.rs index 663fd563a60..d3b2d15feae 100644 --- a/sway-core/src/decl_engine/ref.rs +++ b/sway-core/src/decl_engine/ref.rs @@ -20,11 +20,6 @@ //! `fn my_function() { .. }`, and to use [DeclRef] for cases like function //! application `my_function()`. -use std::hash::{Hash, Hasher}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -35,6 +30,10 @@ use crate::{ semantic_analysis::TypeCheckContext, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; pub type DeclRefFunction = DeclRef>; pub type DeclRefTrait = DeclRef>; @@ -53,7 +52,7 @@ pub type DeclRefMixedInterface = DeclRef; /// Represents the use of / syntactic reference to a declaration. A /// smart-wrapper around a [DeclId], containing additional information about a /// declaration. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeclRef { /// The name of the declaration. // NOTE: In the case of storage, the name is "storage". @@ -103,7 +102,7 @@ where let decl_engine = ctx.engines.de(); if ctx .type_subst_map - .source_ids_contains_concrete_type(ctx.engines) + .is_some_and(|tsm| tsm.source_ids_contains_concrete_type(ctx.engines)) || !decl_engine.get(&self.id).is_concrete(ctx.engines) { let mut decl = (*decl_engine.get(&self.id)).clone(); diff --git a/sway-core/src/engine_threading.rs b/sway-core/src/engine_threading.rs index 2af209c807f..c5e48557e72 100644 --- a/sway-core/src/engine_threading.rs +++ b/sway-core/src/engine_threading.rs @@ -7,6 +7,7 @@ use std::{ cmp::Ordering, fmt, hash::{BuildHasher, Hash, Hasher}, + sync::Arc, }; use sway_types::{SourceEngine, Span}; @@ -40,7 +41,7 @@ impl Engines { &self.source_engine } - /// Removes all data associated with `program_id` from the declaration and type engines. + /// Removes all data associated with `program_id` from the engines. /// It is intended to be used during garbage collection to remove any data that is no longer needed. pub fn clear_program(&mut self, program_id: &sway_types::ProgramId) { self.type_engine.clear_program(program_id); @@ -49,7 +50,7 @@ impl Engines { self.query_engine.clear_program(program_id); } - /// Removes all data associated with `source_id` from the declaration and type engines. + /// Removes all data associated with `source_id` from the engines. /// It is intended to be used during garbage collection to remove any data that is no longer needed. pub fn clear_module(&mut self, source_id: &sway_types::SourceId) { self.type_engine.clear_module(source_id); @@ -258,6 +259,12 @@ impl HashWithEngines for Box { } } +impl HashWithEngines for Arc { + fn hash(&self, state: &mut H, engines: &Engines) { + (**self).hash(state, engines) + } +} + pub trait EqWithEngines: PartialEqWithEngines {} pub struct PartialEqWithEnginesContext<'a> { diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index ad2d5a307ff..9a986c54656 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -1,4 +1,7 @@ -use std::ops::{BitAnd, BitOr, BitXor, Not, Rem}; +use std::{ + io::Read, + ops::{BitAnd, BitOr, BitXor, Not, Rem}, +}; use crate::{ engine_threading::*, @@ -221,7 +224,7 @@ pub(crate) fn compile_constant_expression_to_constant( // definition, rather than the actual call site. ty::TyExpressionVariant::FunctionApplication { call_path, .. } => { let span = call_path.span(); - let span = if span == Span::dummy() { + let span = if span.is_dummy() { const_expr.span.clone() } else { span @@ -1363,6 +1366,136 @@ fn const_eval_intrinsic( }), } } + Intrinsic::Transmute => { + let src_type = &intrinsic.type_arguments[0]; + let src_ir_type = convert_resolved_type_id( + lookup.engines.te(), + lookup.engines.de(), + lookup.context, + src_type.type_id, + &src_type.span, + ) + .unwrap(); + + let dst_type = &intrinsic.type_arguments[1]; + let dst_ir_type = convert_resolved_type_id( + lookup.engines.te(), + lookup.engines.de(), + lookup.context, + dst_type.type_id, + &dst_type.span, + ) + .unwrap(); + + // check IR sizes match + let src_ir_type_in_bytes = src_ir_type.size(lookup.context).in_bytes(); + let dst_ir_type_in_bytes = dst_ir_type.size(lookup.context).in_bytes(); + if src_ir_type_in_bytes != dst_ir_type_in_bytes { + return Err(ConstEvalError::CompileError); + } + + fn append_bytes( + ctx: &Context<'_>, + bytes: &mut Vec, + t: &Type, + value: &ConstantValue, + ) -> Result<(), ConstEvalError> { + match t.get_content(ctx) { + TypeContent::Array(item_type, size) => match value { + ConstantValue::Array(items) => { + assert!(*size as usize == items.len()); + for item in items { + append_bytes(ctx, bytes, item_type, &item.value)?; + } + } + _ => unreachable!(), + }, + TypeContent::Uint(8) => match value { + ConstantValue::Uint(v) => { + bytes.extend((*v as u8).to_be_bytes()); + } + _ => unreachable!(), + }, + TypeContent::Uint(16) => match value { + ConstantValue::Uint(v) => { + bytes.extend([0u8, 0u8, 0u8, 0u8, 0u8, 0u8]); + bytes.extend((*v as u16).to_be_bytes()); + } + _ => unreachable!(), + }, + TypeContent::Uint(32) => match value { + ConstantValue::Uint(v) => { + bytes.extend([0u8, 0u8, 0u8, 0u8]); + bytes.extend((*v as u32).to_be_bytes()); + } + _ => unreachable!(), + }, + TypeContent::Uint(64) => match value { + ConstantValue::Uint(v) => { + bytes.extend((*v).to_be_bytes()); + } + _ => unreachable!(), + }, + _ => return Err(ConstEvalError::CompileError), + } + Ok(()) + } + + fn transmute_bytes( + ctx: &Context<'_>, + bytes: &mut std::io::Cursor>, + t: &Type, + ) -> Result { + Ok(match t.get_content(ctx) { + TypeContent::Uint(8) => { + let mut buffer = [0u8]; + let _ = bytes.read_exact(&mut buffer); + Constant { + ty: Type::get_uint8(ctx), + value: ConstantValue::Uint(buffer[0] as u64), + } + } + TypeContent::Uint(16) => { + let mut buffer = [0u8; 8]; // u16 = u64 at runtime + let _ = bytes.read_exact(&mut buffer); + let buffer = [buffer[6], buffer[7]]; + Constant { + ty: Type::get_uint16(ctx), + value: ConstantValue::Uint(u16::from_be_bytes(buffer) as u64), + } + } + TypeContent::Uint(32) => { + let mut buffer = [0u8; 8]; // u32 = u64 at runtime + let _ = bytes.read_exact(&mut buffer); + let buffer = [buffer[4], buffer[5], buffer[6], buffer[7]]; + Constant { + ty: Type::get_uint32(ctx), + value: ConstantValue::Uint(u32::from_be_bytes(buffer) as u64), + } + } + TypeContent::Uint(64) => { + let mut buffer = [0u8; 8]; + let _ = bytes.read_exact(&mut buffer); + Constant { + ty: Type::get_uint64(ctx), + value: ConstantValue::Uint(u64::from_be_bytes(buffer)), + } + } + _ => return Err(ConstEvalError::CompileError), + }) + } + + let mut runtime_bytes = vec![]; + append_bytes( + lookup.context, + &mut runtime_bytes, + &src_ir_type, + &args[0].value, + )?; + let mut cursor = std::io::Cursor::new(runtime_bytes); + let c = transmute_bytes(lookup.context, &mut cursor, &dst_ir_type)?; + Ok(Some(c)) + } } } diff --git a/sway-core/src/ir_generation/convert.rs b/sway-core/src/ir_generation/convert.rs index 4d0ee1d20c7..f95217fb2b4 100644 --- a/sway-core/src/ir_generation/convert.rs +++ b/sway-core/src/ir_generation/convert.rs @@ -184,7 +184,6 @@ fn convert_resolved_type_info( TypeInfo::Placeholder(_) => reject_type!("Placeholder"), TypeInfo::TypeParam(_) => reject_type!("TypeParam"), TypeInfo::ErrorRecovery(_) => reject_type!("Error recovery"), - TypeInfo::Storage { .. } => reject_type!("Storage"), TypeInfo::TraitType { .. } => reject_type!("TraitType"), }) } diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index c97ad7a94ff..4171056c2e7 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -660,9 +660,13 @@ impl<'eng> FnCompiler<'eng> { span_md_idx, ) } - ty::TyExpressionVariant::IntrinsicFunction(kind) => { - self.compile_intrinsic_function(context, md_mgr, kind, ast_expr.span.clone()) - } + ty::TyExpressionVariant::IntrinsicFunction(kind) => self.compile_intrinsic_function( + context, + md_mgr, + kind, + ast_expr.span.clone(), + ast_expr.return_type, + ), ty::TyExpressionVariant::AbiName(_) => { let val = Value::new_constant(context, Constant::new_unit(context)); Ok(TerminatorValue::new(val, context)) @@ -869,6 +873,7 @@ impl<'eng> FnCompiler<'eng> { span: _, }: &ty::TyIntrinsicFunctionKind, span: Span, + return_type: TypeId, ) -> Result { fn store_key_in_local_mem( compiler: &mut FnCompiler, @@ -2174,7 +2179,59 @@ impl<'eng> FnCompiler<'eng> { } Intrinsic::Slice => self.compile_intrinsic_slice(arguments, context, md_mgr), Intrinsic::ElemAt => self.compile_intrinsic_elem_at(arguments, context, md_mgr), + Intrinsic::Transmute => { + self.compile_intrinsic_transmute(arguments, return_type, context, md_mgr, &span) + } + } + } + + fn compile_intrinsic_transmute( + &mut self, + arguments: &[ty::TyExpression], + return_type: TypeId, + context: &mut Context, + md_mgr: &mut MetadataManager, + span: &Span, + ) -> Result { + assert!(arguments.len() == 1); + + let te = self.engines.te(); + let de = self.engines.de(); + + let return_type_ir_type = convert_resolved_type_id(te, de, context, return_type, span)?; + let return_type_ir_type_ptr = Type::new_ptr(context, return_type_ir_type); + + let first_argument_expr = &arguments[0]; + let first_argument_value = return_on_termination_or_extract!( + self.compile_expression_to_value(context, md_mgr, first_argument_expr)? + ); + let first_argument_type = first_argument_value + .get_type(context) + .expect("transmute first argument type not found"); + let first_argument_ptr = save_to_local_return_ptr(self, context, first_argument_value)?; + + // check IR sizes match + let first_arg_size = first_argument_type.size(context).in_bytes(); + let return_type_size = return_type_ir_type.size(context).in_bytes(); + if first_arg_size != return_type_size { + return Err(CompileError::Internal( + "Types size do not match", + span.clone(), + )); } + + let u64 = Type::get_uint64(context); + let first_argument_ptr = self + .current_block + .append(context) + .ptr_to_int(first_argument_ptr, u64); + let first_argument_ptr = self + .current_block + .append(context) + .int_to_ptr(first_argument_ptr, return_type_ir_type_ptr); + + let final_value = self.current_block.append(context).load(first_argument_ptr); + Ok(TerminatorValue::new(final_value, context)) } fn ptr_to_first_element( @@ -3975,8 +4032,9 @@ impl<'eng> FnCompiler<'eng> { if field_tys.len() != 1 && contents.is_some() { // Insert the value too. // Only store if the value does not diverge. + let contents_expr = contents.unwrap(); let contents_value = return_on_termination_or_extract!( - self.compile_expression_to_value(context, md_mgr, contents.unwrap())? + self.compile_expression_to_value(context, md_mgr, contents_expr)? ); let contents_type = contents_value.get_type(context).ok_or_else(|| { CompileError::Internal( @@ -3984,6 +4042,20 @@ impl<'eng> FnCompiler<'eng> { enum_decl.span.clone(), ) })?; + + let variant_type = field_tys[1].get_field_type(context, tag as u64).unwrap(); + if contents_type != variant_type { + return Err(CompileError::Internal( + format!( + "Expression type \"{}\" and Variant type \"{}\" do not match", + contents_type.as_string(context), + variant_type.as_string(context) + ) + .leak(), + contents_expr.span.clone(), + )); + } + let gep_val = self .current_block .append(context) @@ -4266,6 +4338,14 @@ impl<'eng> FnCompiler<'eng> { base_type: &Type, span_md_idx: Option, ) -> Result { + // Use the `struct_field_names` to get a field id that is unique even for zero-sized values that live in the same slot. + // We calculate the `unique_field_id` early, here, before the `storage_filed_names` get consumed by `get_storage_key` below. + let unique_field_id = get_storage_field_id( + &storage_field_names, + &struct_field_names, + context.experimental, + ); + // Get the actual storage key as a `Bytes32` as well as the offset, in words, // within the slot. The offset depends on what field of the top level storage // variable is being accessed. @@ -4299,7 +4379,7 @@ impl<'eng> FnCompiler<'eng> { // particular slot is the remaining offset, in words. ( add_to_b256( - get_storage_key(storage_field_names.clone(), key.clone()), + get_storage_key(storage_field_names, key, context.experimental), offset_in_slots, ), offset_remaining, @@ -4356,7 +4436,6 @@ impl<'eng> FnCompiler<'eng> { .add_metadatum(context, span_md_idx); // Store the field identifier as the third field in the `StorageKey` struct - let unique_field_id = get_storage_field_id(storage_field_names, struct_field_names); // use the struct_field_names to get a field id that is unique even for zero-sized values that live in the same slot let field_id = convert_literal_to_value(context, &Literal::B256(unique_field_id.into())) .add_metadatum(context, span_md_idx); let gep_2_val = diff --git a/sway-core/src/ir_generation/storage.rs b/sway-core/src/ir_generation/storage.rs index 14fd2b8ef00..4f42a74a2e8 100644 --- a/sway-core/src/ir_generation/storage.rs +++ b/sway-core/src/ir_generation/storage.rs @@ -3,6 +3,7 @@ use crate::fuel_prelude::{ fuel_tx::StorageSlot, fuel_types::{Bytes32, Bytes8}, }; +use sway_features::ExperimentalFeatures; use sway_ir::{ constant::{Constant, ConstantValue}, context::Context, @@ -20,28 +21,31 @@ enum InByte8Padding { } /// Hands out storage keys using storage field names or an existing key. -/// Basically returns sha256("storage::::.") +/// Basically returns sha256((0u8, "storage::::.")) /// or key if defined. -pub(super) fn get_storage_key(storage_field_names: Vec, key: Option) -> Bytes32 { - if let Some(key) = key { - return key.to_be_bytes().into(); +pub(super) fn get_storage_key( + storage_field_names: Vec, + key: Option, + experimental: ExperimentalFeatures, +) -> Bytes32 { + match key { + Some(key) => key.to_be_bytes().into(), + None => hash_storage_key_string(get_storage_key_string(&storage_field_names), experimental), } - - Hasher::hash(get_storage_key_string(storage_field_names)) } -pub fn get_storage_key_string(storage_field_names: Vec) -> String { +pub fn get_storage_key_string(storage_field_names: &[String]) -> String { if storage_field_names.len() == 1 { format!( "{}{}{}", - sway_utils::constants::STORAGE_DOMAIN, + sway_utils::constants::STORAGE_TOP_LEVEL_NAMESPACE, sway_utils::constants::STORAGE_FIELD_SEPARATOR, storage_field_names.last().unwrap(), ) } else { format!( "{}{}{}{}{}", - sway_utils::constants::STORAGE_DOMAIN, + sway_utils::constants::STORAGE_TOP_LEVEL_NAMESPACE, sway_utils::constants::STORAGE_NAMESPACE_SEPARATOR, storage_field_names .iter() @@ -56,10 +60,11 @@ pub fn get_storage_key_string(storage_field_names: Vec) -> String { } /// Hands out unique storage field ids using storage field names and struct field names. -/// Basically returns sha256("storage::::...") +/// Basically returns sha256((0u8, "storage::::...")). pub(super) fn get_storage_field_id( - storage_field_names: Vec, - struct_field_names: Vec, + storage_field_names: &[String], + struct_field_names: &[String], + experimental: ExperimentalFeatures, ) -> Bytes32 { let data = format!( "{}{}", @@ -74,7 +79,32 @@ pub(super) fn get_storage_field_id( ) } ); - Hasher::hash(data) + + hash_storage_key_string(data, experimental) +} + +fn hash_storage_key_string( + storage_key_string: String, + experimental: ExperimentalFeatures, +) -> Bytes32 { + let mut hasher = Hasher::default(); + // Certain storage types, like, e.g., `StorageMap` allow + // storage slots of their contained elements to be defined + // based on developer's input. E.g., the `key` in a `StorageMap` + // used to calculate the storage slot is a developer input. + // + // To ensure that pre-images of such storage slots can never + // be the same as a pre-image of compiler generated key of storage + // field, we prefix the pre-images with a single byte that denotes + // the domain. Storage types like `StorageMap` must have a different + // domain prefix than the `STORAGE_DOMAIN` which is 0u8. + // + // For detailed elaboration see: https://github.com/FuelLabs/sway/issues/6317 + if experimental.storage_domains { + hasher.input(sway_utils::constants::STORAGE_DOMAIN); + } + hasher.input(storage_key_string); + hasher.finalize() } use uint::construct_uint; @@ -109,17 +139,18 @@ pub fn serialize_to_storage_slots( key: Option, ty: &Type, ) -> Vec { + let experimental = context.experimental; match &constant.value { ConstantValue::Undef => vec![], // If not being a part of an aggregate, single byte values like `bool`, `u8`, and unit // are stored as a byte at the beginning of the storage slot. ConstantValue::Unit if ty.is_unit(context) => vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new([0; 32]), )], ConstantValue::Bool(b) if ty.is_bool(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new([ if *b { 1 } else { 0 }, 0, @@ -158,7 +189,7 @@ pub fn serialize_to_storage_slots( } ConstantValue::Uint(b) if ty.is_uint8(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new([ *b as u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -168,7 +199,7 @@ pub fn serialize_to_storage_slots( // Similarly, other uint values are stored at the beginning of the storage slot. ConstantValue::Uint(n) if ty.is_uint(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new( n.to_be_bytes() .iter() @@ -182,13 +213,13 @@ pub fn serialize_to_storage_slots( } ConstantValue::U256(b) if ty.is_uint_of(context, 256) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new(b.to_be_bytes()), )] } ConstantValue::B256(b) if ty.is_b256(context) => { vec![StorageSlot::new( - get_storage_key(storage_field_names, key), + get_storage_key(storage_field_names, key, experimental), Bytes32::new(b.to_be_bytes()), )] } @@ -224,8 +255,10 @@ pub fn serialize_to_storage_slots( type_size_in_bytes, ty.as_string(context) ); + + let storage_key = get_storage_key(storage_field_names, key, experimental); (0..(type_size_in_bytes + 31) / 32) - .map(|i| add_to_b256(get_storage_key(storage_field_names.clone(), key.clone()), i)) + .map(|i| add_to_b256(storage_key, i)) .zip((0..packed.len() / 4).map(|i| { Bytes32::new( Vec::from_iter((0..4).flat_map(|j| *packed[4 * i + j])) diff --git a/sway-core/src/language/asm.rs b/sway-core/src/language/asm.rs index c8fcbb429a5..409e343eef6 100644 --- a/sway-core/src/language/asm.rs +++ b/sway-core/src/language/asm.rs @@ -1,8 +1,8 @@ +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::{BaseIdent, Ident, Span}; -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Serialize, Deserialize)] pub struct AsmOp { pub(crate) op_name: Ident, pub(crate) op_args: Vec, @@ -43,7 +43,7 @@ impl PartialEq for AsmOp { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct AsmRegister { pub(crate) name: String, } diff --git a/sway-core/src/language/call_path.rs b/sway-core/src/language/call_path.rs index 8036d3ecab8..4ef90706af1 100644 --- a/sway-core/src/language/call_path.rs +++ b/sway-core/src/language/call_path.rs @@ -1,27 +1,25 @@ -use std::{ - cmp::Ordering, - fmt, - hash::{Hash, Hasher}, - sync::Arc, -}; - use crate::{ engine_threading::{ DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines, OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext, }, + parsed::QualifiedPathType, Engines, Ident, Namespace, }; - +use serde::{Deserialize, Serialize}; +use std::{ + cmp::Ordering, + fmt, + hash::{Hash, Hasher}, + sync::Arc, +}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; use sway_types::{span::Span, Spanned}; -use super::parsed::QualifiedPathType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct CallPathTree { pub qualified_call_path: QualifiedCallPath, pub children: Vec, @@ -75,7 +73,7 @@ impl OrdWithEngines for CallPathTree { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct QualifiedCallPath { pub call_path: CallPath, @@ -179,7 +177,7 @@ impl DebugWithEngines for QualifiedCallPath { /// In the expression `a::b::c()`, `a` and `b` are the prefixes and `c` is the suffix. /// `c` can be any type `T`, but in practice `c` is either an `Ident` or a `TypeInfo`. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize, Deserialize)] pub struct CallPath { pub prefixes: Vec, pub suffix: T, diff --git a/sway-core/src/language/lazy_op.rs b/sway-core/src/language/lazy_op.rs index 73e3daae256..abcb6149d26 100644 --- a/sway-core/src/language/lazy_op.rs +++ b/sway-core/src/language/lazy_op.rs @@ -1,4 +1,6 @@ -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum LazyOp { And, Or, diff --git a/sway-core/src/language/literal.rs b/sway-core/src/language/literal.rs index afedaad12d0..df0bc8735fb 100644 --- a/sway-core/src/language/literal.rs +++ b/sway-core/src/language/literal.rs @@ -1,15 +1,14 @@ use crate::{type_system::*, Engines}; - -use sway_error::error::CompileError; -use sway_types::{integer_bits::IntegerBits, span, u256::U256}; - +use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, num::{IntErrorKind, ParseIntError}, }; +use sway_error::error::CompileError; +use sway_types::{integer_bits::IntegerBits, span, u256::U256}; -#[derive(Debug, Clone, Eq)] +#[derive(Debug, Clone, Eq, Serialize, Deserialize)] pub enum Literal { U8(u8), U16(u16), diff --git a/sway-core/src/language/parsed/declaration/impl_trait.rs b/sway-core/src/language/parsed/declaration/impl_trait.rs index 48ba779155e..ed0ee15bf35 100644 --- a/sway-core/src/language/parsed/declaration/impl_trait.rs +++ b/sway-core/src/language/parsed/declaration/impl_trait.rs @@ -72,7 +72,7 @@ pub struct ImplSelfOrTrait { pub trait_decl_ref: Option, pub implementing_for: TypeArgument, pub items: Vec, - // the span of the whole impl trait and block + /// The [Span] of the whole impl trait and block. pub(crate) block_span: Span, } diff --git a/sway-core/src/language/parsed/declaration/trait.rs b/sway-core/src/language/parsed/declaration/trait.rs index 12e76e554c6..89bff7b4e94 100644 --- a/sway-core/src/language/parsed/declaration/trait.rs +++ b/sway-core/src/language/parsed/declaration/trait.rs @@ -1,7 +1,4 @@ -use std::hash::{Hash, Hasher}; - use super::{ConstantDeclaration, FunctionDeclaration, FunctionParameter}; - use crate::{ decl_engine::{parsed_id::ParsedDeclId, DeclRefTrait}, engine_threading::*, @@ -9,16 +6,18 @@ use crate::{ transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, span::Span, Named, Spanned}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum TraitItem { TraitFn(ParsedDeclId), Constant(ParsedDeclId), Type(ParsedDeclId), // to handle parser recovery: Error represents an incomplete trait item - Error(Box<[Span]>, ErrorEmitted), + Error(Box<[Span]>, #[serde(skip)] ErrorEmitted), } impl EqWithEngines for TraitItem {} @@ -75,7 +74,7 @@ impl Spanned for TraitDeclaration { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Supertrait { pub name: CallPath, pub decl_ref: Option, diff --git a/sway-core/src/language/parsed/expression/mod.rs b/sway-core/src/language/parsed/expression/mod.rs index 90d41fbf19b..d6f6f2df54b 100644 --- a/sway-core/src/language/parsed/expression/mod.rs +++ b/sway-core/src/language/parsed/expression/mod.rs @@ -1,5 +1,3 @@ -use std::{cmp::Ordering, fmt, hash::Hasher}; - use crate::{ decl_engine::parsed_id::ParsedDeclId, engine_threading::{ @@ -10,6 +8,8 @@ use crate::{ type_system::TypeBinding, Engines, TypeArgument, TypeId, }; +use serde::{Deserialize, Serialize}; +use std::{cmp::Ordering, fmt, hash::Hasher}; use sway_error::handler::ErrorEmitted; use sway_types::{ident::Ident, Span, Spanned}; @@ -198,7 +198,7 @@ impl Spanned for AmbiguousSuffix { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct QualifiedPathType { pub ty: TypeArgument, pub as_trait: TypeId, @@ -370,6 +370,7 @@ impl PartialEqWithEngines for IntrinsicFunctionExpression { pub struct WhileLoopExpression { pub condition: Box, pub body: CodeBlock, + pub is_desugared_for_loop: bool, } impl EqWithEngines for WhileLoopExpression {} diff --git a/sway-core/src/language/parsed/use_statement.rs b/sway-core/src/language/parsed/use_statement.rs index ceda688d75f..106fa21e04a 100644 --- a/sway-core/src/language/parsed/use_statement.rs +++ b/sway-core/src/language/parsed/use_statement.rs @@ -1,7 +1,8 @@ use crate::{language::Visibility, parsed::Span}; +use serde::{Deserialize, Serialize}; use sway_types::ident::Ident; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ImportType { Star, SelfImport(Span), diff --git a/sway-core/src/language/purity.rs b/sway-core/src/language/purity.rs index 4b498b2fcdd..46961a8d0df 100644 --- a/sway-core/src/language/purity.rs +++ b/sway-core/src/language/purity.rs @@ -1,7 +1,9 @@ +use serde::{Deserialize, Serialize}; + /// The purity of a function is related to its access of contract storage. If a function accesses /// or could potentially access contract storage, it is [Purity::Impure]. If a function does not utilize any /// any accesses (reads _or_ writes) of storage, then it is [Purity::Pure]. -#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub enum Purity { #[default] Pure, diff --git a/sway-core/src/language/ty/ast_node.rs b/sway-core/src/language/ty/ast_node.rs index 59d9e942004..34dcdf95572 100644 --- a/sway-core/src/language/ty/ast_node.rs +++ b/sway-core/src/language/ty/ast_node.rs @@ -1,11 +1,3 @@ -use std::{ - fmt::{self, Debug}, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Span}; - use crate::{ decl_engine::*, engine_threading::*, @@ -18,12 +10,19 @@ use crate::{ type_system::*, types::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + fmt::{self, Debug}, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Span}; pub trait GetDeclIdent { fn get_decl_ident(&self, engines: &Engines) -> Option; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyAstNode { pub content: TyAstNodeContent, pub span: Span, @@ -353,13 +352,13 @@ impl TyAstNode { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyAstNodeContent { Declaration(TyDecl), Expression(TyExpression), // a no-op node used for something that just issues a side effect, like an import statement. SideEffect(TySideEffect), - Error(Box<[Span]>, ErrorEmitted), + Error(Box<[Span]>, #[serde(skip)] ErrorEmitted), } impl EqWithEngines for TyAstNodeContent {} diff --git a/sway-core/src/language/ty/code_block.rs b/sway-core/src/language/ty/code_block.rs index 6ae9b0d0dea..77a841ff4bc 100644 --- a/sway-core/src/language/ty/code_block.rs +++ b/sway-core/src/language/ty/code_block.rs @@ -1,14 +1,13 @@ -use std::hash::Hasher; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::Span; - use crate::{ decl_engine::*, engine_threading::*, language::ty::*, semantic_analysis::TypeCheckContext, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::Hasher; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Span; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyCodeBlock { pub contents: Vec, pub(crate) whole_block_span: Span, diff --git a/sway-core/src/language/ty/declaration/abi.rs b/sway-core/src/language/ty/declaration/abi.rs index 5ad5ea2c3dc..4d3371394ed 100644 --- a/sway-core/src/language/ty/declaration/abi.rs +++ b/sway-core/src/language/ty/declaration/abi.rs @@ -1,18 +1,17 @@ +use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem}; use crate::{ engine_threading::*, language::parsed::{self, AbiDeclaration}, transform, type_system::*, }; +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::{Ident, Named, Span, Spanned}; -use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem}; - /// A [TyAbiDecl] contains the type-checked version of the parse tree's /// `AbiDeclaration`. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyAbiDecl { /// The name of the abi trait (also known as a "contract trait") pub name: Ident, @@ -76,12 +75,9 @@ impl HashWithEngines for TyAbiDecl { impl CreateTypeId for TyAbiDecl { fn create_type_id(&self, engines: &Engines) -> TypeId { - let type_engine = engines.te(); - let ty = TypeInfo::ContractCaller { - abi_name: AbiName::Known(self.name.clone().into()), - address: None, - }; - type_engine.insert(engines, ty, self.name.span().source_id()) + engines + .te() + .new_contract_caller(engines, AbiName::Known(self.name.clone().into()), None) } } diff --git a/sway-core/src/language/ty/declaration/configurable.rs b/sway-core/src/language/ty/declaration/configurable.rs index da7349fc91b..3de69ed1425 100644 --- a/sway-core/src/language/ty/declaration/configurable.rs +++ b/sway-core/src/language/ty/declaration/configurable.rs @@ -1,11 +1,3 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::{DeclId, DeclMapping, DeclRef, ReplaceDecls}, engine_threading::*, @@ -15,8 +7,15 @@ use crate::{ transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyConfigurableDecl { pub call_path: CallPath, pub value: Option, diff --git a/sway-core/src/language/ty/declaration/constant.rs b/sway-core/src/language/ty/declaration/constant.rs index c8acda6b5cf..35b675e6ace 100644 --- a/sway-core/src/language/ty/declaration/constant.rs +++ b/sway-core/src/language/ty/declaration/constant.rs @@ -1,11 +1,3 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::{DeclMapping, ReplaceDecls}, engine_threading::*, @@ -15,8 +7,15 @@ use crate::{ transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyConstantDecl { pub call_path: CallPath, pub value: Option, diff --git a/sway-core/src/language/ty/declaration/declaration.rs b/sway-core/src/language/ty/declaration/declaration.rs index 9bd68ec0046..5a9ba831149 100644 --- a/sway-core/src/language/ty/declaration/declaration.rs +++ b/sway-core/src/language/ty/declaration/declaration.rs @@ -1,3 +1,11 @@ +use crate::{ + decl_engine::*, + engine_threading::*, + language::{parsed::Declaration, ty::*, Visibility}, + type_system::*, + types::*, +}; +use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, @@ -9,15 +17,7 @@ use sway_error::{ }; use sway_types::{Ident, Named, Span, Spanned}; -use crate::{ - decl_engine::*, - engine_threading::*, - language::{parsed::Declaration, ty::*, Visibility}, - type_system::*, - types::*, -}; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyDecl { VariableDecl(Box), ConstantDecl(ConstantDecl), @@ -33,7 +33,7 @@ pub enum TyDecl { // If type parameters are defined for a function, they are put in the namespace just for // the body of that function. GenericTypeForFunctionScope(GenericTypeForFunctionScope), - ErrorRecovery(Span, ErrorEmitted), + ErrorRecovery(Span, #[serde(skip)] ErrorEmitted), StorageDecl(StorageDecl), TypeAliasDecl(TypeAliasDecl), } @@ -46,70 +46,70 @@ pub trait TyDeclParsedType { type ParsedType; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConstantDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfigurableDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TraitTypeDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct FunctionDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TraitDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct StructDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct EnumDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct EnumVariantDecl { pub enum_ref: DeclRefEnum, pub variant_name: Ident, pub variant_decl_span: Span, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ImplSelfOrTrait { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct AbiDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct GenericTypeForFunctionScope { pub name: Ident, pub type_id: TypeId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct StorageDecl { pub decl_id: DeclId, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TypeAliasDecl { pub decl_id: DeclId, } @@ -740,31 +740,9 @@ impl TyDecl { decl.return_type.type_id } TyDecl::StructDecl(StructDecl { decl_id }) => { - let decl = decl_engine.get_struct(decl_id); - type_engine.insert( - engines, - TypeInfo::Struct(*decl_id), - decl.name().span().source_id(), - ) - } - TyDecl::EnumDecl(EnumDecl { decl_id }) => { - let decl = decl_engine.get_enum(decl_id); - type_engine.insert( - engines, - TypeInfo::Enum(*decl_id), - decl.name().span().source_id(), - ) - } - TyDecl::StorageDecl(StorageDecl { decl_id, .. }) => { - let storage_decl = decl_engine.get_storage(decl_id); - type_engine.insert( - engines, - TypeInfo::Storage { - fields: storage_decl.fields_as_typed_struct_fields(), - }, - storage_decl.span().source_id(), - ) + type_engine.insert_struct(engines, *decl_id) } + TyDecl::EnumDecl(EnumDecl { decl_id }) => type_engine.insert_enum(engines, *decl_id), TyDecl::TypeAliasDecl(TypeAliasDecl { decl_id, .. }) => { let decl = decl_engine.get_type_alias(decl_id); decl.create_type_id(engines) diff --git a/sway-core/src/language/ty/declaration/enum.rs b/sway-core/src/language/ty/declaration/enum.rs index 2ce5e3eae46..126fb4549a5 100644 --- a/sway-core/src/language/ty/declaration/enum.rs +++ b/sway-core/src/language/ty/declaration/enum.rs @@ -1,26 +1,23 @@ +use crate::{ + engine_threading::*, + has_changes, + language::{parsed::EnumDeclaration, ty::TyDeclParsedType, CallPath, Visibility}, + transform, + type_system::*, +}; +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, hash::{Hash, Hasher}, }; - -use monomorphization::MonomorphizeHelper; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; use sway_types::{Ident, Named, Span, Spanned}; -use crate::{ - engine_threading::*, - has_changes, - language::{parsed::EnumDeclaration, CallPath, Visibility}, - transform, - type_system::*, -}; - -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyEnumDecl { pub call_path: CallPath, pub type_parameters: Vec, @@ -133,7 +130,7 @@ impl Spanned for TyEnumVariant { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyEnumVariant { pub name: Ident, pub type_argument: TypeArgument, diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index 8bb26f1f598..6849ccaa7db 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -1,37 +1,31 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use monomorphization::MonomorphizeHelper; -use sha2::{Digest, Sha256}; -use sway_error::handler::{ErrorEmitted, Handler}; - use crate::{ + decl_engine::*, + engine_threading::*, has_changes, + language::{parsed, ty::*, Inline, Purity, Visibility}, language::{ parsed::{FunctionDeclaration, FunctionDeclarationKind}, CallPath, }, - transform::AttributeKind, -}; - -use crate::{ - decl_engine::*, - engine_threading::*, - language::{parsed, ty::*, Inline, Purity, Visibility}, semantic_analysis::TypeCheckContext, - transform, + transform::{self, AttributeKind}, type_system::*, types::*, }; - +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::{ constants::{INLINE_ALWAYS_NAME, INLINE_NEVER_NAME}, Ident, Named, Span, Spanned, }; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyFunctionDeclKind { Default, Entry, @@ -39,7 +33,7 @@ pub enum TyFunctionDeclKind { Test, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyFunctionDecl { pub name: Ident, pub body: TyCodeBlock, @@ -489,7 +483,7 @@ impl TyFunctionDecl { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyFunctionParameter { pub name: Ident, pub is_reference: bool, diff --git a/sway-core/src/language/ty/declaration/impl_trait.rs b/sway-core/src/language/ty/declaration/impl_trait.rs index 0c2d25aa5fd..6125eeb9569 100644 --- a/sway-core/src/language/ty/declaration/impl_trait.rs +++ b/sway-core/src/language/ty/declaration/impl_trait.rs @@ -1,7 +1,4 @@ -use std::hash::{Hash, Hasher}; - -use sway_types::{Ident, Named, Span, Spanned}; - +use super::{TyDeclParsedType, TyTraitItem}; use crate::{ decl_engine::DeclRefMixedInterface, engine_threading::*, @@ -9,13 +6,14 @@ use crate::{ language::{parsed::ImplSelfOrTrait, CallPath}, type_system::*, }; - -use super::{TyDeclParsedType, TyTraitItem}; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_types::{Ident, Named, Span, Spanned}; pub type TyImplItem = TyTraitItem; // impl Trait for Type -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyImplSelfOrTrait { pub impl_type_parameters: Vec, pub trait_name: CallPath, diff --git a/sway-core/src/language/ty/declaration/storage.rs b/sway-core/src/language/ty/declaration/storage.rs index 767d5728ee7..1036159a826 100644 --- a/sway-core/src/language/ty/declaration/storage.rs +++ b/sway-core/src/language/ty/declaration/storage.rs @@ -1,20 +1,21 @@ -use std::hash::{Hash, Hasher}; - -use sway_error::{ - error::{CompileError, StructFieldUsageContext}, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ engine_threading::*, - language::{parsed::StorageDeclaration, ty::*, Visibility}, + ir_generation::storage::get_storage_key_string, + language::parsed::StorageDeclaration, transform::{self}, + ty::*, type_system::*, Namespace, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::{ + error::{CompileError, StructFieldUsageContext}, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageDecl { pub fields: Vec, pub span: Span, @@ -233,27 +234,6 @@ impl TyStorageDecl { return_type, )) } - - pub(crate) fn fields_as_typed_struct_fields(&self) -> Vec { - self.fields - .iter() - .map( - |TyStorageField { - ref name, - ref type_argument, - ref span, - ref attributes, - .. - }| TyStructField { - visibility: Visibility::Public, - name: name.clone(), - span: span.clone(), - type_argument: type_argument.clone(), - attributes: attributes.clone(), - }, - ) - .collect() - } } impl Spanned for TyStorageField { @@ -262,7 +242,7 @@ impl Spanned for TyStorageField { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageField { pub name: Ident, pub namespace_names: Vec, @@ -273,6 +253,22 @@ pub struct TyStorageField { pub attributes: transform::AttributesMap, } +impl TyStorageField { + /// Returns the full name of the [TyStorageField], consisting + /// of its name preceded by its full namespace path. + /// E.g., "storage::ns1::ns1.name". + pub fn full_name(&self) -> String { + get_storage_key_string( + &self + .namespace_names + .iter() + .map(|i| i.as_str().to_string()) + .chain(vec![self.name.as_str().to_string()]) + .collect::>(), + ) + } +} + impl EqWithEngines for TyStorageField {} impl PartialEqWithEngines for TyStorageField { fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { diff --git a/sway-core/src/language/ty/declaration/struct.rs b/sway-core/src/language/ty/declaration/struct.rs index c4dc7e3e219..e64281b1ea9 100644 --- a/sway-core/src/language/ty/declaration/struct.rs +++ b/sway-core/src/language/ty/declaration/struct.rs @@ -1,24 +1,21 @@ -use std::{ - cmp::Ordering, - hash::{Hash, Hasher}, -}; - -use monomorphization::MonomorphizeHelper; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ engine_threading::*, error::module_can_be_changed, has_changes, - language::{parsed::StructDeclaration, CallPath, Visibility}, + language::{parsed::StructDeclaration, ty::TyDeclParsedType, CallPath, Visibility}, transform, type_system::*, Namespace, }; +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; +use std::{ + cmp::Ordering, + hash::{Hash, Hasher}, +}; +use sway_types::{Ident, Named, Span, Spanned}; -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStructDecl { pub call_path: CallPath, pub fields: Vec, @@ -182,7 +179,7 @@ impl From for (bool, bool) { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyStructField { pub visibility: Visibility, pub name: Ident, diff --git a/sway-core/src/language/ty/declaration/trait.rs b/sway-core/src/language/ty/declaration/trait.rs index f0c7ee24ff3..14970814fe3 100644 --- a/sway-core/src/language/ty/declaration/trait.rs +++ b/sway-core/src/language/ty/declaration/trait.rs @@ -1,12 +1,3 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - -use monomorphization::MonomorphizeHelper; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::{ DeclEngineReplace, DeclRefConstant, DeclRefFunction, DeclRefTraitFn, DeclRefTraitType, @@ -16,6 +7,7 @@ use crate::{ has_changes, language::{ parsed::{self, TraitDeclaration}, + ty::{TyDecl, TyDeclParsedType}, CallPath, Visibility, }, semantic_analysis::{ @@ -25,10 +17,16 @@ use crate::{ transform, type_system::*, }; +use monomorphization::MonomorphizeHelper; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -use super::{TyDecl, TyDeclParsedType}; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyTraitDecl { pub name: Ident, pub type_parameters: Vec, @@ -46,7 +44,7 @@ impl TyDeclParsedType for TyTraitDecl { type ParsedType = TraitDeclaration; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyTraitInterfaceItem { TraitFn(DeclRefTraitFn), Constant(DeclRefConstant), @@ -82,7 +80,7 @@ impl DebugWithEngines for TyTraitInterfaceItem { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyTraitItem { Fn(DeclRefFunction), Constant(DeclRefConstant), diff --git a/sway-core/src/language/ty/declaration/trait_type.rs b/sway-core/src/language/ty/declaration/trait_type.rs index 24925afa457..9c9cee3e5eb 100644 --- a/sway-core/src/language/ty/declaration/trait_type.rs +++ b/sway-core/src/language/ty/declaration/trait_type.rs @@ -1,18 +1,15 @@ +use crate::{ + engine_threading::*, has_changes, language::parsed::TraitTypeDeclaration, + language::ty::TyDeclParsedType, transform, type_system::*, +}; +use serde::{Deserialize, Serialize}; use std::{ fmt, hash::{Hash, Hasher}, }; - use sway_types::{Ident, Named, Span, Spanned}; -use crate::{ - engine_threading::*, has_changes, language::parsed::TraitTypeDeclaration, transform, - type_system::*, -}; - -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyTraitType { pub name: Ident, pub attributes: transform::AttributesMap, diff --git a/sway-core/src/language/ty/declaration/type_alias.rs b/sway-core/src/language/ty/declaration/type_alias.rs index e2e5844de3f..9c41fae8f50 100644 --- a/sway-core/src/language/ty/declaration/type_alias.rs +++ b/sway-core/src/language/ty/declaration/type_alias.rs @@ -1,17 +1,14 @@ -use std::hash::{Hash, Hasher}; - -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ engine_threading::*, - language::{parsed::TypeAliasDeclaration, CallPath, Visibility}, + language::{parsed::TypeAliasDeclaration, ty::TyDeclParsedType, CallPath, Visibility}, transform, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_types::{Ident, Named, Span, Spanned}; -use super::TyDeclParsedType; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyTypeAliasDecl { pub name: Ident, pub call_path: CallPath, @@ -64,15 +61,9 @@ impl SubstTypes for TyTypeAliasDecl { impl CreateTypeId for TyTypeAliasDecl { fn create_type_id(&self, engines: &Engines) -> TypeId { - let type_engine = engines.te(); - type_engine.insert( - engines, - TypeInfo::Alias { - name: self.name.clone(), - ty: self.ty.clone(), - }, - self.name.span().source_id(), - ) + engines + .te() + .new_alias(engines, self.name.clone(), self.ty.clone()) } } diff --git a/sway-core/src/language/ty/declaration/variable.rs b/sway-core/src/language/ty/declaration/variable.rs index d7eb80ad7c6..5337651b8e5 100644 --- a/sway-core/src/language/ty/declaration/variable.rs +++ b/sway-core/src/language/ty/declaration/variable.rs @@ -1,14 +1,13 @@ -use std::hash::{Hash, Hasher}; - -use sway_types::{Ident, Named, Spanned}; - use crate::{ engine_threading::*, language::{parsed::VariableDeclaration, ty::*}, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_types::{Ident, Named, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyVariableDecl { pub name: Ident, pub body: TyExpression, diff --git a/sway-core/src/language/ty/expression/asm.rs b/sway-core/src/language/ty/expression/asm.rs index 04944125258..6e4ad95af3c 100644 --- a/sway-core/src/language/ty/expression/asm.rs +++ b/sway-core/src/language/ty/expression/asm.rs @@ -1,10 +1,9 @@ +use crate::{engine_threading::*, language::ty::*, type_system::*}; +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::Ident; -use crate::{engine_threading::*, language::ty::*, type_system::*}; - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyAsmRegisterDeclaration { pub initializer: Option, pub(crate) name: Ident, diff --git a/sway-core/src/language/ty/expression/contract.rs b/sway-core/src/language/ty/expression/contract.rs index 2bdec40421e..926aba9923c 100644 --- a/sway-core/src/language/ty/expression/contract.rs +++ b/sway-core/src/language/ty/expression/contract.rs @@ -1,6 +1,7 @@ use crate::language::ty::*; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ContractCallParams { // This is none in encoding V1 pub(crate) func_selector: Option<[u8; 4]>, diff --git a/sway-core/src/language/ty/expression/expression.rs b/sway-core/src/language/ty/expression/expression.rs index 15f57369007..4f369d3c269 100644 --- a/sway-core/src/language/ty/expression/expression.rs +++ b/sway-core/src/language/ty/expression/expression.rs @@ -1,13 +1,3 @@ -use std::{fmt, hash::Hasher}; - -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, - type_error::TypeError, - warning::{CompileWarning, Warning}, -}; -use sway_types::{Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -21,8 +11,17 @@ use crate::{ type_system::*, types::*, }; +use serde::{Deserialize, Serialize}; +use std::{fmt, hash::Hasher}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, + type_error::TypeError, + warning::{CompileWarning, Warning}, +}; +use sway_types::{Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyExpression { pub expression: TyExpressionVariant, pub return_type: TypeId, @@ -369,7 +368,7 @@ impl TyExpression { let type_engine = engines.te(); TyExpression { expression: TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None), + return_type: type_engine.id_of_error_recovery(err), span, } } diff --git a/sway-core/src/language/ty/expression/expression_variant.rs b/sway-core/src/language/ty/expression/expression_variant.rs index 9908bb09f5b..ea221466273 100644 --- a/sway-core/src/language/ty/expression/expression_variant.rs +++ b/sway-core/src/language/ty/expression/expression_variant.rs @@ -1,13 +1,3 @@ -use std::{ - collections::VecDeque, - fmt::{self, Write}, - hash::{Hash, Hasher}, -}; - -use indexmap::IndexMap; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Named, Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -20,8 +10,17 @@ use crate::{ }, type_system::*, }; +use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use std::{ + collections::VecDeque, + fmt::{self, Write}, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Named, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyExpressionVariant { Literal(Literal), FunctionApplication { diff --git a/sway-core/src/language/ty/expression/intrinsic_function.rs b/sway-core/src/language/ty/expression/intrinsic_function.rs index 4fb4e72c3bc..d7646ecf64c 100644 --- a/sway-core/src/language/ty/expression/intrinsic_function.rs +++ b/sway-core/src/language/ty/expression/intrinsic_function.rs @@ -1,18 +1,18 @@ -use std::{ - fmt, - hash::{Hash, Hasher}, -}; - use crate::{ abi_generation::abi_str::AbiStrContext, engine_threading::*, has_changes, language::ty::*, type_system::*, types::*, }; use itertools::Itertools; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + hash::{Hash, Hasher}, +}; use sway_ast::Intrinsic; use sway_error::handler::{ErrorEmitted, Handler}; use sway_types::Span; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyIntrinsicFunctionKind { pub kind: Intrinsic, pub arguments: Vec, diff --git a/sway-core/src/language/ty/expression/reassignment.rs b/sway-core/src/language/ty/expression/reassignment.rs index 54a8e740c5c..698af692dda 100644 --- a/sway-core/src/language/ty/expression/reassignment.rs +++ b/sway-core/src/language/ty/expression/reassignment.rs @@ -1,11 +1,3 @@ -use std::{ - borrow::Cow, - hash::{Hash, Hasher}, -}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Ident, Span, Spanned}; - use crate::{ decl_engine::*, engine_threading::*, @@ -17,14 +9,21 @@ use crate::{ }, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::{ + borrow::Cow, + hash::{Hash, Hasher}, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Ident, Span, Spanned}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyReassignment { pub lhs: TyReassignmentTarget, pub rhs: TyExpression, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TyReassignmentTarget { /// An [TyExpression] representing a single variable or a path /// to a part of an aggregate. @@ -258,7 +257,7 @@ impl UpdateConstantExpression for TyReassignment { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum ProjectionKind { StructField { name: Ident, diff --git a/sway-core/src/language/ty/expression/scrutinee.rs b/sway-core/src/language/ty/expression/scrutinee.rs index 68c51af26eb..78fde994732 100644 --- a/sway-core/src/language/ty/expression/scrutinee.rs +++ b/sway-core/src/language/ty/expression/scrutinee.rs @@ -1,19 +1,19 @@ -use sway_types::{Ident, Span}; - use crate::{ decl_engine::{DeclRefEnum, DeclRefStruct}, language::{ty::*, *}, type_system::*, }; +use serde::{Deserialize, Serialize}; +use sway_types::{Ident, Span}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyScrutinee { pub variant: TyScrutineeVariant, pub type_id: TypeId, pub span: Span, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum TyScrutineeVariant { Or(Vec), CatchAll, @@ -36,7 +36,7 @@ pub enum TyScrutineeVariant { Tuple(Vec), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TyStructScrutineeField { pub field: Ident, pub scrutinee: Option, diff --git a/sway-core/src/language/ty/expression/storage.rs b/sway-core/src/language/ty/expression/storage.rs index 127d64fd20b..adaa6f28730 100644 --- a/sway-core/src/language/ty/expression/storage.rs +++ b/sway-core/src/language/ty/expression/storage.rs @@ -1,13 +1,11 @@ +use super::TyExpression; +use crate::{engine_threading::*, type_system::TypeId}; +use serde::{Deserialize, Serialize}; use std::hash::{Hash, Hasher}; - use sway_types::{Ident, Span, Spanned}; -use crate::{engine_threading::*, type_system::TypeId}; - -use super::TyExpression; - /// Describes the full storage access including all the subfields -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageAccess { pub fields: Vec, pub storage_field_names: Vec, @@ -64,7 +62,7 @@ impl TyStorageAccess { } /// Describes a single subfield access in the sequence when accessing a subfield within storage. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStorageAccessDescriptor { pub name: Ident, pub type_id: TypeId, diff --git a/sway-core/src/language/ty/expression/struct_exp_field.rs b/sway-core/src/language/ty/expression/struct_exp_field.rs index 5f879640fb3..7262f38a901 100644 --- a/sway-core/src/language/ty/expression/struct_exp_field.rs +++ b/sway-core/src/language/ty/expression/struct_exp_field.rs @@ -1,8 +1,3 @@ -use std::hash::{Hash, Hasher}; - -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::Ident; - use crate::{ decl_engine::*, engine_threading::*, @@ -10,8 +5,12 @@ use crate::{ semantic_analysis::{TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext}, type_system::*, }; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Ident; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TyStructExpressionField { pub name: Ident, pub value: TyExpression, diff --git a/sway-core/src/language/ty/side_effect/include_statement.rs b/sway-core/src/language/ty/side_effect/include_statement.rs index 5d35f02b722..666e5b63a58 100644 --- a/sway-core/src/language/ty/side_effect/include_statement.rs +++ b/sway-core/src/language/ty/side_effect/include_statement.rs @@ -1,8 +1,8 @@ use crate::language::Visibility; - +use serde::{Deserialize, Serialize}; use sway_types::{ident::Ident, Span, Spanned}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TyIncludeStatement { pub span: Span, pub visibility: Visibility, diff --git a/sway-core/src/language/ty/side_effect/side_effect.rs b/sway-core/src/language/ty/side_effect/side_effect.rs index 41f2a5b945b..9e8e672c5fa 100644 --- a/sway-core/src/language/ty/side_effect/side_effect.rs +++ b/sway-core/src/language/ty/side_effect/side_effect.rs @@ -1,11 +1,12 @@ use super::{TyIncludeStatement, TyUseStatement}; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TySideEffect { pub side_effect: TySideEffectVariant, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum TySideEffectVariant { IncludeStatement(TyIncludeStatement), UseStatement(TyUseStatement), diff --git a/sway-core/src/language/ty/side_effect/use_statement.rs b/sway-core/src/language/ty/side_effect/use_statement.rs index 5d9c0cf1ca1..476a58907ef 100644 --- a/sway-core/src/language/ty/side_effect/use_statement.rs +++ b/sway-core/src/language/ty/side_effect/use_statement.rs @@ -1,7 +1,8 @@ use crate::language::parsed; +use serde::{Deserialize, Serialize}; use sway_types::{ident::Ident, Span, Spanned}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct TyUseStatement { pub call_path: Vec, pub span: Span, diff --git a/sway-core/src/language/ty/variable_mutability.rs b/sway-core/src/language/ty/variable_mutability.rs index ba2532028b6..b1831af1279 100644 --- a/sway-core/src/language/ty/variable_mutability.rs +++ b/sway-core/src/language/ty/variable_mutability.rs @@ -1,6 +1,7 @@ use crate::language::Visibility; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub enum VariableMutability { // mutable Mutable, diff --git a/sway-core/src/language/visibility.rs b/sway-core/src/language/visibility.rs index a3838e06aff..e6b19912e7e 100644 --- a/sway-core/src/language/visibility.rs +++ b/sway-core/src/language/visibility.rs @@ -1,4 +1,6 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Visibility { Private, Public, diff --git a/sway-core/src/lib.rs b/sway-core/src/lib.rs index d66b8e779eb..402a81d1242 100644 --- a/sway-core/src/lib.rs +++ b/sway-core/src/lib.rs @@ -740,6 +740,7 @@ pub fn compile_to_ast( // Parse the program to a concrete syntax tree (CST). let parse_program_opt = time_expr!( + package_name, "parse the program to a concrete syntax tree (CST)", "parse_cst", parse(input, handler, engines, build_config, experimental), @@ -764,6 +765,7 @@ pub fn compile_to_ast( // Type check (+ other static analysis) the CST to a typed AST. let typed_res = time_expr!( + package_name, "parse the concrete syntax tree (CST) to a typed AST", "parse_ast", parsed_to_ast( @@ -980,7 +982,7 @@ pub fn compile_to_bytecode( package_name: &str, experimental: ExperimentalFeatures, ) -> Result { - let asm_res = compile_to_asm( + let mut asm_res = compile_to_asm( handler, engines, input, @@ -989,13 +991,41 @@ pub fn compile_to_bytecode( package_name, experimental, )?; - asm_to_bytecode(handler, asm_res, source_map, engines.se(), build_config) + asm_to_bytecode( + handler, + &mut asm_res, + source_map, + engines.se(), + build_config, + ) +} + +/// Size of the prelude's CONFIGURABLES_OFFSET section, in bytes. +pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8; +/// Offset (in bytes) of the CONFIGURABLES_OFFSET section in the prelude. +pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16; +/// Total size of the prelude in bytes. Instructions start right after. +pub const PRELUDE_SIZE_IN_BYTES: usize = 32; + +/// Given bytecode, overwrite the existing offset to configurables offset in the prelude with the given one. +pub fn set_bytecode_configurables_offset( + compiled_bytecode: &mut CompiledBytecode, + md: &[u8; PRELUDE_CONFIGURABLES_SIZE_IN_BYTES], +) { + assert!( + compiled_bytecode.bytecode.len() + >= PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES + PRELUDE_CONFIGURABLES_SIZE_IN_BYTES + ); + let code = &mut compiled_bytecode.bytecode; + for (index, byte) in md.iter().enumerate() { + code[index + PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES] = *byte; + } } /// Given the assembly (opcodes), compile to [CompiledBytecode], containing the asm in bytecode form. pub fn asm_to_bytecode( handler: &Handler, - mut asm: CompiledAsm, + asm: &mut CompiledAsm, source_map: &mut SourceMap, source_engine: &SourceEngine, build_config: &BuildConfig, diff --git a/sway-core/src/semantic_analysis/ast_node/code_block.rs b/sway-core/src/semantic_analysis/ast_node/code_block.rs index 330b8e4e4e9..02cf5e581e7 100644 --- a/sway-core/src/semantic_analysis/ast_node/code_block.rs +++ b/sway-core/src/semantic_analysis/ast_node/code_block.rs @@ -11,15 +11,20 @@ impl ty::TyCodeBlock { ctx: &mut SymbolCollectionContext, code_block: &CodeBlock, ) -> Result<(), ErrorEmitted> { - let _ = ctx.scoped(engines, code_block.whole_block_span.clone(), |scoped_ctx| { - let _ = code_block - .contents - .iter() - .map(|node| ty::TyAstNode::collect(handler, engines, scoped_ctx, node)) - .filter_map(|res| res.ok()) - .collect::>(); - Ok(()) - }); + let _ = ctx.scoped( + engines, + code_block.whole_block_span.clone(), + None, + |scoped_ctx| { + let _ = code_block + .contents + .iter() + .map(|node| ty::TyAstNode::collect(handler, engines, scoped_ctx, node)) + .filter_map(|res| res.ok()) + .collect::>(); + Ok(()) + }, + ); Ok(()) } @@ -91,8 +96,6 @@ impl ty::TyCodeBlock { ctx: &TypeCheckContext, code_block: &TyCodeBlock, ) -> (TypeId, Span) { - let engines = ctx.engines(); - let implicit_return_span = code_block .contents .iter() @@ -122,12 +125,8 @@ impl ty::TyCodeBlock { .. }), .. - } => Some( - ctx.engines - .te() - .insert(engines, TypeInfo::Never, span.source_id()), - ), - // find the implicit return, if any, and use it as the code block's return type. + } => Some(ctx.engines.te().id_of_never()), + // Find the implicit return, if any, and use it as the code block's return type. // The fact that there is at most one implicit return is an invariant held by the parser. ty::TyAstNode { content: @@ -153,11 +152,7 @@ impl ty::TyCodeBlock { _ => None, } }) - .unwrap_or_else(|| { - ctx.engines - .te() - .insert(engines, TypeInfo::Tuple(Vec::new()), span.source_id()) - }); + .unwrap_or_else(|| ctx.engines.te().id_of_unit()); (block_type, span) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs index bb0bc9e2fb8..30db0276496 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/abi.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use sway_error::error::CompileError; use sway_types::{Ident, Named, Span, Spanned}; @@ -39,14 +39,10 @@ impl ty::TyAbiDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let abi_decl = engines.pe().get_abi(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - abi_decl.name.clone(), - Declaration::AbiDeclaration(*decl_id), - )?; + let decl = Declaration::AbiDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, abi_decl.name.clone(), decl.clone())?; - let _ = ctx.scoped(engines, abi_decl.span.clone(), |scoped_ctx| { + let _ = ctx.scoped(engines, abi_decl.span.clone(), Some(decl), |scoped_ctx| { abi_decl.interface_surface.iter().for_each(|item| { let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item); }); @@ -79,6 +75,8 @@ impl ty::TyAbiDecl { // so we don't support the case of calling a contract's own interface // from itself. This is by design. + // The span of the `abi_decl` `name` points to the file (use site) in which + // the ABI is getting declared, so we can use it as the `use_site_span`. let self_type_param = TypeParameter::new_self_type(ctx.engines, name.span()); let self_type_id = self_type_param.type_id; @@ -161,31 +159,19 @@ impl ty::TyAbiDecl { ctx.engines.de().insert(const_decl.clone(), Some(&decl_id)); new_interface_surface .push(ty::TyTraitInterfaceItem::Constant(decl_ref.clone())); - - let const_name = const_decl.call_path.suffix.clone(); - ctx.insert_symbol( - handler, - const_name.clone(), - ty::TyDecl::ConstantDecl(ty::ConstantDecl { - decl_id: *decl_ref.id(), - }), - )?; - - const_name + const_decl.call_path.suffix.clone() } TraitItem::Type(decl_id) => { let type_decl = engines.pe().get_trait_type(&decl_id).as_ref().clone(); handler.emit_err(CompileError::AssociatedTypeNotSupportedInAbi { span: type_decl.span.clone(), }); - let type_decl = ty::TyTraitType::type_check(handler, ctx.by_ref(), type_decl)?; let decl_ref = ctx.engines().de().insert(type_decl.clone(), Some(&decl_id)); new_interface_surface .push(ty::TyTraitInterfaceItem::Type(decl_ref.clone())); - type_decl.name } TraitItem::Error(_, _) => { @@ -274,6 +260,8 @@ impl ty::TyAbiDecl { (false, Span::dummy()) }; + let mut const_symbols = HashMap::::new(); + handler.scope(|handler| { for item in interface_surface.iter() { match item { @@ -337,9 +325,8 @@ impl ty::TyAbiDecl { let const_decl = decl_engine.get_constant(decl_ref); let const_name = const_decl.call_path.suffix.clone(); all_items.push(TyImplItem::Constant(decl_ref.clone())); - let _ = ctx.insert_symbol( - handler, - const_name.clone(), + const_symbols.insert( + const_name, ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id: *decl_ref.id(), }), @@ -395,10 +382,24 @@ impl ty::TyAbiDecl { } ty::TyTraitItem::Constant(decl_ref) => { let const_decl = decl_engine.get_constant(decl_ref); - all_items.push(TyImplItem::Constant(decl_engine.insert_arc( + let const_name = const_decl.name().clone(); + let const_has_value = const_decl.value.is_some(); + let decl_id = decl_engine.insert_arc( const_decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref(), - ))); + ); + all_items.push(TyImplItem::Constant(decl_id.clone())); + + // If this non-interface item has a value, then we want to overwrite the + // the previously inserted constant symbol from the interface surface. + if const_has_value { + const_symbols.insert( + const_name, + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + decl_id: *decl_id.id(), + }), + ); + } } ty::TyTraitItem::Type(decl_ref) => { let type_decl = decl_engine.get_type(decl_ref); @@ -409,6 +410,12 @@ impl ty::TyAbiDecl { } } } + + // Insert the constants into the namespace. + for (name, decl) in const_symbols.into_iter() { + let _ = ctx.insert_symbol(handler, name, decl); + } + // Insert the methods of the ABI into the namespace. // Specifically do not check for conflicting definitions because // this is just a temporary namespace for type checking and diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs index 55ef6a25e79..9efcc2392d3 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/auto_impl.rs @@ -8,14 +8,14 @@ use crate::{ Purity, }, semantic_analysis::TypeCheckContext, - Engines, TypeId, TypeInfo, TypeParameter, + Engines, TypeArgument, TypeInfo, TypeParameter, }; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; use sway_parse::Parse; -use sway_types::{integer_bits::IntegerBits, BaseIdent, Named, ProgramId, Span, Spanned}; +use sway_types::{BaseIdent, Named, ProgramId, Span, Spanned}; /// Contains all information needed to implement AbiEncode pub struct EncodingAutoImplContext<'a, 'b> @@ -38,7 +38,7 @@ where T: Parse, { // Uncomment this to see what is being generated - //println!("{}", input); + // println!("{}", input); let handler = <_>::default(); let source_id = @@ -75,11 +75,8 @@ where } else { format!( "<{}>", - itertools::intersperse( - type_parameters.iter().map(|x| { x.name_ident.as_str() }), - ", " - ) - .collect::() + itertools::intersperse(type_parameters.iter().map(|x| { x.name.as_str() }), ", ") + .collect::() ) } } @@ -94,7 +91,7 @@ where for t in type_parameters.iter() { code.push_str(&format!( "{}: {},\n", - t.name_ident.as_str(), + t.name.as_str(), itertools::intersperse( [extra_constraint].into_iter().chain( t.trait_constraints @@ -198,7 +195,7 @@ where code.push_str(&format!( "{field_name}: buffer.decode::<{field_type_name}>(),", field_name = f.name.as_str(), - field_type_name = Self::generate_type(engines, f.type_argument.type_id)?, + field_type_name = Self::generate_type(engines, &f.type_argument)?, )); } @@ -220,7 +217,7 @@ where format!("{} => {}::{}, \n", x.tag, enum_name, name) }, _ => { - let variant_type_name = Self::generate_type(engines, x.type_argument.type_id)?; + let variant_type_name = Self::generate_type(engines, &x.type_argument)?; format!("{tag_value} => {enum_name}::{variant_name}(buffer.decode::<{variant_type}>()), \n", tag_value = x.tag, enum_name = enum_name, @@ -499,92 +496,15 @@ where } } - fn generate_type(engines: &Engines, type_id: TypeId) -> Option { - let name = match &*engines.te().get(type_id) { - TypeInfo::UnknownGeneric { name, .. } => name.to_string(), - TypeInfo::Placeholder(type_param) => type_param.name_ident.to_string(), - TypeInfo::StringSlice => "str".into(), - TypeInfo::StringArray(x) => format!("str[{}]", x.val()), - TypeInfo::UnsignedInteger(x) => match x { - IntegerBits::Eight => "u8", - IntegerBits::Sixteen => "u16", - IntegerBits::ThirtyTwo => "u32", - IntegerBits::SixtyFour => "u64", - IntegerBits::V256 => "u256", - } - .into(), - TypeInfo::Boolean => "bool".into(), - TypeInfo::Custom { - qualified_call_path: call_path, - .. - } => call_path.call_path.suffix.to_string(), - TypeInfo::Tuple(fields) => { - if fields.is_empty() { - return Some("()".into()); - } - let field_strs = fields - .iter() - .map(|field| Self::generate_type(engines, field.type_id)) - .collect::>>()?; - format!("({},)", field_strs.join(", ")) - } - TypeInfo::B256 => "b256".into(), - TypeInfo::Enum(decl_id) => { - let decl = engines.de().get_enum(decl_id); - - let type_parameters = decl - .type_parameters - .iter() - .map(|x| Self::generate_type(engines, x.type_id)) - .collect::>>()? - .join(", "); - - let type_parameters = if !type_parameters.is_empty() { - format!("<{type_parameters}>") - } else { - type_parameters - }; - - format!("{}{type_parameters}", decl.call_path.suffix.as_str()) - } - TypeInfo::Struct(decl_id) => { - let decl = engines.de().get(decl_id); - - let type_parameters = decl - .type_parameters - .iter() - .map(|x| Self::generate_type(engines, x.type_id)) - .collect::>>()? - .join(", "); - - let type_parameters = if !type_parameters.is_empty() { - format!("<{type_parameters}>") - } else { - type_parameters - }; - - format!("{}{type_parameters}", decl.call_path.suffix.as_str()) - } - TypeInfo::Array(elem_ty, count) => { - format!( - "[{}; {}]", - Self::generate_type(engines, elem_ty.type_id)?, - count.val() - ) - } - TypeInfo::Slice(elem_ty) => { - format!( - "__slice[{}]", - Self::generate_type(engines, elem_ty.type_id)? - ) - } - TypeInfo::RawUntypedPtr => "raw_ptr".into(), - TypeInfo::RawUntypedSlice => "raw_slice".into(), - TypeInfo::Alias { name, .. } => name.to_string(), - _ => return None, - }; - - Some(name) + // The safest way would be to return a canonical fully qualified type path. + // We do not have a way to do this at the moment, so the best way is to use + // exactly what was typed by the user, to accommodate aliased imports. + fn generate_type(engines: &Engines, t: &TypeArgument) -> Option { + match &*engines.te().get(t.type_id) { + // when a function does not define a return type, the span points to the whole signature. + TypeInfo::Tuple(v) if v.is_empty() => Some("()".into()), + _ => Some(t.span().as_str().to_string()), + } } pub(crate) fn generate_contract_entry( @@ -616,7 +536,7 @@ where let Some(args_types) = decl .parameters .iter() - .map(|x| Self::generate_type(engines, x.type_argument.type_id)) + .map(|x| Self::generate_type(engines, &x.type_argument)) .collect::>>() else { let err = handler.emit_err(CompileError::UnknownType { @@ -641,7 +561,7 @@ where ) .collect::(); - let Some(return_type) = Self::generate_type(engines, decl.return_type.type_id) else { + let Some(return_type) = Self::generate_type(engines, &decl.return_type) else { let err = handler.emit_err(CompileError::UnknownType { span: Span::dummy(), }); @@ -677,8 +597,7 @@ where let fallback = if let Some(fallback_fn) = fallback_fn { let fallback_fn = engines.de().get(&fallback_fn); - let Some(return_type) = Self::generate_type(engines, fallback_fn.return_type.type_id) - else { + let Some(return_type) = Self::generate_type(engines, &fallback_fn.return_type) else { let err = handler.emit_err(CompileError::UnknownType { span: Span::dummy(), }); @@ -746,7 +665,7 @@ where let Some(args_types) = decl .parameters .iter() - .map(|x| Self::generate_type(engines, x.type_argument.type_id)) + .map(|x| Self::generate_type(engines, &x.type_argument)) .collect::>>() else { let err = handler.emit_err(CompileError::UnknownType { @@ -839,7 +758,7 @@ where let Some(args_types) = decl .parameters .iter() - .map(|x| Self::generate_type(engines, x.type_argument.type_id)) + .map(|x| Self::generate_type(engines, &x.type_argument)) .collect::>>() else { let err = handler.emit_err(CompileError::UnknownType { @@ -863,7 +782,7 @@ where ) .collect::(); - let Some(return_type) = Self::generate_type(engines, decl.return_type.type_id) else { + let Some(return_type) = Self::generate_type(engines, &decl.return_type) else { let err = handler.emit_err(CompileError::UnknownType { span: Span::dummy(), }); diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs index 6c9f5e7f404..7fefd0c1636 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs @@ -19,7 +19,6 @@ use crate::{ }, semantic_analysis::*, EnforceTypeArguments, Engines, SubstTypes, TypeArgument, TypeBinding, TypeCheckTypeBinding, - TypeInfo, }; impl ty::TyConfigurableDecl { @@ -68,7 +67,7 @@ impl ty::TyConfigurableDecl { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // this subst is required to replace associated types, namely TypeInfo::TraitType. type_ascription.type_id.subst(&ctx.subst_ctx()); @@ -84,7 +83,7 @@ impl ty::TyConfigurableDecl { let (value, decode_fn) = if ctx.experimental.new_encoding { let mut ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::RawUntypedSlice, None)) + .with_type_annotation(type_engine.id_of_raw_slice()) .with_help_text("Configurables must evaluate to slices."); let value = value.map(|value| { @@ -93,21 +92,9 @@ impl ty::TyConfigurableDecl { }); let mut arguments = VecDeque::default(); - arguments.push_back( - engines - .te() - .insert(engines, TypeInfo::RawUntypedSlice, None), - ); - arguments.push_back(engines.te().insert( - engines, - TypeInfo::UnsignedInteger(sway_types::integer_bits::IntegerBits::SixtyFour), - None, - )); - arguments.push_back( - engines - .te() - .insert(engines, TypeInfo::RawUntypedSlice, None), - ); + arguments.push_back(engines.te().id_of_raw_slice()); + arguments.push_back(engines.te().id_of_u64()); + arguments.push_back(engines.te().id_of_raw_slice()); let value_span = value .as_ref() diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs index e5cca67ecde..6a0c788d2a8 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/constant.rs @@ -61,7 +61,7 @@ impl ty::TyConstantDecl { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // this subst is required to replace associated types, namely TypeInfo::TraitType. type_ascription.type_id.subst(&ctx.subst_ctx()); @@ -129,7 +129,7 @@ impl ty::TyConstantDecl { call_path, span, attributes: Default::default(), - return_type: type_engine.insert(engines, TypeInfo::Unknown, None), + return_type: type_engine.new_unknown(), type_ascription, value: None, visibility, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index 663891261bd..6047c8776aa 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -157,8 +157,7 @@ impl TyDecl { let fn_decl = engines.pe().get_function(&decl_id); let span = fn_decl.span.clone(); - let mut ctx = - ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.with_type_annotation(type_engine.new_unknown()); let fn_decl = match ty::TyFunctionDecl::type_check( handler, ctx.by_ref(), @@ -188,26 +187,20 @@ impl TyDecl { // save decl_refs for the LSP for supertrait in trait_decl.supertraits.iter_mut() { - let _ = ctx - .namespace() - .resolve_call_path_typed( - handler, - engines, - &supertrait.name, - ctx.self_type(), - ) - .map(|supertrait_decl| { - if let ty::TyDecl::TraitDecl(ty::TraitDecl { - decl_id: supertrait_decl_id, - }) = supertrait_decl - { - supertrait.decl_ref = Some(DeclRef::new( - engines.de().get(&supertrait_decl_id).name.clone(), - supertrait_decl_id, - engines.de().get(&supertrait_decl_id).span.clone(), - )); - } - }); + let _ = + ctx.resolve_call_path(handler, &supertrait.name) + .map(|supertrait_decl| { + if let ty::TyDecl::TraitDecl(ty::TraitDecl { + decl_id: supertrait_decl_id, + }) = supertrait_decl + { + supertrait.decl_ref = Some(DeclRef::new( + engines.de().get(&supertrait_decl_id).name.clone(), + supertrait_decl_id, + engines.de().get(&supertrait_decl_id).span.clone(), + )); + } + }); } let decl: ty::TyDecl = decl_engine @@ -302,12 +295,7 @@ impl TyDecl { // Choose which items are going to be visible depending if this is an abi impl // or trait impl - let t = ctx.namespace().resolve_call_path_typed( - &Handler::default(), - engines, - &impl_trait.trait_name, - ctx.self_type(), - ); + let t = ctx.resolve_call_path(&Handler::default(), &impl_trait.trait_name); let empty_vec = vec![]; let impl_trait_items = if let Ok(ty::TyDecl::TraitDecl { .. }) = t { @@ -370,26 +358,20 @@ impl TyDecl { // save decl_refs for the LSP for supertrait in abi_decl.supertraits.iter_mut() { - let _ = ctx - .namespace() - .resolve_call_path_typed( - handler, - engines, - &supertrait.name, - ctx.self_type(), - ) - .map(|supertrait_decl| { - if let ty::TyDecl::TraitDecl(ty::TraitDecl { - decl_id: supertrait_decl_id, - }) = supertrait_decl - { - supertrait.decl_ref = Some(DeclRef::new( - engines.de().get(&supertrait_decl_id).name.clone(), - supertrait_decl_id, - engines.de().get(&supertrait_decl_id).span.clone(), - )); - } - }); + let _ = + ctx.resolve_call_path(handler, &supertrait.name) + .map(|supertrait_decl| { + if let ty::TyDecl::TraitDecl(ty::TraitDecl { + decl_id: supertrait_decl_id, + }) = supertrait_decl + { + supertrait.decl_ref = Some(DeclRef::new( + engines.de().get(&supertrait_decl_id).name.clone(), + supertrait_decl_id, + engines.de().get(&supertrait_decl_id).span.clone(), + )); + } + }); } let decl: ty::TyDecl = decl_engine.insert(abi_decl.clone(), Some(&decl_id)).into(); @@ -442,25 +424,32 @@ impl TyDecl { let initializer = ty::TyExpression::type_check(handler, ctx.by_ref(), &initializer)?; - let mut key_ty_expression = None; - if let Some(key_expression) = key_expression { - let mut key_ctx = ctx.with_type_annotation(engines.te().insert( - engines, - TypeInfo::B256, - None, - )); - - key_ty_expression = Some(ty::TyExpression::type_check( - handler, - key_ctx.by_ref(), - &key_expression, - )?); - } + let key_expression = match key_expression { + Some(key_expression) => { + let key_ctx = ctx + .with_type_annotation(engines.te().id_of_b256()) + .with_help_text("Storage keys must have type \"b256\"."); + + // TODO: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. + // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is + // not treated as an error in the `type_check()`'s result. + let typed_expr = handler.scope(|handler| { + ty::TyExpression::type_check( + handler, + key_ctx, + &key_expression, + ) + })?; + + Some(typed_expr) + } + None => None, + }; fields_buf.push(ty::TyStorageField { name, namespace_names: namespace_names.clone(), - key_expression: key_ty_expression, + key_expression, type_argument, initializer, span: field_span, @@ -522,9 +511,7 @@ impl TyDecl { // Resolve the type that the type alias replaces let new_ty = ctx .resolve_type(handler, ty.type_id, &span, EnforceTypeArguments::Yes, None) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // create the type alias decl using the resolved type above let decl = ty::TyTypeAliasDecl { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs index 0434857f18f..5f564978960 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/enum.rs @@ -16,15 +16,13 @@ impl ty::TyEnumDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let enum_decl = engines.pe().get_enum(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - enum_decl.name.clone(), - Declaration::EnumDeclaration(*decl_id), - )?; + let decl = Declaration::EnumDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, enum_decl.name.clone(), decl.clone())?; // create a namespace for the decl, used to create a scope for generics - let _ = ctx.scoped(engines, enum_decl.span.clone(), |mut _ctx| Ok(())); + let _ = ctx.scoped(engines, enum_decl.span.clone(), Some(decl), |mut _ctx| { + Ok(()) + }); Ok(()) } @@ -87,7 +85,6 @@ impl ty::TyEnumVariant { variant: EnumVariant, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let mut type_argument = variant.type_argument; type_argument.type_id = ctx .resolve_type( @@ -97,7 +94,7 @@ impl ty::TyEnumVariant { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Ok(ty::TyEnumVariant { name: variant.name.clone(), type_argument, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs index 4b5b306cb98..2b1fcd5d5a2 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function.rs @@ -28,15 +28,11 @@ impl ty::TyFunctionDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let fn_decl = engines.pe().get_function(decl_id); - let _ = ctx.insert_parsed_symbol( - handler, - engines, - fn_decl.name.clone(), - Declaration::FunctionDeclaration(*decl_id), - ); + let decl = Declaration::FunctionDeclaration(*decl_id); + let _ = ctx.insert_parsed_symbol(handler, engines, fn_decl.name.clone(), decl.clone()); // create a namespace for the function - let _ = ctx.scoped(engines, fn_decl.span.clone(), |scoped_ctx| { + let _ = ctx.scoped(engines, fn_decl.span.clone(), Some(decl), |scoped_ctx| { TyCodeBlock::collect(handler, engines, scoped_ctx, &fn_decl.body) }); Ok(()) @@ -85,7 +81,6 @@ impl ty::TyFunctionDecl { let mut return_type = fn_decl.return_type.clone(); let type_engine = ctx.engines.te(); - let engines = ctx.engines(); // If functions aren't allowed in this location, return an error. if ctx.functions_disallowed() { @@ -146,9 +141,7 @@ impl ty::TyFunctionDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let (visibility, is_contract_call) = if is_method { if is_in_impl_self { @@ -329,7 +322,7 @@ impl TypeCheckFinalization for ty::TyFunctionDecl { fn test_function_selector_behavior() { use crate::language::Visibility; use crate::Engines; - use sway_types::{integer_bits::IntegerBits, Ident, Span}; + use sway_types::{Ident, Span}; let engines = Engines::default(); let handler = Handler::default(); @@ -373,11 +366,7 @@ fn test_function_selector_behavior() { mutability_span: Span::dummy(), type_argument: engines .te() - .insert( - &engines, - TypeInfo::StringArray(Length::new(5, Span::dummy())), - None, - ) + .insert_string_array_without_annotations(&engines, 5) .into(), }, ty::TyFunctionParameter { @@ -386,16 +375,10 @@ fn test_function_selector_behavior() { is_mutable: false, mutability_span: Span::dummy(), type_argument: TypeArgument { - type_id: engines.te().insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), - None, - ), - initial_type_id: engines.te().insert( - &engines, - TypeInfo::StringArray(Length::new(5, Span::dummy())), - None, - ), + type_id: engines.te().id_of_u32(), + initial_type_id: engines + .te() + .insert_string_array_without_annotations(&engines, 5), span: Span::dummy(), call_path_tree: None, }, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs index 324a2d14404..be929464af6 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/function/function_parameter.rs @@ -17,7 +17,6 @@ impl ty::TyFunctionParameter { parameter: FunctionParameter, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let FunctionParameter { name, @@ -35,7 +34,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); type_argument.type_id.check_type_parameter_bounds( handler, @@ -71,7 +70,6 @@ impl ty::TyFunctionParameter { parameter: &FunctionParameter, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let FunctionParameter { name, @@ -90,7 +88,7 @@ impl ty::TyFunctionParameter { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let typed_parameter = ty::TyFunctionParameter { name: name.clone(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs index 8d88a8989d8..f881cbbef60 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs @@ -9,7 +9,7 @@ use sway_error::{ error::{CompileError, InterfaceName}, handler::{ErrorEmitted, Handler}, }; -use sway_types::{Ident, Span, Spanned}; +use sway_types::{Ident, Named, Span, Spanned}; use crate::{ decl_engine::{parsed_id::ParsedDeclId, *}, @@ -17,12 +17,12 @@ use crate::{ language::{ parsed::*, ty::{ - self, TyConstantDecl, TyDecl, TyFunctionDecl, TyImplItem, TyImplSelfOrTrait, - TyTraitInterfaceItem, TyTraitItem, TyTraitType, + self, ConstantDecl, TyConstantDecl, TyDecl, TyFunctionDecl, TyImplItem, + TyImplSelfOrTrait, TyTraitInterfaceItem, TyTraitItem, TyTraitType, }, *, }, - namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure}, + namespace::{IsExtendingExistingImpl, IsImplSelf, TraitMap, TryInsertingTraitImplOnFailure}, semantic_analysis::{ symbol_collection_context::SymbolCollectionContext, AbiMode, ConstShadowingMode, TyNodeDepGraphNodeId, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, @@ -39,27 +39,34 @@ impl TyImplSelfOrTrait { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let impl_trait = engines.pe().get_impl_self_or_trait(decl_id); + + let decl = Declaration::ImplSelfOrTrait(*decl_id); ctx.insert_parsed_symbol( handler, engines, impl_trait.trait_name.suffix.clone(), - Declaration::ImplSelfOrTrait(*decl_id), + decl.clone(), )?; - let _ = ctx.scoped(engines, impl_trait.block_span.clone(), |scoped_ctx| { - impl_trait.items.iter().for_each(|item| match item { - ImplItem::Fn(decl_id) => { - let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); - } - ImplItem::Constant(decl_id) => { - let _ = TyConstantDecl::collect(handler, engines, scoped_ctx, decl_id); - } - ImplItem::Type(decl_id) => { - let _ = TyTraitType::collect(handler, engines, scoped_ctx, decl_id); - } - }); - Ok(()) - }); + let _ = ctx.scoped( + engines, + impl_trait.block_span.clone(), + Some(decl), + |scoped_ctx| { + impl_trait.items.iter().for_each(|item| match item { + ImplItem::Fn(decl_id) => { + let _ = TyFunctionDecl::collect(handler, engines, scoped_ctx, decl_id); + } + ImplItem::Constant(decl_id) => { + let _ = TyConstantDecl::collect(handler, engines, scoped_ctx, decl_id); + } + ImplItem::Type(decl_id) => { + let _ = TyTraitType::collect(handler, engines, scoped_ctx, decl_id); + } + }); + Ok(()) + }, + ); Ok(()) } @@ -83,8 +90,13 @@ impl TyImplSelfOrTrait { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - // Create a new type parameter for the Self type - let self_type_param = TypeParameter::new_self_type(engines, implementing_for.span()); + // Create a new type parameter for the Self type. + // For the `use_site_span` of the self type parameter we take the `block_span`. + // This is the span of the whole impl trait and block and thus, points to + // the code in the source file in which the self type is used in the implementation. + let self_type_use_site_span = block_span.clone(); + let self_type_param = + TypeParameter::new_self_type(engines, self_type_use_site_span.clone()); let self_type_id = self_type_param.type_id; // create a namespace for the impl @@ -157,14 +169,10 @@ impl TyImplSelfOrTrait { // Update the context let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_self_type(Some(implementing_for.type_id)); - let impl_trait = match ctx - .namespace() - .resolve_call_path_typed(handler, engines, &trait_name, ctx.self_type()) - .ok() - { + let impl_trait = match ctx.resolve_call_path(handler, &trait_name).ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { let mut trait_decl = (*decl_engine.get_trait(&decl_id)).clone(); @@ -248,7 +256,7 @@ impl TyImplSelfOrTrait { } let self_type_param = - TypeParameter::new_self_type(engines, abi.span.clone()); + TypeParameter::new_self_type(engines, self_type_use_site_span); // Unify the "self" type param from the abi declaration with // the type that we are implementing for. handler.scope(|h| { @@ -340,9 +348,11 @@ impl TyImplSelfOrTrait { ctx.with_const_shadowing_mode(ConstShadowingMode::ItemStyle) .allow_functions() .scoped(handler, Some(block_span.clone()), |mut ctx| { - // Create a new type parameter for the "self type". + // Create a new type parameter for the self type. let self_type_param = - TypeParameter::new_self_type(engines, implementing_for.span()); + // Same as with impl trait or ABI, we take the `block_span` as the `use_site_span` + // of the self type. + TypeParameter::new_self_type(engines, block_span.clone()); let self_type_id = self_type_param.type_id; // create the trait name @@ -413,7 +423,7 @@ impl TyImplSelfOrTrait { let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); // type check the items inside of the impl block let mut new_items = vec![]; @@ -688,20 +698,19 @@ fn type_check_trait_implementation( ctx.namespace_mut() .module_mut(engines) .write(engines, |m| { - m.current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - handler, - implementing_for, - &trait_supertraits - .iter() - .map(|x| x.into()) - .collect::>(), - block_span, - engines, - TryInsertingTraitImplOnFailure::Yes, - code_block_first_pass.into(), - ) + TraitMap::check_if_trait_constraints_are_satisfied_for_type( + handler, + m, + implementing_for, + &trait_supertraits + .iter() + .map(|x| x.into()) + .collect::>(), + block_span, + engines, + TryInsertingTraitImplOnFailure::Yes, + code_block_first_pass.into(), + ) })?; for (type_arg, type_param) in trait_type_arguments.iter().zip(trait_type_parameters) { @@ -854,41 +863,29 @@ fn type_check_trait_implementation( let decl_ref = decl_engine.insert(type_decl.clone(), Some(decl_id)); impld_item_refs.insert((name, implementing_for), TyTraitItem::Type(decl_ref)); - let old_type_decl_info1 = TypeInfo::TraitType { - name: type_decl.name.clone(), - trait_type_id: implementing_for, - }; - let old_type_decl_info2 = TypeInfo::TraitType { - name: type_decl.name.clone(), - trait_type_id: type_engine.insert( - engines, - TypeInfo::UnknownGeneric { - // Using Span::dummy just to match the type substitution, type is not used anywhere else. - name: Ident::new_with_override("Self".into(), Span::dummy()), - trait_constraints: VecSet(vec![]), - parent: None, - is_from_type_parameter: false, - }, - None, - ), - }; + // We want the `Self` type to have the span that points to an arbitrary location within + // the source file in which the trait is implemented for a type. The `trait_name` points + // to the name in the `impl for ...` and is thus a good candidate. + let self_type_id = type_engine + .new_unknown_generic_self(trait_name.span(), false) + .0; if let Some(type_arg) = type_decl.ty.clone() { trait_type_mapping.extend( &TypeSubstMap::from_type_parameters_and_type_arguments( - vec![type_engine.insert( + vec![type_engine.insert_trait_type( engines, - old_type_decl_info1, - type_decl.name.span().source_id(), + type_decl.name.clone(), + implementing_for, )], vec![type_arg.type_id], ), ); trait_type_mapping.extend( &TypeSubstMap::from_type_parameters_and_type_arguments( - vec![type_engine.insert( + vec![type_engine.insert_trait_type( engines, - old_type_decl_info2, - type_decl.name.span().source_id(), + type_decl.name.clone(), + self_type_id, )], vec![type_arg.type_id], ), @@ -898,6 +895,54 @@ fn type_check_trait_implementation( } } + for item in impl_items { + match item { + ImplItem::Fn(_impl_method_id) => {} + ImplItem::Constant(decl_id) => { + let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); + let mut const_decl = type_check_const_decl( + handler, + ctx.by_ref().with_type_subst(&trait_type_mapping), + &const_decl, + trait_name, + is_contract, + &impld_item_refs, + &constant_checklist, + ) + .unwrap_or_else(|_| ty::TyConstantDecl::error(ctx.engines(), const_decl.clone())); + + const_decl.subst(&SubstTypesContext::new( + engines, + &trait_type_mapping, + !ctx.code_block_first_pass(), + )); + + // Remove this constant from the checklist. + let name = const_decl.call_path.suffix.clone(); + constant_checklist.remove(&name); + + // Add this constant to the "impld decls". + let decl_ref = decl_engine.insert(const_decl, Some(decl_id)); + impld_item_refs.insert( + (name.clone(), implementing_for), + TyTraitItem::Constant(decl_ref.clone()), + ); + + let prev_const_shadowing_mode = ctx.const_shadowing_mode; + ctx.const_shadowing_mode = ConstShadowingMode::Allow; + let _ = ctx.insert_symbol( + handler, + name, + TyDecl::ConstantDecl(ConstantDecl { + decl_id: *decl_ref.id(), + }), + ); + ctx.const_shadowing_mode = prev_const_shadowing_mode; + } + ImplItem::Type(_) => {} + } + } + for item in impl_items { match item { ImplItem::Fn(impl_method_id) => { @@ -929,33 +974,7 @@ fn type_check_trait_implementation( let decl_ref = decl_engine.insert(impl_method, Some(impl_method_id)); impld_item_refs.insert((name, implementing_for), TyTraitItem::Fn(decl_ref)); } - ImplItem::Constant(decl_id) => { - let const_decl = engines.pe().get_constant(decl_id).as_ref().clone(); - let mut const_decl = type_check_const_decl( - handler, - ctx.by_ref().with_type_subst(&trait_type_mapping), - &const_decl, - trait_name, - is_contract, - &impld_item_refs, - &constant_checklist, - ) - .unwrap_or_else(|_| ty::TyConstantDecl::error(ctx.engines(), const_decl.clone())); - - const_decl.subst(&SubstTypesContext::new( - engines, - &trait_type_mapping, - !ctx.code_block_first_pass(), - )); - - // Remove this constant from the checklist. - let name = const_decl.call_path.suffix.clone(); - constant_checklist.remove(&name); - - // Add this constant to the "impld decls". - let decl_ref = decl_engine.insert(const_decl, Some(decl_id)); - impld_item_refs.insert((name, implementing_for), TyTraitItem::Constant(decl_ref)); - } + ImplItem::Constant(_decl_id) => {} ImplItem::Type(_) => {} } } @@ -1106,7 +1125,7 @@ fn type_check_impl_method( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let interface_name = || -> InterfaceName { if is_contract { @@ -1315,6 +1334,50 @@ fn type_check_impl_method( }) } +fn trait_const_item_value( + trait_decl: TyDecl, + engines: &Engines, + const_decl: &TyConstantDecl, +) -> Option { + fn get_const_decl_from_trait_items( + engines: &Engines, + items: &[TyTraitInterfaceItem], + name: &Ident, + ) -> Option> { + for item in items.iter() { + match item { + TyTraitInterfaceItem::Constant(decl) => { + let const_decl = engines.de().get_constant(decl.id()); + if const_decl.name() == name { + return Some(const_decl); + } + } + _ => continue, + } + } + None + } + + let trait_or_abi_const_decl = match trait_decl { + TyDecl::TraitDecl(decl) => get_const_decl_from_trait_items( + engines, + &engines.de().get_trait(&decl.decl_id).interface_surface, + const_decl.name(), + ), + TyDecl::AbiDecl(decl) => get_const_decl_from_trait_items( + engines, + &engines.de().get_abi(&decl.decl_id).interface_surface, + const_decl.name(), + ), + _ => unreachable!(), + }; + + match trait_or_abi_const_decl { + Some(trait_or_abi_const_decl) => trait_or_abi_const_decl.value.clone(), + None => None, + } +} + #[allow(clippy::too_many_arguments)] fn type_check_const_decl( handler: &Handler, @@ -1335,7 +1398,7 @@ fn type_check_const_decl( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let interface_name = || -> InterfaceName { if is_contract { @@ -1346,10 +1409,25 @@ fn type_check_const_decl( }; // type check the constant declaration - let const_decl = ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; + let mut const_decl = ty::TyConstantDecl::type_check(handler, ctx.by_ref(), const_decl.clone())?; let const_name = const_decl.call_path.suffix.clone(); + // Ensure that there is an expression if the constant in the base trait is not defined. + let trait_decl = ctx.resolve_call_path(handler, trait_name)?; + + let trait_const_item_value = trait_const_item_value(trait_decl, engines, &const_decl); + if trait_const_item_value.is_none() && const_decl.value.is_none() { + return Err(handler.emit_err(CompileError::ConstantRequiresExpression { + span: const_decl.span.clone(), + })); + } + + // Ensure the constant decl has a value, if none was set then it inherits the base trait/abi value. + if const_decl.value.is_none() { + const_decl.value = trait_const_item_value; + } + // Ensure that there aren't multiple definitions of this constant if impld_constant_ids.contains_key(&(const_name.clone(), self_type_id)) { return Err( @@ -1416,7 +1494,7 @@ fn type_check_type_decl( let mut ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let interface_name = || -> InterfaceName { if is_contract { @@ -1572,14 +1650,8 @@ fn handle_supertraits( } match ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed( - &Handler::default(), - engines, - &supertrait.name, - ctx.self_type(), - ) + .resolve_call_path(&Handler::default(), &supertrait.name) .ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs index 08e0984b7ed..7df2bb722d4 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/storage.rs @@ -4,8 +4,7 @@ use crate::{ decl_engine::parsed_id::ParsedDeclId, fuel_prelude::fuel_tx::StorageSlot, ir_generation::{ - const_eval::compile_constant_expression_to_constant, - storage::{get_storage_key_string, serialize_to_storage_slots}, + const_eval::compile_constant_expression_to_constant, storage::serialize_to_storage_slots, }, language::{ parsed::StorageDeclaration, @@ -54,32 +53,27 @@ impl ty::TyStorageDecl { let slots = f.get_initialized_storage_slots(engines, context, md_mgr, module); // Check if slot with same key was already used and throw warning. - if let Ok(slots) = slots.clone() { - for s in slots.into_iter() { + if let Ok(slots) = &slots { + for s in slots.iter() { if let Some(old_field) = slot_fields.insert(*s.key(), f.clone()) { handler.emit_warn(CompileWarning { span: f.span(), warning_content: sway_error::warning::Warning::DuplicatedStorageKey { - key: format!("{:X} ", s.key()), - field1: get_storage_key_string( - old_field - .namespace_names - .iter() - .map(|i| i.as_str().to_string()) - .chain(vec![old_field - .name - .as_str() - .to_string()]) - .collect::>(), - ), - field2: get_storage_key_string( - f.namespace_names - .iter() - .map(|i| i.as_str().to_string()) - .chain(vec![f.name.as_str().to_string()]) - .collect::>(), - ), + first_field: (&old_field.name).into(), + first_field_full_name: old_field.full_name(), + first_field_key_is_compiler_generated: old_field + .key_expression + .is_none(), + second_field: (&f.name).into(), + second_field_full_name: f.full_name(), + second_field_key_is_compiler_generated: f + .key_expression + .is_none(), + key: format!("0x{:x}", s.key()), + experimental_storage_domains: context + .experimental + .storage_domains, }, }) } @@ -151,7 +145,7 @@ impl ty::TyStorageField { Ok(Some(key)) } else { Err(CompileError::Internal( - "Expected B256 key", + "Storage keys must have type \"b256\".", key_expression.span.clone(), )) } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs index 0d3a7a25d34..18e7a6e394e 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/struct.rs @@ -16,15 +16,16 @@ impl ty::TyStructDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let struct_decl = engines.pe().get_struct(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - struct_decl.name.clone(), - Declaration::StructDeclaration(*decl_id), - )?; + let decl = Declaration::StructDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, struct_decl.name.clone(), decl.clone())?; // create a namespace for the decl, used to create a scope for generics - let _ = ctx.scoped(engines, struct_decl.span.clone(), |_scoped_ctx| Ok(())); + let _ = ctx.scoped( + engines, + struct_decl.span.clone(), + Some(decl), + |_scoped_ctx| Ok(()), + ); Ok(()) } @@ -93,9 +94,7 @@ impl ty::TyStructField { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(ctx.engines(), TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let field = ty::TyStructField { visibility: field.visibility, name: field.name, diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs index d74932eea9e..0a791301737 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/supertrait.rs @@ -53,14 +53,8 @@ pub(crate) fn insert_supertraits_into_namespace( } let decl = ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed( - &Handler::default(), - engines, - &supertrait.name, - ctx.self_type(), - ) + .resolve_call_path(&Handler::default(), &supertrait.name) .ok(); match (decl.clone(), supertraits_of) { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs index 9a0ed2942eb..e25a568cb3d 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use parsed_id::ParsedDeclId; use sway_error::{ @@ -6,7 +6,7 @@ use sway_error::{ handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; -use sway_types::{style::is_upper_camel_case, Ident, Spanned}; +use sway_types::{style::is_upper_camel_case, Ident, Named, Spanned}; use crate::{ decl_engine::*, @@ -53,15 +53,11 @@ impl TyTraitDecl { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let trait_decl = engines.pe().get_trait(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - trait_decl.name.clone(), - Declaration::TraitDeclaration(*decl_id), - )?; + let decl = Declaration::TraitDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, trait_decl.name.clone(), decl.clone())?; // A temporary namespace for checking within the trait's scope. - let _ = ctx.scoped(engines, trait_decl.span.clone(), |scoped_ctx| { + let _ = ctx.scoped(engines, trait_decl.span.clone(), Some(decl), |scoped_ctx| { trait_decl.interface_surface.iter().for_each(|item| { let _ = TyTraitItem::collect(handler, engines, scoped_ctx, item); }); @@ -100,7 +96,9 @@ impl TyTraitDecl { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - // Create a new type parameter for the "self type". + // Create a new type parameter for the self type. + // The span of the `trait_decl` `name` points to the file (use site) in which + // the trait is getting declared, so we can use it as the `use_site_span`. let self_type_param = TypeParameter::new_self_type(engines, name.span()); let self_type = self_type_param.type_id; @@ -508,6 +506,8 @@ impl TyTraitDecl { .collect(), ); + let mut const_symbols = HashMap::::new(); + for item in interface_surface.iter() { match item { ty::TyTraitInterfaceItem::TraitFn(decl_ref) => { @@ -525,11 +525,10 @@ impl TyTraitDecl { } ty::TyTraitInterfaceItem::Constant(decl_ref) => { let const_decl = decl_engine.get_constant(decl_ref); - let const_name = const_decl.call_path.suffix.clone(); all_items.push(TyImplItem::Constant(decl_ref.clone())); - let _ = ctx.insert_symbol( - handler, - const_name.clone(), + let const_name = const_decl.call_path.suffix.clone(); + const_symbols.insert( + const_name, ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id: *decl_ref.id(), }), @@ -566,10 +565,24 @@ impl TyTraitDecl { &type_mapping, !ctx.code_block_first_pass(), )); - all_items.push(TyImplItem::Constant(decl_engine.insert( + let const_name = const_decl.name().clone(); + let const_has_value = const_decl.value.is_some(); + let decl_id = decl_engine.insert( const_decl, decl_engine.get_parsed_decl_id(decl_ref.id()).as_ref(), - ))); + ); + all_items.push(TyImplItem::Constant(decl_id.clone())); + + // If this non-interface item has a value, then we want to overwrite the + // the previously inserted constant symbol from the interface surface. + if const_has_value { + const_symbols.insert( + const_name, + ty::TyDecl::ConstantDecl(ty::ConstantDecl { + decl_id: *decl_id.id(), + }), + ); + } } ty::TyTraitItem::Type(decl_ref) => { let mut type_decl = (*decl_engine.get_type(decl_ref)).clone(); @@ -586,6 +599,11 @@ impl TyTraitDecl { } } + // Insert the constants into the namespace. + for (name, decl) in const_symbols.into_iter() { + let _ = ctx.insert_symbol(handler, name, decl); + } + // Insert the methods of the trait into the namespace. // Specifically do not check for conflicting definitions because // this is just a temporary namespace for type checking and diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs index 07bd2feee81..0777b17bcf5 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_fn.rs @@ -24,13 +24,11 @@ impl ty::TyTraitFn { decl_id: &ParsedDeclId, ) -> Result<(), ErrorEmitted> { let trait_fn = engines.pe().get_trait_fn(decl_id); - ctx.insert_parsed_symbol( - handler, - engines, - trait_fn.name.clone(), - Declaration::TraitFnDeclaration(*decl_id), - )?; - let _ = ctx.scoped(engines, trait_fn.span.clone(), |_scoped_ctx| Ok(())); + let decl = Declaration::TraitFnDeclaration(*decl_id); + ctx.insert_parsed_symbol(handler, engines, trait_fn.name.clone(), decl.clone())?; + let _ = ctx.scoped(engines, trait_fn.span.clone(), Some(decl), |_scoped_ctx| { + Ok(()) + }); Ok(()) } @@ -49,7 +47,6 @@ impl ty::TyTraitFn { } = trait_fn; let type_engine = ctx.engines.te(); - let engines = ctx.engines(); // Create a namespace for the trait function. ctx.by_ref().scoped(handler, Some(span.clone()), |mut ctx| { @@ -80,9 +77,7 @@ impl ty::TyTraitFn { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let trait_fn = ty::TyTraitFn { name: name.clone(), diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs index 262c2a5ef36..27338cede56 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs @@ -14,8 +14,7 @@ use crate::{ symbol_collection_context::SymbolCollectionContext, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, }, - type_system::*, - Engines, + EnforceTypeArguments, Engines, }; impl ty::TyTraitType { @@ -58,9 +57,7 @@ impl ty::TyTraitType { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Some(ty) } else { None @@ -92,11 +89,7 @@ impl ty::TyTraitType { name, attributes, ty: ty_opt, - implementing_type: engines.te().insert( - engines, - TypeInfo::new_self_type(Span::dummy()), - None, - ), + implementing_type: engines.te().new_self_type(engines, Span::dummy()), span, } } diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs index cd9bff70750..ea66d6e6194 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/variable.rs @@ -48,7 +48,7 @@ impl ty::TyVariableDecl { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let mut ctx = ctx .with_type_annotation(type_ascription.type_id) .with_help_text( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index 0219bec7d15..421509fbc81 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -106,8 +106,118 @@ impl ty::TyIntrinsicFunctionKind { type_check_slice(handler, ctx, kind, arguments, type_arguments, span) } Intrinsic::ElemAt => type_check_elem_at(arguments, handler, kind, span, ctx), + Intrinsic::Transmute => { + type_check_transmute(arguments, handler, kind, type_arguments, span, ctx) + } + } + } +} + +fn type_check_transmute( + arguments: &[Expression], + handler: &Handler, + kind: Intrinsic, + type_arguments: &[TypeArgument], + span: Span, + mut ctx: TypeCheckContext, +) -> Result<(TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { + if arguments.len() != 1 { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { + name: kind.to_string(), + expected: 1, + span, + })); + } + + let engines = ctx.engines(); + + // Both type arguments needs to be explicitly defined + if type_arguments.len() != 2 { + return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumTArgs { + name: kind.to_string(), + expected: 2, + span, + })); + } + + let src_type = ctx + .resolve_type( + handler, + type_arguments[0].type_id, + &type_arguments[0].span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); + let return_type = ctx + .resolve_type( + handler, + type_arguments[1].type_id, + &type_arguments[1].span, + EnforceTypeArguments::Yes, + None, + ) + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); + + // Forbid ref and ptr types + fn forbid_ref_ptr_types( + engines: &Engines, + handler: &Handler, + t: TypeId, + span: &Span, + ) -> Result<(), ErrorEmitted> { + let types = t.extract_any_including_self( + engines, + &|t| { + matches!( + t, + TypeInfo::StringSlice + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Ptr(_) + | TypeInfo::Slice(_) + | TypeInfo::Ref { .. } + ) + }, + vec![], + 0, + ); + if !types.is_empty() { + Err(handler.emit_err(CompileError::TypeNotAllowed { + reason: sway_error::error::TypeNotAllowedReason::NotAllowedInTransmute, + span: span.clone(), + })) + } else { + Ok(()) } } + + forbid_ref_ptr_types(engines, handler, src_type, &type_arguments[0].span)?; + forbid_ref_ptr_types(engines, handler, return_type, &type_arguments[1].span)?; + + // check first argument + let arg_type = engines.te().get(src_type); + let first_argument_typed_expr = { + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(engines.te().insert( + engines, + (*arg_type).clone(), + type_arguments[0].span.source_id(), + )); + ty::TyExpression::type_check(handler, ctx, &arguments[0]).unwrap() + }; + + Ok(( + TyIntrinsicFunctionKind { + kind, + arguments: vec![first_argument_typed_expr], + type_arguments: type_arguments.to_vec(), + span, + }, + return_type, + )) } fn type_check_elem_at( @@ -132,7 +242,7 @@ fn type_check_elem_at( // check first argument let first_argument_span = arguments[0].span.clone(); - let first_argument_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let first_argument_type = type_engine.new_unknown(); let first_argument_typed_expr = { let ctx = ctx .by_ref() @@ -163,32 +273,16 @@ fn type_check_elem_at( }; // index argument - let index_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); let index_typed_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(index_type); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, &arguments[1])? }; - let return_type = type_engine.insert( - engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: TypeArgument { - type_id: elem_type_type_id, - initial_type_id: elem_type_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }, - None, - ); + let return_type = + type_engine.insert_ref_without_annotations(engines, to_mutable_value, elem_type_type_id); Ok(( TyIntrinsicFunctionKind { @@ -221,36 +315,26 @@ fn type_check_slice( let engines = ctx.engines(); // start index argument - let start_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); let start_ty_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(start_type); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, &arguments[1])? }; // end index argument - let end_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); let end_ty_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(end_type); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, &arguments[2])? }; // check first argument let first_argument_span = arguments[0].span.clone(); - let first_argument_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let first_argument_type = type_engine.new_unknown(); let first_argument_ty_expr = { let ctx = ctx .by_ref() @@ -288,18 +372,8 @@ fn type_check_slice( elem_type_arg: TypeArgument, ) -> TypeId { let type_engine = engines.te(); - let slice_type_id = - type_engine.insert(engines, TypeInfo::Slice(elem_type_arg.clone()), None); - let ref_to_slice_type = TypeInfo::Ref { - to_mutable_value, - referenced_type: TypeArgument { - type_id: slice_type_id, - initial_type_id: slice_type_id, - span: Span::dummy(), - call_path_tree: None, - }, - }; - type_engine.insert(engines, ref_to_slice_type, None) + let slice_type_id = type_engine.insert_slice(engines, elem_type_arg); + type_engine.insert_ref_without_annotations(engines, to_mutable_value, slice_type_id) } // first argument can be ref to array or ref to slice @@ -375,45 +449,22 @@ fn type_check_encode_as_raw_slice( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let buffer_expr = { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, &arguments[0].clone())? }; - let return_type = type_engine.insert(engines, TypeInfo::RawUntypedSlice, None); - let kind = ty::TyIntrinsicFunctionKind { kind, arguments: vec![buffer_expr], type_arguments: vec![], span, }; - Ok((kind, return_type)) -} - -// TODO: Rename to `new_tuple` and move to `TypeInfo` once https://github.com/FuelLabs/sway/issues/5991 is implemented. -fn new_encoding_buffer_tuple( - engines: &Engines, - items: impl IntoIterator, - span: Span, -) -> TypeInfo { - let te = engines.te(); - let items = items - .into_iter() - .map(|x| te.insert(engines, x, None)) - .map(|type_id| TypeArgument { - initial_type_id: type_id, - type_id, - span: span.clone(), - call_path_tree: None, - }) - .collect(); - TypeInfo::Tuple(items) + Ok((kind, type_engine.id_of_raw_slice())) } fn type_check_encode_buffer_empty( @@ -432,56 +483,29 @@ fn type_check_encode_buffer_empty( })); } - let type_engine = ctx.engines.te(); - let engines = ctx.engines(); - - let return_type = new_encoding_buffer_tuple( - engines, - [ - TypeInfo::RawUntypedPtr, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - ], - span.clone(), - ); - let return_type = type_engine.insert(engines, return_type, None); - let kind = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], type_arguments: vec![], span, }; - Ok((kind, return_type)) + + Ok((kind, get_encoding_buffer_type(ctx.engines()))) } -fn encode_buffer_type(engines: &Engines) -> TypeInfo { - let raw_ptr = engines.te().insert(engines, TypeInfo::RawUntypedPtr, None); - let uint64 = engines.te().insert( +/// Returns the [TypeId] of the buffer type used in encoding: `(raw_ptr, u64, u64)`. +/// The buffer type is a shareable [TypeInfo::Tuple], so it will be inserted into +/// the [TypeEngine] only once, when this method is called for the first time. +fn get_encoding_buffer_type(engines: &Engines) -> TypeId { + let type_engine = engines.te(); + type_engine.insert_tuple_without_annotations( engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - TypeInfo::Tuple(vec![ - TypeArgument { - type_id: raw_ptr, - initial_type_id: raw_ptr, - span: Span::dummy(), - call_path_tree: None, - }, - TypeArgument { - type_id: uint64, - initial_type_id: uint64, - span: Span::dummy(), - call_path_tree: None, - }, - TypeArgument { - type_id: uint64, - initial_type_id: uint64, - span: Span::dummy(), - call_path_tree: None, - }, - ]) + vec![ + type_engine.id_of_raw_ptr(), + type_engine.id_of_u64(), + type_engine.id_of_u64(), + ], + ) } fn type_check_encode_append( @@ -503,7 +527,7 @@ fn type_check_encode_append( let type_engine = ctx.engines.te(); let engines = ctx.engines(); - let buffer_type = type_engine.insert(engines, encode_buffer_type(engines), None); + let buffer_type = get_encoding_buffer_type(engines); let buffer_expr = { let ctx = ctx .by_ref() @@ -513,7 +537,7 @@ fn type_check_encode_append( }; let item_span = arguments[1].span.clone(); - let item_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let item_type = type_engine.new_unknown(); let item_expr = { let ctx = ctx .by_ref() @@ -574,7 +598,7 @@ fn type_check_not( })); } - let return_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let return_type = type_engine.new_unknown(); let mut ctx = ctx.with_help_text("").with_type_annotation(return_type); @@ -616,7 +640,6 @@ fn type_check_size_of_val( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -627,7 +650,7 @@ fn type_check_size_of_val( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, @@ -635,12 +658,7 @@ fn type_check_size_of_val( type_arguments: vec![], span: span.clone(), }; - let return_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - span.source_id(), - ); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_u64())) } /// Signature: `__size_of() -> u64` @@ -685,7 +703,7 @@ fn type_check_size_of_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -697,12 +715,7 @@ fn type_check_size_of_type( }], span, }; - let return_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_u64())) } /// Signature: `__is_reference_type() -> bool` @@ -740,7 +753,7 @@ fn type_check_is_reference_type( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -752,10 +765,7 @@ fn type_check_is_reference_type( }], span, }; - Ok(( - intrinsic_function, - type_engine.insert(engines, TypeInfo::Boolean, None), - )) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__assert_is_str_array()` @@ -793,7 +803,7 @@ fn type_check_assert_is_str_array( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, arguments: vec![], @@ -805,10 +815,7 @@ fn type_check_assert_is_str_array( }], span, }; - Ok(( - intrinsic_function, - type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), - )) + Ok((intrinsic_function, type_engine.id_of_unit())) } fn type_check_to_str_array( @@ -832,17 +839,9 @@ fn type_check_to_str_array( match &arg.kind { ExpressionKind::Literal(Literal::String(s)) => { - let literal_length = s.as_str().len(); - let l = Length::new(literal_length, s.clone()); - let t = TypeInfo::StringArray(l); - let span = arg.span.clone(); - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::Unknown, - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown()); let new_type = ty::TyExpression::type_check(handler, ctx.by_ref(), arg)?; Ok(( @@ -852,7 +851,7 @@ fn type_check_to_str_array( type_arguments: vec![], span, }, - type_engine.insert(engines, t, None), + type_engine.insert_string_array_without_annotations(engines, s.as_str().len()), )) } _ => Err(handler.emit_err(CompileError::ExpectedStringLiteral { @@ -880,7 +879,6 @@ fn type_check_cmp( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -889,9 +887,7 @@ fn type_check_cmp( span, })); } - let mut ctx = - ctx.by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown()); let lhs = &arguments[0]; let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; @@ -926,7 +922,7 @@ fn type_check_cmp( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Boolean, None), + type_engine.id_of_bool(), )) } @@ -964,19 +960,11 @@ fn type_check_gtf( } // Type check the first argument which is the index - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let index = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; // Type check the second argument which is the tx field ID - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let tx_field_id = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; let targ = type_arguments[0].clone(); @@ -993,7 +981,7 @@ fn type_check_gtf( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Ok(( ty::TyIntrinsicFunctionKind { @@ -1022,7 +1010,6 @@ fn type_check_addr_of( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1033,7 +1020,7 @@ fn type_check_addr_of( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let copy_type_info = type_engine .to_typeinfo(exp.return_type, &span) @@ -1053,8 +1040,7 @@ fn type_check_addr_of( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::RawUntypedPtr, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_raw_ptr())) } /// Signature: `__state_load_clear(key: b256, slots: u64) -> bool` @@ -1069,7 +1055,6 @@ fn type_check_state_clear( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1082,7 +1067,7 @@ fn type_check_state_clear( // `key` argument let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -1100,11 +1085,7 @@ fn type_check_state_clear( } // `slots` argument - let mut ctx = ctx.with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.with_type_annotation(type_engine.id_of_u64()); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; // Typed intrinsic @@ -1114,8 +1095,7 @@ fn type_check_state_clear( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__state_load_word(key: b256) -> u64` @@ -1140,7 +1120,7 @@ fn type_check_state_load_word( } let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let key_ty = type_engine .to_typeinfo(exp.return_type, &span) @@ -1159,12 +1139,7 @@ fn type_check_state_load_word( type_arguments: vec![], span, }; - let return_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_u64())) } /// Signature: `__state_store_word(key: b256, val: u64) -> bool` @@ -1198,7 +1173,7 @@ fn type_check_state_store_word( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -1214,15 +1189,11 @@ fn type_check_state_store_word( hint: "Argument type must be B256, a key into the state storage".to_string(), })); } - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.with_type_annotation(type_engine.new_unknown()); let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; - let ctx = ctx.with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let ctx = ctx.with_type_annotation(type_engine.id_of_u64()); let type_argument = type_arguments.first().map(|targ| { - let ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let ctx = ctx.with_type_annotation(type_engine.new_unknown()); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) @@ -1236,7 +1207,7 @@ fn type_check_state_store_word( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); TypeArgument { type_id, initial_type_id, @@ -1250,8 +1221,7 @@ fn type_check_state_store_word( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__state_load_quad(key: b256, ptr: raw_ptr, slots: u64)` @@ -1292,7 +1262,7 @@ fn type_check_state_quad( } let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let key_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; let key_ty = type_engine .to_typeinfo(key_exp.return_type, &span) @@ -1308,16 +1278,12 @@ fn type_check_state_quad( hint: "Argument type must be B256, a key into the state storage".to_string(), })); } - let mut ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.with_type_annotation(type_engine.new_unknown()); let val_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; - let mut ctx = ctx.with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.with_type_annotation(type_engine.id_of_u64()); let number_of_slots_exp = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[2])?; let type_argument = type_arguments.first().map(|targ| { - let ctx = ctx.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let ctx = ctx.with_type_annotation(type_engine.new_unknown()); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) @@ -1331,7 +1297,7 @@ fn type_check_state_quad( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); TypeArgument { type_id, initial_type_id, @@ -1345,8 +1311,7 @@ fn type_check_state_quad( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }; - let return_type = type_engine.insert(engines, TypeInfo::Boolean, None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_bool())) } /// Signature: `__log(val: T)` @@ -1360,7 +1325,6 @@ fn type_check_log( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1372,7 +1336,7 @@ fn type_check_log( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let exp = ty::TyExpression::type_check(handler, ctx, &arguments[0])?; let intrinsic_function = ty::TyIntrinsicFunctionKind { kind, @@ -1380,8 +1344,7 @@ fn type_check_log( type_arguments: vec![], span, }; - let return_type = type_engine.insert(engines, TypeInfo::Tuple(vec![]), None); - Ok((intrinsic_function, return_type)) + Ok((intrinsic_function, type_engine.id_of_unit())) } /// Signature: `__add(lhs: T, rhs: T) -> T` @@ -1420,7 +1383,6 @@ fn type_check_arith_binary_op( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1437,7 +1399,7 @@ fn type_check_arith_binary_op( })); } - let return_type = type_engine.insert(engines, TypeInfo::Numeric, None); + let return_type = type_engine.new_numeric(); let mut ctx = ctx .by_ref() .with_type_annotation(return_type) @@ -1485,7 +1447,7 @@ fn type_check_bitwise_binary_op( })); } - let return_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let return_type = type_engine.new_unknown(); let mut ctx = ctx .by_ref() .with_type_annotation(return_type) @@ -1551,7 +1513,7 @@ fn type_check_shift_binary_op( })); } - let return_type = engines.te().insert(engines, TypeInfo::Unknown, None); + let return_type = engines.te().new_unknown(); let lhs = &arguments[0]; let lhs = ty::TyExpression::type_check( handler, @@ -1566,7 +1528,7 @@ fn type_check_shift_binary_op( handler, ctx.by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation(engines.te().insert(engines, TypeInfo::Numeric, None)), + .with_type_annotation(engines.te().new_numeric()), rhs, )?; @@ -1605,7 +1567,6 @@ fn type_check_revert( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 1 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1624,11 +1585,7 @@ fn type_check_revert( } // Type check the argument which is the revert code - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let revert_code = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; Ok(( @@ -1638,7 +1595,7 @@ fn type_check_revert( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Never, None), + type_engine.id_of_never(), )) } @@ -1653,7 +1610,6 @@ fn type_check_jmp_mem( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if !arguments.is_empty() { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1678,7 +1634,7 @@ fn type_check_jmp_mem( type_arguments: vec![], span, }, - type_engine.insert(engines, TypeInfo::Never, None), + type_engine.id_of_never(), )) } @@ -1728,11 +1684,9 @@ fn type_check_ptr_ops( EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); - let mut ctx = - ctx.by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.new_unknown()); let lhs = &arguments[0]; let lhs = ty::TyExpression::type_check(handler, ctx.by_ref(), lhs)?; @@ -1754,11 +1708,7 @@ fn type_check_ptr_ops( let ctx = ctx .by_ref() .with_help_text("Incorrect argument type") - .with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + .with_type_annotation(type_engine.id_of_u64()); let rhs = ty::TyExpression::type_check(handler, ctx, rhs)?; Ok(( @@ -1813,7 +1763,7 @@ fn type_check_smo( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let initial_type_info = type_engine .to_typeinfo(targ.type_id, &targ.span) .map_err(|e| handler.emit_err(e.into())) @@ -1827,7 +1777,7 @@ fn type_check_smo( EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); TypeArgument { type_id, initial_type_id, @@ -1837,9 +1787,7 @@ fn type_check_smo( }); // Type check the first argument which is the recipient address, so it has to be a `b256`. - let mut ctx = - ctx.by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::B256, None)); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_b256()); let recipient = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[0])?; // Type check the second argument which is the data, which can be anything. If a type @@ -1847,18 +1795,12 @@ fn type_check_smo( let mut ctx = ctx.by_ref().with_type_annotation( type_argument .clone() - .map_or(type_engine.insert(engines, TypeInfo::Unknown, None), |ta| { - ta.type_id - }), + .map_or(type_engine.new_unknown(), |ta| ta.type_id), ); let data = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[1])?; // Type check the third argument which is the amount of coins to send, so it has to be a `u64`. - let mut ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - )); + let mut ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_u64()); let coins = ty::TyExpression::type_check(handler, ctx.by_ref(), &arguments[2])?; Ok(( @@ -1868,7 +1810,7 @@ fn type_check_smo( type_arguments: type_argument.map_or(vec![], |ta| vec![ta]), span, }, - type_engine.insert(engines, TypeInfo::Tuple(vec![]), None), + type_engine.id_of_unit(), )) } @@ -1885,7 +1827,6 @@ fn type_check_contract_ret( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if arguments.len() != 2 { return Err(handler.emit_err(CompileError::IntrinsicIncorrectNumArgs { @@ -1909,13 +1850,11 @@ fn type_check_contract_ret( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, x) }) .collect::, _>>()?; - let t = ctx.engines.te().insert(ctx.engines, TypeInfo::Never, None); - Ok(( ty::TyIntrinsicFunctionKind { kind: Intrinsic::ContractRet, @@ -1923,7 +1862,7 @@ fn type_check_contract_ret( type_arguments: vec![], span, }, - t, + ctx.engines.te().id_of_never(), )) } @@ -1939,17 +1878,11 @@ fn type_check_contract_call( span: Span, ) -> Result<(ty::TyIntrinsicFunctionKind, TypeId), ErrorEmitted> { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); if !type_arguments.is_empty() { return Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span })); } - let return_type_id = ctx - .engines - .te() - .insert(ctx.engines, TypeInfo::Tuple(vec![]), None); - // Arguments let arguments: Vec = arguments .iter() @@ -1957,7 +1890,7 @@ fn type_check_contract_call( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, x) }) .collect::, _>>()?; @@ -1969,5 +1902,5 @@ fn type_check_contract_call( span, }; - Ok((intrinsic_function, return_type_id)) + Ok((intrinsic_function, type_engine.id_of_unit())) } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs index 31306c2f247..792de9d779b 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/instantiate.rs @@ -1,5 +1,5 @@ use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{integer_bits::IntegerBits, Ident, Span}; +use sway_types::{Ident, Span}; use crate::{ language::{ty, LazyOp, Literal}, @@ -7,7 +7,7 @@ use crate::{ typed_expression::{instantiate_lazy_operator, instantiate_tuple_index_access}, TypeCheckContext, }, - Engines, TypeId, TypeInfo, + Engines, TypeId, }; /// Simplifies instantiation of desugared code in the match expression and match arms. @@ -23,19 +23,11 @@ pub(super) struct Instantiate { impl Instantiate { pub(super) fn new(engines: &Engines, span: Span) -> Self { let type_engine = engines.te(); - let u64_type = type_engine.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ); - let boolean_type = type_engine.insert(engines, TypeInfo::Boolean, None); - let revert_type = type_engine.insert(engines, TypeInfo::Never, None); - Self { span, - u64_type, - boolean_type, - revert_type, + u64_type: type_engine.id_of_u64(), + boolean_type: type_engine.id_of_bool(), + revert_type: type_engine.id_of_never(), } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs index 39cd872146d..3f7856f4854 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/matcher.rs @@ -12,7 +12,7 @@ use crate::{ }, TypeCheckContext, }, - Ident, TypeId, TypeInfo, UnifyCheck, + Ident, TypeId, UnifyCheck, }; use sway_error::{ @@ -20,7 +20,7 @@ use sway_error::{ handler::{ErrorEmitted, Handler}, }; -use sway_types::{integer_bits::IntegerBits, span::Span, Named, Spanned}; +use sway_types::{span::Span, Named, Spanned}; /// A single requirement in the form ` == ` that has to be /// fulfilled for the match arm to match. @@ -492,20 +492,12 @@ fn match_enum( expression: ty::TyExpressionVariant::EnumTag { exp: Box::new(exp.clone()), }, - return_type: type_engine.insert( - ctx.engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ), + return_type: type_engine.id_of_u64(), span: exp.span.clone(), }, ty::TyExpression { expression: ty::TyExpressionVariant::Literal(Literal::U64(variant.tag as u64)), - return_type: type_engine.insert( - ctx.engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - None, - ), + return_type: type_engine.id_of_u64(), span: exp.span.clone(), }, ); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs index 7e110b86e49..09ac73392db 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_branch.rs @@ -17,7 +17,7 @@ use crate::{ ty::{self, MatchBranchCondition, MatchedOrVariantIndexVars, TyExpression}, }, semantic_analysis::*, - Engines, TypeArgument, TypeInfo, UnifyCheck, + Engines, TypeInfo, UnifyCheck, }; use super::{instantiate::Instantiate, matcher::matcher, ReqDeclTree}; @@ -92,9 +92,8 @@ impl ty::TyMatchBranch { for (ident, is_struct_field) in variables { let default_handler = &Handler::default(); // If there exist a configurable with the same name as the pattern variable. - if let Ok(ty::TyDecl::ConfigurableDecl(configurable_decl)) = ctx - .namespace() - .resolve_symbol_typed(default_handler, engines, &ident, ctx.self_type()) + if let Ok(ty::TyDecl::ConfigurableDecl(configurable_decl)) = + ctx.resolve_symbol(default_handler, &ident) { let name = (&ident).into(); let configurable_span = engines @@ -619,7 +618,7 @@ fn instantiate_branch_condition_result_var_declarations_and_matched_or_variant_i ) -> Result<(VarDecl, Vec), ErrorEmitted> { let type_engine = ctx.engines.te(); // At this point we have the guarantee that we have: - // - exactly the same variables in each OR variant + // - exactly the same variables in each of the OR variants // - that variables of the same name are of the same type // - that we do not have duplicates in variable names inside of alternatives @@ -645,18 +644,10 @@ fn instantiate_branch_condition_result_var_declarations_and_matched_or_variant_i // All variants have same variable types and names, thus we pick them from the first alternative. let tuple_field_types = carry_over_vars[0] .iter() - .map(|(_, var_body)| TypeArgument { - type_id: var_body.return_type, - initial_type_id: var_body.return_type, - span: var_body.span.clone(), // Although not needed, this span can be mapped to var declaration. - call_path_tree: None, - }) + .map(|(_, var_body)| var_body.return_type) .collect(); - let tuple_type = type_engine.insert( - ctx.engines, - TypeInfo::Tuple(tuple_field_types), - instantiate.dummy_span().source_id(), - ); + let tuple_type = + type_engine.insert_tuple_without_annotations(ctx.engines, tuple_field_types); let variable_names = carry_over_vars[0] .iter() .map(|(ident, _)| ident.clone()) diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs index bd271a7f638..98168776ac2 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_match_expression.rs @@ -12,7 +12,7 @@ use crate::{ ast_node::expression::typed_expression::instantiate_if_expression, expression::match_expression::typed::instantiate::Instantiate, TypeCheckContext, }, - CompileError, TypeId, TypeInfo, + CompileError, TypeEngine, TypeId, TypeInfo, }; use std::{collections::BTreeMap, ops::ControlFlow}; use sway_error::handler::{ErrorEmitted, Handler}; @@ -32,19 +32,19 @@ struct Trie { nodes: Vec, } -fn revert(never_type_id: TypeId, u64_type_id: TypeId) -> TyExpression { +fn revert(type_engine: &TypeEngine) -> TyExpression { TyExpression { expression: TyExpressionVariant::IntrinsicFunction(TyIntrinsicFunctionKind { kind: sway_ast::Intrinsic::Revert, arguments: vec![TyExpression { expression: TyExpressionVariant::Literal(crate::language::Literal::U64(17)), - return_type: u64_type_id, + return_type: type_engine.id_of_u64(), span: Span::dummy(), }], type_arguments: vec![], span: Span::dummy(), }), - return_type: never_type_id, + return_type: type_engine.id_of_never(), span: Span::dummy(), } } @@ -124,18 +124,7 @@ impl ty::TyMatchExpression { &self, mut ctx: TypeCheckContext<'_>, ) -> Result { - let never_type_id = ctx.engines.te().insert(ctx.engines, TypeInfo::Never, None); - - let u64_type_id = ctx.engines.te().insert( - ctx.engines, - TypeInfo::UnsignedInteger(sway_types::integer_bits::IntegerBits::SixtyFour), - None, - ); - - let bool_type_id = ctx - .engines - .te() - .insert(ctx.engines, TypeInfo::Boolean, None); + let type_engine = ctx.engines.te(); let branch_return_type_id = self .branches @@ -163,7 +152,7 @@ impl ty::TyMatchExpression { .filter(|x| x.condition.is_none()) .map(|x| x.result.clone()) .next() - .unwrap_or_else(|| revert(never_type_id, u64_type_id)); + .unwrap_or_else(|| revert(type_engine)); // All the match string slices, ignoring the wildcard let match_arms_string_slices = self @@ -246,7 +235,7 @@ impl ty::TyMatchExpression { expression: TyExpressionVariant::Literal( crate::language::Literal::U64(k as u64), ), - return_type: u64_type_id, + return_type: type_engine.id_of_u64(), span: Span::dummy(), }), }, @@ -285,7 +274,6 @@ impl ty::TyMatchExpression { .generate_radix_tree_checks( ctx.by_ref(), matched_value, - u64_type_id, branch_return_type_id, wildcard_return_expr.clone(), trie, @@ -297,7 +285,7 @@ impl ty::TyMatchExpression { expression: TyExpressionVariant::IfExp { condition: Box::new(TyExpression { expression, - return_type: bool_type_id, + return_type: type_engine.id_of_bool(), span: self.span.clone(), }), then: Box::new(then_node), @@ -373,28 +361,18 @@ impl ty::TyMatchExpression { &self, ctx: TypeCheckContext<'_>, matched_value: &TyExpression, - u64_type_id: TypeId, branch_return_type_id: TypeId, wildcard_return_expr: TyExpression, trie: Trie, packed_strings: &str, ) -> Result { - //generate code - let bool_type_id = ctx - .engines - .te() - .insert(ctx.engines, TypeInfo::Boolean, None); - - let string_slice_type_id = - ctx.engines - .te() - .insert(ctx.engines, TypeInfo::StringSlice, None); + let type_engine = ctx.engines.te(); let packed_strings_expr = TyExpression { expression: TyExpressionVariant::Literal(crate::language::Literal::String( Span::from_string(packed_strings.to_string()), )), - return_type: string_slice_type_id, + return_type: type_engine.id_of_string_slice(), span: Span::dummy(), }; @@ -405,8 +383,8 @@ impl ty::TyMatchExpression { &trie.nodes, 0, 0, - bool_type_id, - u64_type_id, + type_engine.id_of_bool(), + type_engine.id_of_u64(), branch_return_type_id, 1, wildcard_return_expr, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs index fddb0ee7b21..acfec750058 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/match_expression/typed/typed_scrutinee.rs @@ -3,7 +3,7 @@ use sway_error::{ error::{CompileError, StructFieldUsageContext}, handler::{ErrorEmitted, Handler}, }; -use sway_types::{BaseIdent, Ident, Span, Spanned}; +use sway_types::{Ident, Span, Spanned}; use crate::{ decl_engine::{DeclEngineGetParsedDeclId, DeclEngineInsert}, @@ -26,8 +26,6 @@ impl TyScrutinee { let engines = ctx.engines(); match scrutinee { Scrutinee::Or { elems, span } => { - let type_id = type_engine.insert(engines, TypeInfo::Unknown, None); - let mut typed_elems = Vec::with_capacity(elems.len()); for scrutinee in elems { typed_elems.push(ty::TyScrutinee::type_check( @@ -38,28 +36,22 @@ impl TyScrutinee { } let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Or(typed_elems), - type_id, + type_id: type_engine.new_unknown(), span, }; Ok(typed_scrutinee) } Scrutinee::CatchAll { span } => { - let type_id = type_engine.insert(engines, TypeInfo::Unknown, None); - let dummy_type_param = TypeParameter { - type_id, - initial_type_id: type_id, - name_ident: BaseIdent::new_with_override("_".into(), span.clone()), - trait_constraints: vec![], - trait_constraints_span: Span::dummy(), - is_from_parent: false, - }; let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::CatchAll, - type_id: type_engine.insert( - engines, - TypeInfo::Placeholder(dummy_type_param), - span.source_id(), - ), + // The `span` will mostly point to a "_" in code. However, match expressions + // are heavily used in code generation, e.g., to generate code for contract + // function selection in the `__entry` and sometimes the span does not point + // to a "_". But it is always in the code in which the match expression is. + type_id: type_engine.new_placeholder(TypeParameter::new_placeholder( + type_engine.new_unknown(), + span.clone(), + )), span, }; Ok(typed_scrutinee) @@ -163,11 +155,7 @@ fn type_check_variable( let type_engine = engines.te(); let decl_engine = engines.de(); - let typed_scrutinee = match ctx - .namespace() - .resolve_symbol_typed(&Handler::default(), engines, &name, ctx.self_type()) - .ok() - { + let typed_scrutinee = match ctx.resolve_symbol(&Handler::default(), &name).ok() { // If the name represents a constant, then we turn it into a [ty::TyScrutineeVariant::Constant]. Some(ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. })) => { let constant_decl = (*decl_engine.get_constant(&decl_id)).clone(); @@ -207,7 +195,7 @@ fn type_check_variable( // appropriate helpful errors, depending on the exact usage of that configurable. _ => ty::TyScrutinee { variant: ty::TyScrutineeVariant::Variable(name), - type_id: type_engine.insert(ctx.engines(), TypeInfo::Unknown, None), + type_id: type_engine.new_unknown(), span, }, }; @@ -227,9 +215,7 @@ fn type_check_struct( let decl_engine = engines.de(); // find the struct definition from the name - let unknown_decl = - ctx.namespace() - .resolve_symbol_typed(handler, engines, &struct_name, ctx.self_type())?; + let unknown_decl = ctx.resolve_symbol(handler, &struct_name)?; let struct_id = unknown_decl.to_struct_decl(handler, ctx.engines())?; let mut struct_decl = (*decl_engine.get_struct(&struct_id)).clone(); @@ -425,11 +411,7 @@ fn type_check_struct( decl_engine.get_parsed_decl_id(&struct_id).as_ref(), ); let typed_scrutinee = ty::TyScrutinee { - type_id: type_engine.insert( - ctx.engines(), - TypeInfo::Struct(*struct_ref.id()), - struct_ref.span().source_id(), - ), + type_id: type_engine.insert_struct(engines, *struct_ref.id()), span, variant: ty::TyScrutineeVariant::StructScrutinee { struct_ref, @@ -496,23 +478,13 @@ fn type_check_enum( is_absolute: call_path.is_absolute, }; // find the enum definition from the name - let unknown_decl = ctx.namespace().resolve_call_path_typed( - handler, - engines, - &enum_callpath, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_call_path(handler, &enum_callpath)?; let enum_id = unknown_decl.to_enum_id(handler, ctx.engines())?; (enum_callpath.span(), enum_id, unknown_decl) } None => { // we may have an imported variant - let decl = ctx.namespace().resolve_call_path_typed( - handler, - engines, - &call_path, - ctx.self_type(), - )?; + let decl = ctx.resolve_call_path(handler, &call_path)?; if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = decl.clone() { (call_path.suffix.span(), *enum_ref.id(), decl) } else { @@ -552,11 +524,7 @@ fn type_check_enum( value: Box::new(typed_value), instantiation_call_path: call_path, }, - type_id: type_engine.insert( - engines, - TypeInfo::Enum(*enum_ref.id()), - enum_ref.span().source_id(), - ), + type_id: type_engine.insert_enum(engines, *enum_ref.id()), span, }; @@ -581,20 +549,17 @@ fn type_check_tuple( }, ); } - let type_id = type_engine.insert( + let type_id = type_engine.insert_tuple( engines, - TypeInfo::Tuple( - typed_elems - .iter() - .map(|x| TypeArgument { - type_id: x.type_id, - initial_type_id: x.type_id, - span: span.clone(), - call_path_tree: None, - }) - .collect(), - ), - span.source_id(), + typed_elems + .iter() + .map(|elem| TypeArgument { + type_id: elem.type_id, + initial_type_id: elem.type_id, + span: elem.span.clone(), + call_path_tree: None, + }) + .collect(), ); let typed_scrutinee = ty::TyScrutinee { variant: ty::TyScrutineeVariant::Tuple(typed_elems), diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs index 229f38dd9c2..62f88759358 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs @@ -23,8 +23,8 @@ use crate::{ language::{ parsed::*, ty::{ - self, GetDeclIdent, TyCodeBlock, TyDecl, TyExpression, TyExpressionVariant, TyImplItem, - TyReassignmentTarget, VariableMutability, + self, GetDeclIdent, StructAccessInfo, TyCodeBlock, TyDecl, TyExpression, + TyExpressionVariant, TyImplItem, TyReassignmentTarget, VariableMutability, }, *, }, @@ -38,17 +38,19 @@ use crate::{ use ast_node::declaration::{insert_supertraits_into_namespace, SupertraitOf}; use either::Either; use indexmap::IndexMap; +use namespace::{LexicalScope, Module, ResolvedDeclaration}; use rustc_hash::FxHashSet; use std::collections::{HashMap, VecDeque}; use sway_ast::intrinsics::Intrinsic; use sway_error::{ convert_parse_tree_error::ConvertParseTreeError, - error::CompileError, + error::{CompileError, StructFieldUsageContext}, handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; use sway_types::{integer_bits::IntegerBits, u256::U256, Ident, Named, Span, Spanned}; use symbol_collection_context::SymbolCollectionContext; +use type_resolve::{resolve_call_path, VisibilityCheck}; #[allow(clippy::too_many_arguments)] impl ty::TyExpression { @@ -214,7 +216,7 @@ impl ty::TyExpression { .iter() .map(|branch| { // create a new namespace for this branch result - ctx.scoped(engines, branch.span.clone(), |scoped_ctx| { + ctx.scoped(engines, branch.span.clone(), None, |scoped_ctx| { Self::collect(handler, engines, scoped_ctx, &branch.result) }) .0 @@ -309,14 +311,7 @@ impl ty::TyExpression { is_absolute: false, }; if matches!( - ctx.namespace() - .resolve_call_path_typed( - &Handler::default(), - engines, - &call_path, - ctx.self_type() - ) - .ok(), + ctx.resolve_call_path(&Handler::default(), &call_path,).ok(), Some(ty::TyDecl::EnumVariantDecl { .. }) ) { Self::type_check_delineated_path( @@ -355,11 +350,7 @@ impl ty::TyExpression { ) } ExpressionKind::LazyOperator(LazyOperatorExpression { op, lhs, rhs }) => { - let ctx = ctx.by_ref().with_type_annotation(type_engine.insert( - engines, - TypeInfo::Boolean, - None, - )); + let ctx = ctx.by_ref().with_type_annotation(type_engine.id_of_bool()); Self::type_check_lazy_operator(handler, ctx, op.clone(), lhs, rhs, span) } ExpressionKind::CodeBlock(contents) => { @@ -477,7 +468,7 @@ impl ty::TyExpression { ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_help_text(""); Self::type_check_array_index(handler, ctx, prefix, index, span) } @@ -488,7 +479,7 @@ impl ty::TyExpression { }) => { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_help_text(""); Self::type_check_storage_access( handler, @@ -510,16 +501,25 @@ impl ty::TyExpression { arguments, span, ), - ExpressionKind::WhileLoop(WhileLoopExpression { condition, body }) => { - Self::type_check_while_loop(handler, ctx.by_ref(), condition, body, span) - } + ExpressionKind::WhileLoop(WhileLoopExpression { + condition, + body, + is_desugared_for_loop, + }) => Self::type_check_while_loop( + handler, + ctx.by_ref(), + condition, + body, + *is_desugared_for_loop, + span, + ), ExpressionKind::ForLoop(ForLoopExpression { desugared }) => { Self::type_check_for_loop(handler, ctx.by_ref(), desugared) } ExpressionKind::Break => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Break, - return_type: type_engine.insert(engines, TypeInfo::Never, None), + return_type: type_engine.id_of_never(), span, }; Ok(expr) @@ -527,7 +527,7 @@ impl ty::TyExpression { ExpressionKind::Continue => { let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Continue, - return_type: type_engine.insert(engines, TypeInfo::Never, None), + return_type: type_engine.id_of_never(), span, }; Ok(expr) @@ -563,7 +563,7 @@ impl ty::TyExpression { .unwrap_or_else(|err| ty::TyExpression::error(err, expr_span, engines)); let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Return(Box::new(expr)), - return_type: type_engine.insert(engines, TypeInfo::Never, None), + return_type: type_engine.id_of_never(), span, }; Ok(typed_expr) @@ -593,7 +593,7 @@ impl ty::TyExpression { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // Literals of type Numeric can now be resolved if typed_expression.return_type is // an UnsignedInteger or a Numeric @@ -620,20 +620,19 @@ impl ty::TyExpression { fn type_check_literal(engines: &Engines, lit: Literal, span: Span) -> ty::TyExpression { let type_engine = engines.te(); let return_type = match &lit { - Literal::String(_) => TypeInfo::StringSlice, - Literal::Numeric(_) => TypeInfo::Numeric, - Literal::U8(_) => TypeInfo::UnsignedInteger(IntegerBits::Eight), - Literal::U16(_) => TypeInfo::UnsignedInteger(IntegerBits::Sixteen), - Literal::U32(_) => TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), - Literal::U64(_) => TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - Literal::U256(_) => TypeInfo::UnsignedInteger(IntegerBits::V256), - Literal::Boolean(_) => TypeInfo::Boolean, - Literal::B256(_) => TypeInfo::B256, + Literal::String(_) => type_engine.id_of_string_slice(), + Literal::Numeric(_) => type_engine.new_numeric(), + Literal::U8(_) => type_engine.id_of_u8(), + Literal::U16(_) => type_engine.id_of_u16(), + Literal::U32(_) => type_engine.id_of_u32(), + Literal::U64(_) => type_engine.id_of_u64(), + Literal::U256(_) => type_engine.id_of_u256(), + Literal::Boolean(_) => type_engine.id_of_bool(), + Literal::B256(_) => type_engine.id_of_b256(), }; - let id = type_engine.insert(engines, return_type, span.source_id()); ty::TyExpression { expression: ty::TyExpressionVariant::Literal(lit), - return_type: id, + return_type, span, } } @@ -647,11 +646,7 @@ impl ty::TyExpression { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); - let exp = match ctx - .namespace() - .resolve_symbol_typed(&Handler::default(), engines, &name, ctx.self_type()) - .ok() - { + let exp = match ctx.resolve_symbol(&Handler::default(), &name).ok() { Some(ty::TyDecl::VariableDecl(decl)) => { let ty::TyVariableDecl { name: decl_name, @@ -782,7 +777,6 @@ impl ty::TyExpression { span: Span, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let (typed_block, block_return_type) = match ty::TyCodeBlock::type_check(handler, ctx.by_ref(), contents, false) { @@ -790,10 +784,7 @@ impl ty::TyExpression { let (block_type, _span) = TyCodeBlock::compute_return_type_and_span(&ctx, &res); (res, block_type) } - Err(_err) => ( - ty::TyCodeBlock::default(), - type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None), - ), + Err(_err) => (ty::TyCodeBlock::default(), type_engine.id_of_unit()), }; let exp = ty::TyExpression { @@ -820,7 +811,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("The condition of an if expression must be a boolean expression.") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean, None)); + .with_type_annotation(type_engine.id_of_bool()); ty::TyExpression::type_check(handler, ctx, &condition) .unwrap_or_else(|err| ty::TyExpression::error(err, condition.span(), engines)) }; @@ -883,7 +874,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, value) .unwrap_or_else(|err| ty::TyExpression::error(err, value.span().clone(), engines)) }; @@ -1071,20 +1062,27 @@ impl ty::TyExpression { // 2. Check that initialized registers are not reassigned in the `asm` block. check_asm_block_validity(handler, &asm, &ctx)?; - let asm_span = asm + // Take the span of the returns register, or as a fallback, the span of the + // whole ASM block. + let asm_returns_span = asm .returns .clone() .map(|x| x.1) .unwrap_or_else(|| asm.whole_block_span.clone()); + let return_type = ctx .resolve_type( handler, - type_engine.insert(engines, asm.return_type.clone(), asm_span.source_id()), - &asm_span, + type_engine.insert( + engines, + asm.return_type.clone(), + asm_returns_span.source_id(), + ), + &asm_returns_span, EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // type check the initializers let typed_registers = asm @@ -1095,9 +1093,10 @@ impl ty::TyExpression { |AsmRegisterDeclaration { name, initializer }| ty::TyAsmRegisterDeclaration { name, initializer: initializer.map(|initializer| { - let ctx = ctx.by_ref().with_help_text("").with_type_annotation( - type_engine.insert(engines, TypeInfo::Unknown, None), - ); + let ctx = ctx + .by_ref() + .with_help_text("") + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, &initializer).unwrap_or_else( |err| ty::TyExpression::error(err, initializer.span(), engines), @@ -1132,7 +1131,7 @@ impl ty::TyExpression { let mut ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let parent = ty::TyExpression::type_check(handler, ctx.by_ref(), prefix)?; let exp = instantiate_struct_field_access( handler, @@ -1168,7 +1167,7 @@ impl ty::TyExpression { .as_ref() .map(|field_type_ids| field_type_ids[i].clone()) .unwrap_or_else(|| { - let initial_type_id = type_engine.insert(engines, TypeInfo::Unknown, None); + let initial_type_id = type_engine.new_unknown(); TypeArgument { type_id: initial_type_id, initial_type_id, @@ -1195,11 +1194,7 @@ impl ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: typed_fields, }, - return_type: ctx.engines.te().insert( - engines, - TypeInfo::Tuple(typed_field_types), - span.source_id(), - ), + return_type: ctx.engines.te().insert_tuple(engines, typed_field_types), span, }; Ok(exp) @@ -1256,12 +1251,14 @@ impl ty::TyExpression { let storage_key_ident = Ident::new_with_override("StorageKey".into(), span.clone()); // Search for the struct declaration with the call path above. - let storage_key_decl = ctx.namespace().root().resolve_symbol( + let storage_key_decl = resolve_call_path( handler, engines, + ctx.namespace().root(), &storage_key_mod_path, - &storage_key_ident, + &storage_key_ident.into(), None, + VisibilityCheck::No, )?; let storage_key_struct_decl_id = storage_key_decl @@ -1297,11 +1294,7 @@ impl ty::TyExpression { .get_parsed_decl_id(&storage_key_struct_decl_id) .as_ref(), ); - access_type = type_engine.insert( - engines, - TypeInfo::Struct(*storage_key_struct_decl_ref.id()), - storage_key_struct_decl_ref.span().source_id(), - ); + access_type = type_engine.insert_struct(engines, *storage_key_struct_decl_ref.id()); Ok(ty::TyExpression { expression: ty::TyExpressionVariant::StorageAccess(storage_access), @@ -1323,7 +1316,7 @@ impl ty::TyExpression { let ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); let parent = ty::TyExpression::type_check(handler, ctx, &prefix)?; let exp = instantiate_tuple_index_access(handler, engines, parent, index, index_span, span)?; @@ -1420,12 +1413,7 @@ impl ty::TyExpression { is_absolute, }; if matches!( - ctx.namespace().resolve_call_path_typed( - &Handler::default(), - engines, - &call_path, - ctx.self_type() - ), + ctx.resolve_call_path(&Handler::default(), &call_path,), Ok(ty::TyDecl::EnumVariantDecl { .. }) ) { // if it's a singleton it's either an enum variant or a function @@ -1480,13 +1468,7 @@ impl ty::TyExpression { suffix: before.inner.clone(), is_absolute, }; - ctx.namespace() - .resolve_call_path_typed( - &Handler::default(), - engines, - &probe_call_path, - ctx.self_type(), - ) + ctx.resolve_call_path(&Handler::default(), &probe_call_path) .and_then(|decl| decl.to_enum_id(&Handler::default(), ctx.engines())) .map(|decl_ref| decl_engine.get_enum(&decl_ref)) .and_then(|decl| { @@ -1793,18 +1775,13 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("An address that is being ABI cast must be of type b256") - .with_type_annotation(type_engine.insert(engines, TypeInfo::B256, None)); + .with_type_annotation(type_engine.id_of_b256()); ty::TyExpression::type_check(handler, ctx, address) .unwrap_or_else(|err| ty::TyExpression::error(err, err_span, engines)) }; // look up the call path and get the declaration it references - let abi = ctx.namespace().resolve_call_path_typed( - handler, - engines, - &abi_name, - ctx.self_type(), - )?; + let abi = ctx.resolve_call_path(handler, &abi_name)?; let abi_ref = match abi { ty::TyDecl::AbiDecl(ty::AbiDecl { decl_id }) => { let abi_decl = engines.de().get(&decl_id); @@ -1825,23 +1802,15 @@ impl ty::TyExpression { match abi_name { // look up the call path and get the declaration it references AbiName::Known(abi_name) => { - let unknown_decl = ctx.namespace().resolve_call_path_typed( - handler, - engines, - abi_name, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_call_path(handler, abi_name)?; unknown_decl.to_abi_ref(handler, engines)? } AbiName::Deferred => { return Ok(ty::TyExpression { - return_type: type_engine.insert( + return_type: type_engine.new_contract_caller( engines, - TypeInfo::ContractCaller { - abi_name: AbiName::Deferred, - address: None, - }, - span.source_id(), + AbiName::Deferred, + None, ), expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, span, @@ -1865,13 +1834,10 @@ impl ty::TyExpression { .. } = &*abi_decl; - let return_type = type_engine.insert( + let return_type = type_engine.new_contract_caller( engines, - TypeInfo::ContractCaller { - abi_name: AbiName::Known(abi_name.clone()), - address: Some(Box::new(address_expr.clone())), - }, - abi_name.span().source_id(), + AbiName::Known(abi_name.clone()), + Some(Box::new(address_expr.clone())), ); // Retrieve the interface surface for this abi. @@ -1961,25 +1927,13 @@ impl ty::TyExpression { let engines = ctx.engines(); if contents.is_empty() { - let elem_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let elem_type = type_engine.new_unknown(); return Ok(ty::TyExpression { expression: ty::TyExpressionVariant::Array { elem_type, contents: Vec::new(), }, - return_type: type_engine.insert( - engines, - TypeInfo::Array( - TypeArgument { - type_id: elem_type, - span: Span::dummy(), - call_path_tree: None, - initial_type_id: elem_type, - }, - Length::new(0, Span::dummy()), - ), - None, - ), + return_type: type_engine.insert_array_without_annotations(engines, elem_type, 0), span, }); }; @@ -2036,25 +1990,13 @@ impl ty::TyExpression { }; let elem_type = type_engine.insert(engines, initial_type.clone(), None); - let array_count = typed_contents.len(); + let length = typed_contents.len(); let expr = ty::TyExpression { expression: ty::TyExpressionVariant::Array { elem_type, contents: typed_contents, }, - return_type: type_engine.insert( - engines, - TypeInfo::Array( - TypeArgument { - type_id: elem_type, - span: Span::dummy(), - call_path_tree: None, - initial_type_id: elem_type, - }, - Length::new(array_count, Span::dummy()), - ), - None, - ), + return_type: type_engine.insert_array_without_annotations(engines, elem_type, length), span, }; @@ -2079,7 +2021,7 @@ impl ty::TyExpression { let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); ty::TyExpression::type_check(handler, ctx, prefix)? }); @@ -2126,10 +2068,9 @@ impl ty::TyExpression { }; let index_te = { - let type_info_u64 = TypeInfo::UnsignedInteger(IntegerBits::SixtyFour); let ctx = ctx .with_help_text("Array index must be of type \"u64\".") - .with_type_annotation(type_engine.insert(engines, type_info_u64, None)); + .with_type_annotation(type_engine.id_of_u64()); ty::TyExpression::type_check(handler, ctx, index)? }; @@ -2171,25 +2112,31 @@ impl ty::TyExpression { mut ctx: TypeCheckContext, condition: &Expression, body: &CodeBlock, + is_desugared_for_loop: bool, span: Span, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let typed_condition = { let ctx = ctx .by_ref() - .with_type_annotation(type_engine.insert(engines, TypeInfo::Boolean, None)) + .with_type_annotation(type_engine.id_of_bool()) .with_help_text("A while loop's loop condition must be a boolean expression."); ty::TyExpression::type_check(handler, ctx, condition)? }; - let unit_ty = type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None); - let mut ctx = ctx.with_type_annotation(unit_ty).with_help_text( - "A while loop's loop body cannot implicitly return a value. Try \ + let unit_ty = type_engine.id_of_unit(); + let mut ctx = ctx + .with_type_annotation(unit_ty) + .with_help_text(if is_desugared_for_loop { + "A for loop's loop body cannot implicitly return a value. Try \ assigning it to a mutable variable declared outside of the loop \ - instead.", - ); + instead." + } else { + "A while loop's loop body cannot implicitly return a value. Try \ + assigning it to a mutable variable declared outside of the loop \ + instead." + }); let typed_body = ty::TyCodeBlock::type_check(handler, ctx.by_ref(), body, false)?; let exp = ty::TyExpression { @@ -2222,7 +2169,7 @@ impl ty::TyExpression { let engines = ctx.engines(); let mut ctx = ctx - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) .with_help_text(""); let (lhs, expected_rhs_type) = match lhs { @@ -2269,12 +2216,7 @@ impl ty::TyExpression { let (decl_reference_name, decl_reference_rhs, decl_reference_type) = match &reference_exp.expression { TyExpressionVariant::VariableExpression { name, .. } => { - let var_decl = ctx.namespace().resolve_symbol_typed( - handler, - engines, - name, - ctx.self_type(), - )?; + let var_decl = ctx.resolve_symbol(handler, name)?; let TyDecl::VariableDecl(var_decl) = var_decl else { return Err(handler.emit_err(CompileError::Internal( @@ -2334,12 +2276,7 @@ impl ty::TyExpression { match expr.kind { ExpressionKind::Variable(name) => { // check that the reassigned name exists - let unknown_decl = ctx.namespace().resolve_symbol_typed( - handler, - engines, - &name, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_symbol(handler, &name)?; match unknown_decl { TyDecl::VariableDecl(variable_decl) => { @@ -2407,15 +2344,10 @@ impl ty::TyExpression { expr = prefix; } ExpressionKind::ArrayIndex(ArrayIndexExpression { prefix, index }) => { - let type_info_u64 = TypeInfo::UnsignedInteger(IntegerBits::SixtyFour); let ctx = ctx .by_ref() .with_help_text("Array index must be of type \"u64\".") - .with_type_annotation(type_engine.insert( - engines, - type_info_u64, - None, - )); + .with_type_annotation(type_engine.id_of_u64()); let typed_index = ty::TyExpression::type_check(handler, ctx, index.as_ref()) .unwrap_or_else(|err| { @@ -2438,7 +2370,8 @@ impl ty::TyExpression { let indices = indices.into_iter().rev().collect::>(); let (ty_of_field, _ty_of_parent) = ctx.namespace().program_id(engines).read(engines, |m| { - m.current_items().find_subfield_type( + Self::find_subfield_type( + m, handler, ctx.engines(), ctx.namespace(), @@ -2470,11 +2403,203 @@ impl ty::TyExpression { lhs, rhs, })), - return_type: type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), None), + return_type: type_engine.id_of_unit(), span, }) } + pub fn find_subfield_type( + module: &Module, + handler: &Handler, + engines: &Engines, + namespace: &Namespace, + base_name: &Ident, + projections: &[ty::ProjectionKind], + ) -> Result<(TypeId, TypeId), ErrorEmitted> { + let ret = module.walk_scope_chain(|lexical_scope| { + Self::find_subfield_type_helper( + lexical_scope, + handler, + engines, + namespace, + base_name, + projections, + ) + })?; + + if let Some(ret) = ret { + Ok(ret) + } else { + // Symbol not found + Err(handler.emit_err(CompileError::UnknownVariable { + var_name: base_name.clone(), + span: base_name.span(), + })) + } + } + + /// Returns a tuple where the first element is the [TypeId] of the actual expression, and + /// the second is the [TypeId] of its parent. + fn find_subfield_type_helper( + lexical_scope: &LexicalScope, + handler: &Handler, + engines: &Engines, + namespace: &Namespace, + base_name: &Ident, + projections: &[ty::ProjectionKind], + ) -> Result, ErrorEmitted> { + let type_engine = engines.te(); + let decl_engine = engines.de(); + + let symbol = match lexical_scope.items.symbols.get(base_name).cloned() { + Some(s) => s, + None => { + return Ok(None); + } + }; + let mut symbol = match symbol { + ResolvedDeclaration::Parsed(_) => unreachable!(), + ResolvedDeclaration::Typed(ty_decl) => ty_decl.return_type(handler, engines)?, + }; + let mut symbol_span = base_name.span(); + let mut parent_rover = symbol; + let mut full_span_for_error = base_name.span(); + for projection in projections { + let resolved_type = match type_engine.to_typeinfo(symbol, &symbol_span) { + Ok(resolved_type) => resolved_type, + Err(error) => { + return Err(handler.emit_err(CompileError::TypeError(error))); + } + }; + match (resolved_type, projection) { + ( + TypeInfo::Struct(decl_ref), + ty::ProjectionKind::StructField { name: field_name }, + ) => { + let struct_decl = decl_engine.get_struct(&decl_ref); + let (struct_can_be_changed, is_public_struct_access) = + StructAccessInfo::get_info(engines, &struct_decl, namespace).into(); + + let field_type_id = match struct_decl.find_field(field_name) { + Some(struct_field) => { + if is_public_struct_access && struct_field.is_private() { + return Err(handler.emit_err(CompileError::StructFieldIsPrivate { + field_name: field_name.into(), + struct_name: struct_decl.call_path.suffix.clone(), + field_decl_span: struct_field.name.span(), + struct_can_be_changed, + usage_context: StructFieldUsageContext::StructFieldAccess, + })); + } + + struct_field.type_argument.type_id + } + None => { + return Err(handler.emit_err(CompileError::StructFieldDoesNotExist { + field_name: field_name.into(), + available_fields: struct_decl + .accessible_fields_names(is_public_struct_access), + is_public_struct_access, + struct_name: struct_decl.call_path.suffix.clone(), + struct_decl_span: struct_decl.span(), + struct_is_empty: struct_decl.is_empty(), + usage_context: StructFieldUsageContext::StructFieldAccess, + })); + } + }; + parent_rover = symbol; + symbol = field_type_id; + symbol_span = field_name.span().clone(); + full_span_for_error = Span::join(full_span_for_error, &field_name.span()); + } + (TypeInfo::Tuple(fields), ty::ProjectionKind::TupleField { index, index_span }) => { + let field_type_opt = { + fields + .get(*index) + .map(|TypeArgument { type_id, .. }| type_id) + }; + let field_type = match field_type_opt { + Some(field_type) => field_type, + None => { + return Err(handler.emit_err(CompileError::TupleIndexOutOfBounds { + index: *index, + count: fields.len(), + tuple_type: engines.help_out(symbol).to_string(), + span: index_span.clone(), + prefix_span: full_span_for_error.clone(), + })); + } + }; + parent_rover = symbol; + symbol = *field_type; + symbol_span = index_span.clone(); + full_span_for_error = Span::join(full_span_for_error, index_span); + } + ( + TypeInfo::Array(elem_ty, array_length), + ty::ProjectionKind::ArrayIndex { index, index_span }, + ) => { + parent_rover = symbol; + symbol = elem_ty.type_id; + symbol_span = index_span.clone(); + + if let Some(index_literal) = index + .expression + .as_literal() + .and_then(|x| x.cast_value_to_u64()) + { + if index_literal >= array_length.val() as u64 { + return Err(handler.emit_err(CompileError::ArrayOutOfBounds { + index: index_literal, + count: array_length.val() as u64, + span: index.span.clone(), + })); + } + } + + // `index_span` does not contain the enclosing square brackets. + // Which means, if this array index access is the last one before the + // erroneous expression, the `full_span_for_error` will be missing the + // closing `]`. We can live with this small glitch so far. To fix it, + // we would need to bring the full span of the index all the way from + // the parsing stage. An effort that doesn't pay off at the moment. + // TODO: Include the closing square bracket into the error span. + full_span_for_error = Span::join(full_span_for_error, index_span); + } + (actually, ty::ProjectionKind::StructField { name }) => { + return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { + actually: engines.help_out(actually).to_string(), + storage_variable: None, + field_name: name.into(), + span: full_span_for_error, + })); + } + ( + actually, + ty::ProjectionKind::TupleField { + index, index_span, .. + }, + ) => { + return Err( + handler.emit_err(CompileError::TupleElementAccessOnNonTuple { + actually: engines.help_out(actually).to_string(), + span: full_span_for_error, + index: *index, + index_span: index_span.clone(), + }), + ); + } + (actually, ty::ProjectionKind::ArrayIndex { .. }) => { + return Err(handler.emit_err(CompileError::NotIndexable { + actually: engines.help_out(actually).to_string(), + span: full_span_for_error, + })); + } + } + } + Ok(Some((symbol, parent_rover))) + } + fn type_check_ref( handler: &Handler, mut ctx: TypeCheckContext<'_>, @@ -2496,7 +2621,7 @@ impl ty::TyExpression { TypeInfo::Ref { referenced_type, .. } => referenced_type.type_id, - _ => type_engine.insert(engines, TypeInfo::Unknown, None), + _ => type_engine.new_unknown(), }; let ctx = ctx @@ -2518,16 +2643,13 @@ impl ty::TyExpression { } }; - let expr_type_argument: TypeArgument = expr.return_type.into(); + let expr_return_type = expr.return_type; let typed_expr = ty::TyExpression { expression: ty::TyExpressionVariant::Ref(Box::new(expr)), - return_type: type_engine.insert( + return_type: type_engine.insert_ref_without_annotations( engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: expr_type_argument, - }, - None, + to_mutable_value, + expr_return_type, ), span, }; @@ -2601,15 +2723,8 @@ impl ty::TyExpression { // Since `&mut T` coerces into `&T` we always go with a lesser expectation, `&T`. // Thus, `to_mutable_vale` is set to false. let type_annotation = match &*type_engine.get(ctx.type_annotation()) { - TypeInfo::Unknown => type_engine.insert(engines, TypeInfo::Unknown, None), - _ => type_engine.insert( - engines, - TypeInfo::Ref { - to_mutable_value: false, - referenced_type: ctx.type_annotation().into(), - }, - None, - ), + TypeInfo::Unknown => type_engine.new_unknown(), + _ => type_engine.insert_ref_without_annotations(engines, false, ctx.type_annotation()), }; let deref_ctx = ctx @@ -2710,7 +2825,7 @@ impl ty::TyExpression { num.to_string().parse().map(Literal::Numeric).map_err(|e| { Literal::handle_parse_int_error(engines, e, TypeInfo::Numeric, span.clone()) }), - type_engine.insert(engines, TypeInfo::Numeric, None), + type_engine.new_numeric(), ), _ => unreachable!("Unexpected type for integer literals"), }, @@ -2843,15 +2958,13 @@ fn check_asm_block_validity( // Emit warning if this register shadows a constant, or a configurable, or a variable. let temp_handler = Handler::default(); - let decl = ctx.namespace().resolve_call_path_typed( + let decl = ctx.resolve_call_path( &temp_handler, - ctx.engines, &CallPath { prefixes: vec![], suffix: sway_types::BaseIdent::new(span.clone()), is_absolute: true, }, - None, ); let shadowing_item = match decl { @@ -2949,19 +3062,9 @@ mod tests { handler, &engines, expr, - engines.te().insert( - &engines, - TypeInfo::Array( - TypeArgument { - type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - span: Span::dummy(), - call_path_tree: None, - initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - }, - Length::new(2, Span::dummy()), - ), - None, - ), + engines + .te() + .insert_array_without_annotations(&engines, engines.te().id_of_bool(), 2), ExperimentalFeatures::default(), )?; expr.type_check_analyze(handler, &mut TypeCheckAnalysisContext::new(&engines))?; @@ -3089,19 +3192,9 @@ mod tests { &handler, &engines, &expr, - engines.te().insert( - &engines, - TypeInfo::Array( - TypeArgument { - type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - span: Span::dummy(), - call_path_tree: None, - initial_type_id: engines.te().insert(&engines, TypeInfo::Boolean, None), - }, - Length::new(0, Span::dummy()), - ), - None, - ), + engines + .te() + .insert_array_without_annotations(&engines, engines.te().id_of_bool(), 0), ExperimentalFeatures::default(), ); let (errors, warnings) = handler.consume(); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs index 35ddcb183ca..742cadb1691 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/enum_instantiation.rs @@ -56,11 +56,7 @@ pub(crate) fn instantiate_enum( match (&args, &*type_engine.get(enum_variant.type_argument.type_id)) { ([], ty) if ty.is_unit() => Ok(ty::TyExpression { - return_type: type_engine.insert( - engines, - TypeInfo::Enum(*enum_ref.id()), - enum_ref.span().source_id(), - ), + return_type: type_engine.insert_enum(engines, *enum_ref.id()), expression: ty::TyExpressionVariant::EnumInstantiation { tag: enum_variant.tag, contents: None, @@ -140,20 +136,16 @@ pub(crate) fn instantiate_enum( .with_help_text(help_text) .with_type_annotation(enum_variant_type_id); - // TODO-IG: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. - // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is - // not treated as an error in the `type_check()`'s result. + // TODO: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. + // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is + // not treated as an error in the `type_check()`'s result. let typed_expr = handler .scope(|handler| ty::TyExpression::type_check(handler, enum_ctx, single_expr))?; // Create the resulting enum type based on the enum we have instantiated. // Note that we clone the `enum_ref` but the unification we do below will // affect the types behind that new enum decl reference. - let type_id = type_engine.insert( - engines, - TypeInfo::Enum(*enum_ref.id()), - enum_ref.span().source_id(), - ); + let type_id = type_engine.insert_enum(engines, *enum_ref.id()); // The above type check will unify the type behind the `enum_variant_type_id` // and the resulting expression type. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs index bdd3679c869..9b1a5e4ebc8 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/if_expression.rs @@ -22,7 +22,7 @@ pub(crate) fn instantiate_if_expression( let ty_to_check = if r#else.is_some() { ctx.type_annotation() } else { - type_engine.insert(engines, TypeInfo::Tuple(vec![]), then.span.source_id()) + type_engine.id_of_unit() }; // We check then_type_is_never and else_type_is_never before unifying to make sure we don't @@ -62,9 +62,10 @@ pub(crate) fn instantiate_if_expression( Box::new(r#else) }); - let r#else_ret_ty = r#else.as_ref().map(|x| x.return_type).unwrap_or_else(|| { - type_engine.insert(engines, TypeInfo::Tuple(Vec::new()), span.source_id()) - }); + let r#else_ret_ty = r#else + .as_ref() + .map(|x| x.return_type) + .unwrap_or_else(|| type_engine.id_of_unit()); // delay emitting the errors until we decide if this is a missing else branch or some other set of errors let h = Handler::default(); diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index 3c118c43536..c5cb709b70c 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -20,7 +20,7 @@ use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, }; -use sway_types::{constants, integer_bits::IntegerBits, BaseIdent, IdentUnique}; +use sway_types::{constants, BaseIdent, IdentUnique}; use sway_types::{constants::CONTRACT_CALL_COINS_PARAMETER_NAME, Spanned}; use sway_types::{Ident, Span}; @@ -45,14 +45,24 @@ pub(crate) fn type_check_method_application( let ctx = ctx .by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + .with_type_annotation(type_engine.new_unknown()); // Ignore errors in method parameters // On the second pass we will throw the errors if they persist. let arg_handler = Handler::default(); let arg_opt = ty::TyExpression::type_check(&arg_handler, ctx, arg).ok(); - let needs_second_pass = arg_handler.has_errors(); + let has_errors = arg_handler.has_errors(); + let has_numerics = arg_opt + .as_ref() + .map(|x| { + x.return_type + .extract_inner_types(engines, IncludeSelf::Yes) + .iter() + .any(|x| matches!(&*engines.te().get(*x), TypeInfo::Numeric)) + }) + .unwrap_or_default(); + let needs_second_pass = has_errors || has_numerics; if index == 0 { // We want to emit errors in the self parameter and ignore TraitConstraintNotSatisfied with Placeholder @@ -82,7 +92,7 @@ pub(crate) fn type_check_method_application( .iter() .map(|(arg, _has_errors)| match arg { Some(arg) => arg.return_type, - None => type_engine.insert(engines, TypeInfo::Unknown, None), + None => type_engine.new_unknown(), }) .collect(), )?; @@ -130,7 +140,7 @@ pub(crate) fn type_check_method_application( } else { ctx.by_ref() .with_help_text("") - .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) + .with_type_annotation(type_engine.new_unknown()) }; args_buf.push_back( @@ -183,17 +193,13 @@ pub(crate) fn type_check_method_application( | constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME => { untyped_contract_call_params_map .insert(param.name.to_string(), param.value.clone()); - let type_annotation = type_engine.insert( - engines, - if param.name.span().as_str() - != constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME - { - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) - } else { - TypeInfo::B256 - }, - param.name.span().source_id(), - ); + let type_annotation = if param.name.span().as_str() + != constants::CONTRACT_CALL_ASSET_ID_PARAMETER_NAME + { + type_engine.id_of_u64() + } else { + type_engine.id_of_b256() + }; let ctx = ctx .by_ref() .with_help_text("") @@ -219,13 +225,10 @@ pub(crate) fn type_check_method_application( // if the coins contract call parameter is not specified // it's considered to be zero and hence no error needs to be reported if let Some(coins_expr) = contract_call_params_map.get(CONTRACT_CALL_COINS_PARAMETER_NAME) { - if coins_analysis::possibly_nonzero_u64_expression( - ctx.namespace(), - ctx.engines, - coins_expr, - ) && !method - .attributes - .contains_key(&crate::transform::AttributeKind::Payable) + if coins_analysis::possibly_nonzero_u64_expression(&ctx, coins_expr) + && !method + .attributes + .contains_key(&crate::transform::AttributeKind::Payable) { return Err( handler.emit_err(CompileError::CoinsPassedToNonPayableMethod { @@ -282,12 +285,7 @@ pub(crate) fn type_check_method_application( ) -> Result<(), ErrorEmitted> { match exp { ty::TyExpressionVariant::VariableExpression { name, .. } => { - let unknown_decl = ctx.namespace().resolve_symbol_typed( - &Handler::default(), - ctx.engines, - name, - ctx.self_type(), - )?; + let unknown_decl = ctx.resolve_symbol(&Handler::default(), name)?; let is_decl_mutable = match unknown_decl { ty::TyDecl::ConstantDecl { .. } => false, @@ -443,21 +441,10 @@ pub(crate) fn type_check_method_application( asset_id_expr: Expression, gas_expr: Expression, ) -> Expression { - let tuple_args_type_id = ctx.engines.te().insert( - ctx.engines, - TypeInfo::Tuple( - typed_arguments - .iter() - .map(|&type_id| TypeArgument { - type_id, - initial_type_id: type_id, - span: Span::dummy(), - call_path_tree: None, - }) - .collect(), - ), - None, - ); + let tuple_args_type_id = ctx + .engines + .te() + .insert_tuple_without_annotations(ctx.engines, typed_arguments); Expression { kind: ExpressionKind::FunctionApplication(Box::new( FunctionApplicationExpression { @@ -608,7 +595,7 @@ pub(crate) fn type_check_method_application( for p in method.type_parameters.clone() { if p.is_from_parent { if let Some(impl_type_param) = - names_index.get(&p.name_ident).and_then(|type_param_index| { + names_index.get(&p.name).and_then(|type_param_index| { implementing_type_parameters.get(*type_param_index) }) { @@ -672,7 +659,7 @@ pub(crate) fn type_check_method_application( // This handles the case of substituting the generic blanket type by call_path_typeid. for p in method.type_parameters.clone() { - if p.name_ident.as_str() == qualified_call_path.call_path.suffix.as_str() { + if p.name.as_str() == qualified_call_path.call_path.suffix.as_str() { subst_type_parameters.push(t.initial_type_id); subst_type_arguments.push(call_path_typeid); break; @@ -682,13 +669,10 @@ pub(crate) fn type_check_method_application( // This will subst inner method_application placeholders with the already resolved // current method application type parameter for p in method.type_parameters.clone() { - if names_type_ids.contains_key(&p.name_ident) { - subst_type_parameters.push(engines.te().insert( - engines, - TypeInfo::Placeholder(p.clone()), - p.span().source_id(), - )); - subst_type_arguments.push(p.type_id); + if names_type_ids.contains_key(&p.name) { + let type_parameter_type_id = p.type_id; + subst_type_parameters.push(engines.te().new_placeholder(p)); + subst_type_arguments.push(type_parameter_type_id); } } @@ -818,19 +802,15 @@ pub(crate) fn resolve_method_name( // type check the call path let type_id = call_path_binding .type_check_with_type_info(handler, &mut ctx) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // find the module that the symbol is in let type_info_prefix = ctx .namespace() .prepend_module_path(&call_path_binding.inner.prefixes); - ctx.namespace().lookup_submodule_from_absolute_path( - handler, - engines, - &type_info_prefix, - )?; + ctx.namespace() + .root_module() + .lookup_submodule(handler, engines, &type_info_prefix)?; // find the method let decl_ref = ctx.find_method_for_type( @@ -867,7 +847,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments_types .front() .cloned() - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); + .unwrap_or_else(|| type_engine.new_unknown()); // find the method let decl_ref = ctx.find_method_for_type( @@ -891,7 +871,7 @@ pub(crate) fn resolve_method_name( let type_id = arguments_types .front() .cloned() - .unwrap_or_else(|| type_engine.insert(engines, TypeInfo::Unknown, None)); + .unwrap_or_else(|| type_engine.new_unknown()); // find the method let decl_ref = ctx.find_method_for_type( diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs index 1d84a623fbd..ef900927271 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/struct_instantiation.rs @@ -59,38 +59,34 @@ pub(crate) fn struct_instantiation( let type_arguments = type_arguments.to_vec(); - let type_info = match (suffix.as_str(), type_arguments.is_empty()) { - ("Self", true) => TypeInfo::new_self_type(suffix.span()), + // We first create a custom type and then resolve it to the struct type. + let custom_type_id = match (suffix.as_str(), type_arguments.is_empty()) { + ("Self", true) => type_engine.new_self_type(engines, suffix.span()), ("Self", false) => { return Err(handler.emit_err(CompileError::TypeArgumentsNotAllowed { span: suffix.span(), })); } - (_, true) => TypeInfo::Custom { - qualified_call_path: suffix.clone().into(), - type_arguments: None, - }, - (_, false) => TypeInfo::Custom { - qualified_call_path: suffix.clone().into(), - type_arguments: Some(type_arguments), - }, + (_, true) => type_engine.new_custom_from_name(engines, suffix.clone()), + (_, false) => type_engine.new_custom(engines, suffix.clone().into(), Some(type_arguments)), }; // find the module that the struct decl is in let type_info_prefix = ctx.namespace().prepend_module_path(prefixes); ctx.namespace() - .lookup_submodule_from_absolute_path(handler, engines, &type_info_prefix)?; + .root_module() + .lookup_submodule(handler, engines, &type_info_prefix)?; // resolve the type of the struct decl let type_id = ctx .resolve_type( handler, - type_engine.insert(engines, type_info, suffix.span().source_id()), + custom_type_id, inner_span, EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // extract the struct name and fields from the type info let type_info = type_engine.get(type_id); @@ -338,8 +334,7 @@ fn collect_struct_constructors( // but that would be a way too much of suggestions, and moreover, it is also not a design pattern/guideline // that we wish to encourage. namespace.program_id(engines).read(engines, |m| { - m.current_items() - .get_items_for_type(engines, struct_type_id) + m.get_items_for_type(engines, struct_type_id) .iter() .filter_map(|item| match item { ResolvedTraitImplItem::Parsed(_) => unreachable!(), @@ -389,7 +384,6 @@ fn type_check_field_arguments( ) -> Result, ErrorEmitted> { handler.scope(|handler| { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let mut typed_fields = vec![]; let mut missing_fields = vec![]; @@ -403,9 +397,9 @@ fn type_check_field_arguments( .with_type_annotation(struct_field.type_argument.type_id) .with_unify_generic(true); - // TODO-IG: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. - // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is - // not treated as an error in the `type_check()`'s result. + // TODO: Remove the `handler.scope` once https://github.com/FuelLabs/sway/issues/5606 gets solved. + // We need it here so that we can short-circuit in case of a `TypeMismatch` error which is + // not treated as an error in the `type_check()`'s result. let typed_expr = handler .scope(|handler| ty::TyExpression::type_check(handler, ctx, &field.value)); @@ -434,11 +428,7 @@ fn type_check_field_arguments( name: struct_field.name.clone(), value: ty::TyExpression { expression: ty::TyExpressionVariant::Tuple { fields: vec![] }, - return_type: type_engine.insert( - engines, - TypeInfo::ErrorRecovery(err), - None, - ), + return_type: type_engine.id_of_error_recovery(err), span: span.clone(), }, }); diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 3a6ea5f2153..5dee758e227 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -91,11 +91,7 @@ impl ty::TyAstNode { _ => { ctx = ctx .with_help_text("") - .with_type_annotation(type_engine.insert( - engines, - TypeInfo::Unknown, - None, - )); + .with_type_annotation(type_engine.new_unknown()); } } let inner = ty::TyExpression::type_check(handler, ctx, &expr) diff --git a/sway-core/src/semantic_analysis/ast_node/modes.rs b/sway-core/src/semantic_analysis/ast_node/modes.rs index b2e3f25aaf4..b4d5a4aaf6c 100644 --- a/sway-core/src/semantic_analysis/ast_node/modes.rs +++ b/sway-core/src/semantic_analysis/ast_node/modes.rs @@ -9,6 +9,7 @@ pub enum AbiMode { #[derive(Clone, Copy, PartialEq, Eq, Default)] pub enum ConstShadowingMode { + Allow, Sequential, #[default] ItemStyle, diff --git a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs index 1dbad596ed4..1f40ad03ac7 100644 --- a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs +++ b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs @@ -649,7 +649,8 @@ fn effects_of_intrinsic(intr: &sway_ast::Intrinsic) -> HashSet { | EncodeBufferAppend | EncodeBufferAsRawSlice | Slice - | ElemAt => HashSet::new(), + | ElemAt + | Transmute => HashSet::new(), } } diff --git a/sway-core/src/semantic_analysis/coins_analysis.rs b/sway-core/src/semantic_analysis/coins_analysis.rs index 3b2b352f714..c88be235b84 100644 --- a/sway-core/src/semantic_analysis/coins_analysis.rs +++ b/sway-core/src/semantic_analysis/coins_analysis.rs @@ -1,16 +1,14 @@ use sway_error::handler::Handler; -use crate::{language::ty, Engines, Namespace}; +use crate::language::ty; + +use super::TypeCheckContext; // This analysis checks if an expression is known statically to evaluate // to a non-zero value at runtime. // It's intended to be used in the payability analysis to check if a non-payable // method gets called with a non-zero amount of `coins` -pub fn possibly_nonzero_u64_expression( - namespace: &Namespace, - engines: &Engines, - expr: &ty::TyExpression, -) -> bool { +pub fn possibly_nonzero_u64_expression(ctx: &TypeCheckContext, expr: &ty::TyExpression) -> bool { use ty::TyExpressionVariant::*; match &expr.expression { Literal(crate::language::Literal::U64(value)) => *value != 0, @@ -18,29 +16,24 @@ pub fn possibly_nonzero_u64_expression( // not a u64 literal, hence we return true to be on the safe side Literal(_) => true, ConstantExpression { decl, .. } => match &decl.value { - Some(expr) => possibly_nonzero_u64_expression(namespace, engines, expr), + Some(expr) => possibly_nonzero_u64_expression(ctx, expr), None => false, }, ConfigurableExpression { decl, .. } => match &decl.value { - Some(expr) => possibly_nonzero_u64_expression(namespace, engines, expr), + Some(expr) => possibly_nonzero_u64_expression(ctx, expr), None => false, }, VariableExpression { name, .. } => { - match namespace - .resolve_symbol_typed(&Handler::default(), engines, name, None) - .ok() - { + match ctx.resolve_symbol(&Handler::default(), name).ok() { Some(ty_decl) => { match ty_decl { ty::TyDecl::VariableDecl(var_decl) => { - possibly_nonzero_u64_expression(namespace, engines, &var_decl.body) + possibly_nonzero_u64_expression(ctx, &var_decl.body) } ty::TyDecl::ConstantDecl(ty::ConstantDecl { decl_id, .. }) => { - let const_decl = engines.de().get_constant(&decl_id); + let const_decl = ctx.engines.de().get_constant(&decl_id); match &const_decl.value { - Some(value) => { - possibly_nonzero_u64_expression(namespace, engines, value) - } + Some(value) => possibly_nonzero_u64_expression(ctx, value), None => true, } } diff --git a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs index 62203b13dda..308b5c0b989 100644 --- a/sway-core/src/semantic_analysis/namespace/lexical_scope.rs +++ b/sway-core/src/semantic_analysis/namespace/lexical_scope.rs @@ -3,7 +3,7 @@ use crate::{ engine_threading::{Engines, PartialEqWithEngines, PartialEqWithEnginesContext}, language::{ parsed::{Declaration, FunctionDeclaration}, - ty::{self, StructAccessInfo, TyDecl, TyStorageDecl}, + ty::{self, TyDecl, TyStorageDecl}, CallPath, Visibility, }, namespace::*, @@ -15,7 +15,7 @@ use super::{root::ResolvedDeclaration, TraitMap}; use parking_lot::RwLock; use sway_error::{ - error::{CompileError, ShadowingSource, StructFieldUsageContext}, + error::{CompileError, ShadowingSource}, handler::{ErrorEmitted, Handler}, }; use sway_types::{span::Span, IdentUnique, Named, Spanned}; @@ -71,6 +71,9 @@ pub struct LexicalScope { pub children: Vec, /// The parent scope associated with this scope. Will be None for a root scope. pub parent: Option, + /// The declaration associated with this scope. This will initially be a [ParsedDeclId], + /// but can be replaced to be a [DeclId] once the declaration is type checked. + pub declaration: Option, } /// The set of items that exist within some lexical scope via declaration or importing. @@ -161,21 +164,21 @@ impl Items { handler: &Handler, engines: &Engines, symbol: &Ident, - ) -> Result { + ) -> Result, ErrorEmitted> { // Check locally declared items. Any name clash with imports will have already been reported as an error. if let Some(decl) = self.symbols.get(symbol) { - return Ok(decl.clone()); + return Ok(Some(decl.clone())); } // Check item imports if let Some((_, _, decl, _)) = self.use_item_synonyms.get(symbol) { - return Ok(decl.clone()); + return Ok(Some(decl.clone())); } // Check glob imports if let Some(decls) = self.use_glob_synonyms.get(symbol) { if decls.len() == 1 { - return Ok(decls[0].1.clone()); + return Ok(Some(decls[0].1.clone())); } else if decls.is_empty() { return Err(handler.emit_err(CompileError::Internal( "The name {symbol} was bound in a star import, but no corresponding module paths were found", @@ -193,11 +196,7 @@ impl Items { } } - // Symbol not found - Err(handler.emit_err(CompileError::SymbolNotFound { - name: symbol.clone(), - span: symbol.span(), - })) + Ok(None) } pub(crate) fn insert_parsed_symbol( @@ -644,6 +643,9 @@ impl Items { is_alias: bool, item: &ResolvedDeclaration, const_shadowing_mode: ConstShadowingMode| { + if const_shadowing_mode == ConstShadowingMode::Allow { + return; + } match (decl, item) { // TODO: Do not handle any shadowing errors while handling parsed declarations yet, // or else we will emit errors in a different order from the source code order. @@ -768,14 +770,6 @@ impl Items { .clear(); } - pub fn get_items_for_type( - &self, - engines: &Engines, - type_id: TypeId, - ) -> Vec { - self.implemented_traits.get_items_for_type(engines, type_id) - } - pub fn get_impl_spans_for_decl(&self, engines: &Engines, ty_decl: &TyDecl) -> Vec { let handler = Handler::default(); ty_decl @@ -797,24 +791,6 @@ impl Items { .get_impl_spans_for_trait_name(trait_name) } - pub fn get_methods_for_type( - &self, - engines: &Engines, - type_id: TypeId, - ) -> Vec { - self.get_items_for_type(engines, type_id) - .into_iter() - .filter_map(|item| match item { - ResolvedTraitImplItem::Parsed(_) => todo!(), - ResolvedTraitImplItem::Typed(item) => match item { - ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)), - ty::TyTraitItem::Constant(_decl_ref) => None, - ty::TyTraitItem::Type(_decl_ref) => None, - }, - }) - .collect::>() - } - pub(crate) fn has_storage_declared(&self) -> bool { self.declared_storage.is_some() } @@ -839,156 +815,6 @@ impl Items { } } } - - /// Returns a tuple where the first element is the [TypeId] of the actual expression, and - /// the second is the [TypeId] of its parent. - pub(crate) fn find_subfield_type( - &self, - handler: &Handler, - engines: &Engines, - namespace: &Namespace, - base_name: &Ident, - projections: &[ty::ProjectionKind], - ) -> Result<(TypeId, TypeId), ErrorEmitted> { - let type_engine = engines.te(); - let decl_engine = engines.de(); - - let symbol = match self.symbols.get(base_name).cloned() { - Some(s) => s, - None => { - return Err(handler.emit_err(CompileError::UnknownVariable { - var_name: base_name.clone(), - span: base_name.span(), - })); - } - }; - let mut symbol = match symbol { - ResolvedDeclaration::Parsed(_) => unreachable!(), - ResolvedDeclaration::Typed(ty_decl) => ty_decl.return_type(handler, engines)?, - }; - let mut symbol_span = base_name.span(); - let mut parent_rover = symbol; - let mut full_span_for_error = base_name.span(); - for projection in projections { - let resolved_type = match type_engine.to_typeinfo(symbol, &symbol_span) { - Ok(resolved_type) => resolved_type, - Err(error) => { - return Err(handler.emit_err(CompileError::TypeError(error))); - } - }; - match (resolved_type, projection) { - ( - TypeInfo::Struct(decl_ref), - ty::ProjectionKind::StructField { name: field_name }, - ) => { - let struct_decl = decl_engine.get_struct(&decl_ref); - let (struct_can_be_changed, is_public_struct_access) = - StructAccessInfo::get_info(engines, &struct_decl, namespace).into(); - - let field_type_id = match struct_decl.find_field(field_name) { - Some(struct_field) => { - if is_public_struct_access && struct_field.is_private() { - return Err(handler.emit_err(CompileError::StructFieldIsPrivate { - field_name: field_name.into(), - struct_name: struct_decl.call_path.suffix.clone(), - field_decl_span: struct_field.name.span(), - struct_can_be_changed, - usage_context: StructFieldUsageContext::StructFieldAccess, - })); - } - - struct_field.type_argument.type_id - } - None => { - return Err(handler.emit_err(CompileError::StructFieldDoesNotExist { - field_name: field_name.into(), - available_fields: struct_decl - .accessible_fields_names(is_public_struct_access), - is_public_struct_access, - struct_name: struct_decl.call_path.suffix.clone(), - struct_decl_span: struct_decl.span(), - struct_is_empty: struct_decl.is_empty(), - usage_context: StructFieldUsageContext::StructFieldAccess, - })); - } - }; - parent_rover = symbol; - symbol = field_type_id; - symbol_span = field_name.span().clone(); - full_span_for_error = Span::join(full_span_for_error, &field_name.span()); - } - (TypeInfo::Tuple(fields), ty::ProjectionKind::TupleField { index, index_span }) => { - let field_type_opt = { - fields - .get(*index) - .map(|TypeArgument { type_id, .. }| type_id) - }; - let field_type = match field_type_opt { - Some(field_type) => field_type, - None => { - return Err(handler.emit_err(CompileError::TupleIndexOutOfBounds { - index: *index, - count: fields.len(), - tuple_type: engines.help_out(symbol).to_string(), - span: index_span.clone(), - prefix_span: full_span_for_error.clone(), - })); - } - }; - parent_rover = symbol; - symbol = *field_type; - symbol_span = index_span.clone(); - full_span_for_error = Span::join(full_span_for_error, index_span); - } - ( - TypeInfo::Array(elem_ty, _), - ty::ProjectionKind::ArrayIndex { index_span, .. }, - ) => { - parent_rover = symbol; - symbol = elem_ty.type_id; - symbol_span = index_span.clone(); - // `index_span` does not contain the enclosing square brackets. - // Which means, if this array index access is the last one before the - // erroneous expression, the `full_span_for_error` will be missing the - // closing `]`. We can live with this small glitch so far. To fix it, - // we would need to bring the full span of the index all the way from - // the parsing stage. An effort that doesn't pay off at the moment. - // TODO: Include the closing square bracket into the error span. - full_span_for_error = Span::join(full_span_for_error, index_span); - } - (actually, ty::ProjectionKind::StructField { name }) => { - return Err(handler.emit_err(CompileError::FieldAccessOnNonStruct { - actually: engines.help_out(actually).to_string(), - storage_variable: None, - field_name: name.into(), - span: full_span_for_error, - })); - } - ( - actually, - ty::ProjectionKind::TupleField { - index, index_span, .. - }, - ) => { - return Err( - handler.emit_err(CompileError::TupleElementAccessOnNonTuple { - actually: engines.help_out(actually).to_string(), - span: full_span_for_error, - index: *index, - index_span: index_span.clone(), - }), - ); - } - (actually, ty::ProjectionKind::ArrayIndex { .. }) => { - return Err(handler.emit_err(CompileError::NotIndexable { - actually: engines.help_out(actually).to_string(), - span: full_span_for_error, - })); - } - } - } - Ok((symbol, parent_rover)) - } } fn get_path_for_decl( diff --git a/sway-core/src/semantic_analysis/namespace/mod.rs b/sway-core/src/semantic_analysis/namespace/mod.rs index 5fba8b2d90e..8947e8495b0 100644 --- a/sway-core/src/semantic_analysis/namespace/mod.rs +++ b/sway-core/src/semantic_analysis/namespace/mod.rs @@ -17,7 +17,7 @@ pub(super) use trait_map::CodeBlockFirstPass; pub(super) use trait_map::IsExtendingExistingImpl; pub(super) use trait_map::IsImplSelf; pub(super) use trait_map::ResolvedTraitImplItem; -pub(super) use trait_map::TraitMap; +pub use trait_map::TraitMap; pub use trait_map::TryInsertingTraitImplOnFailure; use sway_types::Ident; diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 77aa192b3be..af89e4469c9 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -1,9 +1,14 @@ -use crate::{engine_threading::Engines, language::Visibility, Ident}; +use crate::{ + engine_threading::Engines, + language::{ty, Visibility}, + Ident, TypeId, +}; use super::{ - lexical_scope::{Items, LexicalScope}, + lexical_scope::{Items, LexicalScope, ResolvedFunctionDecl}, root::Root, - LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, + LexicalScopeId, ModuleName, ModulePath, ModulePathBuf, ResolvedDeclaration, + ResolvedTraitImplItem, }; use rustc_hash::FxHasher; @@ -215,6 +220,14 @@ impl Module { .unwrap() } + pub fn get_lexical_scope(&self, id: LexicalScopeId) -> Option<&LexicalScope> { + self.lexical_scopes.get(id) + } + + pub fn get_lexical_scope_mut(&mut self, id: LexicalScopeId) -> Option<&mut LexicalScope> { + self.lexical_scopes.get_mut(id) + } + /// Returns the current lexical scope associated with this module. pub fn current_lexical_scope(&self) -> &LexicalScope { self.lexical_scopes @@ -264,11 +277,16 @@ impl Module { } /// Pushes a new scope to the module's lexical scope hierarchy. - pub fn push_new_lexical_scope(&mut self, span: Span) -> LexicalScopeId { + pub fn push_new_lexical_scope( + &mut self, + span: Span, + declaration: Option, + ) -> LexicalScopeId { let previous_scope_id = self.current_lexical_scope_id(); let new_scoped_id = { self.lexical_scopes.push(LexicalScope { parent: Some(previous_scope_id), + declaration, ..Default::default() }); self.lexical_scopes.len() - 1 @@ -285,6 +303,82 @@ impl Module { let parent_scope_id = self.current_lexical_scope().parent; self.current_lexical_scope_id = parent_scope_id.unwrap_or(0); } + + pub fn walk_scope_chain( + &self, + mut f: impl FnMut(&LexicalScope) -> Result, ErrorEmitted>, + ) -> Result, ErrorEmitted> { + let mut lexical_scope_opt = Some(self.current_lexical_scope()); + while let Some(lexical_scope) = lexical_scope_opt { + let result = f(lexical_scope)?; + if let Some(result) = result { + return Ok(Some(result)); + } + if let Some(parent_scope_id) = lexical_scope.parent { + lexical_scope_opt = self.get_lexical_scope(parent_scope_id); + } else { + lexical_scope_opt = None; + } + } + Ok(None) + } + + pub fn get_items_for_type( + &self, + engines: &Engines, + type_id: TypeId, + ) -> Vec { + let mut vec = vec![]; + let _ = self.walk_scope_chain(|lexical_scope| { + vec.extend( + lexical_scope + .items + .implemented_traits + .get_items_for_type(engines, type_id), + ); + Ok(Some(())) + }); + vec + } + + pub fn resolve_symbol( + &self, + handler: &Handler, + engines: &Engines, + symbol: &Ident, + ) -> Result { + let ret = self.walk_scope_chain(|lexical_scope| { + lexical_scope.items.resolve_symbol(handler, engines, symbol) + })?; + + if let Some(ret) = ret { + Ok(ret) + } else { + // Symbol not found + Err(handler.emit_err(CompileError::SymbolNotFound { + name: symbol.clone(), + span: symbol.span(), + })) + } + } + + pub fn get_methods_for_type( + &self, + engines: &Engines, + type_id: TypeId, + ) -> Vec { + self.get_items_for_type(engines, type_id) + .into_iter() + .filter_map(|item| match item { + ResolvedTraitImplItem::Parsed(_) => unreachable!(), + ResolvedTraitImplItem::Typed(item) => match item { + ty::TyTraitItem::Fn(decl_ref) => Some(ResolvedFunctionDecl::Typed(decl_ref)), + ty::TyTraitItem::Constant(_decl_ref) => None, + ty::TyTraitItem::Type(_decl_ref) => None, + }, + }) + .collect::>() + } } impl From for Module { diff --git a/sway-core/src/semantic_analysis/namespace/namespace.rs b/sway-core/src/semantic_analysis/namespace/namespace.rs index 6ed7fe8007b..17f5a50a996 100644 --- a/sway-core/src/semantic_analysis/namespace/namespace.rs +++ b/sway-core/src/semantic_analysis/namespace/namespace.rs @@ -1,16 +1,10 @@ -use crate::{ - language::{ty, CallPath, Visibility}, - Engines, Ident, TypeId, -}; +use crate::{language::Visibility, Engines, Ident}; use super::{ - module::Module, - root::{ResolvedDeclaration, Root}, - submodule_namespace::SubmoduleNamespace, - ModulePath, ModulePathBuf, + module::Module, root::Root, submodule_namespace::SubmoduleNamespace, ModulePath, ModulePathBuf, }; -use sway_error::handler::{ErrorEmitted, Handler}; +use sway_error::handler::Handler; use sway_types::span::Span; /// The set of items that represent the namespace context passed throughout type checking. @@ -124,15 +118,6 @@ impl Namespace { .unwrap() } - pub fn lookup_submodule_from_absolute_path( - &self, - handler: &Handler, - engines: &Engines, - path: &ModulePath, - ) -> Result<&Module, ErrorEmitted> { - self.root.module.lookup_submodule(handler, engines, path) - } - /// Returns true if the current module being checked is a direct or indirect submodule of /// the module given by the `absolute_module_path`. /// @@ -189,53 +174,6 @@ impl Namespace { root_name != &absolute_module_path[0] } - /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. - pub(crate) fn resolve_symbol( - &self, - handler: &Handler, - engines: &Engines, - symbol: &Ident, - self_type: Option, - ) -> Result { - self.root - .resolve_symbol(handler, engines, &self.mod_path, symbol, self_type) - } - - /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. - pub(crate) fn resolve_symbol_typed( - &self, - handler: &Handler, - engines: &Engines, - symbol: &Ident, - self_type: Option, - ) -> Result { - self.resolve_symbol(handler, engines, symbol, self_type) - .map(|resolved_decl| resolved_decl.expect_typed()) - } - - /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. - pub(crate) fn resolve_call_path_typed( - &self, - handler: &Handler, - engines: &Engines, - call_path: &CallPath, - self_type: Option, - ) -> Result { - self.resolve_call_path(handler, engines, call_path, self_type) - .map(|resolved_decl| resolved_decl.expect_typed()) - } - - /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. - pub(crate) fn resolve_call_path( - &self, - handler: &Handler, - engines: &Engines, - call_path: &CallPath, - self_type: Option, - ) -> Result { - self.root - .resolve_call_path(handler, engines, &self.mod_path, call_path, self_type) - } /// "Enter" the submodule at the given path by returning a new [SubmoduleNamespace]. /// diff --git a/sway-core/src/semantic_analysis/namespace/root.rs b/sway-core/src/semantic_analysis/namespace/root.rs index 7d4e22b7265..99fd5eafc2b 100644 --- a/sway-core/src/semantic_analysis/namespace/root.rs +++ b/sway-core/src/semantic_analysis/namespace/root.rs @@ -7,10 +7,9 @@ use crate::{ language::{ parsed::*, ty::{self, StructDecl, TyDecl}, - CallPath, Visibility, + Visibility, }, namespace::{ModulePath, ModulePathBuf}, - semantic_analysis::type_resolve::{resolve_associated_item, resolve_associated_type}, TypeId, }; use sway_error::{ @@ -683,6 +682,10 @@ impl Root { Ok(()) } + /// Check that all accessed modules in the src path are visible from the dst path. + /// If src and dst have a common ancestor module that is private, this privacy modifier is + /// ignored for visibility purposes, since src and dst are both behind that private visibility + /// modifier. Additionally, items in a private module are visible to its immediate parent. fn check_module_privacy( &self, handler: &Handler, @@ -690,131 +693,34 @@ impl Root { src: &ModulePath, dst: &ModulePath, ) -> Result<(), ErrorEmitted> { - // you are always allowed to access your ancestor's symbols - if !is_ancestor(src, dst) { - // we don't check the first prefix because direct children are always accessible - for prefix in iter_prefixes(src).skip(1) { - let module = self.module.lookup_submodule(handler, engines, prefix)?; - if module.visibility().is_private() { - let prefix_last = prefix[prefix.len() - 1].clone(); - handler.emit_err(CompileError::ImportPrivateModule { - span: prefix_last.span(), - name: prefix_last, - }); - } - } - } - Ok(()) - } - - ////// NAME RESOLUTION ////// - - /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. - /// - /// This is short-hand for concatenating the `mod_path` with the `call_path`'s prefixes and - /// then calling `resolve_symbol` with the resulting path and call_path's suffix. - pub(crate) fn resolve_call_path( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - call_path: &CallPath, - self_type: Option, - ) -> Result { - let (decl, _) = - self.resolve_call_path_and_mod_path(handler, engines, mod_path, call_path, self_type)?; - Ok(decl) - } + // Calculate the number of src prefixes whose privacy is ignored. + let mut ignored_prefixes = 0; - pub(crate) fn resolve_call_path_and_mod_path( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - call_path: &CallPath, - self_type: Option, - ) -> Result<(ResolvedDeclaration, ModulePathBuf), ErrorEmitted> { - let symbol_path: Vec<_> = mod_path + // Ignore visibility of common ancestors + ignored_prefixes += src .iter() - .chain(&call_path.prefixes) - .cloned() - .collect(); - self.resolve_symbol_and_mod_path( - handler, - engines, - &symbol_path, - &call_path.suffix, - self_type, - ) - } + .zip(dst) + .position(|(src_id, dst_id)| src_id != dst_id) + .unwrap_or(dst.len()); - /// Given a path to a module and the identifier of a symbol within that module, resolve its - /// declaration. - /// - /// If the symbol is within the given module's namespace via import, we recursively traverse - /// imports until we find the original declaration. - pub(crate) fn resolve_symbol( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - symbol: &Ident, - self_type: Option, - ) -> Result { - let (decl, _) = - self.resolve_symbol_and_mod_path(handler, engines, mod_path, symbol, self_type)?; - Ok(decl) - } + // Ignore visibility of direct submodules of the destination module + if dst.len() == ignored_prefixes { + ignored_prefixes += 1; + } - fn resolve_symbol_and_mod_path( - &self, - handler: &Handler, - engines: &Engines, - mod_path: &ModulePath, - symbol: &Ident, - self_type: Option, - ) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { - // This block tries to resolve associated types - let mut module = &self.module; - let mut current_mod_path = vec![]; - let mut decl_opt = None; - for ident in mod_path.iter() { - if let Some(decl) = decl_opt { - decl_opt = Some(resolve_associated_type( - handler, engines, module, ident, decl, None, self_type, - )?); - } else { - match module.submodules.get(ident.as_str()) { - Some(ns) => { - module = ns; - current_mod_path.push(ident.clone()); - } - None => { - decl_opt = Some( - module - .current_lexical_scope() - .items - .resolve_symbol(handler, engines, ident)?, - ); - } - } + // Check visibility of remaining submodules in the source path + for prefix in iter_prefixes(src).skip(ignored_prefixes) { + let module = self.module.lookup_submodule(handler, engines, prefix)?; + if module.visibility().is_private() { + let prefix_last = prefix[prefix.len() - 1].clone(); + handler.emit_err(CompileError::ImportPrivateModule { + span: prefix_last.span(), + name: prefix_last, + }); } } - if let Some(decl) = decl_opt { - let decl = - resolve_associated_item(handler, engines, module, symbol, decl, None, self_type)?; - return Ok((decl, current_mod_path)); - } - self.module - .lookup_submodule(handler, engines, mod_path) - .and_then(|module| { - let decl = module - .current_lexical_scope() - .items - .resolve_symbol(handler, engines, symbol)?; - Ok((decl, mod_path.to_vec())) - }) + Ok(()) } } diff --git a/sway-core/src/semantic_analysis/namespace/trait_map.rs b/sway-core/src/semantic_analysis/namespace/trait_map.rs index 15113704762..9eb5e8b3439 100644 --- a/sway-core/src/semantic_analysis/namespace/trait_map.rs +++ b/sway-core/src/semantic_analysis/namespace/trait_map.rs @@ -27,9 +27,11 @@ use crate::{ TypeSubstMap, UnifyCheck, }; +use super::Module; + /// Enum used to pass a value asking for insertion of type into trait map when an implementation /// of the trait cannot be found. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum TryInsertingTraitImplOnFailure { Yes, No, @@ -177,7 +179,6 @@ enum TypeRootFilter { Struct(ParsedDeclId), ContractCaller(String), Array(usize), - Storage, RawUntypedPtr, RawUntypedSlice, Ptr, @@ -190,7 +191,7 @@ enum TypeRootFilter { /// Note: "impl self" blocks are considered traits and are stored in the /// [TraitMap]. #[derive(Clone, Debug, Default)] -pub(crate) struct TraitMap { +pub struct TraitMap { trait_impls: TraitImpls, satisfied_cache: im::HashSet, } @@ -882,7 +883,8 @@ impl TraitMap { }, } in impls.iter() { - if !type_info.can_change(engines) && *type_id == *map_type_id { + if !type_engine.is_type_changeable(engines, &type_info) && *type_id == *map_type_id + { trait_map.insert_inner( map_trait_name.clone(), impl_span.clone(), @@ -1326,8 +1328,8 @@ impl TraitMap { /// Checks to see if the trait constraints are satisfied for a given type. #[allow(clippy::too_many_arguments)] pub(crate) fn check_if_trait_constraints_are_satisfied_for_type( - &mut self, handler: &Handler, + module: &mut Module, type_id: TypeId, constraints: &[TraitConstraint], access_span: &Span, @@ -1352,42 +1354,61 @@ impl TraitMap { } let hash = hasher.finish(); - if self.satisfied_cache.contains(&hash) { - return Ok(()); + { + let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits; + if trait_map.satisfied_cache.contains(&hash) { + return Ok(()); + } } + let all_impld_traits: BTreeSet<(Ident, TypeId)> = + Self::get_all_implemented_traits(module, type_id, engines); + // Call the real implementation and cache when true - match self.check_if_trait_constraints_are_satisfied_for_type_inner( + match Self::check_if_trait_constraints_are_satisfied_for_type_inner( handler, + module, type_id, constraints, access_span, engines, + all_impld_traits, try_inserting_trait_impl_on_failure, code_block_first_pass, ) { Ok(()) => { - self.satisfied_cache.insert(hash); + let trait_map = &mut module.current_lexical_scope_mut().items.implemented_traits; + trait_map.satisfied_cache.insert(hash); Ok(()) } r => r, } } - #[allow(clippy::too_many_arguments)] - fn check_if_trait_constraints_are_satisfied_for_type_inner( - &mut self, - handler: &Handler, + fn get_all_implemented_traits( + module: &Module, type_id: TypeId, - constraints: &[TraitConstraint], - access_span: &Span, engines: &Engines, - try_inserting_trait_impl_on_failure: TryInsertingTraitImplOnFailure, - code_block_first_pass: CodeBlockFirstPass, - ) -> Result<(), ErrorEmitted> { - let type_engine = engines.te(); + ) -> BTreeSet<(Ident, TypeId)> { + let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default(); + let _ = module.walk_scope_chain(|lexical_scope| { + all_impld_traits.extend( + lexical_scope + .items + .implemented_traits + .get_implemented_traits(type_id, engines), + ); + Ok(Some(())) + }); + all_impld_traits + } - let _decl_engine = engines.de(); + fn get_implemented_traits( + &self, + type_id: TypeId, + engines: &Engines, + ) -> BTreeSet<(Ident, TypeId)> { + let type_engine = engines.te(); let unify_check = UnifyCheck::non_dynamic_equality(engines); let impls = self.get_impls(engines, type_id); @@ -1397,17 +1418,14 @@ impl TraitMap { let key = &e.key; let suffix = &key.name.suffix; if unify_check.check(type_id, key.type_id) { - let map_trait_type_id = type_engine.insert( + let map_trait_type_id = type_engine.new_custom( engines, - TypeInfo::Custom { - qualified_call_path: suffix.name.clone().into(), - type_arguments: if suffix.args.is_empty() { - None - } else { - Some(suffix.args.to_vec()) - }, + suffix.name.clone().into(), + if suffix.args.is_empty() { + None + } else { + Some(suffix.args.to_vec()) }, - suffix.name.span().source_id(), ); Some((suffix.name.clone(), map_trait_type_id)) } else { @@ -1416,6 +1434,24 @@ impl TraitMap { }) .collect(); + all_impld_traits + } + + #[allow(clippy::too_many_arguments)] + fn check_if_trait_constraints_are_satisfied_for_type_inner( + handler: &Handler, + module: &mut Module, + type_id: TypeId, + constraints: &[TraitConstraint], + access_span: &Span, + engines: &Engines, + all_impld_traits: BTreeSet<(Ident, TypeId)>, + try_inserting_trait_impl_on_failure: TryInsertingTraitImplOnFailure, + code_block_first_pass: CodeBlockFirstPass, + ) -> Result<(), ErrorEmitted> { + let type_engine = engines.te(); + let unify_check = UnifyCheck::non_dynamic_equality(engines); + let required_traits: BTreeSet<(Ident, TypeId)> = constraints .iter() .map(|c| { @@ -1423,17 +1459,14 @@ impl TraitMap { trait_name: constraint_trait_name, type_arguments: constraint_type_arguments, } = c; - let constraint_type_id = type_engine.insert( + let constraint_type_id = type_engine.new_custom( engines, - TypeInfo::Custom { - qualified_call_path: constraint_trait_name.suffix.clone().into(), - type_arguments: if constraint_type_arguments.is_empty() { - None - } else { - Some(constraint_type_arguments.clone()) - }, + constraint_trait_name.suffix.clone().into(), + if constraint_type_arguments.is_empty() { + None + } else { + Some(constraint_type_arguments.clone()) }, - constraint_trait_name.span().source_id(), ); (c.trait_name.suffix.clone(), constraint_type_id) }) @@ -1457,9 +1490,13 @@ impl TraitMap { try_inserting_trait_impl_on_failure, TryInsertingTraitImplOnFailure::Yes ) { - self.insert_for_type(engines, type_id, code_block_first_pass.clone()); - return self.check_if_trait_constraints_are_satisfied_for_type( + let trait_map = + &mut module.current_lexical_scope_mut().items.implemented_traits; + trait_map.insert_for_type(engines, type_id, code_block_first_pass.clone()); + + return Self::check_if_trait_constraints_are_satisfied_for_type( handler, + module, type_id, constraints, access_span, @@ -1604,7 +1641,6 @@ impl TraitMap { } ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()), Array(_, length) => TypeRootFilter::Array(length.val()), - Storage { .. } => TypeRootFilter::Storage, RawUntypedPtr => TypeRootFilter::RawUntypedPtr, RawUntypedSlice => TypeRootFilter::RawUntypedSlice, Ptr(_) => TypeRootFilter::Ptr, diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index e0a5b5b3f0b..2ca2ee6ad38 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -1029,7 +1029,6 @@ fn type_info_name(type_info: &TypeInfo) -> String { TypeInfo::Struct { .. } => "struct", TypeInfo::Enum { .. } => "enum", TypeInfo::Array(..) => "array", - TypeInfo::Storage { .. } => "contract storage", TypeInfo::RawUntypedPtr => "raw untyped ptr", TypeInfo::RawUntypedSlice => "raw untyped slice", TypeInfo::Ptr(..) => "__ptr", diff --git a/sway-core/src/semantic_analysis/symbol_collection_context.rs b/sway-core/src/semantic_analysis/symbol_collection_context.rs index 2a3be6aa35d..f831c2226ea 100644 --- a/sway-core/src/semantic_analysis/symbol_collection_context.rs +++ b/sway-core/src/semantic_analysis/symbol_collection_context.rs @@ -1,7 +1,6 @@ use crate::{ language::{parsed::Declaration, Visibility}, - namespace::LexicalScopeId, - namespace::ModulePath, + namespace::{LexicalScopeId, ModulePath, ResolvedDeclaration}, semantic_analysis::Namespace, Engines, }; @@ -41,12 +40,14 @@ impl SymbolCollectionContext { &mut self, engines: &Engines, span: Span, + decl: Option, with_scoped_ctx: impl FnOnce(&mut SymbolCollectionContext) -> Result, ) -> (Result, LexicalScopeId) { - let lexical_scope_id: LexicalScopeId = self - .namespace - .module_mut(engines) - .write(engines, |m| m.push_new_lexical_scope(span.clone())); + let decl = decl.map(ResolvedDeclaration::Parsed); + let lexical_scope_id: LexicalScopeId = + self.namespace.module_mut(engines).write(engines, |m| { + m.push_new_lexical_scope(span.clone(), decl.clone()) + }); let ret = with_scoped_ctx(self); self.namespace .module_mut(engines) diff --git a/sway-core/src/semantic_analysis/symbol_resolve_context.rs b/sway-core/src/semantic_analysis/symbol_resolve_context.rs index 01bc631ec0e..7a9155a193a 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve_context.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve_context.rs @@ -1,18 +1,18 @@ use crate::{ engine_threading::*, language::{CallPath, Visibility}, - namespace::{ModulePath, ResolvedDeclaration}, + namespace::ResolvedDeclaration, semantic_analysis::{ast_node::ConstShadowingMode, Namespace}, type_system::TypeId, }; -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{span::Span, Ident, Spanned}; -use sway_utils::iter_prefixes; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{span::Span, Ident}; -use super::{symbol_collection_context::SymbolCollectionContext, GenericShadowingMode}; +use super::{ + symbol_collection_context::SymbolCollectionContext, + type_resolve::{resolve_call_path, VisibilityCheck}, + GenericShadowingMode, +}; /// Contextual state tracked and accumulated throughout symbol resolving. pub struct SymbolResolveContext<'a> { @@ -184,70 +184,14 @@ impl<'a> SymbolResolveContext<'a> { handler: &Handler, call_path: &CallPath, ) -> Result { - self.resolve_call_path_with_visibility_check_and_modpath( + resolve_call_path( handler, + self.engines(), + self.namespace().root(), &self.namespace().mod_path, call_path, + self.self_type(), + VisibilityCheck::Yes, ) } - - /// Resolve a symbol that is potentially prefixed with some path, e.g. `foo::bar::symbol`. - /// - /// This will concatenate the `mod_path` with the `call_path`'s prefixes and - /// then calling `resolve_symbol` with the resulting path and call_path's suffix. - /// - /// The `mod_path` is significant here as we assume the resolution is done within the - /// context of the module pointed to by `mod_path` and will only check the call path prefixes - /// and the symbol's own visibility. - pub(crate) fn resolve_call_path_with_visibility_check_and_modpath( - &self, - handler: &Handler, - mod_path: &ModulePath, - call_path: &CallPath, - ) -> Result { - let (decl, mod_path) = self.namespace().root.resolve_call_path_and_mod_path( - handler, - self.engines, - mod_path, - call_path, - self.self_type, - )?; - - // In case there is no mod path we don't need to check visibility - if mod_path.is_empty() { - return Ok(decl); - } - - // In case there are no prefixes we don't need to check visibility - if call_path.prefixes.is_empty() { - return Ok(decl); - } - - // check the visibility of the call path elements - // we don't check the first prefix because direct children are always accessible - for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = self.namespace().lookup_submodule_from_absolute_path( - handler, - self.engines(), - prefix, - )?; - if module.visibility().is_private() { - let prefix_last = prefix[prefix.len() - 1].clone(); - handler.emit_err(CompileError::ImportPrivateModule { - span: prefix_last.span(), - name: prefix_last, - }); - } - } - - // check the visibility of the symbol itself - if !decl.visibility(self.engines).is_public() { - handler.emit_err(CompileError::ImportPrivateSymbol { - name: call_path.suffix.clone(), - span: call_path.suffix.span(), - }); - } - - Ok(decl) - } } diff --git a/sway-core/src/semantic_analysis/type_check_context.rs b/sway-core/src/semantic_analysis/type_check_context.rs index d6c3a7c45f1..9078be6ff4d 100644 --- a/sway-core/src/semantic_analysis/type_check_context.rs +++ b/sway-core/src/semantic_analysis/type_check_context.rs @@ -30,7 +30,7 @@ use sway_types::{span::Span, Ident, Spanned}; use super::{ symbol_collection_context::SymbolCollectionContext, - type_resolve::{resolve_call_path, resolve_qualified_call_path, resolve_type}, + type_resolve::{resolve_call_path, resolve_qualified_call_path, resolve_type, VisibilityCheck}, GenericShadowingMode, }; @@ -82,7 +82,7 @@ pub struct TypeCheckContext<'a> { /// Whether or not a const declaration shadows previous const declarations sequentially. /// /// This is `Sequential` while checking const declarations in functions, otherwise `ItemStyle`. - const_shadowing_mode: ConstShadowingMode, + pub(crate) const_shadowing_mode: ConstShadowingMode, /// Whether or not a generic type parameters shadows previous generic type parameters. /// /// This is `Disallow` everywhere except while checking type parameters bounds in struct instantiation. @@ -124,8 +124,8 @@ impl<'a> TypeCheckContext<'a> { namespace, engines, collection_ctx, - type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), - function_type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), + type_annotation: engines.te().new_unknown(), + function_type_annotation: engines.te().new_unknown(), unify_generic: false, self_type: None, type_subst: TypeSubstMap::new(), @@ -168,8 +168,8 @@ impl<'a> TypeCheckContext<'a> { collection_ctx, namespace, engines, - type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), - function_type_annotation: engines.te().insert(engines, TypeInfo::Unknown, None), + type_annotation: engines.te().new_unknown(), + function_type_annotation: engines.te().new_unknown(), unify_generic: false, self_type: None, type_subst: TypeSubstMap::new(), @@ -671,39 +671,80 @@ impl<'a> TypeCheckContext<'a> { type_info_prefix, self.self_type(), &self.subst_ctx(), + VisibilityCheck::Yes, ) } + pub(crate) fn resolve_qualified_call_path( + &mut self, + handler: &Handler, + qualified_call_path: &QualifiedCallPath, + ) -> Result { + resolve_qualified_call_path( + handler, + self.engines(), + self.namespace(), + &self.namespace().mod_path.clone(), + qualified_call_path, + self.self_type(), + &self.subst_ctx(), + VisibilityCheck::Yes, + ) + .map(|d| d.expect_typed()) + } + + /// Short-hand for calling [Root::resolve_symbol] on `root` with the `mod_path`. + pub(crate) fn resolve_symbol( + &self, + handler: &Handler, + symbol: &Ident, + ) -> Result { + resolve_call_path( + handler, + self.engines(), + self.namespace().root(), + self.namespace().mod_path(), + &symbol.clone().into(), + self.self_type(), + VisibilityCheck::No, + ) + .map(|d| d.expect_typed()) + } + /// Short-hand for calling [Root::resolve_call_path_with_visibility_check] on `root` with the `mod_path`. pub(crate) fn resolve_call_path_with_visibility_check( &self, handler: &Handler, call_path: &CallPath, - ) -> Result { + ) -> Result { resolve_call_path( handler, self.engines(), - self.namespace(), + self.namespace().root(), &self.namespace().mod_path, call_path, self.self_type(), + VisibilityCheck::Yes, ) + .map(|d| d.expect_typed()) } - pub(crate) fn resolve_qualified_call_path_with_visibility_check( - &mut self, + /// Short-hand for calling [Root::resolve_call_path] on `root` with the `mod_path`. + pub(crate) fn resolve_call_path( + &self, handler: &Handler, - qualified_call_path: &QualifiedCallPath, - ) -> Result { - resolve_qualified_call_path( + call_path: &CallPath, + ) -> Result { + resolve_call_path( handler, self.engines(), - self.namespace(), - &self.namespace().mod_path.clone(), - qualified_call_path, + self.namespace().root(), + self.namespace().mod_path(), + call_path, self.self_type(), - &self.subst_ctx(), + VisibilityCheck::No, ) + .map(|d| d.expect_typed()) } /// Given a name and a type (plus a `self_type` to potentially @@ -726,16 +767,14 @@ impl<'a> TypeCheckContext<'a> { } // grab the local module - let local_module = self.namespace().lookup_submodule_from_absolute_path( + let local_module = self.namespace().root_module().lookup_submodule( handler, self.engines(), &self.namespace().mod_path, )?; // grab the local items from the local module - let local_items = local_module - .current_items() - .get_items_for_type(self.engines, type_id); + let local_items = local_module.get_items_for_type(self.engines, type_id); // resolve the type let type_id = resolve_type( @@ -749,20 +788,19 @@ impl<'a> TypeCheckContext<'a> { None, self.self_type(), &self.subst_ctx(), + VisibilityCheck::Yes, ) - .unwrap_or_else(|err| type_engine.insert(self.engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); // grab the module where the type itself is declared - let type_module = self.namespace().lookup_submodule_from_absolute_path( + let type_module = self.namespace().root_module().lookup_submodule( handler, self.engines(), item_prefix, )?; // grab the items from where the type is declared - let mut type_items = type_module - .current_items() - .get_items_for_type(self.engines, type_id); + let mut type_items = type_module.get_items_for_type(self.engines, type_id); let mut items = local_items; items.append(&mut type_items); @@ -1387,19 +1425,16 @@ impl<'a> TypeCheckContext<'a> { let handler = Handler::default(); let engines = self.engines; let code_block_first_pass = self.code_block_first_pass(); - self.namespace_mut() - .module_mut(engines) - .current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( - &handler, - type_id, - constraints, - &Span::dummy(), - engines, - crate::namespace::TryInsertingTraitImplOnFailure::Yes, - code_block_first_pass.into(), - ) - .is_ok() + TraitMap::check_if_trait_constraints_are_satisfied_for_type( + &handler, + self.namespace_mut().module_mut(engines), + type_id, + constraints, + &Span::dummy(), + engines, + crate::namespace::TryInsertingTraitImplOnFailure::Yes, + code_block_first_pass.into(), + ) + .is_ok() } } diff --git a/sway-core/src/semantic_analysis/type_resolve.rs b/sway-core/src/semantic_analysis/type_resolve.rs index e4c676fda1e..174817fdb5f 100644 --- a/sway-core/src/semantic_analysis/type_resolve.rs +++ b/sway-core/src/semantic_analysis/type_resolve.rs @@ -11,11 +11,18 @@ use crate::{ CallPath, QualifiedCallPath, }, monomorphization::type_decl_opt_to_type_id, - namespace::{Module, ModulePath, ResolvedDeclaration, ResolvedTraitImplItem}, + namespace::{Module, ModulePath, ResolvedDeclaration, ResolvedTraitImplItem, Root}, type_system::SubstTypes, EnforceTypeArguments, Engines, Namespace, SubstTypesContext, TypeId, TypeInfo, }; +/// Specifies if visibility checks should be performed as part of name resolution. +#[derive(Clone, Copy, PartialEq)] +pub enum VisibilityCheck { + Yes, + No, +} + /// Resolve the type of the given [TypeId], replacing any instances of /// [TypeInfo::Custom] with either a monomorphized struct, monomorphized /// enum, or a reference to a type parameter. @@ -31,6 +38,7 @@ pub fn resolve_type( type_info_prefix: Option<&ModulePath>, self_type: Option, subst_ctx: &SubstTypesContext, + check_visibility: VisibilityCheck, ) -> Result { let type_engine = engines.te(); let module_path = type_info_prefix.unwrap_or(mod_path); @@ -47,6 +55,7 @@ pub fn resolve_type( &qualified_call_path, self_type, subst_ctx, + check_visibility, ) .ok(); type_decl_opt_to_type_id( @@ -63,7 +72,7 @@ pub fn resolve_type( subst_ctx, )? } - TypeInfo::Array(mut elem_ty, n) => { + TypeInfo::Array(mut elem_ty, length) => { elem_ty.type_id = resolve_type( handler, engines, @@ -75,18 +84,11 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); - engines.te().insert( - engines, - TypeInfo::Array(elem_ty.clone(), n.clone()), - elem_ty.span.source_id(), - ) + engines.te().insert_array(engines, elem_ty, length) } TypeInfo::Slice(mut elem_ty) => { elem_ty.type_id = resolve_type( @@ -100,18 +102,11 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); - engines.te().insert( - engines, - TypeInfo::Slice(elem_ty.clone()), - elem_ty.span.source_id(), - ) + engines.te().insert_slice(engines, elem_ty) } TypeInfo::Tuple(mut type_arguments) => { for type_argument in type_arguments.iter_mut() { @@ -126,17 +121,12 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } - engines - .te() - .insert(engines, TypeInfo::Tuple(type_arguments), span.source_id()) + engines.te().insert_tuple(engines, type_arguments) } TypeInfo::TraitType { name, @@ -178,21 +168,11 @@ pub fn resolve_type( None, self_type, subst_ctx, + check_visibility, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); - engines.te().insert( - engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: ty.clone(), - }, - None, - ) + engines.te().insert_ref(engines, to_mutable_value, ty) } _ => type_id, }; @@ -203,6 +183,7 @@ pub fn resolve_type( Ok(type_id) } +#[allow(clippy::too_many_arguments)] pub fn resolve_qualified_call_path( handler: &Handler, engines: &Engines, @@ -211,6 +192,7 @@ pub fn resolve_qualified_call_path( qualified_call_path: &QualifiedCallPath, self_type: Option, subst_ctx: &SubstTypesContext, + check_visibility: VisibilityCheck, ) -> Result { let type_engine = engines.te(); if let Some(qualified_path_root) = qualified_call_path.clone().qualified_path_root { @@ -223,10 +205,11 @@ pub fn resolve_qualified_call_path( let type_decl = resolve_call_path( handler, engines, - namespace, + namespace.root(), mod_path, &qualified_call_path.clone().to_call_path(handler)?, self_type, + check_visibility, )?; type_decl_opt_to_type_id( handler, @@ -271,10 +254,11 @@ pub fn resolve_qualified_call_path( resolve_call_path( handler, engines, - namespace, + namespace.root(), mod_path, &qualified_call_path.call_path, self_type, + check_visibility, ) } } @@ -290,14 +274,30 @@ pub fn resolve_qualified_call_path( pub fn resolve_call_path( handler: &Handler, engines: &Engines, - namespace: &Namespace, + root: &Root, mod_path: &ModulePath, call_path: &CallPath, self_type: Option, + check_visibility: VisibilityCheck, ) -> Result { - let (decl, mod_path) = namespace - .root - .resolve_call_path_and_mod_path(handler, engines, mod_path, call_path, self_type)?; + let symbol_path: Vec<_> = mod_path + .iter() + .chain(&call_path.prefixes) + .cloned() + .collect(); + + let (decl, mod_path) = resolve_symbol_and_mod_path( + handler, + engines, + &root.module, + &symbol_path, + &call_path.suffix, + self_type, + )?; + + if check_visibility == VisibilityCheck::No { + return Ok(decl); + } // In case there is no mod path we don't need to check visibility if mod_path.is_empty() { @@ -312,7 +312,7 @@ pub fn resolve_call_path( // check the visibility of the call path elements // we don't check the first prefix because direct children are always accessible for prefix in iter_prefixes(&call_path.prefixes).skip(1) { - let module = namespace.lookup_submodule_from_absolute_path(handler, engines, prefix)?; + let module = root.module.lookup_submodule(handler, engines, prefix)?; if module.visibility().is_private() { let prefix_last = prefix[prefix.len() - 1].clone(); handler.emit_err(CompileError::ImportPrivateModule { @@ -333,7 +333,63 @@ pub fn resolve_call_path( Ok(decl) } -pub fn decl_to_type_info( +fn resolve_symbol_and_mod_path( + handler: &Handler, + engines: &Engines, + module: &Module, + mod_path: &ModulePath, + symbol: &Ident, + self_type: Option, +) -> Result<(ResolvedDeclaration, Vec), ErrorEmitted> { + let mut current_module = module; + // This block tries to resolve associated types + let mut current_mod_path = vec![]; + let mut decl_opt = None; + for ident in mod_path.iter() { + if let Some(decl) = decl_opt { + decl_opt = Some(resolve_associated_type_or_item( + handler, + engines, + current_module, + ident, + decl, + None, + self_type, + )?); + } else { + match current_module.submodules.get(ident.as_str()) { + Some(ns) => { + current_module = ns; + current_mod_path.push(ident.clone()); + } + None => { + decl_opt = Some(current_module.resolve_symbol(handler, engines, ident)?); + } + } + } + } + if let Some(decl) = decl_opt { + let decl = resolve_associated_type_or_item( + handler, + engines, + current_module, + symbol, + decl, + None, + self_type, + )?; + return Ok((decl, current_mod_path)); + } + + module + .lookup_submodule(handler, engines, mod_path) + .and_then(|module| { + let decl = module.resolve_symbol(handler, engines, symbol)?; + Ok((decl, mod_path.to_vec())) + }) +} + +fn decl_to_type_info( handler: &Handler, engines: &Engines, symbol: &Ident, @@ -368,7 +424,7 @@ pub fn decl_to_type_info( } #[allow(clippy::too_many_arguments)] -pub fn resolve_associated_item_from_type_id( +fn resolve_associated_item_from_type_id( handler: &Handler, engines: &Engines, module: &Module, @@ -404,27 +460,7 @@ pub fn resolve_associated_item_from_type_id( } #[allow(clippy::too_many_arguments)] -pub fn resolve_associated_type( - handler: &Handler, - engines: &Engines, - module: &Module, - symbol: &Ident, - decl: ResolvedDeclaration, - as_trait: Option, - self_type: Option, -) -> Result { - let type_info = decl_to_type_info(handler, engines, symbol, decl)?; - let type_id = engines - .te() - .insert(engines, type_info, symbol.span().source_id()); - - resolve_associated_item_from_type_id( - handler, engines, module, symbol, type_id, as_trait, self_type, - ) -} - -#[allow(clippy::too_many_arguments)] -pub fn resolve_associated_item( +fn resolve_associated_type_or_item( handler: &Handler, engines: &Engines, module: &Module, @@ -444,7 +480,7 @@ pub fn resolve_associated_item( } #[allow(clippy::too_many_arguments)] -pub(crate) fn resolve_call_path_and_root_type_id( +fn resolve_call_path_and_root_type_id( handler: &Handler, engines: &Engines, module: &Module, @@ -470,7 +506,7 @@ pub(crate) fn resolve_call_path_and_root_type_id( )?); as_trait = None; } else if let Some(decl) = decl_opt { - decl_opt = Some(resolve_associated_type( + decl_opt = Some(resolve_associated_type_or_item( handler, engines, module, @@ -495,7 +531,7 @@ pub(crate) fn resolve_call_path_and_root_type_id( return Ok(decl); } if let Some(decl) = decl_opt { - let decl = resolve_associated_item( + let decl = resolve_associated_type_or_item( handler, engines, module, diff --git a/sway-core/src/transform/attribute.rs b/sway-core/src/transform/attribute.rs index d29978205c8..d44538befa2 100644 --- a/sway-core/src/transform/attribute.rs +++ b/sway-core/src/transform/attribute.rs @@ -21,6 +21,8 @@ //! #[foo(bar, bar)] use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; +use std::{hash::Hash, sync::Arc}; use sway_ast::Literal; use sway_types::{ constants::{ @@ -29,9 +31,7 @@ use sway_types::{ Ident, Span, Spanned, }; -use std::{hash::Hash, sync::Arc}; - -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct AttributeArg { pub name: Ident, pub value: Option, @@ -47,7 +47,7 @@ impl Spanned for AttributeArg { /// An attribute has a name (i.e "doc", "storage"), /// a vector of possible arguments and /// a span from its declaration. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Attribute { pub name: Ident, pub args: Vec, @@ -55,7 +55,7 @@ pub struct Attribute { } /// Valid kinds of attributes supported by the compiler -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum AttributeKind { Doc, DocComment, @@ -104,7 +104,7 @@ impl AttributeKind { } /// Stores the attributes associated with the type. -#[derive(Default, Clone, Debug, Eq, PartialEq)] +#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct AttributesMap(Arc>>); impl AttributesMap { diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index e40c9148fda..9dc3792c07d 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -542,11 +542,7 @@ pub fn item_fn_to_function_declaration( let return_type = match item_fn.fn_signature.return_type_opt { Some((_right_arrow, ty)) => ty_to_type_argument(context, handler, engines, ty)?, None => { - let type_id = engines.te().insert( - engines, - TypeInfo::Tuple(Vec::new()), - item_fn.fn_signature.span().source_id(), - ); + let type_id = engines.te().id_of_unit(); TypeArgument { type_id, initial_type_id: type_id, @@ -769,7 +765,7 @@ pub fn item_impl_to_declaration( ) .map(ImplItem::Fn), sway_ast::ItemImplItem::Const(const_item) => item_const_to_constant_declaration( - context, handler, engines, const_item, attributes, true, + context, handler, engines, const_item, attributes, false, ) .map(ImplItem::Constant), sway_ast::ItemImplItem::Type(type_item) => trait_type_to_trait_type_declaration( @@ -992,7 +988,7 @@ pub(crate) fn item_const_to_constant_declaration( return Err(errors); } } - engines.te().insert(engines, TypeInfo::Unknown, None).into() + engines.te().new_unknown().into() } }; @@ -1255,18 +1251,11 @@ fn generic_params_opt_to_type_parameters_with_parent( .into_inner() .into_iter() .map(|ident| { - let custom_type = type_engine.insert( - engines, - TypeInfo::Custom { - qualified_call_path: ident.clone().into(), - type_arguments: None, - }, - ident.span().source_id(), - ); + let custom_type = type_engine.new_custom_from_name(engines, ident.clone()); TypeParameter { type_id: custom_type, initial_type_id: custom_type, - name_ident: ident, + name: ident, trait_constraints: Vec::new(), trait_constraints_span: Span::dummy(), is_from_parent, @@ -1286,12 +1275,12 @@ fn generic_params_opt_to_type_parameters_with_parent( { let param_to_edit = if let Some(o) = params .iter_mut() - .find(|TypeParameter { name_ident, .. }| name_ident.as_str() == ty_name.as_str()) + .find(|TypeParameter { name, .. }| name.as_str() == ty_name.as_str()) { o } else if let Some(o2) = parent_params .iter() - .find(|TypeParameter { name_ident, .. }| name_ident.as_str() == ty_name.as_str()) + .find(|TypeParameter { name, .. }| name.as_str() == ty_name.as_str()) { params.push(o2.clone()); params.last_mut().unwrap() @@ -1405,11 +1394,7 @@ fn fn_args_to_function_parameters( (Some(reference), None) => reference.span(), (Some(reference), Some(mutable)) => Span::join(reference.span(), &mutable.span()), }; - let type_id = engines.te().insert( - engines, - TypeInfo::new_self_type(self_token.span()), - self_token.span().source_id(), - ); + let type_id = engines.te().new_self_type(engines, self_token.span()); let mut function_parameters = vec![FunctionParameter { name: Ident::new(self_token.span()), is_reference: ref_self.is_some(), @@ -1461,7 +1446,7 @@ pub(crate) fn type_name_to_type_info_opt(name: &Ident) -> Option { "str" => Some(TypeInfo::StringSlice), "raw_ptr" => Some(TypeInfo::RawUntypedPtr), "raw_slice" => Some(TypeInfo::RawUntypedSlice), - "Self" | "self" => Some(TypeInfo::new_self_type(name.span())), + "Self" => Some(TypeInfo::new_self_type(name.span())), "Contract" => Some(TypeInfo::Contract), _other => None, } @@ -1613,11 +1598,7 @@ fn fn_signature_to_trait_fn( let return_type = match &fn_signature.return_type_opt { Some((_right_arrow, ty)) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert( - engines, - TypeInfo::Tuple(Vec::new()), - fn_signature.span().source_id(), - ); + let type_id = engines.te().id_of_unit(); TypeArgument { type_id, initial_type_id: type_id, @@ -2150,6 +2131,7 @@ fn expr_to_expression( kind: ExpressionKind::WhileLoop(WhileLoopExpression { condition: Box::new(expr_to_expression(context, handler, engines, *condition)?), body: braced_code_block_contents_to_code_block(context, handler, engines, block)?, + is_desugared_for_loop: false, }), span, }, @@ -2754,7 +2736,10 @@ fn expr_to_length( expr: Expr, ) -> Result { let span = expr.span(); - Ok(Length::new(expr_to_usize(context, handler, expr)?, span)) + Ok(Length::from_numeric_literal( + expr_to_usize(context, handler, expr)?, + span, + )) } fn expr_to_usize( @@ -3047,7 +3032,7 @@ fn match_expr_to_expression( let var_decl = engines.pe().insert(VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3131,7 +3116,7 @@ fn for_expr_to_expression( // Declare iterable with iterator return let iterable_decl = engines.pe().insert(VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3164,7 +3149,7 @@ fn for_expr_to_expression( // Declare value_opt = iterable.next() let value_opt_to_next_decl = engines.pe().insert(VariableDeclaration { type_ascription: { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3294,6 +3279,7 @@ fn for_expr_to_expression( span: Span::dummy(), }), body: while_body, + is_desugared_for_loop: true, }), span: Span::dummy(), }), @@ -3349,22 +3335,18 @@ fn path_root_opt_to_bool_and_qualified_path_root( close_angle_bracket_token: _, }), _, - )) => ( - false, - if let Some((_, path_type)) = as_trait { - Some(QualifiedPathType { - ty: ty_to_type_argument(context, handler, engines, *ty)?, - as_trait: engines.te().insert( - engines, - path_type_to_type_info(context, handler, engines, *path_type.clone())?, - path_type.span().source_id(), - ), - as_trait_span: path_type.span(), - }) - } else { - None - }, - ), + )) => (false, { + let (_, path_type) = as_trait; + Some(QualifiedPathType { + ty: ty_to_type_argument(context, handler, engines, *ty)?, + as_trait: engines.te().insert( + engines, + path_type_to_type_info(context, handler, engines, *path_type.clone())?, + path_type.span().source_id(), + ), + as_trait_span: path_type.span(), + }) + }), }) } @@ -3820,7 +3802,7 @@ fn statement_let_to_ast_nodes_unfold( let type_ascription = match ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty)?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3870,7 +3852,7 @@ fn statement_let_to_ast_nodes_unfold( let type_ascription = match &ty_opt { Some(ty) => ty_to_type_argument(context, handler, engines, ty.clone())?, None => { - let type_id = engines.te().insert(engines, TypeInfo::Unknown, None); + let type_id = engines.te().new_unknown(); TypeArgument { type_id, initial_type_id: type_id, @@ -3954,52 +3936,38 @@ fn statement_let_to_ast_nodes_unfold( let tuple_name = generate_tuple_var_name(context.next_destructured_tuple_unique_suffix()); - let tuple_name = Ident::new_with_override(tuple_name, pat_tuple.span().clone()); + let tuple_name = Ident::new_with_override(tuple_name, pat_tuple.span()); - // Acript a second declaration to a tuple of placeholders to check that the tuple - // is properly sized to the pattern + // Ascribe a second declaration to a tuple of placeholders to check that the tuple + // is properly sized to the pattern. let placeholders_type_ascription = { - let type_id = engines.te().insert( + let type_id = engines.te().insert_tuple_without_annotations( engines, - TypeInfo::Tuple( - pat_tuple - .clone() - .into_inner() - .into_iter() - .map(|pat| { - let initial_type_id = - engines.te().insert(engines, TypeInfo::Unknown, None); - let dummy_type_param = TypeParameter { - type_id: initial_type_id, - initial_type_id, - name_ident: Ident::new_with_override( - "_".into(), - pat.span().clone(), - ), - trait_constraints: vec![], - trait_constraints_span: Span::dummy(), - is_from_parent: false, - }; - let initial_type_id = engines.te().insert( - engines, - TypeInfo::Placeholder(dummy_type_param), - None, - ); - TypeArgument { - type_id: initial_type_id, - initial_type_id, - call_path_tree: None, - span: Span::dummy(), - } - }) - .collect(), - ), - tuple_name.span().source_id(), + pat_tuple + .clone() + .into_inner() + .into_iter() + .map(|pat| { + // Since these placeholders are generated specifically for checks, the `pat.span()` must not + // necessarily point to a "_" string in code. E.g., in this example: + // let (a, _) = (0, 0); + // The first `pat.span()` will point to "a", while the second one will indeed point to "_". + // However, their `pat.span()`s will always be in the source file in which the placeholder + // is logically situated. + engines.te().new_placeholder(TypeParameter::new_placeholder( + engines.te().new_unknown(), + pat.span(), + )) + }) + .collect(), ); + + // The type argument is a tuple of place holders of unknowns pointing to + // the tuple pattern. TypeArgument { type_id, initial_type_id: type_id, - span: tuple_name.span(), + span: pat_tuple.span(), call_path_tree: None, } }; @@ -4313,14 +4281,14 @@ fn ty_to_type_parameter( ) -> Result { let type_engine = engines.te(); - let name_ident = match ty { + let name = match ty { Ty::Path(path_type) => path_type_to_ident(context, handler, path_type)?, Ty::Infer { underscore_token } => { - let unknown_type = type_engine.insert(engines, TypeInfo::Unknown, None); + let unknown_type = type_engine.new_unknown(); return Ok(TypeParameter { type_id: unknown_type, initial_type_id: unknown_type, - name_ident: underscore_token.into(), + name: underscore_token.into(), trait_constraints: Vec::default(), trait_constraints_span: Span::dummy(), is_from_parent: false, @@ -4328,25 +4296,18 @@ fn ty_to_type_parameter( } Ty::Tuple(..) => panic!("tuple types are not allowed in this position"), Ty::Array(..) => panic!("array types are not allowed in this position"), - Ty::StringSlice(..) => panic!("str types are not allowed in this position"), - Ty::StringArray { .. } => panic!("str types are not allowed in this position"), + Ty::StringSlice(..) => panic!("str slice types are not allowed in this position"), + Ty::StringArray { .. } => panic!("str array types are not allowed in this position"), Ty::Ptr { .. } => panic!("__ptr types are not allowed in this position"), Ty::Slice { .. } => panic!("__slice types are not allowed in this position"), Ty::Ref { .. } => panic!("ref types are not allowed in this position"), Ty::Never { .. } => panic!("never types are not allowed in this position"), }; - let custom_type = type_engine.insert( - engines, - TypeInfo::Custom { - qualified_call_path: name_ident.clone().into(), - type_arguments: None, - }, - name_ident.span().source_id(), - ); + let custom_type = type_engine.new_custom_from_name(engines, name.clone()); Ok(TypeParameter { type_id: custom_type, initial_type_id: custom_type, - name_ident, + name, trait_constraints: Vec::new(), trait_constraints_span: Span::dummy(), is_from_parent: false, @@ -4635,7 +4596,10 @@ fn path_type_to_type_info( } } None => { - if name.as_str() == "ContractCaller" { + if name.as_str() == "self" { + let error = ConvertParseTreeError::UnknownTypeNameSelf { span }; + return Err(handler.emit_err(error.into())); + } else if name.as_str() == "ContractCaller" { if root_opt.is_some() || !suffix.is_empty() { let error = ConvertParseTreeError::FullySpecifiedTypesNotSupported { span }; return Err(handler.emit_err(error.into())); diff --git a/sway-core/src/type_system/ast_elements/binding.rs b/sway-core/src/type_system/ast_elements/binding.rs index 9a4c7c1dd43..78b4696e313 100644 --- a/sway-core/src/type_system/ast_elements/binding.rs +++ b/sway-core/src/type_system/ast_elements/binding.rs @@ -1,7 +1,3 @@ -use sway_ast::Intrinsic; -use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::{Span, Spanned}; - use crate::{ decl_engine::{ parsed_id::ParsedDeclId, DeclEngineGetParsedDeclId, DeclEngineInsert, DeclId, DeclRef, @@ -18,6 +14,10 @@ use crate::{ type_system::priv_prelude::*, EnforceTypeArguments, Ident, }; +use serde::{Deserialize, Serialize}; +use sway_ast::Intrinsic; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{Span, Spanned}; /// A `TypeBinding` is the result of using turbofish to bind types to /// generic parameters. @@ -78,7 +78,7 @@ use crate::{ /// - `data4` has a type ascription and has type arguments in the `TypeBinding`, /// so, with the type from the value passed to `value`, all three are unified /// together -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TypeBinding { pub inner: T, pub type_arguments: TypeArgs, @@ -103,7 +103,7 @@ pub struct TypeBinding { /// ``` /// So we can have type parameters in the `Prefix` or `Regular` variant but not /// in both. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum TypeArgs { /// `Regular` variant indicates the type arguments are located after the suffix. Regular(Vec), @@ -220,7 +220,8 @@ impl TypeBinding> { // find the module that the symbol is in let type_info_prefix = ctx.namespace().prepend_module_path(&self.inner.prefixes); ctx.namespace() - .lookup_submodule_from_absolute_path(handler, engines, &type_info_prefix)?; + .root_module() + .lookup_submodule(handler, engines, &type_info_prefix)?; // create the type info object let type_info = type_info.apply_type_arguments( @@ -238,7 +239,7 @@ impl TypeBinding> { EnforceTypeArguments::No, Some(&type_info_prefix), ) - .unwrap_or_else(|err| type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None)); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); Ok(type_id) } @@ -286,6 +287,7 @@ impl SymbolResolveTypeBinding for TypeBinding { let engines = ctx.engines(); // Grab the declaration. let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; + // Check to see if this is a function declaration. let fn_decl = unknown_decl .resolve_parsed(engines.de()) @@ -309,11 +311,9 @@ impl TypeCheckTypeBinding for TypeBinding { > { let type_engine = ctx.engines.te(); let decl_engine = ctx.engines.de(); - let engines = ctx.engines(); + // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Check to see if this is a fn declaration. let fn_ref = unknown_decl.to_fn_ref(handler, ctx.engines())?; // Get a new copy from the declaration engine. @@ -339,9 +339,7 @@ impl TypeCheckTypeBinding for TypeBinding { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| type_engine.id_of_error_recovery(err)); } } } @@ -391,9 +389,7 @@ impl TypeCheckTypeBinding for TypeBinding { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Check to see if this is a struct declaration. let struct_id = unknown_decl.to_struct_decl(handler, engines)?; // Get a new copy from the declaration engine. @@ -411,11 +407,7 @@ impl TypeCheckTypeBinding for TypeBinding { new_copy, decl_engine.get_parsed_decl_id(&struct_id).as_ref(), ); - let type_id = type_engine.insert( - engines, - TypeInfo::Struct(*new_struct_ref.id()), - new_struct_ref.span().source_id(), - ); + let type_id = type_engine.insert_struct(engines, *new_struct_ref.id()); Ok((new_struct_ref, Some(type_id), None)) } } @@ -437,9 +429,7 @@ impl TypeCheckTypeBinding for TypeBinding { let decl_engine = ctx.engines.de(); let engines = ctx.engines(); // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Get a new copy from the declaration engine. let enum_id = if let ty::TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = @@ -464,11 +454,7 @@ impl TypeCheckTypeBinding for TypeBinding { // Insert the new copy into the declaration engine. let new_enum_ref = decl_engine.insert(new_copy, decl_engine.get_parsed_decl_id(&enum_id).as_ref()); - let type_id = type_engine.insert( - engines, - TypeInfo::Enum(*new_enum_ref.id()), - new_enum_ref.span().source_id(), - ); + let type_id = type_engine.insert_enum(engines, *new_enum_ref.id()); Ok((new_enum_ref, Some(type_id), Some(unknown_decl))) } } @@ -480,9 +466,7 @@ impl TypeBinding { ctx: &mut TypeCheckContext, ) -> Result>, ErrorEmitted> { // Grab the declaration. - let unknown_decl = ctx - .resolve_qualified_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_qualified_call_path(handler, &self.inner)?; // Check to see if this is a const declaration. let const_ref = unknown_decl.to_const_ref(handler, ctx.engines())?; @@ -505,9 +489,7 @@ impl TypeCheckTypeBinding for TypeBinding { ErrorEmitted, > { // Grab the declaration. - let unknown_decl = ctx - .resolve_call_path_with_visibility_check(handler, &self.inner)? - .expect_typed(); + let unknown_decl = ctx.resolve_call_path_with_visibility_check(handler, &self.inner)?; // Check to see if this is a const declaration. let const_ref = unknown_decl.to_const_ref(handler, ctx.engines())?; diff --git a/sway-core/src/type_system/ast_elements/length.rs b/sway-core/src/type_system/ast_elements/length.rs index 3decee557fd..913e9ce38c6 100644 --- a/sway-core/src/type_system/ast_elements/length.rs +++ b/sway-core/src/type_system/ast_elements/length.rs @@ -1,6 +1,17 @@ use sway_types::{span::Span, Spanned}; -/// Describes a fixed length for types that needs it such as arrays and strings +/// Describes a fixed length for types that need it, e.g., [crate::TypeInfo::Array]. +/// +/// Optionally, if the length is coming from a literal in code, the [Length] +/// also keeps the [Span] of that literal. In that case, we say that the length +/// is annotated. +/// +/// E.g., in this example, the two lengths coming from the literal `3` will +/// have two different spans pointing to the two different strings "3": +/// +/// ```ignore +/// fn copy(a: [u64;3], b: [u64;3]) +/// ``` #[derive(Debug, Clone, Hash)] pub struct Length { val: usize, @@ -8,13 +19,30 @@ pub struct Length { } impl Length { - pub fn new(val: usize, span: Span) -> Self { - Length { val, span } + /// Creates a new [Length] without span annotation. + pub fn new(val: usize) -> Self { + Length { + val, + span: Span::dummy(), + } + } + + /// Creates a new [Length] from a numeric literal. + /// The `span` will be set to the span of the numeric literal. + pub fn from_numeric_literal(val: usize, numeric_literal_span: Span) -> Self { + Length { + val, + span: numeric_literal_span, + } } pub fn val(&self) -> usize { self.val } + + pub fn is_annotated(&self) -> bool { + !self.span.is_dummy() + } } impl Spanned for Length { diff --git a/sway-core/src/type_system/ast_elements/trait_constraint.rs b/sway-core/src/type_system/ast_elements/trait_constraint.rs index e91411595bb..d0ed5e3b0dd 100644 --- a/sway-core/src/type_system/ast_elements/trait_constraint.rs +++ b/sway-core/src/type_system/ast_elements/trait_constraint.rs @@ -1,15 +1,3 @@ -use std::{ - cmp::Ordering, - fmt, - hash::{Hash, Hasher}, -}; - -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::Spanned; - use crate::{ engine_threading::*, language::{parsed::Supertrait, ty, CallPath}, @@ -21,8 +9,19 @@ use crate::{ types::{CollectTypesMetadata, CollectTypesMetadataContext, TypeMetadata}, EnforceTypeArguments, }; +use serde::{Deserialize, Serialize}; +use std::{ + cmp::Ordering, + fmt, + hash::{Hash, Hasher}, +}; +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::Spanned; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TraitConstraint { pub trait_name: CallPath, pub type_arguments: Vec, @@ -170,11 +169,7 @@ impl TraitConstraint { EnforceTypeArguments::Yes, None, ) - .unwrap_or_else(|err| { - ctx.engines - .te() - .insert(ctx.engines(), TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| ctx.engines.te().id_of_error_recovery(err)); } Ok(()) @@ -197,9 +192,8 @@ impl TraitConstraint { let mut type_arguments = type_arguments.clone(); match ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed(&Handler::default(), engines, trait_name, ctx.self_type()) + .resolve_call_path(&Handler::default(), trait_name) .ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { diff --git a/sway-core/src/type_system/ast_elements/type_argument.rs b/sway-core/src/type_system/ast_elements/type_argument.rs index 1476fe6627b..3ab7e5a0322 100644 --- a/sway-core/src/type_system/ast_elements/type_argument.rs +++ b/sway-core/src/type_system/ast_elements/type_argument.rs @@ -1,16 +1,62 @@ use crate::{engine_threading::*, language::CallPathTree, type_system::priv_prelude::*}; +use serde::{Deserialize, Serialize}; use std::{cmp::Ordering, fmt, hash::Hasher}; use sway_types::{Span, Spanned}; -#[derive(Debug, Clone)] +/// [TypeArgument] can be seen as an "annotated reference" to a [TypeInfo]. +/// It holds the [TypeArgument::type_id] which is the actual "reference" +/// to the type, as well as an additional information about that type, +/// called the annotation. +/// +/// If a [TypeArgument] only references a [TypeInfo] and is considered as +/// not being annotated, its `initial_type_id` must be the same as `type_id`, +/// its `span` must be [Span::dummy] and its `call_path_tree` must be `None`. +/// +/// The annotations are ignored when calculating the [TypeArgument]'s hash +/// (with engines) and equality (with engines). +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TypeArgument { + /// The [TypeId] of the "referenced" [TypeInfo]. pub type_id: TypeId, + /// Denotes the initial type that was referenced before the type + /// unification, monomorphization, or replacement of [TypeInfo::Custom]s. pub initial_type_id: TypeId, + /// The [Span] related in code to the [TypeInfo] represented by this + /// [TypeArgument]. This information is mostly used by the LSP and it + /// differs from use case to use case. + /// + /// E.g., in the following example: + /// + /// ```ignore + /// let a: [u64;2] = [0, 0]; + /// let b: [u64;2] = [1, 1]; + /// ``` + /// + /// the type arguments of the [TypeInfo::Array]s of `a` and `b` will + /// have two different spans pointing to two different strings "u64". + /// On the other hand, the two [TypeInfo::Array]s describing the + /// two instances `[0, 0]`, and `[1, 1]` will have neither the array + /// type span set, nor the length span, which means they will not be + /// annotated. pub span: Span, pub call_path_tree: Option, } +impl TypeArgument { + /// Returns true if `self` is annotated by having either + /// its [Self::initial_type_id] different from [Self::type_id], + /// or [Self::span] different from [Span::dummy] + /// or [Self::call_path_tree] different from `None`. + pub fn is_annotated(&self) -> bool { + self.type_id != self.initial_type_id + || self.call_path_tree.is_some() + || !self.span.is_dummy() + } +} + impl From for TypeArgument { + /// Creates *a non-annotated* [TypeArgument] that points + /// to the [TypeInfo] represented by the `type_id`. fn from(type_id: TypeId) -> Self { TypeArgument { type_id, @@ -102,7 +148,7 @@ impl From<&TypeParameter> for TypeArgument { TypeArgument { type_id: type_param.type_id, initial_type_id: type_param.initial_type_id, - span: type_param.name_ident.span(), + span: type_param.name.span(), call_path_tree: None, } } diff --git a/sway-core/src/type_system/ast_elements/type_parameter.rs b/sway-core/src/type_system/ast_elements/type_parameter.rs index 068f486b79f..9f3d24cac81 100644 --- a/sway-core/src/type_system/ast_elements/type_parameter.rs +++ b/sway-core/src/type_system/ast_elements/type_parameter.rs @@ -3,39 +3,64 @@ use crate::{ engine_threading::*, has_changes, language::{ty, CallPath}, - namespace::TryInsertingTraitImplOnFailure, + namespace::{TraitMap, TryInsertingTraitImplOnFailure}, semantic_analysis::{GenericShadowingMode, TypeCheckContext}, type_system::priv_prelude::*, }; - -use sway_error::{ - error::CompileError, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{ident::Ident, span::Span, Spanned}; - +use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, collections::BTreeMap, fmt, hash::{Hash, Hasher}, }; - -#[derive(Clone)] +use sway_error::{ + error::CompileError, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{ident::Ident, span::Span, BaseIdent, Spanned}; + +/// [TypeParameter] describes a generic type parameter, including its +/// monomorphized version. It holds the `name` of the parameter, its +/// `type_id`, and the `initial_type_id`, as well as an additional +/// information about that type parameter, called the annotation. +/// +/// If a [TypeParameter] is considered as not being annotated, +/// its `initial_type_id` must be same as `type_id`, its +/// `trait_constraints_span` must be [Span::dummy] +/// and its `is_from_parent` must be false. +/// +/// The annotations are ignored when calculating the [TypeParameter]'s hash +/// (with engines) and equality (with engines). +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TypeParameter { pub type_id: TypeId, + /// Denotes the initial type represented by the [TypeParameter], before + /// unification, monomorphization, or replacement of [TypeInfo::Custom]s. pub(crate) initial_type_id: TypeId, - pub name_ident: Ident, + pub name: Ident, pub(crate) trait_constraints: Vec, pub(crate) trait_constraints_span: Span, pub(crate) is_from_parent: bool, } +impl TypeParameter { + /// Returns true if `self` is annotated by heaving either + /// its [Self::initial_type_id] different from [Self::type_id], + /// or [Self::trait_constraints_span] different from [Span::dummy] + /// or [Self::is_from_parent] different from false. + pub fn is_annotated(&self) -> bool { + self.type_id != self.initial_type_id + || self.is_from_parent + || !self.trait_constraints_span.is_dummy() + } +} + impl HashWithEngines for TypeParameter { fn hash(&self, state: &mut H, engines: &Engines) { let TypeParameter { type_id, - name_ident, + name, trait_constraints, // these fields are not hashed because they aren't relevant/a // reliable source of obj v. obj distinction @@ -45,7 +70,7 @@ impl HashWithEngines for TypeParameter { } = self; let type_engine = engines.te(); type_engine.get(*type_id).hash(state, engines); - name_ident.hash(state); + name.hash(state); trait_constraints.hash(state, engines); } } @@ -57,7 +82,7 @@ impl PartialEqWithEngines for TypeParameter { type_engine .get(self.type_id) .eq(&type_engine.get(other.type_id), ctx) - && self.name_ident == other.name_ident + && self.name == other.name && self.trait_constraints.eq(&other.trait_constraints, ctx) } } @@ -66,7 +91,7 @@ impl OrdWithEngines for TypeParameter { fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering { let TypeParameter { type_id: lti, - name_ident: ln, + name: ln, trait_constraints: ltc, // these fields are not compared because they aren't relevant/a // reliable source of obj v. obj distinction @@ -76,7 +101,7 @@ impl OrdWithEngines for TypeParameter { } = self; let TypeParameter { type_id: rti, - name_ident: rn, + name: rn, trait_constraints: rtc, // these fields are not compared because they aren't relevant/a // reliable source of obj v. obj distinction @@ -106,7 +131,7 @@ impl SubstTypes for TypeParameter { impl Spanned for TypeParameter { fn span(&self) -> Span { - self.name_ident.span() + self.name.span() } } @@ -118,7 +143,7 @@ impl IsConcrete for TypeParameter { impl DebugWithEngines for TypeParameter { fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result { - write!(f, "{}", self.name_ident)?; + write!(f, "{}", self.name)?; if !self.trait_constraints.is_empty() { write!( f, @@ -134,37 +159,56 @@ impl DebugWithEngines for TypeParameter { } } -impl fmt::Debug for TypeParameter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let _ = write!(f, "{}: {:?}", self.name_ident, self.type_id); - for c in &self.trait_constraints { - let _ = write!(f, "+ {:?}", c.trait_name); - } - write!(f, "") - } -} - impl TypeParameter { - pub(crate) fn new_self_type(engines: &Engines, span: Span) -> TypeParameter { + /// Creates a new [TypeParameter] that represents a `Self` type. + /// The returned type parameter will have its [TypeParameter::name] + /// set to "Self" with the provided `use_site_span`. + /// + /// `Self` type is a [TypeInfo::UnknownGeneric] and therefore [TypeParameter::type_id]s + /// will be set to newly created unknown generic type. + /// + /// Note that the span in general does not point to a reserved word "Self" in + /// the source code, nor is related to it. The `Self` type represents the type + /// in `impl`s and does not necessarily relate to the "Self" keyword in code. + /// + /// Therefore, *the span must always point to a location in the source file in which + /// the particular `Self` type is, e.g., being declared or implemented*. + pub(crate) fn new_self_type(engines: &Engines, use_site_span: Span) -> TypeParameter { let type_engine = engines.te(); - let name = Ident::new_with_override("Self".into(), span.clone()); - let type_id = type_engine.insert( - engines, - TypeInfo::UnknownGeneric { - name: name.clone(), - trait_constraints: VecSet(vec![]), - parent: None, - is_from_type_parameter: true, - }, - span.source_id(), - ); + let (type_id, name) = type_engine.new_unknown_generic_self(use_site_span, true); TypeParameter { type_id, initial_type_id: type_id, - name_ident: name, + name, trait_constraints: vec![], - trait_constraints_span: span, + trait_constraints_span: Span::dummy(), + is_from_parent: false, + } + } + + /// Creates a new [TypeParameter] specifically to be used as the type parameter + /// for a [TypeInfo::Placeholder]. The returned type parameter will have its + /// [TypeParameter::name] set to "_" with the provided `placeholder_or_use_site_span` + /// and its [TypeParameter::type_id]s set to the `type_id`. + /// + /// Note that in the user written code, the span will always point to the place in + /// the source code where "_" is located. In the compiler generated code that is not always the case + /// be the case. For cases when the span does not point to "_" see the comments + /// in the usages of this method. + /// + /// However, *the span must always point to a location in the source file in which + /// the particular placeholder is considered to be used*. + pub(crate) fn new_placeholder( + type_id: TypeId, + placeholder_or_use_site_span: Span, + ) -> TypeParameter { + TypeParameter { + type_id, + initial_type_id: type_id, + name: BaseIdent::new_with_override("_".into(), placeholder_or_use_site_span), + trait_constraints: vec![], + trait_constraints_span: Span::dummy(), is_from_parent: false, } } @@ -176,11 +220,11 @@ impl TypeParameter { ) { let type_parameter_decl = ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { - name: self.name_ident.clone(), + name: self.name.clone(), type_id: self.type_id, }); - let name_a = Ident::new_with_override("self".into(), self.name_ident.span()); - let name_b = Ident::new_with_override("Self".into(), self.name_ident.span()); + let name_a = Ident::new_with_override("self".into(), self.name.span()); + let name_b = Ident::new_with_override("Self".into(), self.name.span()); let _ = ctx.insert_symbol(handler, name_a, type_parameter_decl.clone()); let _ = ctx.insert_symbol(handler, name_b, type_parameter_decl); } @@ -230,11 +274,7 @@ impl TypeParameter { ctx: &TypeCheckContext, tc: &TraitConstraint, ) -> Vec { - match ctx - .namespace() - .resolve_call_path_typed(handler, ctx.engines, &tc.trait_name, ctx.self_type()) - .ok() - { + match ctx.resolve_call_path(handler, &tc.trait_name).ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { let trait_decl = ctx.engines.de().get_trait(&decl_id); let mut result = trait_decl @@ -266,11 +306,10 @@ impl TypeParameter { type_parameter: TypeParameter, ) -> Result { let type_engine = ctx.engines.te(); - let engines = ctx.engines(); let TypeParameter { initial_type_id, - name_ident, + name, trait_constraints, trait_constraints_span, is_from_parent, @@ -296,19 +335,15 @@ impl TypeParameter { // Create type id and type parameter before type checking trait constraints. // This order is required because a trait constraint may depend on its own type parameter. - let type_id = type_engine.insert( - engines, - TypeInfo::UnknownGeneric { - name: name_ident.clone(), - trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), - parent, - is_from_type_parameter: true, - }, - name_ident.span().source_id(), + let type_id = type_engine.new_unknown_generic( + name.clone(), + VecSet(trait_constraints_with_supertraits.clone()), + parent, + true, ); let type_parameter = TypeParameter { - name_ident: name_ident.clone(), + name, type_id, initial_type_id, trait_constraints, @@ -360,15 +395,11 @@ impl TypeParameter { type_engine.replace( ctx.engines(), type_parameter.type_id, - TypeSourceInfo { - type_info: TypeInfo::UnknownGeneric { - name: type_parameter.name_ident.clone(), - trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), - parent, - is_from_type_parameter: true, - } - .into(), - source_id: type_parameter.name_ident.span().source_id().copied(), + TypeInfo::UnknownGeneric { + name: type_parameter.name.clone(), + trait_constraints: VecSet(trait_constraints_with_supertraits.clone()), + parent, + is_from_type_parameter: true, }, ); @@ -405,7 +436,7 @@ impl TypeParameter { ) -> Result<(), ErrorEmitted> { let Self { is_from_parent, - name_ident, + name, type_id, .. } = self; @@ -413,13 +444,11 @@ impl TypeParameter { if *is_from_parent { ctx = ctx.with_generic_shadowing_mode(GenericShadowingMode::Allow); - let sy = ctx - .namespace() - .module(ctx.engines()) - .current_items() - .symbols - .get(name_ident) - .unwrap(); + let sy = ctx.namespace().module(ctx.engines()).resolve_symbol( + handler, + ctx.engines(), + name, + )?; match sy.expect_typed_ref() { ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { @@ -440,15 +469,11 @@ impl TypeParameter { ctx.engines.te().replace( ctx.engines(), *type_id, - TypeSourceInfo { - type_info: TypeInfo::UnknownGeneric { - name: name.clone(), - trait_constraints: trait_constraints.clone(), - parent: Some(*parent_type_id), - is_from_type_parameter: *is_from_type_parameter, - } - .into(), - source_id: name.span().source_id().copied(), + TypeInfo::UnknownGeneric { + name: name.clone(), + trait_constraints: trait_constraints.clone(), + parent: Some(*parent_type_id), + is_from_type_parameter: *is_from_type_parameter, }, ); } @@ -456,7 +481,7 @@ impl TypeParameter { _ => { handler.emit_err(CompileError::Internal( "Unexpected TyDeclaration for TypeParameter.", - self.name_ident.span(), + self.name.span(), )); } } @@ -466,10 +491,10 @@ impl TypeParameter { // declaration. let type_parameter_decl = ty::TyDecl::GenericTypeForFunctionScope(ty::GenericTypeForFunctionScope { - name: name_ident.clone(), + name: name.clone(), type_id: *type_id, }); - ctx.insert_symbol(handler, name_ident.clone(), type_parameter_decl) + ctx.insert_symbol(handler, name.clone(), type_parameter_decl) .ok(); Ok(()) @@ -544,13 +569,9 @@ impl TypeParameter { } } // Check to see if the trait constraints are satisfied. - match ctx - .namespace_mut() - .module_mut(engines) - .current_items_mut() - .implemented_traits - .check_if_trait_constraints_are_satisfied_for_type( + match TraitMap::check_if_trait_constraints_are_satisfied_for_type( handler, + ctx.namespace_mut().module_mut(engines), *type_id, trait_constraints, access_span, @@ -616,9 +637,8 @@ fn handle_trait( handler.scope(|handler| { match ctx - .namespace() // Use the default Handler to avoid emitting the redundant SymbolNotFound error. - .resolve_call_path_typed(&Handler::default(), engines, trait_name, ctx.self_type()) + .resolve_call_path(&Handler::default(), trait_name) .ok() { Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => { diff --git a/sway-core/src/type_system/engine.rs b/sway-core/src/type_system/engine.rs index 7dea1cbb281..8c97dd475af 100644 --- a/sway-core/src/type_system/engine.rs +++ b/sway-core/src/type_system/engine.rs @@ -2,25 +2,140 @@ use crate::{ concurrent_slab::{ConcurrentSlab, ListDisplay}, decl_engine::*, engine_threading::*, + language::{ + parsed::{EnumDeclaration, StructDeclaration}, + ty::{TyEnumDecl, TyExpression, TyStructDecl}, + QualifiedCallPath, + }, type_system::priv_prelude::*, }; use core::fmt::Write; use hashbrown::{hash_map::RawEntryMut, HashMap}; use parking_lot::RwLock; -use std::{sync::Arc, time::Instant}; +use std::{ + hash::{BuildHasher, Hash, Hasher}, + sync::Arc, + time::Instant, +}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, type_error::TypeError, }; -use sway_types::{integer_bits::IntegerBits, span::Span, ProgramId, SourceId}; +use sway_types::{integer_bits::IntegerBits, span::Span, Ident, ProgramId, SourceId, Spanned}; use super::unify::unifier::UnifyKind; +/// To be able to garbage-collect [TypeInfo]s from the [TypeEngine] +/// we need to track which types need to be GCed when a particular +/// module, represented by its source id, is GCed. [TypeSourceInfo] +/// encapsulates this information. +/// +/// For types that should never be GCed the `source_id` must be `None`. +/// +/// The concrete logic of assigning `source_id`s to `type_info`s is +/// given in the [TypeEngine::get_type_fallback_source_id]. +// TODO: This logic will be further improved when https://github.com/FuelLabs/sway/issues/6603 +// is implemented (Optimize `TypeEngine` for garbage collection). +#[derive(Debug, Default, Clone)] +struct TypeSourceInfo { + type_info: Arc, + source_id: Option, +} + +impl TypeSourceInfo { + /// Returns true if the `self` would be equal to another [TypeSourceInfo] + /// created from `type_info` and `source_id`. + /// + /// This method allows us to test equality "upfront", without the need to + /// create a new [TypeSourceInfo] which would require a heap allocation + /// of a new [TypeInfo]. + pub(crate) fn equals( + &self, + type_info: &TypeInfo, + source_id: &Option, + ctx: &PartialEqWithEnginesContext, + ) -> bool { + &self.source_id == source_id && self.type_info.eq(type_info, ctx) + } +} + +impl HashWithEngines for TypeSourceInfo { + fn hash(&self, state: &mut H, engines: &Engines) { + self.type_info.hash(state, engines); + self.source_id.hash(state); + } +} + +impl EqWithEngines for TypeSourceInfo {} +impl PartialEqWithEngines for TypeSourceInfo { + fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { + self.equals(&other.type_info, &other.source_id, ctx) + } +} + +/// Holds the singleton instances of [TypeSourceInfo]s of *replaceable types* that, +/// although being inserted anew into the [TypeEngine], all share the single definition. +/// This means that, e.g., all the different [TypeEngine::slab] entries representing +/// the, e.g., [TypeInfo::Unknown] will point to the same singleton instance +/// of the corresponding [TypeSourceInfo]. +#[derive(Debug, Clone)] +struct SingletonTypeSourceInfos { + /// The single instance of the [TypeSourceInfo] + /// representing the [TypeInfo::Unknown] replaceable type. + unknown: Arc, + /// The single instance of the [TypeSourceInfo] + /// representing the [TypeInfo::Numeric] replaceable type. + numeric: Arc, +} + +/// Holds the instances of [TypeInfo]s and allows exchanging them for [TypeId]s. +/// Supports LSP garbage collection of unused [TypeInfo]s assigned to a particular [SourceId]. +/// +/// ## Intended Usage +/// Inserting [TypeInfo]s into the type engine returns a [TypeId] that can later be used +/// to get the same [TypeInfo] by using the [TypeEngine::get] method. +/// +/// Properly using the various inserting methods is crucial for the optimal work of the type engine. +/// +/// These methods are grouped by the following convention and are intended to be used in the +/// order of precedence given below: +/// - `id_of_`: methods that always return the same [TypeId] for a type. +/// These methods, when inlined, compile to constant [TypeId]s. +/// - `new_`: methods that always return a new [TypeId] for a type. +/// - `insert_[_]`: methods that might insert a new type into the engine, +/// and return a new [TypeId], but also reuse an existing [TypeInfo] and return an existing [TypeId]. +/// - `insert`: the fallback method that should be used only in cases when the type is not known +/// at the call site. +/// +/// ## Internal Implementation +/// [TypeInfo]s are stored in a private [TypeSourceInfo] structure that binds them with a [SourceId] +/// of the module in which they are used. Those [TypeSourceInfo]s are referenced from the `slab`. +/// The actual [TypeId] of a [TypeInfo] is just an index in the `slab`. +/// +/// The engine attempts to maximize the reuse of [TypeSourceInfo]s by holding _shareable types_ +/// (see: [Self::is_type_shareable]) in the `shareable_types` hash map. +/// +/// TODO: Note that the reuse currently happens on the level of [TypeSourceInfo]s, and not [TypeInfo]s. +/// This is not optimal and will be improved in https://github.com/FuelLabs/sway/issues/6603. +/// Also note that because of that, having [TypeInfo] stored in `Arc` within the [TypeSourceInfo] +/// does not bring any real benefits. +/// +/// The implementation of the type engine is primarily directed with the goal of maximizing the +/// reuse of the [TypeSourceInfo]s while at the same time having the [TypeInfo]s bound to [SourceId]s +/// of their use site, so that they can be garbage collected. +/// +/// TODO: Note that the assignment of [SourceId]s to [TypeInfo]s is currently not as optimal as it +/// can be. This will be improved in https://github.com/FuelLabs/sway/issues/6603. #[derive(Debug)] pub struct TypeEngine { slab: ConcurrentSlab, - id_map: RwLock>, + /// Holds [TypeId]s of [TypeSourceInfo]s of shareable types (see: [Self::is_type_shareable]). + /// [TypeSourceInfo]s of shareable types can be reused if the type is used more + /// then once. In that case, for every usage, instead of inserting a new [TypeSourceInfo] instance + /// into the [Self::slab], the [TypeId] of an existing instance is returned. + shareable_types: RwLock, TypeId>>, + singleton_types: RwLock, unifications: ConcurrentSlab, last_replace: RwLock, } @@ -40,12 +155,28 @@ pub(crate) struct Unification { impl Default for TypeEngine { fn default() -> Self { - TypeEngine { + let singleton_types = SingletonTypeSourceInfos { + unknown: TypeSourceInfo { + type_info: TypeInfo::Unknown.into(), + source_id: None, + } + .into(), + numeric: TypeSourceInfo { + type_info: TypeInfo::Numeric.into(), + source_id: None, + } + .into(), + }; + + let mut te = TypeEngine { slab: Default::default(), - id_map: Default::default(), + shareable_types: Default::default(), + singleton_types: RwLock::new(singleton_types), unifications: Default::default(), last_replace: RwLock::new(Instant::now()), - } + }; + te.insert_shareable_built_in_types(); + te } } @@ -53,14 +184,614 @@ impl Clone for TypeEngine { fn clone(&self) -> Self { TypeEngine { slab: self.slab.clone(), - id_map: RwLock::new(self.id_map.read().clone()), + shareable_types: RwLock::new(self.shareable_types.read().clone()), + singleton_types: RwLock::new(self.singleton_types.read().clone()), unifications: self.unifications.clone(), last_replace: RwLock::new(*self.last_replace.read()), } } } +/// Generates: +/// - `id_of_` methods for every provided shareable built-in type. +/// - `insert_shareable_built_in_types` method for initial creation of built-in types within the [TypeEngine]. +/// - `get_shareable_built_in_type_id` method for potential retrieval of built-in types in the [TypeEngine::insert] method. +/// +/// Note that, when invoking the macro, the `unit` and the [TypeInfo::ErrorRecovery] types *must not be provided in the list*. +/// The shareable `unit` type requires a special treatment within the macro, because it is modeled +/// as [TypeInfo::Tuple] with zero elements and not as a separate [TypeInfo] variant. +/// The [TypeInfo::ErrorRecovery], although being an enum variant with the parameter (the [ErrorEmitted] proof), is +/// actually a single type because all the [ErrorEmitted] proofs are the same. +/// This special case is also handled within the macro. +/// +/// Unfortunately, due to limitations of Rust's macro-by-example, the [TypeInfo] must be +/// provided twice during the macro invocation, once as an expression `expr` and once as a pattern `pat`. +/// +/// The macro recursively creates the `id_of_` methods in order to get the proper `usize` value +/// generated, which corresponds to the index of those types within the slab. +macro_rules! type_engine_shareable_built_in_types { + // The base recursive case. + (@step $_idx:expr,) => {}; + + // The actual recursion step that generates the `id_of_` functions. + (@step $idx:expr, ($ty_name:ident, $ti:expr, $ti_pat:pat), $(($tail_ty_name:ident, $tail_ti:expr, $tail_ti_pat:pat),)*) => { + paste::paste! { + pub(crate) const fn [](&self) -> TypeId { + TypeId::new($idx) + } + } + + type_engine_shareable_built_in_types!(@step $idx + 1, $(($tail_ty_name, $tail_ti, $tail_ti_pat),)*); + }; + + // The entry point. Invoking the macro matches this arm. + ($(($ty_name:ident, $ti:expr, $ti_pat:pat),)*) => { + // The `unit` type is a special case. It will be inserted in the slab as the first type. + pub(crate) const fn id_of_unit(&self) -> TypeId { + TypeId::new(0) + } + + // The error recovery type is a special case. It will be inserted in the slab as the second type. + // To preserve the semantics of the `TypeInfo::ErrorRecovery(ErrorEmitted)`, we still insist on + // providing the proof of the error being emitted, although that proof is actually + // not needed to obtain the type id, nor is used within this method at all. + #[allow(unused_variables)] + pub(crate) const fn id_of_error_recovery(&self, error_emitted: ErrorEmitted) -> TypeId { + TypeId::new(1) + } + + // Generate the remaining `id_of_` methods. We start counting the indices from 2. + type_engine_shareable_built_in_types!(@step 2, $(($ty_name, $ti, $ti_pat),)*); + + // Generate the method that initially inserts the built-in shareable types into the `slab` in the right order. + // + // Note that we are inserting the types **only into the `slab`, but not into the `shareable_types`**, + // although they should, by definition, be in the `shareable_types` as well. + // + // What is the reason for not inserting them into the `shareable_types`? + // + // To insert them into the `shareable_types` we need `Engines` to be able to calculate + // the hash and equality with engines, and method is supposed be called internally during the creation + // of the `TypeEngine`. At that moment, we are creating a single, isolated engine, and do not + // have all the engines available. The only way to have it called with all the engines, is + // to do it when `Engines` are created. But this would mean that we cannot have a semantically + // valid `TypeEngine` created in isolation, without the `Engines`, which would be a problematic + // design that breaks cohesion and creates unexpected dependency. + // + // Note that having the built-in shareable types initially inserted only in the `slab` does + // not cause any issues with type insertion and retrieval. The `id_of_` methods return + // indices that are compile-time constants and there is no need for `shareable_types` access. + // Also, calling `insert` with built-in shareable types has an optimized path which will redirect + // to `id_of_` methods, again bypassing the `shareable_types`. + // + // The only negligible small "penalty" comes during replacements of replaceable types, + // where a potential replacement with a built-in shareable type will create a separate instance + // of that built-in type and add it to `shareable_types`. + fn insert_shareable_built_in_types(&mut self) { + use TypeInfo::*; + + let tsi = TypeSourceInfo { + type_info: Tuple(vec![]).into(), + source_id: None, + }; + self.slab.insert(tsi); + + // For the `ErrorRecovery`, we need an `ErrorEmitted` instance. + // All of its instances are the same, so we will use, or perhaps misuse, + // the `Handler::cancel` method here to obtain an instance. + let tsi = TypeSourceInfo { + type_info: ErrorRecovery(crate::Handler::default().cancel()).into(), + source_id: None, + }; + self.slab.insert(tsi); + + $( + let tsi = TypeSourceInfo { + type_info: $ti.into(), + source_id: None, + }; + self.slab.insert(tsi); + )* + } + + /// Returns the [TypeId] of the `type_info` only if the type info is + /// a shareable built-in type, otherwise `None`. + /// + /// For a particular shareable built-in type, the method guarantees to always + /// return the same, existing [TypeId]. + fn get_shareable_built_in_type_id(&self, type_info: &TypeInfo) -> Option { + paste::paste! { + use TypeInfo::*; + match type_info { + Tuple(v) if v.is_empty() => Some(self.id_of_unit()), + // Here we also "pass" the dummy value obtained from `Handler::cancel` which will be + // optimized away. + ErrorRecovery(_) => Some(self.id_of_error_recovery(crate::Handler::default().cancel())), + $( + $ti_pat => Some(self.[]()), + )* + _ => None + } + } + } + + /// Returns true if the type represented by the `type_info` + /// is a shareable built-in type. + fn is_shareable_built_in_type(&self, type_info: &TypeInfo) -> bool { + use TypeInfo::*; + match type_info { + Tuple(v) if v.is_empty() => true, + // Here we also "pass" the dummy value obtained from `Handler::cancel` which will be + // optimized away. + ErrorRecovery(_) => true, + $( + $ti_pat => true, + )* + _ => false + } + } + } +} + impl TypeEngine { + type_engine_shareable_built_in_types!( + (never, Never, Never), + (string_slice, StringSlice, StringSlice), + ( + u8, + UnsignedInteger(IntegerBits::Eight), + UnsignedInteger(IntegerBits::Eight) + ), + ( + u16, + UnsignedInteger(IntegerBits::Sixteen), + UnsignedInteger(IntegerBits::Sixteen) + ), + ( + u32, + UnsignedInteger(IntegerBits::ThirtyTwo), + UnsignedInteger(IntegerBits::ThirtyTwo) + ), + ( + u64, + UnsignedInteger(IntegerBits::SixtyFour), + UnsignedInteger(IntegerBits::SixtyFour) + ), + ( + u256, + UnsignedInteger(IntegerBits::V256), + UnsignedInteger(IntegerBits::V256) + ), + (bool, Boolean, Boolean), + (b256, B256, B256), + (contract, Contract, Contract), + (raw_ptr, RawUntypedPtr, RawUntypedPtr), + (raw_slice, RawUntypedSlice, RawUntypedSlice), + ); + + /// Inserts a new [TypeInfo::Unknown] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Unknown] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_unknown(&self) -> TypeId { + TypeId::new( + self.slab + .insert_arc(self.singleton_types.read().unknown.clone()), + ) + } + + /// Inserts a new [TypeInfo::Numeric] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Numeric] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_numeric(&self) -> TypeId { + TypeId::new( + self.slab + .insert_arc(self.singleton_types.read().numeric.clone()), + ) + } + + /// Inserts a new [TypeInfo::Placeholder] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Placeholder] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_placeholder(&self, type_parameter: TypeParameter) -> TypeId { + self.new_placeholder_impl(TypeInfo::Placeholder(type_parameter)) + } + + fn new_placeholder_impl(&self, placeholder: TypeInfo) -> TypeId { + let source_id = self.get_placeholder_fallback_source_id(&placeholder); + let tsi = TypeSourceInfo { + type_info: placeholder.into(), + source_id, + }; + TypeId::new(self.slab.insert(tsi)) + } + + /// Inserts a new [TypeInfo::UnknownGeneric] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::UnknownGeneric] is an always replaceable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_unknown_generic( + &self, + name: Ident, + trait_constraints: VecSet, + parent: Option, + is_from_type_parameter: bool, + ) -> TypeId { + self.new_unknown_generic_impl(TypeInfo::UnknownGeneric { + name, + trait_constraints, + parent, + is_from_type_parameter, + }) + } + + fn new_unknown_generic_impl(&self, unknown_generic: TypeInfo) -> TypeId { + let source_id = Self::get_unknown_generic_fallback_source_id(&unknown_generic); + let tsi = TypeSourceInfo { + type_info: unknown_generic.into(), + source_id, + }; + TypeId::new(self.slab.insert(tsi)) + } + + /// Inserts a new [TypeInfo::UnknownGeneric] into the [TypeEngine] + /// that represents a `Self` type and returns its [TypeId]. + /// The unknown generic `name` [Ident] will be set to "Self" with the provided `use_site_span`. + /// + /// Note that the span in general does not point to a reserved word "Self" in + /// the source code, nor is related to it. The `Self` type represents the type + /// in `impl`s and does not necessarily relate to the "Self" keyword in code. + /// + /// Therefore, *the span must always point to a location in the source file in which + /// the particular `Self` type is, e.g., being declared or implemented*. + /// + /// Returns the [TypeId] and the [Ident] set to "Self" and the provided `use_site_span`. + pub(crate) fn new_unknown_generic_self( + &self, + use_site_span: Span, + is_from_type_parameter: bool, + ) -> (TypeId, Ident) { + let name = Ident::new_with_override("Self".into(), use_site_span); + let type_id = + self.new_unknown_generic(name.clone(), VecSet(vec![]), None, is_from_type_parameter); + (type_id, name) + } + + /// Inserts a new [TypeInfo::Enum] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable enum type + /// that corresponds to the enum given by the `decl_id`. + pub(crate) fn insert_enum(&self, engines: &Engines, decl_id: DeclId) -> TypeId { + let decl = engines.de().get_enum(&decl_id); + let source_id = Self::get_enum_fallback_source_id(&decl); + let is_shareable_type = self.is_shareable_enum(engines, &decl); + let type_info = TypeInfo::Enum(decl_id); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Struct] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable struct type + /// that corresponds to the struct given by the `decl_id`. + pub(crate) fn insert_struct(&self, engines: &Engines, decl_id: DeclId) -> TypeId { + let decl = engines.de().get_struct(&decl_id); + let source_id = Self::get_struct_fallback_source_id(&decl); + let is_shareable_type = self.is_shareable_struct(engines, &decl); + let type_info = TypeInfo::Struct(decl_id); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Tuple] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable tuple type + /// that corresponds to the tuple given by the `elements`. + pub(crate) fn insert_tuple(&self, engines: &Engines, elements: Vec) -> TypeId { + let source_id = self.get_tuple_fallback_source_id(&elements); + let is_shareable_type = self.is_shareable_tuple(engines, &elements); + let type_info = TypeInfo::Tuple(elements); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_tuple], but intended to be used mostly in the code generation, + /// where the tuple elements are non-annotated [TypeArgument]s that contain + /// only the [TypeId]s provided in the `elements`. + pub(crate) fn insert_tuple_without_annotations( + &self, + engines: &Engines, + elements: Vec, + ) -> TypeId { + self.insert_tuple( + engines, + elements.into_iter().map(|type_id| type_id.into()).collect(), + ) + } + + /// Inserts a new [TypeInfo::Array] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable array type + /// that corresponds to the array given by the `elem_type` and the `length`. + pub(crate) fn insert_array( + &self, + engines: &Engines, + elem_type: TypeArgument, + length: Length, + ) -> TypeId { + let source_id = self.get_array_fallback_source_id(&elem_type, &length); + let is_shareable_type = self.is_shareable_array(engines, &elem_type, &length); + let type_info = TypeInfo::Array(elem_type, length); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_array], but intended to insert arrays without annotations. + // TODO: Unlike `insert_array`, once the https://github.com/FuelLabs/sway/issues/6603 gets implemented, + // this method will get the additional `use_site_source_id` parameter. + pub(crate) fn insert_array_without_annotations( + &self, + engines: &Engines, + elem_type: TypeId, + length: usize, + ) -> TypeId { + self.insert_array(engines, elem_type.into(), Length::new(length)) + } + + /// Inserts a new [TypeInfo::StringArray] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable string array type + /// that corresponds to the string array given by the `length`. + pub(crate) fn insert_string_array(&self, engines: &Engines, length: Length) -> TypeId { + let source_id = Self::get_string_array_fallback_source_id(&length); + let is_shareable_type = self.is_shareable_string_array(&length); + let type_info = TypeInfo::StringArray(length); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_string_array], but intended to insert string arrays without annotations. + // TODO: Unlike `insert_string_array`, once the https://github.com/FuelLabs/sway/issues/6603 gets implemented, + // this method will get the additional `use_site_source_id` parameter. + pub(crate) fn insert_string_array_without_annotations( + &self, + engines: &Engines, + length: usize, + ) -> TypeId { + self.insert_string_array(engines, Length::new(length)) + } + + /// Inserts a new [TypeInfo::ContractCaller] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::ContractCaller] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_contract_caller( + &self, + engines: &Engines, + abi_name: AbiName, + address: Option>, + ) -> TypeId { + // The contract caller type shareability would be calculated as: + // + // !(Self::is_replaceable_contract_caller(abi_name, address) + // || + // Self::is_contract_caller_distinguishable_by_annotations(abi_name, address)) + // + // If the contract caller is replaceable, either the `abi_name` id `Deferred` or the `address` is `None`. + // On the other hand, if the `abi_name` is `Known` or the `address` is `Some`, it will be distinguishable by annotations. + // Which means, it will be either replaceable or distinguishable by annotations, which makes the condition always + // evaluating to false. + // + // The fact that we cannot share `ContractCaller`s is not an issue. In any real-life project, the number of contract callers + // will be negligible, order of magnitude of ~10. + let source_id = Self::get_contract_caller_fallback_source_id(&abi_name, &address); + let type_info = TypeInfo::ContractCaller { abi_name, address }; + self.insert_or_replace_type_source_info(engines, type_info, source_id, false, None) + } + + /// Inserts a new [TypeInfo::Alias] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Alias] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_alias(&self, engines: &Engines, name: Ident, ty: TypeArgument) -> TypeId { + // The alias type shareability would be calculated as `!(false || true) ==>> false`. + let source_id = self.get_alias_fallback_source_id(&name, &ty); + let type_info = TypeInfo::Alias { name, ty }; + self.insert_or_replace_type_source_info(engines, type_info, source_id, false, None) + } + + /// Inserts a new [TypeInfo::Custom] into the [TypeEngine] and returns its [TypeId]. + /// + /// [TypeInfo::Custom] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_custom( + &self, + engines: &Engines, + qualified_call_path: QualifiedCallPath, + type_arguments: Option>, + ) -> TypeId { + let source_id = self.get_custom_fallback_source_id(&qualified_call_path, &type_arguments); + // The custom type shareability would be calculated as `!(true || true) ==>> false`. + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + let is_shareable_type = false; + let type_info = TypeInfo::Custom { + qualified_call_path, + type_arguments, + }; + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Custom] into the [TypeEngine] and returns its [TypeId]. + /// The custom type is defined only by its `name`. In other words, it does not have + /// the qualified call path or type arguments. This is a very common situation in + /// the code that just uses the type name, like, e.g., when instantiating structs: + /// + /// ```ignore + /// let _ = Struct { }; + /// ``` + /// + /// [TypeInfo::Custom] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_custom_from_name(&self, engines: &Engines, name: Ident) -> TypeId { + self.new_custom(engines, name.into(), None) + } + + /// Creates a new [TypeInfo::Custom] that represents a Self type. + /// + /// The `span` must either be a [Span::dummy] or a span pointing + /// to text "Self" or "self", otherwise the method panics. + /// + /// [TypeInfo::Custom] is not a shareable type and the method + /// guarantees that a new (or unused) [TypeId] will be returned on every + /// call. + pub(crate) fn new_self_type(&self, engines: &Engines, span: Span) -> TypeId { + let source_id = span.source_id().copied(); + // The custom type shareability would be calculated as `!(true || true) ==>> false`. + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + let is_shareable_type = false; + let type_info = TypeInfo::new_self_type(span); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Slice] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable slice type + /// that corresponds to the slice given by the `elem_type`. + pub(crate) fn insert_slice(&self, engines: &Engines, elem_type: TypeArgument) -> TypeId { + let source_id = self.get_slice_fallback_source_id(&elem_type); + let is_shareable_type = self.is_shareable_slice(engines, &elem_type); + let type_info = TypeInfo::Slice(elem_type); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Ptr] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable pointer type + /// that corresponds to the pointer given by the `pointee_type`. + pub(crate) fn insert_ptr(&self, engines: &Engines, pointee_type: TypeArgument) -> TypeId { + let source_id = self.get_ptr_fallback_source_id(&pointee_type); + let is_shareable_type = self.is_shareable_ptr(engines, &pointee_type); + let type_info = TypeInfo::Ptr(pointee_type); + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::Ref] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable reference type + /// that corresponds to the reference given by the `referenced_type` and `to_mutable_value`. + pub(crate) fn insert_ref( + &self, + engines: &Engines, + to_mutable_value: bool, + referenced_type: TypeArgument, + ) -> TypeId { + let source_id = self.get_ref_fallback_source_id(&referenced_type); + let is_shareable_type = self.is_shareable_ref(engines, &referenced_type); + let type_info = TypeInfo::Ref { + to_mutable_value, + referenced_type, + }; + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Inserts a new [TypeInfo::TraitType] into the [TypeEngine] and returns + /// its [TypeId], or returns a [TypeId] of an existing shareable trait type type + /// that corresponds to the trait type given by the `name` and `trait_type_id`. + pub(crate) fn insert_trait_type( + &self, + engines: &Engines, + name: Ident, + trait_type_id: TypeId, + ) -> TypeId { + let source_id = self.get_trait_type_fallback_source_id(&name, &trait_type_id); + // The trait type type shareability would be calculated as `!(false || false) ==>> true`. + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + let is_shareable_type = true; + let type_info = TypeInfo::TraitType { + name, + trait_type_id, + }; + self.insert_or_replace_type_source_info( + engines, + type_info, + source_id, + is_shareable_type, + None, + ) + } + + /// Same as [Self::insert_ref], but intended to insert references without annotations. + // TODO: Unlike `insert_ref`, once the https://github.com/FuelLabs/sway/issues/6603 gets implemented, + // this method will get the additional `use_site_source_id` parameter. + pub(crate) fn insert_ref_without_annotations( + &self, + engines: &Engines, + to_mutable_value: bool, + referenced_type: TypeId, + ) -> TypeId { + self.insert_ref(engines, to_mutable_value, referenced_type.into()) + } + /// Inserts a [TypeInfo] into the [TypeEngine] and returns a [TypeId] /// referring to that [TypeInfo]. pub(crate) fn insert( @@ -69,37 +800,1071 @@ impl TypeEngine { ty: TypeInfo, source_id: Option<&SourceId>, ) -> TypeId { - let source_id = source_id.copied().or_else(|| info_to_source_id(&ty)); - let tsi = TypeSourceInfo { - type_info: ty.clone().into(), - source_id, + // Avoid all of the heavy lifting of inserting and replacing logic, if `ty` is a shareable built-in type. + // + // Note that we are ignoring here the eventual `source_id` that could be provided by the caller. + // Ideally, for shareable built-in types that should never be the case, but `insert` is called in + // rare cases where the `ty` is not known and not inspected and is usually providing the use site span. + // + // The reason for ignoring the `source_id` is, because we want these types to be reused and "live forever" + // and never be garbage-collected and thus we do not assign any source id to them. + if let Some(type_id) = self.get_shareable_built_in_type_id(&ty) { + return type_id; + } + + // Same for the replaceable types, avoid heavy lifting. + // Note that we don't want to pack this `match` into a method, because we want to avoid cloning + // of `ty` in the case of it being a `Placeholder` or `UnknownGeneric`. + // + // TODO: Also, note that also here we are ignoring the `source_id` provided by the caller. + // This is only temporary until https://github.com/FuelLabs/sway/issues/6603 gets implemented. + // Until then, this shortcut corresponds to the current `TypeEngine` behavior: + // - `Unknown`s and `Numeric`s never have `source_id` assigned. + // - for `Placeholder`s and `UnknownGeneric`s, the `source_id` is extracted from the call site. + match ty { + TypeInfo::Unknown => return self.new_unknown(), + TypeInfo::Numeric => return self.new_numeric(), + TypeInfo::Placeholder(_) => return self.new_placeholder_impl(ty), + TypeInfo::UnknownGeneric { .. } => return self.new_unknown_generic_impl(ty), + _ => (), + } + + let is_shareable_type = self.is_type_shareable(engines, &ty); + let source_id = source_id + .copied() + .or_else(|| self.get_type_fallback_source_id(engines, &ty)); + + self.insert_or_replace_type_source_info(engines, ty, source_id, is_shareable_type, None) + } + + /// This method performs two actions, depending on the `replace_at_type_id`. + /// + /// If the `replace_at_type_id` is `Some`, this indicates that we want to unconditionally replace the [TypeSourceInfo] + /// currently located at `replace_at_type_id` with the one made of the `ty` + `source_id` pair. + /// In the case of replacement the method always return the [TypeId] provided in `replace_at_type_id`. + /// + /// If the `replace_at_type_id` is `None`, this indicates that we want to insert the [TypeSourceInfo], made of the + /// `ty` + `source_id` pair, into the `TypeEngine`. The insertion into the engine might require a new insert into + /// the `slab` or just returning a [TypeId] of an existing shareable [TypeSourceInfo] that is equal to the one defined by + /// the `ty` + `source_id` pair. + /// + /// If a new insertion is always made, or a reuse is possible, depends on the shareability of `ty` that is given by + /// `is_shareable_type`. + fn insert_or_replace_type_source_info( + &self, + engines: &Engines, + ty: TypeInfo, + source_id: Option, + is_shareable_type: bool, + replace_at_type_id: Option, + ) -> TypeId { + if !is_shareable_type { + let tsi = TypeSourceInfo { + type_info: ty.into(), + source_id, + }; + match replace_at_type_id { + Some(existing_id) => { + self.slab.replace(existing_id.index(), tsi); + existing_id + } + None => TypeId::new(self.slab.insert(tsi)), + } + } else { + let mut shareable_types = self.shareable_types.write(); + + let hash_builder = shareable_types.hasher().clone(); + let ty_hash = + self.compute_hash_without_heap_allocation(engines, &hash_builder, &ty, &source_id); + + let raw_entry = shareable_types.raw_entry_mut().from_hash(ty_hash, |x| { + // Not that the equality with engines of the types contained in the + // `shareable_types` is "strict" in the sense that only one element can equal. + // This is because the types that have annotation fields, a.k.a. distinguishable by + // annotations types, will never end up in the hash map because they are considered + // not to be shareable. + x.equals(&ty, &source_id, &PartialEqWithEnginesContext::new(engines)) + }); + match raw_entry { + RawEntryMut::Occupied(o) => match replace_at_type_id { + Some(existing_id) => { + let existing_type_source_info = o.key(); + self.slab + .replace_arc(existing_id.index(), existing_type_source_info.clone()); + existing_id + } + None => *o.get(), + }, + RawEntryMut::Vacant(v) => { + let tsi = TypeSourceInfo { + type_info: ty.into(), + source_id, + }; + let tsi_arc = Arc::new(tsi); + let type_id = TypeId::new(self.slab.insert_arc(tsi_arc.clone())); + v.insert_with_hasher( + ty_hash, + tsi_arc.clone(), + type_id, + make_hasher(&hash_builder, engines), + ); + match replace_at_type_id { + Some(existing_id) => { + self.slab.replace_arc(existing_id.index(), tsi_arc); + existing_id + } + None => type_id, + } + } + } + } + } + + /// Computes the same hash as the [Hasher] returned by [make_hasher] but without + /// allocating a new [TypeInfo] on the heap. + fn compute_hash_without_heap_allocation( + &self, + engines: &Engines, + hash_builder: &impl BuildHasher, + type_info: &TypeInfo, + source_id: &Option, + ) -> u64 { + let mut state = hash_builder.build_hasher(); + type_info.hash(&mut state, engines); + source_id.hash(&mut state); + state.finish() + } + + /// Returns true if the `ty` is a type that can be replaced by using + /// the [Self::replace] method during the type unification. + fn is_replaceable_type(ty: &TypeInfo) -> bool { + match ty { + TypeInfo::Unknown + | TypeInfo::Numeric + | TypeInfo::Placeholder(_) + | TypeInfo::UnknownGeneric { .. } => true, + TypeInfo::ContractCaller { abi_name, address } => { + Self::is_replaceable_contract_caller(abi_name, address) + } + _ => false, + } + } + + fn is_replaceable_contract_caller( + abi_name: &AbiName, + address: &Option>, + ) -> bool { + address.is_none() || matches!(abi_name, AbiName::Deferred) + } + + /// Returns true if the `ty` is a shareable type. + /// + /// A shareable type instance can be reused by the engine and is put into the [Self::shareable_types]. + fn is_type_shareable(&self, engines: &Engines, ty: &TypeInfo) -> bool { + !(self.is_type_changeable(engines, ty) || self.is_type_distinguishable_by_annotations(ty)) + } + + /// Returns true if the `ty` is a changeable type. A changeable type is either: + /// - a type that can be replaced during the type unification (by calling [Self::replace]). + /// We call such types replaceable types. A typical example would be [TypeInfo::UnknownGeneric]. + /// - or a type that is recursively defined over one or more replaceable types. E.g., a + /// generic enum type `SomeEnum` that is still not monomorphized is a changeable type. + /// Note that a monomorphized version of `SomeEnum`, like e.g., `SomeEnum` *is not + /// changeable*. + /// + /// Note that the changeability of a type is tightly related to the unification process + /// and the process of handling the types within the [TypeEngine]. As such, it is not + /// seen as a property of a type itself, but rather as an information on how the [TypeEngine] + /// treats the type. That's why the definition of the changeability of a type resides + /// inside of the [TypeEngine]. + pub(crate) fn is_type_changeable(&self, engines: &Engines, ty: &TypeInfo) -> bool { + let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); + match ty { + // Shareable built-in types are unchangeable by definition. + // These type have only one shared `TypeInfo` instance per type + // (and one for each unsigned integer). + TypeInfo::StringSlice + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::ErrorRecovery(_) + | TypeInfo::Contract + | TypeInfo::Never => false, + + // Note that `TypeParam` is currently not used at all. + TypeInfo::TypeParam(_) => false, + + // `StringArray`s are not changeable. We will have one shared + // `TypeInfo` instance for every string size. Note that in case + // of explicitly defined string arrays, e.g. in the storage or type ascriptions + // like `str[5]`, we can also have different instances for string + // arrays of the same size, because the `Length` in that case contains + // as well the span of the size (`5` in the example). + TypeInfo::StringArray(_) => false, + + // Replaceable types are, by definition, changeable. + TypeInfo::Unknown + | TypeInfo::Numeric + | TypeInfo::Placeholder(_) + | TypeInfo::UnknownGeneric { .. } => true, + + // The `ContractCaller` can be replaceable, and thus, sometimes changeable. + TypeInfo::ContractCaller { abi_name, address } => { + Self::is_replaceable_contract_caller(abi_name, address) + } + + // For the types are defined over other types, inspect recursively their constituting types. + TypeInfo::Enum(decl_id) => { + let decl = decl_engine.get_enum(decl_id); + self.is_changeable_enum(engines, &decl) + } + TypeInfo::UntypedEnum(decl_id) => { + let decl = parsed_decl_engine.get_enum(decl_id); + self.is_changeable_untyped_enum(engines, &decl) + } + TypeInfo::Struct(decl_id) => { + let decl = decl_engine.get_struct(decl_id); + self.is_changeable_struct(engines, &decl) + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = parsed_decl_engine.get_struct(decl_id); + self.is_changeable_untyped_struct(engines, &decl) + } + TypeInfo::Tuple(elements) => self.is_changeable_tuple(engines, elements), + + // Currently, we support only non-generic aliases. Which means the alias + // will never be changeable. + // TODO: (GENERIC-TYPE-ALIASES) If we ever introduce generic type aliases, update this accordingly. + TypeInfo::Alias { name: _, ty: _ } => false, + + // The following types are changeable if their type argument is changeable. + TypeInfo::Array(ta, _) + | TypeInfo::Slice(ta) + | TypeInfo::Ptr(ta) + | TypeInfo::Ref { + referenced_type: ta, + .. + } => self.is_changeable_type_argument(engines, ta), + + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + TypeInfo::Custom { .. } => true, + TypeInfo::TraitType { .. } => false, + } + } + + /// Returns true if two [TypeInfo] instances that are equal (with engines) and have same hashes (with engines) + /// should potentially still be treated, within the type engine, as different types. + /// + /// [TypeParameter]s, [TypeArgument]s, and [Length]s can be "annotated". This means that, aside from the information they + /// provide, like, e.g., [TypeArgument::type_id] or [Length::val], they can also, optionally, provide additional information + /// most notably various spans. + /// + /// Same is with [Ident]s. From the hashing and equality (with engines) perspective, only the string value matters, + /// but from the strict equality point of view, [Ident]'s span is also relevant. + /// + /// Thus, from the unification and type equivalence perspective, two [TypeArgument]s with the same `type_id` represent + /// the same type. But if those two type arguments differ in their annotations, the [TypeEngine] must be able to distinguish between + /// the equal (from the unification perspective) types that use those two different type arguments. + /// + /// In this example: + /// + /// ```ignore + /// let a: [u64;3] = (0, 0, 0); + /// let b: [u64;3] = (0, 0, 0); + /// ``` + /// + /// `a` and `b` will have the same type, but the span annotations in their [TypeArgument]s and [Length]s will be different + /// (different spans pointing to two "u64"s and two "3"s) and thus the [TypeEngine] must treat those two types as two + /// different types and when inserting them, assign them two different [TypeId]s, although the types themselves are not + /// changeable. + /// + /// To sum it up: + /// - if the `ty` consists of [TypeArgument]s, [TypeParameter]s, or [Length]s, they myst be check for annotations. + /// - if the `ty` contains, e.g., [Ident]s, it is considered to be distinguishable by annotations. + fn is_type_distinguishable_by_annotations(&self, ty: &TypeInfo) -> bool { + match ty { + // Types that do not have any annotations. + TypeInfo::StringSlice + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::ErrorRecovery(_) + | TypeInfo::Never + | TypeInfo::Unknown + | TypeInfo::Numeric + | TypeInfo::Contract + | TypeInfo::TypeParam(_) => false, + + // Types that are always distinguishable because they have the `name: Ident`. + // + // Let's explain this in more detail, taking the `TypeInfo::Alias` as an example. + // `TypeInfo::Alias` consists of the `name: Ident` and the `ty: TypeArgument`. + // + // Consider that we have two aliases with the same name and aliasing the same type but defined in different modules. + // Thus, they would be two _different_ alias types. But because the spans in the `name` and `ty` do not count + // neither for the equality check nor for the hash calculation, those two types will always be equal (with engines) + // and also have the same hashes (with engines). + // + // This means that the `TypeEngine` would see them as the same type which would be wrong. + // The fact that they are always distinguishable by annotations (span in the `name` and spans in the `ty`) + // is actually a fortunate fact here, because it will help the `TypeEngine` to distinguish them. + // + // The consequence of this fact is, that all `TypeInfo::Alias`es are _always distinguishable by annotations_. + // + // The downside is that repeated usages of an actually *same* alias type will create + // unnecessary new instances in the `TypeEngine` for every usage :-( + // + // Luckily, `TraitType`s and `Alias`es are rarely used and the number of their instances + // within the `TypeEngine` will always be negligible, so we don't need to worry about this downside. + // (At the time of writing this comment, out of ~200,000 types in the `TypeEngine` in a + // realistic real-world project only ~20 were type aliases and only ~5 were trait types.) + // And the `UnknownGeneric` is anyhow a changeable type. + TypeInfo::UnknownGeneric { .. } + // | TypeInfo::TraitType { .. } + | TypeInfo::Alias { .. } => true, + + TypeInfo::StringArray(l) => l.is_annotated(), + + // If the contract caller has the `abi_name` defined (AbiName::Know) the span information + // that comes with the `Ident`s of the `CallPath` is not relevant for the equality + // and hashing (with engines) but makes two same names distinguishable. The same thing is + // with the `address` expression. It can be, e.g., the same literal, but it will have different + // spans. Moreover, the same `abi_name`, depending on the context, can represent different + // ABI declarations, like in the example below: + // + // fn a() { + // use ::lib_a::Abi as Abi; // <<<--- `Abi` coming from `lib_**a**`. + // let _ = abi(Abi, 0x1111111111111111111111111111111111111111111111111111111111111111); + // } + + // fn b() { + // use ::lib_b::Abi as Abi; // <<<--- `Abi` coming from `lib_**b**`. + // let _ = abi(Abi, 0x1111111111111111111111111111111111111111111111111111111111111111); + // } + // + // This all means, if a `ContractCaller` has either the `abi_name` or the `address` defined, + // it is distinguishable by annotations. + TypeInfo::ContractCaller { abi_name, address } => Self::is_contract_caller_distinguishable_by_annotations(abi_name, address), + + // Enums `decl`s are either coming from enum declarations, + // or from their monomorphizations. If an enum declaration is generic, + // its type parameters will always be annotated, having, e.g., spans of + // generic parameter names, like, e.g., "T". + // Also, all the enum variants have `TypeArguments` that are _always_ annotated + // with the type span. + // + // In other words, all `TyEnumDecl`s are annotated. + // The question is, if the monomorphization can produce two same `decl`s that + // are differently annotated. E.g., when unifying the generic parameter "T" with "u64", + // like in the below example, will the span of the type parameter "T" change + // to "u64": + // + // let _ = GenericEnum::::A(42u64); + // let _ = GenericEnum::::A(42u64); + // + // In that case, the two equal `decl`s obtained via two monomorphizations above, + // would be differently annotated, and thus, distinguishable by annotations. + // + // The answer is *no*. The monomorphization changes only the `TypeId`s of the + // `TypeParameter`s and `TypeArgument`s but leaves the original spans untouched. + // Therefore, we can never end up in a situation that an annotation differs from + // the one in the original `TyEnumDecl` coming from the enum declaration. + // + // Thus, any two equal `TyEnumDecl`s are never distinguishable by annotations. + TypeInfo::Enum(_) => false, + + // The same argument as above applies to struct and `TyStructDecl`s. + TypeInfo::Struct(_) => false, + + // TODO: (UNTYPED-TYPES) Reassess this once `UntypedEnum` and `UntypedStruct` + // start getting logic. + TypeInfo::UntypedEnum(_) => false, + + // TODO: (UNTYPED-TYPES) Reassess this once `UntypedEnum` and `UntypedStruct` + // start getting logic. + TypeInfo::UntypedStruct(_) => false, + + // Equal (with engines) tuple types can have different annotations and are in that case + // distinguishable by those annotations. E.g., in the example below, the two + // `(u64, u8)` tuples will have different spans for two "u64"s and two "u8"s. + // + // let _: (u64, u8) = (64u64, 8u8); + // let _: (u64, u8) = (64u64, 8u8); + // + // Note that _all the tuples used in code will always be distinguishable by annotations_, + // because they will always have spans either pointing to the values like in `(64u64, 8u8)` + // or to types like in `(u64, u8)`. + // + // Only the tuples used in generated code will not be distinguishable by annotations, + // as well as tuples representing unit types. + TypeInfo::Tuple(elements) => self.is_tuple_distinguishable_by_annotations(elements), + + // The below types are those have `TypeArgument`s (`ta`s) in their definitions. + // Note that we are checking only if those `ta`s are annotated, but not + // recursively if the types they "reference" are annotated ;-) + // We don't need to recursively check if the types behind + // the `ta.type_id`s are distinguishable by annotations. + // This is because two equal (with engines) parent types + // containing `ta`s that pass the above check are also equal in + // case when their full type argument content is compared, + // because the type arguments will be equal in all their fields. + + TypeInfo::Slice(ta) + | TypeInfo::Ptr(ta) + | TypeInfo::Ref { referenced_type: ta, .. } => ta.is_annotated(), + + TypeInfo::Array(ta, l) => { + ta.is_annotated() || l.is_annotated() + } + + // The above reasoning for `TypeArgument`s applies also for the `TypeParameter`s. + // We only need to check if the `tp` is annotated. + TypeInfo::Placeholder(tp) => tp.is_annotated(), + + // TODO: Improve handling of `TypeInfo::Custom` and `TypeInfo::TraitType`` within the `TypeEngine`: + // https://github.com/FuelLabs/sway/issues/6601 + TypeInfo::Custom { .. } => true, + TypeInfo::TraitType { .. } => false, + } + } + + fn is_tuple_distinguishable_by_annotations(&self, elements: &[TypeArgument]) -> bool { + if elements.is_empty() { + false + } else { + elements.iter().any(|ta| ta.is_annotated()) + } + } + + fn is_contract_caller_distinguishable_by_annotations( + abi_name: &AbiName, + address: &Option>, + ) -> bool { + address.is_some() || matches!(abi_name, AbiName::Known(_)) + } + + /// Returns true if the `type_id` represents a changeable type. + /// For the type changeability see [Self::is_type_changeable]. + fn is_type_id_of_changeable_type(&self, engines: &Engines, type_id: TypeId) -> bool { + self.is_type_changeable(engines, &self.slab.get(type_id.index()).type_info) + } + + fn is_changeable_type_argument(&self, engines: &Engines, ta: &TypeArgument) -> bool { + self.is_type_id_of_changeable_type(engines, ta.type_id) + } + + fn is_changeable_enum(&self, engines: &Engines, decl: &TyEnumDecl) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_untyped_enum(&self, engines: &Engines, decl: &EnumDeclaration) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_struct(&self, engines: &Engines, decl: &TyStructDecl) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_untyped_struct(&self, engines: &Engines, decl: &StructDeclaration) -> bool { + self.are_changeable_type_parameters(engines, &decl.type_parameters) + // TODO: Remove once https://github.com/FuelLabs/sway/issues/6687 is fixed. + || + self.module_might_outlive_type_parameters(engines, decl.span.source_id(), &decl.type_parameters) + } + + fn is_changeable_tuple(&self, engines: &Engines, elements: &[TypeArgument]) -> bool { + if elements.is_empty() { + false + } else { + elements + .iter() + .any(|ta| self.is_type_id_of_changeable_type(engines, ta.type_id)) + } + } + + fn are_changeable_type_parameters( + &self, + engines: &Engines, + type_parameters: &[TypeParameter], + ) -> bool { + if type_parameters.is_empty() { + false + } else { + type_parameters + .iter() + .any(|tp| self.is_type_id_of_changeable_type(engines, tp.type_id)) + } + } + + // TODO: Remove this and all `module_might_outlive_xyz` methods once https://github.com/FuelLabs/sway/issues/6687 is fixed. + // + // This method represents the best effort to partially mitigate the issue + // described in https://github.com/FuelLabs/sway/issues/6687, by doing changes only in the `TypeEngine`. + // + // Enum and struct types use it to restrict their shareability and reduce the chance of accessing + // GCed types. + // + // The method takes an **existing** `type_id` and the source id of a particular module (`module_source_id`) + // and checks if the module represented by the `module_source_id` **might** survive LSP garbage collection + // even if the module to which `type_id` is bound gets GCed. + // + // E.g., if the `module_source_id` points to the `Option` declaration of a monomorphized `Option`, + // this method will return true if the `type_id` represents `MyStruct`, because if the `MyStruct`'s module + // gets GCed, the `Option`'s module will "survive" and outlive it, thus pointing via its `TypeArgument` to a + // non-existing, GCed, `MyStruct` type. + // + // E.g., if the `module_source_id` points to the `Option` declaration of a monomorphized `Option`, + // this method will return false if the `type_id` represents `u64`, because the `u64` is not bound to + // any module, and thus, can never be GCed. This means that the `Option`'s module can never outlive it. + fn module_might_outlive_type( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_id: TypeId, + ) -> bool { + fn module_might_outlive_type_source_id( + module_source_id: Option<&SourceId>, + type_source_id: Option, + ) -> bool { + // If the type represented by the `type_id` is not bound to a source id (`type_source_id.is_none()`) + // it cannot be outlived by the module. + // Otherwise, if `type_source_id.is_some()` but is the same as the `module_source_id`, it can be GCed only if + // the `module_source_id` is GCed. + // Otherwise, we cannot guarantee that the module will not outlive the type's module and we must + // be pessimistic and return false. + type_source_id.is_some() && type_source_id != module_source_id.copied() + } + + let tsi = self.slab.get(type_id.index()); + let type_info = &*tsi.type_info; + let type_source_id = tsi.source_id; + + let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); + + // We always must check the `type_id` itself, like, e.h., `MyStruct` in `Option`, ... + module_might_outlive_type_source_id(module_source_id, type_source_id) + || + // ... and also all types it transitively depends on, like, e.g., in `Option>`. + match type_info { + // If a type does not transitively depends on other types, just return `false`. + TypeInfo::StringSlice + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::ErrorRecovery(_) + | TypeInfo::Contract + | TypeInfo::Never => false, + + // Note that `TypeParam` is currently not used at all. + TypeInfo::TypeParam(_) => false, + + TypeInfo::StringArray(_) => false, + + TypeInfo::Unknown + | TypeInfo::Numeric => false, + + TypeInfo::Placeholder(tp) => self.module_might_outlive_type_parameter(engines, module_source_id, tp), + TypeInfo::UnknownGeneric { trait_constraints, parent, .. } => { + parent.is_some_and(|parent_type_id| self.module_might_outlive_type(engines, module_source_id, parent_type_id)) + || + self.module_might_outlive_trait_constraints(engines, module_source_id, trait_constraints) + }, + + TypeInfo::ContractCaller { .. } => false, + + TypeInfo::Enum(decl_id) => { + let decl = decl_engine.get_enum(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::UntypedEnum(decl_id) => { + let decl = parsed_decl_engine.get_enum(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::Struct(decl_id) => { + let decl = decl_engine.get_struct(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = parsed_decl_engine.get_struct(decl_id); + self.module_might_outlive_type_parameters(engines, module_source_id, &decl.type_parameters) + } + TypeInfo::Tuple(elements) => self.module_might_outlive_type_arguments(engines, module_source_id, elements), + + TypeInfo::Alias { ty, .. } => self.module_might_outlive_type_argument(engines, module_source_id, ty), + + TypeInfo::Array(ta, _) + | TypeInfo::Slice(ta) + | TypeInfo::Ptr(ta) + | TypeInfo::Ref { + referenced_type: ta, + .. + } => self.module_might_outlive_type_argument(engines, module_source_id, ta), + + TypeInfo::Custom { type_arguments, .. } => + type_arguments.as_ref().is_some_and(|type_arguments| + self.module_might_outlive_type_arguments(engines, module_source_id, type_arguments)), + TypeInfo::TraitType { trait_type_id, .. } => self.module_might_outlive_type(engines, module_source_id, *trait_type_id) + } + } + + fn module_might_outlive_type_parameter( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_parameter: &TypeParameter, + ) -> bool { + self.module_might_outlive_type(engines, module_source_id, type_parameter.type_id) + || self.module_might_outlive_type( + engines, + module_source_id, + type_parameter.initial_type_id, + ) + || self.module_might_outlive_trait_constraints( + engines, + module_source_id, + &type_parameter.trait_constraints, + ) + } + + fn module_might_outlive_type_parameters( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_parameters: &[TypeParameter], + ) -> bool { + if type_parameters.is_empty() { + false + } else { + type_parameters + .iter() + .any(|tp| self.module_might_outlive_type_parameter(engines, module_source_id, tp)) + } + } + + fn module_might_outlive_type_argument( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_argument: &TypeArgument, + ) -> bool { + self.module_might_outlive_type(engines, module_source_id, type_argument.type_id) + || self.module_might_outlive_type( + engines, + module_source_id, + type_argument.initial_type_id, + ) + } + + fn module_might_outlive_type_arguments( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + type_arguments: &[TypeArgument], + ) -> bool { + if type_arguments.is_empty() { + false + } else { + type_arguments + .iter() + .any(|ta| self.module_might_outlive_type_argument(engines, module_source_id, ta)) + } + } + + fn module_might_outlive_trait_constraint( + &self, + _engines: &Engines, + _module_source_id: Option<&SourceId>, + trait_constraint: &TraitConstraint, + ) -> bool { + // `TraitConstraint`s can contain `TypeArgument`s that can cause endless recursion, + // unless we track already visited types. This happens in cases of recursive generic + // traits like, e.g., `T: Trait`. + // + // We deliberately decide not to track visited types because: + // - `module_might_outlive_type` represents a best effort to mitigate the issue of modules outliving their types. + // It is already not exact. + // - trait constraints with type arguments are rather rare. + // - tracking already visited types is expensive and `module_might_outlive_type` already adds an overhead. + // + // Instead, if the `trait_constraint` contains type arguments, we will bail out and + // conclude that the module might outlive the types in the trait constraint. + !trait_constraint.type_arguments.is_empty() + } + + fn module_might_outlive_trait_constraints( + &self, + engines: &Engines, + module_source_id: Option<&SourceId>, + trait_constraint: &[TraitConstraint], + ) -> bool { + trait_constraint + .iter() + .any(|tc| self.module_might_outlive_trait_constraint(engines, module_source_id, tc)) + } + + // In the `is_shareable_` methods we reuse the logic from the + // `is_type_changeable` and `is_type_distinguishable_by_annotations`. + // This is a very slight and minimal copy of logic, that improves performance + // (Inlining, no additional fetching from the `DeclEngine`, no intensive function + // calls, etc. Don't forget that this is all on a *very* hot path.) + + fn is_shareable_enum(&self, engines: &Engines, decl: &TyEnumDecl) -> bool { + // !(self.is_changeable_enum(decl_engine, decl) || false) + !self.is_changeable_enum(engines, decl) + } + + fn is_shareable_struct(&self, engines: &Engines, decl: &TyStructDecl) -> bool { + // !(self.is_changeable_struct(decl_engine, decl) || false) + !self.is_changeable_struct(engines, decl) + } + + fn is_shareable_tuple(&self, engines: &Engines, elements: &[TypeArgument]) -> bool { + !(self.is_changeable_tuple(engines, elements) + || self.is_tuple_distinguishable_by_annotations(elements)) + } + + fn is_shareable_array( + &self, + engines: &Engines, + elem_type: &TypeArgument, + length: &Length, + ) -> bool { + !(self.is_changeable_type_argument(engines, elem_type) + || elem_type.is_annotated() + || length.is_annotated()) + } + + fn is_shareable_string_array(&self, length: &Length) -> bool { + // !(false || length.is_annotated()) + !length.is_annotated() + } + + fn is_shareable_slice(&self, engines: &Engines, elem_type: &TypeArgument) -> bool { + !(self.is_changeable_type_argument(engines, elem_type) || elem_type.is_annotated()) + } + + fn is_shareable_ptr(&self, engines: &Engines, pointee_type: &TypeArgument) -> bool { + !(self.is_changeable_type_argument(engines, pointee_type) || pointee_type.is_annotated()) + } + + fn is_shareable_ref(&self, engines: &Engines, referenced_type: &TypeArgument) -> bool { + !(self.is_changeable_type_argument(engines, referenced_type) + || referenced_type.is_annotated()) + } + + // TODO: This and other, type-specific, methods that calculate `source_id` have `fallback` in their name. + // They will be called if the `source_id` is not provided in `new` or `insert` methods, + // thus, fallbacks. + // However, some of them actually do calculate the appropriate `source_id` which will for certain + // types and situations always be extracted from the `TypeInfo` and not allowed to be provided + // in `new` or `insert` methods. + // Until https://github.com/FuelLabs/sway/issues/6603 gets implemented, we will call them all + // fallbacks, which corresponds to the current usage, and eventually rename them accordingly + // once we optimize the `TypeEngine` for garbage collection (#6603). + + fn get_type_fallback_source_id(&self, engines: &Engines, ty: &TypeInfo) -> Option { + let decl_engine = engines.de(); + let parsed_decl_engine = engines.pe(); + match ty { + TypeInfo::Unknown + | TypeInfo::Never + | TypeInfo::TypeParam(_) + | TypeInfo::UnsignedInteger(_) + | TypeInfo::Boolean + | TypeInfo::B256 + | TypeInfo::Numeric + | TypeInfo::ErrorRecovery(_) + | TypeInfo::RawUntypedPtr + | TypeInfo::RawUntypedSlice + | TypeInfo::Contract + | TypeInfo::StringSlice => None, + + TypeInfo::UnknownGeneric { .. } => Self::get_unknown_generic_fallback_source_id(ty), + TypeInfo::Placeholder(_) => self.get_placeholder_fallback_source_id(ty), + TypeInfo::StringArray(length) => Self::get_source_id_from_length(length), + TypeInfo::Enum(decl_id) => { + let decl = decl_engine.get_enum(decl_id); + Self::get_enum_fallback_source_id(&decl) + } + TypeInfo::UntypedEnum(decl_id) => { + let decl = parsed_decl_engine.get_enum(decl_id); + Self::get_untyped_enum_fallback_source_id(&decl) + } + TypeInfo::Struct(decl_id) => { + let decl = decl_engine.get_struct(decl_id); + Self::get_struct_fallback_source_id(&decl) + } + TypeInfo::UntypedStruct(decl_id) => { + let decl = parsed_decl_engine.get_struct(decl_id); + Self::get_untyped_struct_fallback_source_id(&decl) + } + TypeInfo::Tuple(elements) => self.get_tuple_fallback_source_id(elements), + TypeInfo::Array(elem_type, length) => { + self.get_array_fallback_source_id(elem_type, length) + } + + TypeInfo::ContractCaller { abi_name, address } => { + Self::get_contract_caller_fallback_source_id(abi_name, address) + } + + TypeInfo::Alias { name, ty } => self.get_alias_fallback_source_id(name, ty), + + TypeInfo::Ptr(ta) + | TypeInfo::Slice(ta) + | TypeInfo::Ref { + referenced_type: ta, + .. + } => self.get_source_id_from_type_argument(ta), + + TypeInfo::Custom { + qualified_call_path, + type_arguments, + } => self.get_custom_fallback_source_id(qualified_call_path, type_arguments), + + TypeInfo::TraitType { + name, + trait_type_id, + } => self.get_trait_type_fallback_source_id(name, trait_type_id), + } + } + + fn get_source_id_from_length(length: &Length) -> Option { + length.span().source_id().copied() + } + + fn get_source_id_from_type_argument(&self, ta: &TypeArgument) -> Option { + // If the `ta` is span-annotated, take the source id from its `span`, + // otherwise, take the source id of the type it represents. + ta.span + .source_id() + .copied() + .or_else(|| self.get_type_source_id(ta.type_id)) + } + + fn get_source_id_from_type_arguments( + &self, + type_arguments: &[TypeArgument], + ) -> Option { + // For type arguments, if they are annotated, we take the use site source file. + // In semantically valid usages, in a vector of `TypeArgument`s, the use site source file + // will be the same for all the elements, so we are taking it from the + // first one that is annotated (which will be the first one or none). + // E.g., in a `TypeInfo::Tuple`, all the `TypeArgument`s will either not be annotated, or will + // all be annotated and situated within the same file. + // + // If the type arguments are not annotated, we are taking the source file of the first type + // pointed by a type argument, that has a source id. + if type_arguments.is_empty() { + None + } else { + type_arguments + .iter() + .find_map(|ta| ta.span.source_id().copied()) + .or_else(|| { + type_arguments + .iter() + .find_map(|ta| self.get_type_source_id(ta.type_id)) + }) + } + } + + fn get_source_id_from_type_parameter(&self, tp: &TypeParameter) -> Option { + // If the `tp` is span-annotated, take the source id from its `span`, + // otherwise, take the source id of the type it represents. + tp.name + .span() + .source_id() + .copied() + .or_else(|| self.get_type_source_id(tp.type_id)) + } + + fn get_placeholder_fallback_source_id(&self, placeholder: &TypeInfo) -> Option { + // `TypeInfo::Placeholder` is an always replaceable type and we know we will + // get a new instance of it in the engine for every "_" occurrence. This means + // that it can never happen that instances from different source files point + // to the same `TypeSourceInfo`. Therefore, we can safely remove an instance + // of a `Placeholder` from the engine if its source file is garbage collected. + // + // The source file itself is always the one in which the `name`, means "_", + // is situated. + let TypeInfo::Placeholder(tp) = &placeholder else { + unreachable!("The `placeholder` is checked to be of variant `TypeInfo::Placeholder`."); + }; + + self.get_source_id_from_type_parameter(tp) + } + + fn get_unknown_generic_fallback_source_id(unknown_generic: &TypeInfo) -> Option { + // `TypeInfo::UnknownGeneric` is an always replaceable type and we know we will + // get a new instance of it in the engine for every, e.g., "", "", etc. occurrence. + // This means that it can never happen that instances from different source files point + // to the same `TypeSourceInfo`. Therefore, we can safely remove an instance + // of an `UnknownGeneric` from the engine if its source file is garbage collected. + // + // The source file itself is always the one in which the `name`, means, e.g. "T1", "T2", etc. + // is situated. + let TypeInfo::UnknownGeneric { name, .. } = &unknown_generic else { + unreachable!( + "The `unknown_generic` is checked to be of variant `TypeInfo::UnknownGeneric`." + ); }; - let mut id_map = self.id_map.write(); + name.span().source_id().copied() + } + + fn get_enum_fallback_source_id(decl: &TyEnumDecl) -> Option { + // For `TypeInfo::Enum`, we are taking the source file in which the enum is declared. + decl.span.source_id().copied() + } + + fn get_untyped_enum_fallback_source_id(decl: &EnumDeclaration) -> Option { + // For `TypeInfo::UntypedEnum`, we are taking the source file in which the enum is declared. + decl.span.source_id().copied() + } + + fn get_struct_fallback_source_id(decl: &TyStructDecl) -> Option { + // For `TypeInfo::Struct`, we are taking the source file in which the struct is declared. + decl.span.source_id().copied() + } + + fn get_untyped_struct_fallback_source_id(decl: &StructDeclaration) -> Option { + // For `TypeInfo::UntypedStruct`, we are taking the source file in which the struct is declared. + decl.span.source_id().copied() + } + + fn get_tuple_fallback_source_id(&self, elements: &[TypeArgument]) -> Option { + self.get_source_id_from_type_arguments(elements) + } + + fn get_array_fallback_source_id( + &self, + elem_type: &TypeArgument, + length: &Length, + ) -> Option { + // For `TypeInfo::Array`, if it is annotated, we take the use site source file. + // This can be found in the `elem_type` and the `length`. + // + // If the array type is not annotated, we are taking the source file of the array element. + assert_eq!( + elem_type.span.source_id(), + length.span().source_id(), + "If an array is annotated, the type argument and the length spans must have the same source id." + ); - let hash_builder = id_map.hasher().clone(); - let ty_hash = make_hasher(&hash_builder, engines)(&tsi); + self.get_source_id_from_type_argument(elem_type) + } - let raw_entry = id_map.raw_entry_mut().from_hash(ty_hash, |x| { - x.eq(&tsi, &PartialEqWithEnginesContext::new(engines)) - }); - match raw_entry { - RawEntryMut::Occupied(o) => return *o.get(), - RawEntryMut::Vacant(_) if ty.can_change(engines) => TypeId::new(self.slab.insert(tsi)), - RawEntryMut::Vacant(v) => { - let type_id = TypeId::new(self.slab.insert(tsi.clone())); - v.insert_with_hasher(ty_hash, tsi, type_id, make_hasher(&hash_builder, engines)); - type_id + fn get_string_array_fallback_source_id(length: &Length) -> Option { + // For `TypeInfo::StringArray`, if it is annotated, we take the use site source file found in the `length`. + Self::get_source_id_from_length(length) + } + + fn get_contract_caller_fallback_source_id( + abi_name: &AbiName, + address: &Option>, + ) -> Option { + // For `TypeInfo::ContractCaller`, if it has an `address`, we take the use site source file found in the it. + // Otherwise, if it has an `abi_name`, we take the source file of the ABI definition. + match address { + Some(addr_expr) => addr_expr.span.source_id().copied(), + None => { + if let AbiName::Known(name) = abi_name { + name.span().source_id().copied() + } else { + None + } } } } + fn get_alias_fallback_source_id(&self, name: &Ident, ty: &TypeArgument) -> Option { + // For `TypeInfo::Alias`, we take the source file in which the alias is declared, if it exists. + // Otherwise, we take the source file of the aliased type `ty`. + name.span() + .source_id() + .copied() + .or_else(|| self.get_source_id_from_type_argument(ty)) + } + + fn get_slice_fallback_source_id(&self, elem_type: &TypeArgument) -> Option { + self.get_source_id_from_type_argument(elem_type) + } + + fn get_ptr_fallback_source_id(&self, pointee_type: &TypeArgument) -> Option { + self.get_source_id_from_type_argument(pointee_type) + } + + fn get_ref_fallback_source_id(&self, referenced_type: &TypeArgument) -> Option { + self.get_source_id_from_type_argument(referenced_type) + } + + fn get_custom_fallback_source_id( + &self, + qualified_call_path: &QualifiedCallPath, + type_arguments: &Option>, + ) -> Option { + // For `TypeInfo::Custom`, we take the source file in which the custom type is used, extracted from the `qualified_call_path`. + // For non-generated source code, this will always exists. + // For potential situation of having a `qualified_call_path` without spans in generated code, we do a fallback and + // extract the source id from the remaining parameters. + qualified_call_path + .call_path + .suffix + .span() + .source_id() + .copied() + .or_else(|| { + type_arguments + .as_ref() + .and_then(|tas| self.get_source_id_from_type_arguments(tas)) + }) + } + + fn get_trait_type_fallback_source_id( + &self, + name: &Ident, + trait_type_id: &TypeId, + ) -> Option { + // For `TypeInfo::TraitType`, we take the source file in which the trait type is declared, extracted from the `name`. + // For non-generated source code, this will always exists. + // For potential situation of having a `name` without spans in generated code, we do a fallback and + // extract the source id from the `trait_type_id`. + name.span() + .source_id() + .copied() + .or_else(|| self.get_type_source_id(*trait_type_id)) + } + + /// Returns the known [SourceId] of a type that already exists + /// in the [TypeEngine]. The type is given by its `type_id`. + fn get_type_source_id(&self, type_id: TypeId) -> Option { + self.slab.get(type_id.index()).source_id + } + fn clear_items(&mut self, keep: F) where F: Fn(&SourceId) -> bool, { self.slab .retain(|_, tsi| tsi.source_id.as_ref().map_or(true, &keep)); - self.id_map + self.shareable_types .write() .retain(|tsi, _| tsi.source_id.as_ref().map_or(true, &keep)); } @@ -114,12 +1879,69 @@ impl TypeEngine { self.clear_items(|id| id != source_id); } - pub fn replace(&self, engines: &Engines, id: TypeId, new_value: TypeSourceInfo) { - if !(*self.slab.get(id.index())).eq(&new_value, &PartialEqWithEnginesContext::new(engines)) - { + /// Replaces the replaceable type behind the `type_id` with the `new_value`. + /// The existing source id will be preserved. + /// + /// Note that, if the `new_value` represents a shareable built-in type, + /// the existing source id will be removed (replaced by `None`). + /// + /// Panics if the type behind the `type_id` is not a replaceable type. + pub fn replace(&self, engines: &Engines, type_id: TypeId, new_value: TypeInfo) { + // We keep the existing source id. `replace_with_new_source_id` is treated just as a common implementation. + let source_id = self.slab.get(type_id.index()).source_id; + self.replace_with_new_source_id(engines, type_id, new_value, source_id); + } + + /// Replaces the replaceable type behind the `type_id` with the `new_value`. + /// The existing source id will also be replaced with the `new_source_id`. + /// + /// Note that, if the `new_value` represents a shareable built-in type, + /// the existing source id will be removed (replaced by `None`). + /// + /// Panics if the type behind the `type_id` is not a replaceable type. + // TODO: Once https://github.com/FuelLabs/sway/issues/6603 gets implemented and we further optimize + // the `TypeEngine` for garbage collection, this variant of `replace` will actually not be + // needed any more. The version of `replace` that uses the initially provided `source_id` will + // be sufficient. + pub fn replace_with_new_source_id( + &self, + engines: &Engines, + id: TypeId, + new_value: TypeInfo, + new_source_id: Option, + ) { + let type_source_info = self.slab.get(id.index()); + assert!( + Self::is_replaceable_type(&type_source_info.type_info), + "The type requested to be replaced is not a replaceable type. The type was: {:#?}.", + &type_source_info.type_info + ); + + if !type_source_info.equals( + &new_value, + &new_source_id, + &PartialEqWithEnginesContext::new(engines), + ) { self.touch_last_replace(); } - self.slab.replace(id.index(), new_value); + let is_shareable_type = self.is_type_shareable(engines, &new_value); + // Shareable built-in types like, e.g., `u64`, should "live forever" and never be + // garbage-collected. When replacing types, like e.g., unknown generics, that + // might be bound to a source id, we will still remove that source id, if the + // replaced type is replaced by a shareable built-in type. This maximizes the + // reuse of sharable built-in types, and also ensures that they are never GCed. + let source_id = if self.is_shareable_built_in_type(&new_value) { + None + } else { + new_source_id + }; + self.insert_or_replace_type_source_info( + engines, + new_value, + source_id, + is_shareable_type, + Some(id), + ); } /// Performs a lookup of `id` into the [TypeEngine]. @@ -386,7 +2208,6 @@ impl TypeEngine { | TypeInfo::B256 | TypeInfo::Contract | TypeInfo::ErrorRecovery(..) - | TypeInfo::Storage { .. } | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Alias { .. } @@ -453,25 +2274,12 @@ impl TypeEngine { | TypeInfo::B256 | TypeInfo::Contract | TypeInfo::ErrorRecovery(..) - | TypeInfo::Storage { .. } | TypeInfo::RawUntypedPtr | TypeInfo::RawUntypedSlice | TypeInfo::Alias { .. } | TypeInfo::TraitType { .. } => {} TypeInfo::Numeric => { - self.unify( - handler, - engines, - type_id, - self.insert( - engines, - TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - span.source_id(), - ), - span, - "", - None, - ); + self.unify(handler, engines, type_id, self.id_of_u64(), span, "", None); } } Ok(()) @@ -491,23 +2299,3 @@ impl TypeEngine { builder } } - -/// Maps specific [TypeInfo] variants to a reserved [SourceId], returning `None` for non-mapped types. -fn info_to_source_id(ty: &TypeInfo) -> Option { - match ty { - TypeInfo::Unknown - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Numeric - | TypeInfo::Boolean - | TypeInfo::B256 - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::StringSlice - | TypeInfo::Contract - | TypeInfo::StringArray(_) - | TypeInfo::Array(_, _) - | TypeInfo::Ref { .. } => Some(SourceId::reserved()), - TypeInfo::Tuple(v) if v.is_empty() => Some(SourceId::reserved()), - _ => None, - } -} diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 7a7480fe838..f429a0d2283 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -1,5 +1,6 @@ #![allow(clippy::mutable_key_type)] use indexmap::IndexMap; +use serde::{Deserialize, Serialize}; use sway_error::{ error::CompileError, handler::{ErrorEmitted, Handler}, @@ -34,7 +35,7 @@ pub enum TreatNumericAs { } /// A identifier to uniquely refer to our type terms -#[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)] +#[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug, Deserialize, Serialize)] pub struct TypeId(usize); impl DisplayWithEngines for TypeId { @@ -80,7 +81,7 @@ impl CollectTypesMetadata for TypeId { } TypeInfo::Placeholder(type_param) => { res.push(TypeMetadata::UnresolvedType( - type_param.name_ident.clone(), + type_param.name.clone(), ctx.call_site_get(self), )); } @@ -94,7 +95,10 @@ impl CollectTypesMetadata for TypeId { impl SubstTypes for TypeId { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges { let type_engine = ctx.engines.te(); - if let Some(matching_id) = ctx.type_subst_map.find_match(*self, ctx.engines) { + if let Some(matching_id) = ctx + .type_subst_map + .and_then(|tsm| tsm.find_match(*self, ctx.engines)) + { if !matches!(&*type_engine.get(matching_id), TypeInfo::ErrorRecovery(_)) { *self = matching_id; HasChanges::Yes @@ -108,7 +112,7 @@ impl SubstTypes for TypeId { } impl TypeId { - pub(super) fn new(index: usize) -> TypeId { + pub(super) const fn new(index: usize) -> TypeId { TypeId(index) } @@ -383,19 +387,6 @@ impl TypeId { .extract_any_including_self(engines, filter_fn, vec![], depth + 1), ); } - TypeInfo::Storage { fields } => { - for field in fields { - extend( - &mut found, - field.type_argument.type_id.extract_any_including_self( - engines, - filter_fn, - vec![], - depth + 1, - ), - ); - } - } TypeInfo::Alias { name: _, ty } => { extend( &mut found, @@ -697,13 +688,7 @@ impl TypeId { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| { - engines.te().insert( - engines, - TypeInfo::ErrorRecovery(err), - None, - ) - }), + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)), ctx.resolve_type( handler, t2.type_id, @@ -711,13 +696,7 @@ impl TypeId { EnforceTypeArguments::No, None, ) - .unwrap_or_else(|err| { - engines.te().insert( - engines, - TypeInfo::ErrorRecovery(err), - None, - ) - }), + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)), ) }) }, diff --git a/sway-core/src/type_system/info.rs b/sway-core/src/type_system/info.rs index 29767d81fc0..e0304d62ed2 100644 --- a/sway-core/src/type_system/info.rs +++ b/sway-core/src/type_system/info.rs @@ -12,20 +12,19 @@ use crate::{ type_system::priv_prelude::*, Ident, }; -use sway_error::{ - error::{CompileError, InvalidImplementingForType}, - handler::{ErrorEmitted, Handler}, -}; -use sway_types::{integer_bits::IntegerBits, span::Span, SourceId}; - +use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, fmt, hash::{Hash, Hasher}, - sync::Arc, }; +use sway_error::{ + error::{CompileError, InvalidImplementingForType}, + handler::{ErrorEmitted, Handler}, +}; +use sway_types::{integer_bits::IntegerBits, span::Span}; -#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum AbiName { Deferred, Known(CallPath), @@ -71,28 +70,6 @@ impl PartialEqWithEngines for VecSet { } } -/// Encapsulates type information and its optional source identifier. -#[derive(Debug, Default, Clone)] -pub struct TypeSourceInfo { - pub(crate) type_info: Arc, - /// The source id that created this type. - pub(crate) source_id: Option, -} - -impl HashWithEngines for TypeSourceInfo { - fn hash(&self, state: &mut H, engines: &Engines) { - self.type_info.hash(state, engines); - self.source_id.hash(state); - } -} - -impl EqWithEngines for TypeSourceInfo {} -impl PartialEqWithEngines for TypeSourceInfo { - fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { - self.type_info.eq(&other.type_info, ctx) && self.source_id == other.source_id - } -} - /// Type information without an associated value, used for type inferencing and definition. #[derive(Debug, Clone, Default)] pub enum TypeInfo { @@ -162,12 +139,6 @@ pub enum TypeInfo { ErrorRecovery(ErrorEmitted), // Static, constant size arrays. Array(TypeArgument, Length), - /// Represents the entire storage declaration struct - /// Stored without initializers here, as typed struct fields, - /// so type checking is able to treat it as a struct with fields. - Storage { - fields: Vec, - }, /// Pointers. /// These are represented in memory as u64 but are a different type since pointers only make /// sense in the context they were created in. Users can obtain pointers via standard library @@ -178,8 +149,12 @@ pub enum TypeInfo { RawUntypedSlice, Ptr(TypeArgument), Slice(TypeArgument), - /// Type Alias. This type and the type `ty` it encapsulates always coerce. They are effectively - /// interchangeable + /// Type aliases. + /// This type and the type `ty` it encapsulates always coerce. They are effectively + /// interchangeable. + /// Currently, we support only non-generic type aliases. + // TODO: (GENERIC-TYPE-ALIASES) If we ever introduce generic type aliases, update the logic + // in the `TypeEngine` accordingly, e.g., the `is_type_changeable`. Alias { name: Ident, ty: TypeArgument, @@ -242,9 +217,6 @@ impl HashWithEngines for TypeInfo { call_path.hash(state, engines); type_arguments.as_deref().hash(state, engines); } - TypeInfo::Storage { fields } => { - fields.hash(state, engines); - } TypeInfo::Array(elem_ty, count) => { elem_ty.hash(state, engines); count.hash(state); @@ -355,16 +327,7 @@ impl PartialEqWithEngines for TypeInfo { && l_decl.fields.eq(&r_decl.fields, ctx) && l_decl.type_parameters.eq(&r_decl.type_parameters, ctx) } - (Self::Tuple(l), Self::Tuple(r)) => l - .iter() - .zip(r.iter()) - .map(|(l, r)| { - (l.type_id == r.type_id) - || type_engine - .get(l.type_id) - .eq(&type_engine.get(r.type_id), ctx) - }) - .all(|x| x), + (Self::Tuple(l), Self::Tuple(r)) => l.eq(r, ctx), ( Self::ContractCaller { abi_name: l_abi_name, @@ -386,9 +349,6 @@ impl PartialEqWithEngines for TypeInfo { .eq(&type_engine.get(r0.type_id), ctx)) && l1.val() == r1.val() } - (Self::Storage { fields: l_fields }, Self::Storage { fields: r_fields }) => { - l_fields.eq(r_fields, ctx) - } ( Self::Alias { name: l_name, @@ -522,9 +482,6 @@ impl OrdWithEngines for TypeInfo { .get(l0.type_id) .cmp(&type_engine.get(r0.type_id), ctx) .then_with(|| l1.val().cmp(&r1.val())), - (TypeInfo::Storage { fields: l_fields }, TypeInfo::Storage { fields: r_fields }) => { - l_fields.cmp(r_fields, ctx) - } ( Self::Alias { name: l_name, @@ -576,7 +533,7 @@ impl DisplayWithEngines for TypeInfo { Unknown => "{unknown}".into(), Never => "!".into(), UnknownGeneric { name, .. } => name.to_string(), - Placeholder(type_param) => type_param.name_ident.to_string(), + Placeholder(type_param) => type_param.name.to_string(), TypeParam(n) => format!("{n}"), StringSlice => "str".into(), StringArray(x) => format!("str[{}]", x.val()), @@ -640,7 +597,6 @@ impl DisplayWithEngines for TypeInfo { Array(elem_ty, count) => { format!("[{}; {}]", engines.help_out(elem_ty), count.val()) } - Storage { .. } => "storage".into(), RawUntypedPtr => "pointer".into(), RawUntypedSlice => "slice".into(), Ptr(ty) => { @@ -780,7 +736,6 @@ impl DebugWithEngines for TypeInfo { Array(elem_ty, count) => { format!("[{:?}; {}]", engines.help_out(elem_ty), count.val()) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { @@ -834,23 +789,31 @@ impl TypeInfo { TypeInfo::Contract => 13, TypeInfo::ErrorRecovery(_) => 14, TypeInfo::Array(_, _) => 15, - TypeInfo::Storage { .. } => 16, - TypeInfo::RawUntypedPtr => 17, - TypeInfo::RawUntypedSlice => 18, - TypeInfo::TypeParam(_) => 19, - TypeInfo::Alias { .. } => 20, - TypeInfo::Ptr(..) => 21, - TypeInfo::Slice(..) => 22, - TypeInfo::StringSlice => 23, - TypeInfo::TraitType { .. } => 24, - TypeInfo::Ref { .. } => 25, - TypeInfo::Never => 26, - TypeInfo::UntypedEnum(_) => 27, - TypeInfo::UntypedStruct(_) => 28, + TypeInfo::RawUntypedPtr => 16, + TypeInfo::RawUntypedSlice => 17, + TypeInfo::TypeParam(_) => 18, + TypeInfo::Alias { .. } => 19, + TypeInfo::Ptr(..) => 20, + TypeInfo::Slice(..) => 21, + TypeInfo::StringSlice => 22, + TypeInfo::TraitType { .. } => 23, + TypeInfo::Ref { .. } => 24, + TypeInfo::Never => 25, + TypeInfo::UntypedEnum(_) => 26, + TypeInfo::UntypedStruct(_) => 27, } } + /// Creates a new [TypeInfo::Custom] that represents a Self type. + /// + /// The `span` must either be a [Span::dummy] or a span pointing + /// to text "Self" or "self", otherwise the method panics. pub(crate) fn new_self_type(span: Span) -> TypeInfo { + assert!( + span.is_dummy() || span.as_str() == "Self" || span.as_str() == "self", + "The Self type span must either be a dummy span, or a span pointing to text \"Self\" or \"self\". The span was pointing to text: \"{}\".", + span.as_str() + ); TypeInfo::Custom { qualified_call_path: QualifiedCallPath { call_path: CallPath { @@ -1302,7 +1265,6 @@ impl TypeInfo { | TypeInfo::Contract | TypeInfo::ErrorRecovery(_) | TypeInfo::Array(_, _) - | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::Alias { .. } @@ -1380,7 +1342,6 @@ impl TypeInfo { | TypeInfo::ContractCaller { .. } | TypeInfo::Custom { .. } | TypeInfo::Contract - | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) | TypeInfo::TraitType { .. } => { @@ -1444,7 +1405,6 @@ impl TypeInfo { )), TypeInfo::Unknown | TypeInfo::ContractCaller { .. } - | TypeInfo::Storage { .. } | TypeInfo::Placeholder(_) | TypeInfo::TypeParam(_) => Err(handler.emit_err( CompileError::TypeIsNotValidAsImplementingFor { @@ -1457,54 +1417,6 @@ impl TypeInfo { } } - pub(crate) fn can_change(&self, engines: &Engines) -> bool { - // TODO: there might be an optimization here that if the type params hold - // only non-dynamic types, then it doesn't matter that there are type params - match self { - TypeInfo::UntypedEnum(decl_id) => { - let decl = engines.pe().get_enum(decl_id); - !decl.type_parameters.is_empty() - } - TypeInfo::UntypedStruct(decl_id) => { - let decl = engines.pe().get_struct(decl_id); - !decl.type_parameters.is_empty() - } - TypeInfo::Enum(decl_ref) => { - let decl = engines.de().get_enum(decl_ref); - !decl.type_parameters.is_empty() - } - TypeInfo::Struct(decl_ref) => { - let decl = engines.de().get_struct(decl_ref); - !decl.type_parameters.is_empty() - } - TypeInfo::StringArray(_) - | TypeInfo::StringSlice - | TypeInfo::UnsignedInteger(_) - | TypeInfo::Boolean - | TypeInfo::B256 - | TypeInfo::RawUntypedPtr - | TypeInfo::RawUntypedSlice - | TypeInfo::Ptr(_) - | TypeInfo::ErrorRecovery(_) - | TypeInfo::TraitType { .. } - | TypeInfo::Never => false, - TypeInfo::Unknown - | TypeInfo::UnknownGeneric { .. } - | TypeInfo::ContractCaller { .. } - | TypeInfo::Custom { .. } - | TypeInfo::Tuple(_) - | TypeInfo::Array(_, _) - | TypeInfo::Slice(_) - | TypeInfo::Contract - | TypeInfo::Storage { .. } - | TypeInfo::Numeric - | TypeInfo::Placeholder(_) - | TypeInfo::TypeParam(_) - | TypeInfo::Alias { .. } - | TypeInfo::Ref { .. } => true, - } - } - /// Checks if a given [TypeInfo] has a valid constructor. pub(crate) fn has_valid_constructor(&self, decl_engine: &DeclEngine) -> bool { match self { @@ -1807,7 +1719,6 @@ impl TypeInfo { length.val() ) } - Storage { .. } => "contract storage".into(), RawUntypedPtr => "raw untyped ptr".into(), RawUntypedSlice => "raw untyped slice".into(), Ptr(ty) => { diff --git a/sway-core/src/type_system/mod.rs b/sway-core/src/type_system/mod.rs index 37446b5843c..fedf09bb480 100644 --- a/sway-core/src/type_system/mod.rs +++ b/sway-core/src/type_system/mod.rs @@ -77,32 +77,22 @@ fn generic_enum_resolution() { a: _ } */ - let generic_type = engines.te().insert( - &engines, - TypeInfo::UnknownGeneric { - name: generic_name.clone(), - trait_constraints: VecSet(Vec::new()), - parent: None, - is_from_type_parameter: false, - }, - None, - ); - let placeholder_type = engines.te().insert( - &engines, - TypeInfo::Placeholder(TypeParameter { - type_id: generic_type, - initial_type_id: generic_type, - name_ident: generic_name.clone(), - trait_constraints: vec![], - trait_constraints_span: sp.clone(), - is_from_parent: false, - }), - None, - ); + let generic_type = + engines + .te() + .new_unknown_generic(generic_name.clone(), VecSet(vec![]), None, false); + let placeholder_type = engines.te().new_placeholder(TypeParameter { + type_id: generic_type, + initial_type_id: generic_type, + name: generic_name.clone(), + trait_constraints: vec![], + trait_constraints_span: sp.clone(), + is_from_parent: false, + }); let placeholder_type_param = TypeParameter { type_id: placeholder_type, initial_type_id: placeholder_type, - name_ident: generic_name.clone(), + name: generic_name.clone(), trait_constraints: vec![], trait_constraints_span: sp.clone(), is_from_parent: false, @@ -133,16 +123,14 @@ fn generic_enum_resolution() { }, None, ); - let ty_1 = engines - .te() - .insert(&engines, TypeInfo::Enum(*decl_ref_1.id()), None); + let ty_1 = engines.te().insert_enum(&engines, *decl_ref_1.id()); /* Result { a: bool } */ - let boolean_type = engines.te().insert(&engines, TypeInfo::Boolean, None); + let boolean_type = engines.te().id_of_bool(); let variant_types = vec![ty::TyEnumVariant { name: a_name, tag: 0, @@ -158,7 +146,7 @@ fn generic_enum_resolution() { let type_param = TypeParameter { type_id: boolean_type, initial_type_id: boolean_type, - name_ident: generic_name, + name: generic_name, trait_constraints: vec![], trait_constraints_span: sp.clone(), is_from_parent: false, @@ -177,9 +165,7 @@ fn generic_enum_resolution() { }, None, ); - let ty_2 = engines - .te() - .insert(&engines, TypeInfo::Enum(*decl_ref_2.id()), None); + let ty_2 = engines.te().insert_enum(&engines, *decl_ref_2.id()); // Unify them together... let h = Handler::default(); @@ -206,12 +192,8 @@ fn basic_numeric_unknown() { let sp = Span::dummy(); // numerics - let id = engines.te().insert(&engines, TypeInfo::Numeric, None); - let id2 = engines.te().insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::Eight), - None, - ); + let id = engines.te().new_numeric(); + let id2 = engines.te().id_of_u8(); // Unify them together... let h = Handler::default(); @@ -232,12 +214,8 @@ fn unify_numerics() { let sp = Span::dummy(); // numerics - let id = engines.te().insert(&engines, TypeInfo::Numeric, None); - let id2 = engines.te().insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::Eight), - None, - ); + let id = engines.te().new_numeric(); + let id2 = engines.te().id_of_u8(); // Unify them together... let h = Handler::default(); @@ -259,12 +237,8 @@ fn unify_numerics_2() { let sp = Span::dummy(); // numerics - let id = type_engine.insert(&engines, TypeInfo::Numeric, None); - let id2 = type_engine.insert( - &engines, - TypeInfo::UnsignedInteger(IntegerBits::Eight), - None, - ); + let id = engines.te().new_numeric(); + let id2 = engines.te().id_of_u8(); // Unify them together... let h = Handler::default(); diff --git a/sway-core/src/type_system/monomorphization.rs b/sway-core/src/type_system/monomorphization.rs index 674650896db..6eb6581e96a 100644 --- a/sway-core/src/type_system/monomorphization.rs +++ b/sway-core/src/type_system/monomorphization.rs @@ -11,10 +11,10 @@ use crate::{ CallPath, }, namespace::{ModulePath, ResolvedDeclaration}, - semantic_analysis::type_resolve::resolve_type, + semantic_analysis::type_resolve::{resolve_type, VisibilityCheck}, type_system::ast_elements::create_type_id::CreateTypeId, EnforceTypeArguments, Engines, Namespace, SubstTypes, SubstTypesContext, TypeArgument, TypeId, - TypeInfo, TypeParameter, TypeSubstMap, + TypeParameter, TypeSubstMap, }; pub(crate) trait MonomorphizeHelper { @@ -129,12 +129,9 @@ where None, self_type, subst_ctx, + VisibilityCheck::Yes, ) - .unwrap_or_else(|err| { - engines - .te() - .insert(engines, TypeInfo::ErrorRecovery(err), None) - }); + .unwrap_or_else(|err| engines.te().id_of_error_recovery(err)); } let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments( value @@ -259,11 +256,7 @@ pub(crate) fn type_decl_opt_to_type_id( ); // create the type id from the copy - type_engine.insert( - engines, - TypeInfo::Struct(*new_decl_ref.id()), - new_decl_ref.span().source_id(), - ) + type_engine.insert_struct(engines, *new_decl_ref.id()) } Some(ResolvedDeclaration::Typed(ty::TyDecl::EnumDecl(ty::EnumDecl { decl_id: original_id, @@ -293,11 +286,7 @@ pub(crate) fn type_decl_opt_to_type_id( ); // create the type id from the copy - type_engine.insert( - engines, - TypeInfo::Enum(*new_decl_ref.id()), - new_decl_ref.span().source_id(), - ) + type_engine.insert_enum(engines, *new_decl_ref.id()) } Some(ResolvedDeclaration::Typed(ty::TyDecl::TypeAliasDecl(ty::TypeAliasDecl { decl_id: original_id, @@ -305,8 +294,8 @@ pub(crate) fn type_decl_opt_to_type_id( }))) => { let new_copy = decl_engine.get_type_alias(&original_id); - // TODO: monomorphize the copy, in place, when generic type aliases are - // supported + // TODO: (GENERIC-TYPE-ALIASES) Monomorphize the copy, in place, once generic type aliases are + // supported. new_copy.create_type_id(engines) } @@ -321,14 +310,7 @@ pub(crate) fn type_decl_opt_to_type_id( if let Some(ty) = &decl_type.ty { ty.type_id } else if let Some(implementing_type) = self_type { - type_engine.insert( - engines, - TypeInfo::TraitType { - name: decl_type.name.clone(), - trait_type_id: implementing_type, - }, - decl_type.name.span().source_id(), - ) + type_engine.insert_trait_type(engines, decl_type.name.clone(), implementing_type) } else { return Err(handler.emit_err(CompileError::Internal( "Self type not provided.", @@ -341,7 +323,7 @@ pub(crate) fn type_decl_opt_to_type_id( name: call_path.to_string(), span: call_path.span(), }); - type_engine.insert(engines, TypeInfo::ErrorRecovery(err), None) + type_engine.id_of_error_recovery(err) } }) } diff --git a/sway-core/src/type_system/priv_prelude.rs b/sway-core/src/type_system/priv_prelude.rs index fdf2a4138a9..477cf76f169 100644 --- a/sway-core/src/type_system/priv_prelude.rs +++ b/sway-core/src/type_system/priv_prelude.rs @@ -22,5 +22,5 @@ pub use super::{ engine::IsConcrete, engine::TypeEngine, id::{IncludeSelf, TreatNumericAs, TypeId}, - info::{AbiEncodeSizeHint, AbiName, TypeInfo, TypeSourceInfo}, + info::{AbiEncodeSizeHint, AbiName, TypeInfo}, }; diff --git a/sway-core/src/type_system/substitute/subst_map.rs b/sway-core/src/type_system/substitute/subst_map.rs index 4b1a9fa93c7..36de9b4846a 100644 --- a/sway-core/src/type_system/substitute/subst_map.rs +++ b/sway-core/src/type_system/substitute/subst_map.rs @@ -8,7 +8,6 @@ use crate::{ type_system::priv_prelude::*, }; use std::{collections::BTreeMap, fmt}; -use sway_types::Spanned; type SourceType = TypeId; type DestinationType = TypeId; @@ -94,11 +93,7 @@ impl TypeSubstMap { .map(|type_param| { ( type_param.type_id, - type_engine.insert( - engines, - TypeInfo::Placeholder(type_param.clone()), - type_param.name_ident.span().source_id(), - ), + type_engine.new_placeholder(type_param.clone()), ) }) .collect(); @@ -256,29 +251,6 @@ impl TypeSubstMap { vec![type_argument.type_id], ) } - ( - TypeInfo::Storage { - fields: type_parameters, - }, - TypeInfo::Storage { - fields: type_arguments, - }, - ) => { - let type_parameters = type_parameters - .iter() - .map(|x| x.type_argument.type_id) - .collect::>(); - let type_arguments = type_arguments - .iter() - .map(|x| x.type_argument.type_id) - .collect::>(); - TypeSubstMap::from_superset_and_subset_helper( - type_engine, - decl_engine, - type_parameters, - type_arguments, - ) - } (TypeInfo::Unknown, TypeInfo::Unknown) | (TypeInfo::Boolean, TypeInfo::Boolean) | (TypeInfo::B256, TypeInfo::B256) @@ -350,10 +322,10 @@ impl TypeSubstMap { /// A match is potentially created (i.e. a new [TypeId] is created) in these /// circumstances: /// - `type_id` is one of the following: [TypeInfo::Struct], [TypeInfo::Enum], - /// [TypeInfo::Array], [TypeInfo::Tuple], [TypeInfo::Storage], [TypeInfo::Alias], - /// [TypeInfo::Alias], [TypeInfo::Ptr], [TypeInfo::Slice], or [TypeInfo::Ref], - /// and one of the contained types (e.g. a struct field, or a referenced type) - /// finds a match in a recursive call to `find_match`. + /// [TypeInfo::Array], [TypeInfo::Tuple], [TypeInfo::Alias], [TypeInfo::Ptr], + /// [TypeInfo::Slice], or [TypeInfo::Ref], + /// - and one of the contained types (e.g. a struct field, or a referenced type) + /// finds a match in a recursive call to `find_match`. /// /// A match cannot be found in any other circumstance. pub(crate) fn find_match(&self, type_id: TypeId, engines: &Engines) -> Option { @@ -440,11 +412,7 @@ impl TypeSubstMap { if need_to_create_new { let new_decl_ref = decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&decl_id).as_ref()); - Some(type_engine.insert( - engines, - TypeInfo::Struct(*new_decl_ref.id()), - new_decl_ref.decl_span().source_id(), - )) + Some(type_engine.insert_struct(engines, *new_decl_ref.id())) } else { None } @@ -469,75 +437,37 @@ impl TypeSubstMap { if need_to_create_new { let new_decl_ref = decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&decl_id).as_ref()); - Some(type_engine.insert( - engines, - TypeInfo::Enum(*new_decl_ref.id()), - new_decl_ref.decl_span().source_id(), - )) + Some(type_engine.insert_enum(engines, *new_decl_ref.id())) } else { None } } - TypeInfo::Array(mut elem_ty, count) => { - self.find_match(elem_ty.type_id, engines).map(|type_id| { - elem_ty.type_id = type_id; - type_engine.insert( - engines, - TypeInfo::Array(elem_ty.clone(), count.clone()), - elem_ty.span.source_id(), - ) + TypeInfo::Array(mut elem_type, length) => { + self.find_match(elem_type.type_id, engines).map(|type_id| { + elem_type.type_id = type_id; + type_engine.insert_array(engines, elem_type, length) }) } - TypeInfo::Slice(mut elem_ty) => { - let type_id = self.find_match(elem_ty.type_id, engines)?; - elem_ty.type_id = type_id; - Some(type_engine.insert( - engines, - TypeInfo::Slice(elem_ty.clone()), - elem_ty.span.source_id(), - )) + TypeInfo::Slice(mut elem_type) => { + self.find_match(elem_type.type_id, engines).map(|type_id| { + elem_type.type_id = type_id; + type_engine.insert_slice(engines, elem_type) + }) } TypeInfo::Tuple(fields) => { let mut need_to_create_new = false; - let mut source_id = None; let fields = fields .into_iter() .map(|mut field| { if let Some(type_id) = self.find_match(field.type_id, engines) { need_to_create_new = true; - source_id = field.span.source_id().cloned(); field.type_id = type_id; } field.clone() }) .collect::>(); if need_to_create_new { - Some(type_engine.insert(engines, TypeInfo::Tuple(fields), source_id.as_ref())) - } else { - None - } - } - TypeInfo::Storage { fields } => { - let mut need_to_create_new = false; - let mut source_id = None; - let fields = fields - .into_iter() - .map(|mut field| { - if let Some(type_id) = self.find_match(field.type_argument.type_id, engines) - { - need_to_create_new = true; - source_id = field.span.source_id().copied(); - field.type_argument.type_id = type_id; - } - field.clone() - }) - .collect::>(); - if need_to_create_new { - Some(type_engine.insert( - engines, - TypeInfo::Storage { fields }, - source_id.as_ref(), - )) + Some(type_engine.insert_tuple(engines, fields)) } else { None } @@ -545,19 +475,12 @@ impl TypeSubstMap { TypeInfo::Alias { name, mut ty } => { self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert( - engines, - TypeInfo::Alias { - name: name.clone(), - ty: ty.clone(), - }, - ty.span.source_id(), - ) + type_engine.new_alias(engines, name, ty) }) } TypeInfo::Ptr(mut ty) => self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert(engines, TypeInfo::Ptr(ty.clone()), ty.span.source_id()) + type_engine.insert_ptr(engines, ty) }), TypeInfo::TraitType { .. } => iter_for_match(engines, self, &type_info), TypeInfo::Ref { @@ -565,14 +488,7 @@ impl TypeSubstMap { referenced_type: mut ty, } => self.find_match(ty.type_id, engines).map(|type_id| { ty.type_id = type_id; - type_engine.insert( - engines, - TypeInfo::Ref { - to_mutable_value, - referenced_type: ty.clone(), - }, - ty.span.source_id(), - ) + type_engine.insert_ref(engines, to_mutable_value, ty) }), TypeInfo::Unknown | TypeInfo::Never @@ -607,7 +523,7 @@ fn iter_for_match( TypeInfo::Placeholder(current_type_param), ) = ((*source_type_info).clone(), type_info) { - if source_type_param.name_ident.as_str() == current_type_param.name_ident.as_str() + if source_type_param.name.as_str() == current_type_param.name.as_str() && current_type_param .trait_constraints .iter() diff --git a/sway-core/src/type_system/substitute/subst_types.rs b/sway-core/src/type_system/substitute/subst_types.rs index f5107ebd59a..8b2ea5068e1 100644 --- a/sway-core/src/type_system/substitute/subst_types.rs +++ b/sway-core/src/type_system/substitute/subst_types.rs @@ -24,31 +24,39 @@ impl std::ops::BitOr for HasChanges { } } -pub struct SubstTypesContext<'a, 'b> { - pub engines: &'a Engines, - pub type_subst_map: &'b TypeSubstMap, +pub struct SubstTypesContext<'eng, 'tsm> { + pub engines: &'eng Engines, + pub type_subst_map: Option<&'tsm TypeSubstMap>, pub subst_function_body: bool, } -impl<'a, 'b> SubstTypesContext<'a, 'b> { +impl<'eng, 'tsm> SubstTypesContext<'eng, 'tsm> { pub fn new( - engines: &'a Engines, - type_subst_map: &'b TypeSubstMap, + engines: &'eng Engines, + type_subst_map: &'tsm TypeSubstMap, subst_function_body: bool, - ) -> SubstTypesContext<'a, 'b> { + ) -> SubstTypesContext<'eng, 'tsm> { SubstTypesContext { engines, - type_subst_map, + type_subst_map: Some(type_subst_map), subst_function_body, } } + + pub fn dummy(engines: &'eng Engines) -> SubstTypesContext<'eng, 'tsm> { + SubstTypesContext { + engines, + type_subst_map: None, + subst_function_body: false, + } + } } pub trait SubstTypes { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges; fn subst(&mut self, ctx: &SubstTypesContext) -> HasChanges { - if ctx.type_subst_map.is_empty() { + if ctx.type_subst_map.is_some_and(|tsm| tsm.is_empty()) { HasChanges::No } else { self.subst_inner(ctx) diff --git a/sway-core/src/type_system/unify/unifier.rs b/sway-core/src/type_system/unify/unifier.rs index 41b72802602..b77bd83fe9a 100644 --- a/sway-core/src/type_system/unify/unifier.rs +++ b/sway-core/src/type_system/unify/unifier.rs @@ -61,15 +61,11 @@ impl<'a> Unifier<'a> { expected_type_info: &TypeInfo, span: &Span, ) { - let type_engine = self.engines.te(); - let source_id = span.source_id().copied(); - type_engine.replace( + self.engines.te().replace_with_new_source_id( self.engines, received, - TypeSourceInfo { - type_info: expected_type_info.clone().into(), - source_id, - }, + expected_type_info.clone(), + span.source_id().copied(), ); } @@ -80,15 +76,11 @@ impl<'a> Unifier<'a> { received_type_info: &TypeInfo, span: &Span, ) { - let type_engine = self.engines.te(); - let source_id = span.source_id().copied(); - type_engine.replace( + self.engines.te().replace_with_new_source_id( self.engines, expected, - TypeSourceInfo { - type_info: received_type_info.clone().into(), - source_id, - }, + received_type_info.clone(), + span.source_id().copied(), ); } diff --git a/sway-core/src/type_system/unify/unify_check.rs b/sway-core/src/type_system/unify/unify_check.rs index 9adb491678c..ed8cdbbbb2b 100644 --- a/sway-core/src/type_system/unify/unify_check.rs +++ b/sway-core/src/type_system/unify/unify_check.rs @@ -527,7 +527,6 @@ impl<'a> UnifyCheck<'a> { // engine (TypeInfo::Unknown, TypeInfo::Unknown) => false, (TypeInfo::Numeric, TypeInfo::Numeric) => false, - (TypeInfo::Storage { .. }, TypeInfo::Storage { .. }) => false, // these cases are able to be directly compared (TypeInfo::Contract, TypeInfo::Contract) => true, diff --git a/sway-error/Cargo.toml b/sway-error/Cargo.toml index c8810d96b91..9a9744a5d7c 100644 --- a/sway-error/Cargo.toml +++ b/sway-error/Cargo.toml @@ -16,11 +16,9 @@ smallvec.workspace = true strsim.workspace = true sway-types.workspace = true thiserror.workspace = true -uwuify = { workspace = true, optional = true } [features] default = [] -uwu = ["uwuify"] [lints.clippy] iter_over_hash_type = "deny" diff --git a/sway-error/src/convert_parse_tree_error.rs b/sway-error/src/convert_parse_tree_error.rs index 8b8a96528a0..fc95d213b37 100644 --- a/sway-error/src/convert_parse_tree_error.rs +++ b/sway-error/src/convert_parse_tree_error.rs @@ -121,6 +121,8 @@ pub enum ConvertParseTreeError { UnexpectedValueForCfgExperimental { span: Span }, #[error("Unexpected attribute value: \"{value}\" for attribute: \"cfg\"")] InvalidCfgArg { span: Span, value: String }, + #[error("Unknown type name \"self\". A self type with a similar name exists (notice the capitalization): `Self`")] + UnknownTypeNameSelf { span: Span }, } impl Spanned for ConvertParseTreeError { @@ -185,6 +187,7 @@ impl Spanned for ConvertParseTreeError { ConvertParseTreeError::ExpectedCfgProgramTypeArgValue { span } => span.clone(), ConvertParseTreeError::UnexpectedValueForCfgExperimental { span } => span.clone(), ConvertParseTreeError::InvalidCfgArg { span, .. } => span.clone(), + ConvertParseTreeError::UnknownTypeNameSelf { span } => span.clone(), } } } diff --git a/sway-error/src/diagnostic.rs b/sway-error/src/diagnostic.rs index ddfe86bfb92..504734309e8 100644 --- a/sway-error/src/diagnostic.rs +++ b/sway-error/src/diagnostic.rs @@ -154,7 +154,6 @@ pub struct Label { label_type: LabelType, span: Span, text: String, - friendly_text: String, source_path: Option, } @@ -176,13 +175,11 @@ impl Label { } fn new(source_engine: &SourceEngine, label_type: LabelType, span: Span, text: String) -> Label { - let friendly_text = Self::maybe_uwuify(text.as_str()); let source_path = Self::get_source_path(source_engine, &span); Label { label_type, span, text, - friendly_text, source_path, } } @@ -204,10 +201,6 @@ impl Label { self.text.as_ref() } - pub fn friendly_text(&self) -> &str { - self.friendly_text.as_ref() - } - pub fn source_path(&self) -> Option<&SourcePath> { self.source_path.as_ref() } @@ -227,23 +220,6 @@ impl Label { _ => None, } } - - #[cfg(all(feature = "uwu", any(target_arch = "x86", target_arch = "x86_64")))] - fn maybe_uwuify(raw: &str) -> String { - use uwuifier::uwuify_str_sse; - uwuify_str_sse(raw) - } - - #[cfg(all(feature = "uwu", not(any(target_arch = "x86", target_arch = "x86_64"))))] - fn maybe_uwuify(raw: &str) -> String { - compile_error!("The `uwu` feature only works on x86 or x86_64 processors."); - Default::default() - } - - #[cfg(not(feature = "uwu"))] - fn maybe_uwuify(raw: &str) -> String { - raw.to_string() - } } impl Default for Label { @@ -252,7 +228,6 @@ impl Default for Label { label_type: LabelType::Info, span: Span::dummy(), text: "".to_string(), - friendly_text: "".to_string(), source_path: None, } } diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index 3998426f92e..d9ce634fa1b 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -679,6 +679,8 @@ pub enum CompileError { span: Span, prefix_span: Span, }, + #[error("Constant requires expression.")] + ConstantRequiresExpression { span: Span }, #[error("Constants cannot be shadowed. {shadowing_source} \"{name}\" shadows constant of the same name.")] ConstantsCannotBeShadowed { /// Defines what shadows the constant. @@ -1161,6 +1163,7 @@ impl Spanned for CompileError { ContractStorageFromExternalContext { span, .. } => span.clone(), InvalidOpcodeFromPredicate { span, .. } => span.clone(), ArrayOutOfBounds { span, .. } => span.clone(), + ConstantRequiresExpression { span, .. } => span.clone(), ConstantsCannotBeShadowed { name, .. } => name.span(), ConfigurablesCannotBeShadowed { name, .. } => name.span(), ConfigurablesCannotBeMatchedAgainst { name, .. } => name.span(), @@ -2812,6 +2815,9 @@ pub enum TypeNotAllowedReason { #[error("slices or types containing slices on `const` are not allowed.")] SliceInConst, + + #[error("references, pointers, slices, string slices or types containing any of these are not allowed.")] + NotAllowedInTransmute, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/sway-error/src/handler.rs b/sway-error/src/handler.rs index 24d2222da1b..ddb4d3b24f5 100644 --- a/sway-error/src/handler.rs +++ b/sway-error/src/handler.rs @@ -1,5 +1,4 @@ use crate::{error::CompileError, warning::CompileWarning}; - use core::cell::RefCell; /// A handler with which you can emit diagnostics. @@ -127,7 +126,7 @@ impl Handler { } /// Proof that an error was emitted through a `Handler`. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] pub struct ErrorEmitted { _priv: (), } diff --git a/sway-error/src/warning.rs b/sway-error/src/warning.rs index 78a4ac8953b..dce69c85805 100644 --- a/sway-error/src/warning.rs +++ b/sway-error/src/warning.rs @@ -1,4 +1,7 @@ -use crate::diagnostic::{Code, Diagnostic, Hint, Issue, Reason, ToDiagnostic}; +use crate::{ + diagnostic::{Code, Diagnostic, Hint, Issue, Reason, ToDiagnostic}, + formatting::Indent, +}; use core::fmt; @@ -128,9 +131,15 @@ pub enum Warning { message: String, }, DuplicatedStorageKey { + first_field: IdentUnique, + first_field_full_name: String, + first_field_key_is_compiler_generated: bool, + second_field: IdentUnique, + second_field_full_name: String, + second_field_key_is_compiler_generated: bool, key: String, - field1: String, - field2: String, + // True if the experimental feature `storage_domains` is used. + experimental_storage_domains: bool, }, } @@ -279,7 +288,8 @@ impl fmt::Display for Warning { You can enable the new behavior with the --experimental-private-modules flag, which will become the default behavior in a later release. More details are available in the related RFC: https://github.com/FuelLabs/sway-rfcs/blob/master/rfcs/0008-private-modules.md"), UsingDeprecated { message } => write!(f, "{}", message), - DuplicatedStorageKey { key, field1, field2 } => write!(f, "Two storage fields are using the same storage key.\nFirst field: {field1}\nSecond field: {field2}\nKey: {key}"), + DuplicatedStorageKey { first_field_full_name, second_field_full_name, key, .. } => + write!(f, "Two storage fields have the same storage key.\nFirst field: {first_field_full_name}\nSecond field: {second_field_full_name}\nKey: {key}"), } } } @@ -412,6 +422,58 @@ impl ToDiagnostic for CompileWarning { "Consider adding assembly instructions or a return register to the ASM block, or removing the block altogether.".to_string(), ], }, + DuplicatedStorageKey { first_field, first_field_full_name, first_field_key_is_compiler_generated, second_field, second_field_full_name, second_field_key_is_compiler_generated, key, experimental_storage_domains } => Diagnostic { + reason: Some(Reason::new(code(1), "Two storage fields have the same storage key".to_string())), + issue: Issue::warning( + source_engine, + first_field.span(), + format!("\"{first_field_full_name}\" has the same storage key as \"{second_field_full_name}\"."), + ), + hints: vec![ + Hint::info( + source_engine, + second_field.span(), + format!("\"{second_field_full_name}\" is declared here."), + ), + ], + help: vec![ + if *first_field_key_is_compiler_generated || *second_field_key_is_compiler_generated { + format!("The key of \"{}\" is generated by the compiler using the following formula:", + if *first_field_key_is_compiler_generated { + first_field_full_name + } else { + second_field_full_name + } + ) + } else { + "Both keys are explicitly defined by using the `in` keyword.".to_string() + }, + if *first_field_key_is_compiler_generated || *second_field_key_is_compiler_generated { + if *experimental_storage_domains { + format!("{}sha256((0u8, \"{}\"))", + Indent::Single, + if *first_field_key_is_compiler_generated { + first_field_full_name + } else { + second_field_full_name + } + ) + } else { + format!("{}sha256(\"{}\")", + Indent::Single, + if *first_field_key_is_compiler_generated { + first_field_full_name + } else { + second_field_full_name + } + ) + } + } else { + Diagnostic::help_none() + }, + format!("The common key is: {key}.") + ], + }, _ => Diagnostic { // TODO: Temporary we use self here to achieve backward compatibility. // In general, self must not be used and will not be used once we diff --git a/sway-features/src/lib.rs b/sway-features/src/lib.rs index 55d50920891..fdff644741a 100644 --- a/sway-features/src/lib.rs +++ b/sway-features/src/lib.rs @@ -131,6 +131,8 @@ impl ExperimentalFeatures { features! { new_encoding = true, "https://github.com/FuelLabs/sway/issues/5727", + storage_domains = false, + "https://github.com/FuelLabs/sway/issues/6701", } #[derive(Clone, Debug, Default, Parser)] @@ -228,6 +230,7 @@ mod tests { let mut features = ExperimentalFeatures { new_encoding: false, + ..Default::default() }; std::env::set_var("FORC_EXPERIMENTAL", "new_encoding"); diff --git a/sway-ir/Cargo.toml b/sway-ir/Cargo.toml index 331302af16b..c4264f9281c 100644 --- a/sway-ir/Cargo.toml +++ b/sway-ir/Cargo.toml @@ -18,6 +18,7 @@ once_cell.workspace = true peg.workspace = true prettydiff.workspace = true rustc-hash.workspace = true +serde = { version = "1.0", features = ["derive"] } slotmap.workspace = true sway-features.workspace = true sway-ir-macros.workspace = true diff --git a/sway-ir/src/irtype.rs b/sway-ir/src/irtype.rs index 1771ca954bc..dc96427d56a 100644 --- a/sway-ir/src/irtype.rs +++ b/sway-ir/src/irtype.rs @@ -642,7 +642,7 @@ impl TypeSize { /// the value in aggregates. E.g., in an array of `u8`, each `u8` is "padded" /// to its size of one byte while as a struct field, it will be right padded /// to 8 bytes. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize)] pub enum Padding { Left { target_size: usize }, Right { target_size: usize }, diff --git a/sway-ir/src/optimize/memcpyopt.rs b/sway-ir/src/optimize/memcpyopt.rs index 265db81695b..fbce2059c59 100644 --- a/sway-ir/src/optimize/memcpyopt.rs +++ b/sway-ir/src/optimize/memcpyopt.rs @@ -301,7 +301,6 @@ fn local_copy_prop( available_copies.remove(copy); } } - copies.retain(|copy| available_copies.contains(copy)); } if let Some(copies) = dest_to_copies.get_mut(&sym) { for copy in &*copies { @@ -333,9 +332,17 @@ fn local_copy_prop( available_copies.remove(copy); } } - copies.retain(|copy| available_copies.contains(copy)); } } + // Update src_to_copies and dest_to_copies to remove every copy not in available_copies. + src_to_copies.retain(|_, copies| { + copies.retain(|copy| available_copies.contains(copy)); + !copies.is_empty() + }); + dest_to_copies.retain(|_, copies| { + copies.retain(|copy| available_copies.contains(copy)); + !copies.is_empty() + }); } ReferredSymbols::Incomplete(_) => { // The only safe thing we can do is to clear all information. diff --git a/sway-ir/tests/tests.rs b/sway-ir/tests/tests.rs index 743b3523977..5e6ccaeaa8f 100644 --- a/sway-ir/tests/tests.rs +++ b/sway-ir/tests/tests.rs @@ -29,6 +29,8 @@ fn run_tests bool>(sub_dir: &str, opt_fn: F) { let experimental = ExperimentalFeatures { new_encoding: false, + // TODO: Properly support experimental features in IR tests. + ..Default::default() }; let mut ir = sway_ir::parser::parse(&input, &source_engine, experimental).unwrap_or_else( diff --git a/sway-lib-core/src/ops.sw b/sway-lib-core/src/ops.sw index 371bbff5382..c49147bccae 100644 --- a/sway-lib-core/src/ops.sw +++ b/sway-lib-core/src/ops.sw @@ -995,7 +995,7 @@ impl BitwiseXor for u8 { } /// Trait to evaluate if one value is greater than or equal, or less than or equal to another of the same type. -trait OrdEq: Ord + Eq { +pub trait OrdEq: Ord + Eq { } { /// Evaluates if one value of the same type is greater or equal to than another. /// diff --git a/sway-lib-core/src/primitive_conversions.sw b/sway-lib-core/src/primitive_conversions.sw index 3160a5eca02..f0a1a14de81 100644 --- a/sway-lib-core/src/primitive_conversions.sw +++ b/sway-lib-core/src/primitive_conversions.sw @@ -45,10 +45,7 @@ impl u32 { input: u64 } } -} -// TODO: This must be in a separate impl block until https://github.com/FuelLabs/sway/issues/1548 is resolved -impl u32 { /// Extends a `u32` to a `u256`. /// /// # Returns @@ -114,10 +111,7 @@ impl u16 { input: u64 } } -} -// TODO: This must be in a separate impl block until https://github.com/FuelLabs/sway/issues/1548 is resolved -impl u16 { /// Extends a `u16` to a `u256`. /// /// # Returns @@ -204,10 +198,7 @@ impl u8 { input: u64 } } -} -// TODO: This must be in a separate impl block until https://github.com/FuelLabs/sway/issues/1548 is resolved -impl u8 { /// Extends a `u8` to a `u256`. /// /// # Returns diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index 1296e940826..5b5c817e914 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -584,10 +584,7 @@ impl Bytes { pub fn ptr(self) -> raw_ptr { self.buf.ptr() } -} -// Need to use separate impl blocks for now: https://github.com/FuelLabs/sway/issues/1548 -impl Bytes { /// Divides one Bytes into two at an index. /// /// # Additional Information @@ -692,7 +689,7 @@ impl Bytes { /// assert(bytes.capacity() == first_cap + second_cap); /// } /// ``` - pub fn append(ref mut self, ref mut other: self) { + pub fn append(ref mut self, ref mut other: Self) { let other_len = other.len(); if other_len == 0 { return @@ -927,27 +924,56 @@ impl AbiDecode for Bytes { } } -// TODO: Uncomment when fixed. https://github.com/FuelLabs/sway/issues/6567 -// #[test] -// fn ok_bytes_buffer_ownership() { -// let mut original_array = [1u8, 2u8, 3u8, 4u8]; -// let slice = raw_slice::from_parts::(__addr_of(original_array), 4); - -// // Check Bytes duplicates the original slice -// let mut bytes = Bytes::from(slice); -// bytes.set(0, 5); -// assert(original_array[0] == 1); - -// // At this point, slice equals [5, 2, 3, 4] -// let encoded_slice = encode(bytes); - -// // `Bytes` should duplicate the underlying buffer, -// // so when we write to it, it should not change -// // `encoded_slice` -// let mut bytes = abi_decode::(encoded_slice); -// bytes.set(0, 6); -// assert(bytes.get(0) == Some(6)); - -// let mut bytes = abi_decode::(encoded_slice); -// assert(bytes.get(0) == Some(5)); -// } +#[test] +fn ok_bytes_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Bytes duplicates the original slice + let mut bytes = Bytes::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Bytes` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::(encoded_slice); + assert(bytes.get(0) == Some(5)); +} + +#[test] +fn ok_bytes_bigger_than_3064() { + let mut v: Bytes = Bytes::new(); + + // We allocate 1024 bytes initially, this is throw away because + // it is not big enough for the buffer. + // Then we used to double the buffer to 2048. + // Then we write an `u64` with the length of the buffer. + // Then we write the buffer itself. + // (1024 + 2048) - 8 = 3064 + // Thus, we need a buffer with 3065 bytes to write into the red zone + let mut a = 3065; + while a > 0 { + v.push(1u8); + a -= 1; + } + + // This red zone should not be overwritten + let red_zone = asm(size: 1024) { + aloc size; + hp: raw_ptr + }; + red_zone.write(0xFFFFFFFFFFFFFFFF); + assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); + + let _ = encode(v); + + assert(red_zone.read::() == 0xFFFFFFFFFFFFFFFF); +} diff --git a/sway-lib-std/src/error_signals.sw b/sway-lib-std/src/error_signals.sw index bbc4f6f291b..87f86699378 100644 --- a/sway-lib-std/src/error_signals.sw +++ b/sway-lib-std/src/error_signals.sw @@ -35,3 +35,10 @@ pub const FAILED_ASSERT_SIGNAL = 0xffff_ffff_ffff_0004; /// /// The value is: 18446744073709486085 pub const FAILED_ASSERT_NE_SIGNAL = 0xffff_ffff_ffff_0005; + +/// A revert with this value signals that it was caused by a call to `std::revert::revert_with_log`. +/// +/// # Additional Information +/// +/// The value is: 18446744073709486086 +pub const REVERT_WITH_LOG_SIGNAL = 0xffff_ffff_ffff_0006; diff --git a/sway-lib-std/src/outputs.sw b/sway-lib-std/src/outputs.sw index 69ccac1b23b..527a94de2fc 100644 --- a/sway-lib-std/src/outputs.sw +++ b/sway-lib-std/src/outputs.sw @@ -28,6 +28,9 @@ pub const GTF_OUTPUT_COIN_ASSET_ID = 0x303; // pub const GTF_OUTPUT_CONTRACT_CREATED_CONTRACT_ID = 0x307; // pub const GTF_OUTPUT_CONTRACT_CREATED_STATE_ROOT = 0x308; +const OUTPUT_VARIABLE_ASSET_ID_OFFSET = 48; +const OUTPUT_VARIABLE_TO_OFFSET = 8; + /// The output type for a transaction. pub enum Output { /// A coin output. @@ -228,6 +231,10 @@ pub fn output_asset_id(index: u64) -> Option { match output_type(index) { Some(Output::Coin) => Some(AssetId::from(__gtf::(index, GTF_OUTPUT_COIN_ASSET_ID))), Some(Output::Change) => Some(AssetId::from(__gtf::(index, GTF_OUTPUT_COIN_ASSET_ID))), + Some(Output::Variable) => { + let ptr = output_pointer(index).unwrap(); + Some(AssetId::from(ptr.add_uint_offset(OUTPUT_VARIABLE_ASSET_ID_OFFSET).read::())) + }, _ => None, } } @@ -260,6 +267,10 @@ pub fn output_asset_to(index: u64) -> Option

{ match output_type(index) { Some(Output::Coin) => Some(__gtf::
(index, GTF_OUTPUT_COIN_TO)), Some(Output::Change) => Some(__gtf::
(index, GTF_OUTPUT_COIN_TO)), + Some(Output::Variable) => { + let ptr = output_pointer(index).unwrap(); + Some(Address::from(ptr.add_uint_offset(OUTPUT_VARIABLE_TO_OFFSET).read::())) + }, _ => None, } } diff --git a/sway-lib-std/src/prelude.sw b/sway-lib-std/src/prelude.sw index 6f207cc7b45..b86eb26ec31 100644 --- a/sway-lib-std/src/prelude.sw +++ b/sway-lib-std/src/prelude.sw @@ -21,13 +21,13 @@ pub use ::vec::{Vec, VecIter}; pub use ::assert::{assert, assert_eq, assert_ne}; pub use ::option::Option::{self, *}; pub use ::result::Result::{self, *}; -pub use ::revert::{require, revert}; +pub use ::revert::{require, revert, revert_with_log}; // Convert pub use ::convert::From; // Primitive conversions -pub use ::primitive_conversions::{b256::*, str::*, u16::*, u256::*, u32::*, u64::*, u8::*,}; +pub use ::primitive_conversions::{b256::*, str::*, u16::*, u256::*, u32::*, u64::*, u8::*}; // Logging pub use ::logging::log; diff --git a/sway-lib-std/src/revert.sw b/sway-lib-std/src/revert.sw index ba6ddeadf88..f53dd5378d2 100644 --- a/sway-lib-std/src/revert.sw +++ b/sway-lib-std/src/revert.sw @@ -2,7 +2,7 @@ library; use ::logging::log; -use ::error_signals::FAILED_REQUIRE_SIGNAL; +use ::error_signals::{FAILED_REQUIRE_SIGNAL, REVERT_WITH_LOG_SIGNAL}; /// Will either panic or revert with a given number depending on the context. /// @@ -71,3 +71,35 @@ where revert(FAILED_REQUIRE_SIGNAL) } } + +/// Reverts unconditionally and logs `value`. +/// +/// # Arguments +/// +/// * `value`: [T] - The value which will be logged. +/// +/// # Reverts +/// +/// * Reverts unconditionally. +/// +/// # Examples +/// +/// ```sway +/// fn foo() { +/// revert_with_log("Example error message"); +/// } +/// ``` +#[cfg(experimental_new_encoding = false)] +pub fn revert_with_log(value: T) { + log(value); + revert(REVERT_WITH_LOG_SIGNAL) +} + +#[cfg(experimental_new_encoding = true)] +pub fn revert_with_log(value: T) +where + T: AbiEncode, +{ + log(value); + revert(REVERT_WITH_LOG_SIGNAL) +} diff --git a/sway-lib-std/src/storage/storage_map.sw b/sway-lib-std/src/storage/storage_map.sw index 360ed95ade3..4d7aca969ae 100644 --- a/sway-lib-std/src/storage/storage_map.sw +++ b/sway-lib-std/src/storage/storage_map.sw @@ -6,6 +6,22 @@ use ::result::Result; use ::storage::storage_api::*; use ::storage::storage_key::*; +/// The storage domain value of the [StorageMap]. +/// +/// Storage slots of elements contained within a [StorageMap] +/// are calculated based on developers' or users' input (the key). +/// +/// To ensure that pre-images used to calculate storage slots can never +/// be the same as a pre-image of a compiler generated key of a storage +/// field, we prefix the pre-images with a single byte that denotes +/// the storage map domain. +/// +/// The domain prefix for the [StorageMap] is 1u8. +/// +/// For detailed elaboration see: https://github.com/FuelLabs/sway/issues/6317 +#[cfg(experimental_storage_domains = true)] +const STORAGE_MAP_DOMAIN: u8 = 1; + /// Errors pertaining to the `StorageMap` struct. pub enum StorageMapError { /// Indicates that a value already exists for the key. @@ -51,7 +67,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); write::(key, 0, value); } @@ -85,7 +101,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); StorageKey::::new(key, 0, key) } @@ -124,7 +140,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); clear::(key, 0) } @@ -175,7 +191,7 @@ where where K: Hash, { - let key = sha256((key, self.field_id())); + let key = self.get_slot_key(key); let val = read::(key, 0); @@ -189,4 +205,14 @@ where } } } + + #[cfg(experimental_storage_domains = false)] + fn get_slot_key(self, key: K) -> b256 { + sha256((key, self.field_id())) + } + + #[cfg(experimental_storage_domains = true)] + fn get_slot_key(self, key: K) -> b256 { + sha256((STORAGE_MAP_DOMAIN, key, self.field_id())) + } } diff --git a/sway-lib-std/src/u128.sw b/sway-lib-std/src/u128.sw index 8eb22317b64..ef016cfe560 100644 --- a/sway-lib-std/src/u128.sw +++ b/sway-lib-std/src/u128.sw @@ -668,6 +668,17 @@ impl core::ops::Divide for U128 { } } +impl core::ops::Mod for U128 { + fn modulo(self, other: Self) -> Self { + assert(other != Self::zero()); + + // a mod b = a - b * (a / b) + let quotient = self / other; + let product = quotient * other; + self - product + } +} + fn u64_checked_add(a: u64, b: u64) -> Option { let of = asm(a: a, b: b, res) { add res a b; diff --git a/sway-lib-std/src/vec.sw b/sway-lib-std/src/vec.sw index 8ae7fe65da7..5b7830b848c 100644 --- a/sway-lib-std/src/vec.sw +++ b/sway-lib-std/src/vec.sw @@ -705,27 +705,26 @@ impl Iterator for VecIter { } } -// TODO: Uncomment when fixed. https://github.com/FuelLabs/sway/issues/6567 -// #[test] -// fn ok_vec_buffer_ownership() { -// let mut original_array = [1u8, 2u8, 3u8, 4u8]; -// let slice = raw_slice::from_parts::(__addr_of(original_array), 4); - -// // Check Vec duplicates the original slice -// let mut bytes = Vec::::from(slice); -// bytes.set(0, 5); -// assert(original_array[0] == 1); - -// // At this point, slice equals [5, 2, 3, 4] -// let encoded_slice = encode(bytes); - -// // `Vec` should duplicate the underlying buffer, -// // so when we write to it, it should not change -// // `encoded_slice` -// let mut bytes = abi_decode::>(encoded_slice); -// bytes.set(0, 6); -// assert(bytes.get(0) == Some(6)); - -// let mut bytes = abi_decode::>(encoded_slice); -// assert(bytes.get(0) == Some(5)); -// } +#[test] +fn ok_vec_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Vec duplicates the original slice + let mut bytes = Vec::::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Vec` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::>(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::>(encoded_slice); + assert(bytes.get(0) == Some(5)); +} diff --git a/sway-lsp/README.md b/sway-lsp/README.md index 940ec11a269..ffae83b3f0c 100644 --- a/sway-lsp/README.md +++ b/sway-lsp/README.md @@ -27,3 +27,13 @@ _Coming Soon_ 1. Install the [Fuel toolchain](https://fuellabs.github.io/fuelup/master/installation/index.html). 1. Ensure `forc-lsp` is installed correctly by entering `forc-lsp --version` into your terminal. 1. Install the [Sway VSCode plugin](https://marketplace.visualstudio.com/items?itemName=FuelLabs.sway-vscode-plugin). + +## Trying out the local version + +To try out the local LSP version: + +1. Install the local version of the server: `cargo install --path ./forc-plugins/forc-lsp`. +1. Open VSCode settings and set the `Sway-lsp › Diagnostic: Bin Path` to the installed `forc-lsp` binary. The path to the binary will be listed at the end of the `cargo install` command and is usually: `/home//.cargo/bin/forc-lsp`. +1. Open an arbitrary Sway project. E.g., `./examples/arrays`. +1. Open the _Output_ window in VSCode and select _Sway Language Server_ from the drop down menu. +1. Start coding and observe the LSP output in the _Output_ window. This window will also show any `dbg!` or `eprintln!` lines. \ No newline at end of file diff --git a/sway-lsp/benches/lsp_benchmarks/requests.rs b/sway-lsp/benches/lsp_benchmarks/requests.rs index c2c79eaf25c..ce9081cd7a9 100644 --- a/sway-lsp/benches/lsp_benchmarks/requests.rs +++ b/sway-lsp/benches/lsp_benchmarks/requests.rs @@ -24,8 +24,8 @@ fn benchmarks(c: &mut Criterion) { c.bench_function("document_symbol", |b| { b.iter(|| { session - .symbol_information(&uri) - .map(DocumentSymbolResponse::Flat) + .document_symbols(&uri) + .map(DocumentSymbolResponse::Nested) }) }); diff --git a/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs b/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs index 8b64838e1c3..d12bbd402b1 100644 --- a/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs +++ b/sway-lsp/src/capabilities/code_actions/common/generate_impl.rs @@ -21,7 +21,7 @@ pub(crate) trait GenerateImplCodeAction<'a, T: Spanned>: CodeAction<'a, T> { Some( type_params .iter() - .map(|param| param.name_ident.to_string()) + .map(|param| param.name.to_string()) .collect::>() .join(", "), ) diff --git a/sway-lsp/src/capabilities/completion.rs b/sway-lsp/src/capabilities/completion.rs index a2b77814cb9..8c057a20675 100644 --- a/sway-lsp/src/capabilities/completion.rs +++ b/sway-lsp/src/capabilities/completion.rs @@ -5,12 +5,11 @@ use lsp_types::{ }; use sway_core::{ language::ty::{TyAstNodeContent, TyDecl, TyFunctionDecl, TyFunctionParameter}, - namespace::Items, - Engines, TypeId, TypeInfo, + Engines, Namespace, TypeId, TypeInfo, }; pub(crate) fn to_completion_items( - namespace: &Items, + namespace: &Namespace, engines: &Engines, ident_to_complete: &TokenIdent, fn_decl: &TyFunctionDecl, @@ -24,7 +23,7 @@ pub(crate) fn to_completion_items( /// Gathers the given [`TypeId`] struct's fields and methods and builds completion items. fn completion_items_for_type_id( engines: &Engines, - namespace: &Items, + namespace: &Namespace, type_id: TypeId, position: Position, ) -> Vec { @@ -46,7 +45,10 @@ fn completion_items_for_type_id( } } - for method in namespace.get_methods_for_type(engines, type_id) { + for method in namespace + .module(engines) + .get_methods_for_type(engines, type_id) + { let method = method.expect_typed(); let fn_decl = engines.de().get_function(&method.id().clone()); let params = &fn_decl.parameters; @@ -134,7 +136,7 @@ fn replace_self_with_type_str( /// if it can resolve `a` in the given function. fn type_id_of_raw_ident( engines: &Engines, - namespace: &Items, + namespace: &Namespace, ident_name: &str, fn_decl: &TyFunctionDecl, ) -> Option { @@ -152,6 +154,7 @@ fn type_id_of_raw_ident( if parts[i].ends_with(')') { let method_name = parts[i].split_at(parts[i].find('(').unwrap_or(0)).0; curr_type_id = namespace + .module(engines) .get_methods_for_type(engines, curr_type_id?) .into_iter() .find_map(|method| { diff --git a/sway-lsp/src/capabilities/document_symbol.rs b/sway-lsp/src/capabilities/document_symbol.rs index 79f90b1eeba..5e31b65ff4a 100644 --- a/sway-lsp/src/capabilities/document_symbol.rs +++ b/sway-lsp/src/capabilities/document_symbol.rs @@ -1,60 +1,514 @@ -use crate::core::token::{SymbolKind, Token, TokenIdent}; -use dashmap::mapref::multiple::RefMulti; -use lsp_types::{self, Location, SymbolInformation, Url}; - -pub fn to_symbol_information<'a, I>(tokens: I, url: &Url) -> Vec -where - I: Iterator>, -{ - tokens - .map(|entry| { - let (ident, token) = entry.pair(); - symbol_info(ident, token, url.clone()) +use crate::core::{token::get_range_from_span, token_map::TokenMap}; +use lsp_types::{self, DocumentSymbol, Url}; +use std::path::PathBuf; +use sway_core::{ + language::ty::{ + TyAbiDecl, TyAstNodeContent, TyConstantDecl, TyDecl, TyEnumDecl, TyFunctionDecl, + TyFunctionParameter, TyProgram, TyStorageDecl, TyStructDecl, TyTraitInterfaceItem, + TyTraitItem, TyTraitType, + }, + Engines, TypeArgument, +}; +use sway_types::{Span, Spanned}; + +/// Generates a hierarchical document symbol tree for LSP code outline/navigation. +/// Processes declarations (functions, structs, enums, etc.) into nested symbols, +/// preserving parent-child relationships like functions with their variables, +/// structs with their fields, and traits with their methods. +pub fn to_document_symbols( + uri: &Url, + path: &PathBuf, + ty_program: &TyProgram, + engines: &Engines, + token_map: &TokenMap, +) -> Vec { + let source_id = engines.se().get_source_id(path); + + // Find if there is a configurable symbol in the token map that belongs to the current file + // We will add children symbols to this when we encounter configurable declarations below. + let mut configurable_symbol = token_map + .tokens_for_file(uri) + .find(|item| item.key().name == "configurable") + .map(|item| { + DocumentSymbolBuilder::new() + .name(item.key().name.clone()) + .kind(lsp_types::SymbolKind::STRUCT) + .range(item.key().range) + .selection_range(item.key().range) + .children(vec![]) + .build() + }); + + // Only include nodes that originate from the file. + let mut nodes: Vec<_> = (if ty_program.root.span.source_id() == Some(&source_id) { + Some(ty_program.root.all_nodes.iter()) + } else { + ty_program + .root + .submodules_recursive() + .find(|(_, submodule)| submodule.module.span.source_id() == Some(&source_id)) + .map(|(_, submodule)| submodule.module.all_nodes.iter()) + }) + .into_iter() + .flatten() + .filter_map(|node| { + match &node.content { + TyAstNodeContent::Declaration(decl) => match decl { + TyDecl::FunctionDecl(decl) => { + let fn_decl = engines.de().get_function(&decl.decl_id); + let range = get_range_from_span(&fn_decl.name.span()); + let detail = Some(fn_decl_detail(&fn_decl.parameters, &fn_decl.return_type)); + let children = collect_variables_from_func_decl(engines, &fn_decl); + let func_symbol = DocumentSymbolBuilder::new() + .name(fn_decl.name.span().str().to_string()) + .kind(lsp_types::SymbolKind::FUNCTION) + .range(range) + .selection_range(range) + .detail(detail) + .children(children) + .build(); + Some(func_symbol) + } + TyDecl::EnumDecl(decl) => { + let enum_decl = engines.de().get_enum(&decl.decl_id); + let span = enum_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + let children = collect_enum_variants(&enum_decl); + let enum_symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::ENUM) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(enum_symbol) + } + TyDecl::StructDecl(decl) => { + let struct_decl = engines.de().get_struct(&decl.decl_id); + let span = struct_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + let children = collect_struct_fields(&struct_decl); + let struct_symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::STRUCT) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(struct_symbol) + } + TyDecl::AbiDecl(decl) => { + let abi_decl = engines.de().get_abi(&decl.decl_id); + let decl_str = abi_decl.span().str(); + let name = extract_header(&decl_str); + let range = get_range_from_span(&abi_decl.name.span()); + let children = collect_fns_from_abi_decl(engines, &abi_decl); + let abi_symbol = DocumentSymbolBuilder::new() + .name(name) + .kind(lsp_types::SymbolKind::NAMESPACE) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(abi_symbol) + } + TyDecl::TraitDecl(decl) => { + let trait_decl = engines.de().get_trait(&decl.decl_id); + let decl_str = trait_decl.span().str().to_string(); + let name = extract_header(&decl_str); + let range = get_range_from_span(&trait_decl.name.span()); + let children = + collect_interface_surface(engines, &trait_decl.interface_surface); + let trait_symbol = DocumentSymbolBuilder::new() + .name(name) + .kind(lsp_types::SymbolKind::INTERFACE) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(trait_symbol) + } + TyDecl::TraitTypeDecl(decl) => { + let trait_type_decl = engines.de().get_type(&decl.decl_id); + Some(build_trait_symbol(&trait_type_decl)) + } + TyDecl::ImplSelfOrTrait(decl) => { + let impl_trait_decl = engines.de().get_impl_self_or_trait(&decl.decl_id); + let decl_str = impl_trait_decl.span().str().to_string(); + let name = extract_header(&decl_str); + let range = get_range_from_span(&impl_trait_decl.trait_name.suffix.span()); + let children = collect_ty_trait_items(engines, &impl_trait_decl.items); + let symbol = DocumentSymbolBuilder::new() + .name(name) + .kind(lsp_types::SymbolKind::NAMESPACE) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(symbol) + } + TyDecl::ConstantDecl(decl) => { + let const_decl = engines.de().get_constant(&decl.decl_id); + Some(build_constant_symbol(&const_decl)) + } + TyDecl::StorageDecl(decl) => { + let storage_decl = engines.de().get_storage(&decl.decl_id); + let span = storage_decl.storage_keyword.span(); + let range = get_range_from_span(&span); + let children = collect_fields_from_storage(&storage_decl); + let storage_symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::STRUCT) + .range(range) + .selection_range(range) + .children(children) + .build(); + Some(storage_symbol) + } + TyDecl::ConfigurableDecl(decl) => { + let configurable_decl = engines.de().get_configurable(&decl.decl_id); + let span = configurable_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + let symbol = DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::FIELD) + .detail(Some( + configurable_decl.type_ascription.span.as_str().to_string(), + )) + .range(range) + .selection_range(range) + .build(); + // Add symbol to the end of configurable_symbol's children field + configurable_symbol + .as_mut()? + .children + .as_mut()? + .push(symbol); + None + } + _ => None, + }, + _ => None, + } + }) + .collect(); + + // Add configurable symbol to the end after all children symbols have been added + if let Some(symbol) = configurable_symbol { + nodes.push(symbol); + } + + // Sort by range start position + nodes.sort_by_key(|node| node.range.start); + nodes +} + +fn build_constant_symbol(const_decl: &TyConstantDecl) -> DocumentSymbol { + let span = const_decl.call_path.suffix.span(); + let range = get_range_from_span(&span); + DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::CONSTANT) + .detail(Some(const_decl.type_ascription.span.as_str().to_string())) + .range(range) + .selection_range(range) + .build() +} + +fn build_trait_symbol(trait_type_decl: &TyTraitType) -> DocumentSymbol { + let span = trait_type_decl.name.span(); + let range = get_range_from_span(&span); + DocumentSymbolBuilder::new() + .name(span.str().to_string()) + .kind(lsp_types::SymbolKind::TYPE_PARAMETER) + .range(range) + .selection_range(range) + .build() +} + +fn collect_interface_surface( + engines: &Engines, + items: &[TyTraitInterfaceItem], +) -> Vec { + items + .iter() + .map(|item| match item { + TyTraitInterfaceItem::TraitFn(decl_ref) => { + let fn_decl = engines.de().get_trait_fn(decl_ref); + build_function_symbol( + &fn_decl.name.span(), + &fn_decl.parameters, + &fn_decl.return_type, + ) + } + TyTraitInterfaceItem::Constant(decl_ref) => { + let const_decl = engines.de().get_constant(decl_ref); + build_constant_symbol(&const_decl) + } + TyTraitInterfaceItem::Type(decl_ref) => { + let trait_type_decl = engines.de().get_type(decl_ref); + build_trait_symbol(&trait_type_decl) + } + }) + .collect() +} + +fn collect_ty_trait_items(engines: &Engines, items: &[TyTraitItem]) -> Vec { + items + .iter() + .filter_map(|item| match item { + TyTraitItem::Fn(decl_ref) => Some(engines.de().get_function(decl_ref)), + _ => None, + }) + .map(|fn_decl| { + let children = collect_variables_from_func_decl(engines, &fn_decl); + let mut symbol = build_function_symbol( + &fn_decl.name.span(), + &fn_decl.parameters, + &fn_decl.return_type, + ); + symbol.children = Some(children); + symbol }) .collect() } -/// Given a `token::SymbolKind`, return the `lsp_types::SymbolKind` that corresponds to it. -pub(crate) fn symbol_kind(symbol_kind: &SymbolKind) -> lsp_types::SymbolKind { - match symbol_kind { - SymbolKind::Field => lsp_types::SymbolKind::FIELD, - SymbolKind::BuiltinType | SymbolKind::TypeParameter => { - lsp_types::SymbolKind::TYPE_PARAMETER +fn collect_fields_from_storage(decl: &TyStorageDecl) -> Vec { + decl.fields + .iter() + .map(|field| build_field_symbol(&field.name.span(), &field.type_argument)) + .collect() +} + +fn build_field_symbol(span: &Span, type_argument: &TypeArgument) -> DocumentSymbol { + let range = get_range_from_span(span); + DocumentSymbolBuilder::new() + .name(span.clone().str().to_string()) + .detail(Some(type_argument.span.as_str().to_string())) + .kind(lsp_types::SymbolKind::FIELD) + .range(range) + .selection_range(range) + .build() +} + +fn build_function_symbol( + span: &Span, + parameters: &[TyFunctionParameter], + return_type: &TypeArgument, +) -> DocumentSymbol { + let range = get_range_from_span(span); + DocumentSymbolBuilder::new() + .name(span.clone().str().to_string()) + .detail(Some(fn_decl_detail(parameters, return_type))) + .kind(lsp_types::SymbolKind::FUNCTION) + .range(range) + .selection_range(range) + .build() +} + +fn collect_fns_from_abi_decl(engines: &Engines, decl: &TyAbiDecl) -> Vec { + decl.interface_surface + .iter() + .filter_map(|item| match item { + TyTraitInterfaceItem::TraitFn(decl_ref) => Some(engines.de().get_trait_fn(decl_ref)), + _ => None, + }) + .map(|trait_fn| { + build_function_symbol( + &trait_fn.name.span(), + &trait_fn.parameters, + &trait_fn.return_type, + ) + }) + .collect() +} + +fn collect_struct_fields(decl: &TyStructDecl) -> Vec { + decl.fields + .iter() + .map(|field| build_field_symbol(&field.name.span(), &field.type_argument)) + .collect() +} + +// Collect all enum variants +fn collect_enum_variants(decl: &TyEnumDecl) -> Vec { + decl.variants + .iter() + .map(|variant| { + let range = get_range_from_span(&variant.name.span()); + // Check for the presence of a CallPathTree, and if it exists, use the type information as the detail. + let detail = variant + .type_argument + .call_path_tree + .as_ref() + .map(|_| Some(variant.type_argument.span.as_str().to_string())) + .unwrap_or(None); + + DocumentSymbolBuilder::new() + .name(variant.name.span().str().to_string()) + .kind(lsp_types::SymbolKind::ENUM_MEMBER) + .range(range) + .selection_range(range) + .detail(detail) + .build() + }) + .collect() +} + +// Collect all variables declared within the function body +fn collect_variables_from_func_decl( + engines: &Engines, + decl: &TyFunctionDecl, +) -> Vec { + decl.body + .contents + .iter() + .filter_map(|node| { + if let TyAstNodeContent::Declaration(TyDecl::VariableDecl(var_decl)) = &node.content { + let range = get_range_from_span(&var_decl.name.span()); + let type_name = format!("{}", engines.help_out(var_decl.type_ascription.type_id)); + let symbol = DocumentSymbolBuilder::new() + .name(var_decl.name.span().str().to_string()) + .kind(lsp_types::SymbolKind::VARIABLE) + .range(range) + .selection_range(range) + .detail((!type_name.is_empty()).then_some(type_name)) + .build(); + Some(symbol) + } else { + None + } + }) + .collect() +} + +// Generate the signature for functions +fn fn_decl_detail(parameters: &[TyFunctionParameter], return_type: &TypeArgument) -> String { + let params = parameters + .iter() + .map(|p| format!("{}: {}", p.name, p.type_argument.span.as_str())) + .collect::>() + .join(", "); + + // Check for the presence of a CallPathTree, and if it exists, add it to the return type. + let return_type = return_type + .call_path_tree + .as_ref() + .map(|_| format!(" -> {}", return_type.span.as_str())) + .unwrap_or_default(); + format!("fn({}){}", params, return_type) +} + +/// Extracts the header of a sway construct such as an `impl` block or `abi` declaration, +/// including any generic parameters, traits, or super traits, up to (but not including) +/// the opening `{` character. Trims any trailing whitespace. +/// +/// If the `{` character is not found, the entire string is returned without trailing whitespace. +/// +/// # Examples +/// +/// ``` +/// let impl_example = "impl Setter for FooBarData {\n fn set(self, new_value: T) -> Self {\n FooBarData {\n value: new_value,\n }\n }\n}"; +/// let result = extract_header(impl_example); +/// assert_eq!(result, "impl Setter for FooBarData"); +/// +/// let abi_example = "abi MyAbi : MySuperAbi {\n fn bar();\n}"; +/// let result = extract_header(abi_example); +/// assert_eq!(result, "abi MyAbi : MySuperAbi"); +/// ``` +fn extract_header(s: &str) -> &str { + if let Some(pos) = s.find('{') { + s[..pos].trim_end() + } else { + s.trim_end() + } +} + +/// Builder for creating [`DocumentSymbol`] instances with method chaining. +/// Initializes with empty name, NULL kind, and zero position ranges. +pub struct DocumentSymbolBuilder { + name: String, + detail: Option, + kind: lsp_types::SymbolKind, + tags: Option>, + range: lsp_types::Range, + selection_range: lsp_types::Range, + children: Option>, + deprecated: Option, +} + +impl Default for DocumentSymbolBuilder { + fn default() -> Self { + Self::new() + } +} + +impl DocumentSymbolBuilder { + pub fn new() -> Self { + Self { + name: String::new(), + kind: lsp_types::SymbolKind::NULL, + range: lsp_types::Range::new( + lsp_types::Position::new(0, 0), + lsp_types::Position::new(0, 0), + ), + selection_range: lsp_types::Range::new( + lsp_types::Position::new(0, 0), + lsp_types::Position::new(0, 0), + ), + detail: None, + tags: None, + children: None, + deprecated: None, } - SymbolKind::Function | SymbolKind::DeriveHelper | SymbolKind::Intrinsic => { - lsp_types::SymbolKind::FUNCTION + } + + pub fn name(mut self, name: impl Into) -> Self { + self.name = name.into(); + self + } + + pub fn kind(mut self, kind: lsp_types::SymbolKind) -> Self { + self.kind = kind; + self + } + + pub fn range(mut self, range: lsp_types::Range) -> Self { + self.range = range; + self + } + + pub fn selection_range(mut self, range: lsp_types::Range) -> Self { + self.selection_range = range; + self + } + + pub fn detail(mut self, detail: Option) -> Self { + self.detail = detail; + self + } + + pub fn tags(mut self, tags: Vec) -> Self { + self.tags = Some(tags); + self + } + + pub fn children(mut self, children: Vec) -> Self { + self.children = Some(children); + self + } + + pub fn build(self) -> DocumentSymbol { + #[allow(warnings)] + DocumentSymbol { + name: self.name, + detail: self.detail, + kind: self.kind, + tags: self.tags, + range: self.range, + selection_range: self.selection_range, + children: self.children, + deprecated: self.deprecated, } - SymbolKind::Const => lsp_types::SymbolKind::CONSTANT, - SymbolKind::Struct => lsp_types::SymbolKind::STRUCT, - SymbolKind::Trait => lsp_types::SymbolKind::INTERFACE, - SymbolKind::Module => lsp_types::SymbolKind::MODULE, - SymbolKind::Enum => lsp_types::SymbolKind::ENUM, - SymbolKind::Variant => lsp_types::SymbolKind::ENUM_MEMBER, - SymbolKind::BoolLiteral => lsp_types::SymbolKind::BOOLEAN, - SymbolKind::StringLiteral => lsp_types::SymbolKind::STRING, - SymbolKind::NumericLiteral => lsp_types::SymbolKind::NUMBER, - SymbolKind::ValueParam - | SymbolKind::ByteLiteral - | SymbolKind::Variable - | SymbolKind::TypeAlias - | SymbolKind::TraitType - | SymbolKind::Keyword - | SymbolKind::SelfKeyword - | SymbolKind::SelfTypeKeyword - | SymbolKind::ProgramTypeKeyword - | SymbolKind::Unknown => lsp_types::SymbolKind::VARIABLE, - } -} - -#[allow(warnings)] -// TODO: the "deprecated: None" field is deprecated according to this library -fn symbol_info(ident: &TokenIdent, token: &Token, url: Url) -> SymbolInformation { - SymbolInformation { - name: ident.name.to_string(), - kind: symbol_kind(&token.kind), - location: Location::new(url, ident.range), - tags: None, - container_name: None, - deprecated: None, } } diff --git a/sway-lsp/src/capabilities/formatting.rs b/sway-lsp/src/capabilities/formatting.rs index e4b1596991b..06d5b58b59b 100644 --- a/sway-lsp/src/capabilities/formatting.rs +++ b/sway-lsp/src/capabilities/formatting.rs @@ -24,7 +24,7 @@ pub fn get_page_text_edit( ) -> Result { // we only format if code is correct let formatted_code = formatter - .format(text.clone(), None) + .format(text.clone()) .map_err(LanguageServerError::FormatError)?; let text_lines_count = text.split('\n').count(); diff --git a/sway-lsp/src/core/session.rs b/sway-lsp/src/core/session.rs index 0129c8fa583..864cac9811a 100644 --- a/sway-lsp/src/core/session.rs +++ b/sway-lsp/src/core/session.rs @@ -19,7 +19,7 @@ use crate::{ use dashmap::DashMap; use forc_pkg as pkg; use lsp_types::{ - CompletionItem, GotoDefinitionResponse, Location, Position, Range, SymbolInformation, Url, + CompletionItem, DocumentSymbol, GotoDefinitionResponse, Location, Position, Range, Url, }; use parking_lot::RwLock; use pkg::{ @@ -231,7 +231,7 @@ impl Session { let program = compiled_program.typed.clone()?; let engines = self.engines.read(); return Some(capabilities::completion::to_completion_items( - program.root.namespace.module(&engines).current_items(), + &program.root.namespace, &engines, ident_to_complete, fn_decl, @@ -248,12 +248,23 @@ impl Session { Some(program.root.namespace) } - pub fn symbol_information(&self, url: &Url) -> Option> { - let _p = tracing::trace_span!("symbol_information").entered(); - let tokens = self.token_map.tokens_for_file(url); - self.sync - .to_workspace_url(url.clone()) - .map(|url| capabilities::document_symbol::to_symbol_information(tokens, &url)) + /// Generate hierarchical document symbols for the given file. + pub fn document_symbols(&self, url: &Url) -> Option> { + let _p = tracing::trace_span!("document_symbols").entered(); + let path = url.to_file_path().ok()?; + self.compiled_program + .read() + .typed + .as_ref() + .map(|ty_program| { + capabilities::document_symbol::to_document_symbols( + url, + &path, + ty_program, + &self.engines.read(), + &self.token_map, + ) + }) } /// Populate [Documents] with sway files found in the workspace. diff --git a/sway-lsp/src/handlers/request.rs b/sway-lsp/src/handlers/request.rs index fb4b72d86a8..68d9de0b27c 100644 --- a/sway-lsp/src/handlers/request.rs +++ b/sway-lsp/src/handlers/request.rs @@ -67,8 +67,8 @@ pub async fn handle_document_symbol( .await { Ok((uri, session)) => Ok(session - .symbol_information(&uri) - .map(DocumentSymbolResponse::Flat)), + .document_symbols(&uri) + .map(DocumentSymbolResponse::Nested)), Err(err) => { tracing::error!("{}", err.to_string()); Ok(None) diff --git a/sway-lsp/src/server_state.rs b/sway-lsp/src/server_state.rs index 5e2a227f3f5..cafb4bb5fe6 100644 --- a/sway-lsp/src/server_state.rs +++ b/sway-lsp/src/server_state.rs @@ -130,13 +130,9 @@ impl ServerState { while let Ok(msg) = rx.recv() { match msg { TaskMessage::CompilationContext(ctx) => { - dbg!(); let uri = ctx.uri.as_ref().unwrap().clone(); - dbg!(); let session = ctx.session.as_ref().unwrap().clone(); - dbg!(); let mut engines_clone = session.engines.read().clone(); - dbg!(); // Perform garbage collection if enabled to manage memory usage. if ctx.gc_options.gc_enabled { @@ -151,16 +147,13 @@ impl ServerState { ); } } - dbg!(); let lsp_mode = Some(LspConfig { optimized_build: ctx.optimized_build, file_versions: ctx.file_versions, }); - dbg!(); // Set the is_compiling flag to true so that the wait_for_parsing function knows that we are compiling is_compiling.store(true, Ordering::SeqCst); - dbg!(); match session::parse_project( &uri, &engines_clone, @@ -170,10 +163,10 @@ impl ServerState { ) { Ok(()) => { let path = uri.to_file_path().unwrap(); - // Find the module id from the path + // Find the program id from the path match session::program_id_from_path(&path, &engines_clone) { Ok(program_id) => { - // Use the module id to get the metrics for the module + // Use the program id to get the metrics for the program if let Some(metrics) = session.metrics.get(&program_id) { // It's very important to check if the workspace AST was reused to determine if we need to overwrite the engines. // Because the engines_clone has garbage collection applied. If the workspace AST was reused, we need to keep the old engines @@ -202,26 +195,21 @@ impl ServerState { } } Err(_err) => { - dbg!(_err); *last_compilation_state.write() = LastCompilationState::Failed; } } - dbg!(); // Reset the flags to false is_compiling.store(false, Ordering::SeqCst); retrigger_compilation.store(false, Ordering::SeqCst); - dbg!(); // Make sure there isn't any pending compilation work if rx.is_empty() { // finished compilation, notify waiters finished_compilation.notify_waiters(); } - dbg!(); } TaskMessage::Terminate => { - dbg!(); // If we receive a terminate message, we need to exit the thread return; } @@ -305,7 +293,6 @@ impl ServerState { session: Arc, ) { let diagnostics = self.diagnostics(&uri, session.clone()); - dbg!(&diagnostics); // Note: Even if the computed diagnostics vec is empty, we still have to push the empty Vec // in order to clear former diagnostics. Newly pushed diagnostics always replace previously pushed diagnostics. if let Some(client) = self.client.as_ref() { diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 87f30cd8017..1578975143e 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -1059,7 +1059,7 @@ impl Parse for EnumVariant { impl Parse for TypeParameter { fn parse(&self, ctx: &ParseContext) { ctx.tokens.insert( - ctx.ident(&self.name_ident), + ctx.ident(&self.name), Token::from_parsed( ParsedAstToken::TypeParameter(self.clone()), SymbolKind::TypeParameter, diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 9d23bae7316..7fc3461abca 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -659,7 +659,7 @@ impl Parse for ty::FunctionDecl { ctx, type_param.type_id, &typed_token, - type_param.name_ident.span(), + type_param.name.span(), ); }); collect_type_argument(ctx, &func_decl.return_type); @@ -672,8 +672,8 @@ impl Parse for ty::FunctionDecl { if let Some(param_decl_ident) = func_decl .type_parameters .par_iter() - .find_any(|type_param| type_param.name_ident.as_str() == ident.as_str()) - .map(|type_param| type_param.name_ident.clone()) + .find_any(|type_param| type_param.name.as_str() == ident.as_str()) + .map(|type_param| type_param.name.clone()) { token.type_def = Some(TypeDefinition::Ident(param_decl_ident)); } @@ -732,7 +732,7 @@ impl Parse for ty::StructDecl { adaptive_iter(&struct_decl.type_parameters, |type_param| { if let Some(mut token) = ctx .tokens - .try_get_mut_with_retry(&ctx.ident(&type_param.name_ident)) + .try_get_mut_with_retry(&ctx.ident(&type_param.name)) { token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedParameter(type_param.clone())); @@ -759,7 +759,7 @@ impl Parse for ty::ImplSelfOrTrait { ctx, param.type_id, &TypedAstToken::TypedParameter(param.clone()), - param.name_ident.span(), + param.name.span(), ); }); adaptive_iter(&trait_name.prefixes, |ident| { @@ -958,7 +958,7 @@ impl Parse for ty::TyFunctionDecl { ctx, type_param.type_id, &typed_token, - type_param.name_ident.span(), + type_param.name.span(), ); }); collect_type_argument(ctx, &self.return_type); @@ -971,8 +971,8 @@ impl Parse for ty::TyFunctionDecl { if let Some(param_decl_ident) = self .type_parameters .par_iter() - .find_any(|type_param| type_param.name_ident.as_str() == ident.as_str()) - .map(|type_param| type_param.name_ident.clone()) + .find_any(|type_param| type_param.name.as_str() == ident.as_str()) + .map(|type_param| type_param.name.clone()) { token.type_def = Some(TypeDefinition::Ident(param_decl_ident)); } @@ -1329,7 +1329,7 @@ fn collect_type_id( ctx, param.type_id, &TypedAstToken::TypedParameter(param.clone()), - param.name_ident.span(), + param.name.span(), ); }); adaptive_iter(&decl.variants, |variant| { @@ -1349,7 +1349,7 @@ fn collect_type_id( ctx, param.type_id, &TypedAstToken::TypedParameter(param.clone()), - param.name_ident.span(), + param.name.span(), ); }); adaptive_iter(&decl.fields, |field| { @@ -1373,11 +1373,6 @@ fn collect_type_id( }); } } - TypeInfo::Storage { fields } => { - adaptive_iter(fields, |field| { - field.parse(ctx); - }); - } _ => { if let Some(token) = ctx .tokens @@ -1458,7 +1453,7 @@ fn collect_enum(ctx: &ParseContext, decl_id: &DeclId, declaratio adaptive_iter(&enum_decl.type_parameters, |type_param| { if let Some(mut token) = ctx .tokens - .try_get_mut_with_retry(&ctx.ident(&type_param.name_ident)) + .try_get_mut_with_retry(&ctx.ident(&type_param.name)) { token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedParameter(type_param.clone())); token.type_def = Some(TypeDefinition::TypeId(type_param.type_id)); diff --git a/sway-lsp/tests/integration/lsp.rs b/sway-lsp/tests/integration/lsp.rs index b187510b5fb..0b5303994cb 100644 --- a/sway-lsp/tests/integration/lsp.rs +++ b/sway-lsp/tests/integration/lsp.rs @@ -247,7 +247,7 @@ pub(crate) async fn semantic_tokens_request(server: &ServerState, uri: &Url) { } } -pub(crate) async fn document_symbol_request(server: &ServerState, uri: &Url) { +pub(crate) async fn document_symbols_request(server: &ServerState, uri: &Url) { let params = DocumentSymbolParams { text_document: TextDocumentIdentifier { uri: uri.clone() }, work_done_progress_params: Default::default(), @@ -256,8 +256,62 @@ pub(crate) async fn document_symbol_request(server: &ServerState, uri: &Url) { let response = request::handle_document_symbol(server, params) .await .unwrap(); - if let Some(DocumentSymbolResponse::Flat(res)) = response { - assert!(!res.is_empty()); + + if let Some(DocumentSymbolResponse::Nested(symbols)) = response { + // Check for enum with its variants + let enum_symbol = symbols + .iter() + .find(|s| s.name == "NumberOrString") + .expect("Should find NumberOrString enum"); + assert_eq!(enum_symbol.kind, SymbolKind::ENUM); + let variants = enum_symbol + .children + .as_ref() + .expect("Enum should have variants"); + assert_eq!(variants.len(), 2); + assert!(variants.iter().any(|v| v.name == "Number")); + assert!(variants.iter().any(|v| v.name == "String")); + + // Check for struct with its fields + let struct_symbol = symbols + .iter() + .find(|s| s.name == "Data") + .expect("Should find Data struct"); + assert_eq!(struct_symbol.kind, SymbolKind::STRUCT); + let fields = struct_symbol + .children + .as_ref() + .expect("Struct should have fields"); + assert_eq!(fields.len(), 2); + assert!(fields + .iter() + .any(|f| f.name == "value" && f.detail.as_deref() == Some("NumberOrString"))); + assert!(fields + .iter() + .any(|f| f.name == "address" && f.detail.as_deref() == Some("u64"))); + + // Check for impl with nested function and variable + let impl_symbol = symbols + .iter() + .find(|s| s.name == "impl FooABI for Contract") + .expect("Should find impl block"); + let impl_fns = impl_symbol + .children + .as_ref() + .expect("Impl should have functions"); + let main_fn = impl_fns + .iter() + .find(|f| f.name == "main") + .expect("Should find main function"); + let vars = main_fn + .children + .as_ref() + .expect("Function should have variables"); + assert!(vars + .iter() + .any(|v| v.name == "_data" && v.detail.as_deref() == Some("Data"))); + } else { + panic!("Expected nested document symbols response"); } } diff --git a/sway-lsp/tests/lib.rs b/sway-lsp/tests/lib.rs index c377db53bf5..f37a8cc1da9 100644 --- a/sway-lsp/tests/lib.rs +++ b/sway-lsp/tests/lib.rs @@ -5,18 +5,18 @@ pub mod integration; use crate::integration::{code_actions, lsp}; use lsp_types::*; use rayon::prelude::*; -use std::{fs, panic, path::PathBuf, process::Command, sync::Mutex}; +use std::{ + fs, panic, + path::PathBuf, + process::{Command, Stdio}, + sync::Mutex, +}; use sway_lsp::{ config::LspClient, handlers::{notification, request}, server_state::ServerState, }; -use sway_lsp_test_utils::{ - assert_server_requests, dir_contains_forc_manifest, doc_comments_dir, e2e_language_dir, - e2e_test_dir, generic_impl_self_dir, get_fixture, load_sway_example, random_delay, - runnables_test_dir, self_impl_reassignment_dir, setup_panic_hook, sway_workspace_dir, - test_fixtures_dir, -}; +use sway_lsp_test_utils::*; use tower_lsp::LspService; /// Holds the information needed to check the response of a goto definition request. @@ -1952,7 +1952,7 @@ lsp_capability_test!( ); lsp_capability_test!( document_symbol, - lsp::document_symbol_request, + lsp::document_symbols_request, doc_comments_dir().join("src/main.sw") ); lsp_capability_test!( @@ -2161,35 +2161,75 @@ async fn garbage_collection_runner(path: PathBuf) { shutdown_and_exit(&mut service).await; } +/// Contains representable individual projects suitable for GC tests, +/// as well as projects in which GC was failing, and that are not +/// included in [garbage_collection_all_language_tests]. #[test] -fn garbage_collection_storage() { - let p = sway_workspace_dir() - .join("sway-lsp/tests/fixtures/garbage_collection/storage_contract") - .join("src/main.sw"); - run_async!({ - garbage_collection_runner(p).await; - }); +fn garbage_collection_tests() -> Result<(), String> { + let mut tests = vec![ + // TODO: Enable this test once https://github.com/FuelLabs/sway/issues/6687 is fixed. + // ( + // "option_eq".into(), + // sway_workspace_dir() + // .join(e2e_stdlib_dir()) + // .join("option_eq") + // .join("src/main.sw"), + // ), + ( + "arrays".into(), + sway_workspace_dir() + .join("examples/arrays") + .join("src/main.sw"), + ), + ( + "minimal_script".into(), + sway_workspace_dir() + .join("sway-lsp/tests/fixtures/garbage_collection/minimal_script") + .join("src/main.sw"), + ), + ( + "paths".into(), + test_fixtures_dir().join("tokens/paths/src/main.sw"), + ), + ( + "storage_contract".into(), + sway_workspace_dir() + .join("sway-lsp/tests/fixtures/garbage_collection/storage_contract") + .join("src/main.sw"), + ), + ]; + + tests.sort(); + + run_garbage_collection_tests(&tests, None) } #[test] -fn garbage_collection_paths() { - let p = test_fixtures_dir().join("tokens/paths/src/main.sw"); - run_async!({ - garbage_collection_runner(p).await; - }); +fn garbage_collection_all_language_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_language_dir()) } #[test] -fn garbage_collection_minimal_script() { - let p = sway_workspace_dir() - .join("sway-lsp/tests/fixtures/garbage_collection/minimal_script") - .join("src/main.sw"); - run_async!({ - garbage_collection_runner(p).await; - }); +#[ignore = "Additional stress test for GC. Run it locally when working on code that affects GC."] +fn garbage_collection_all_should_pass_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_should_pass_dir()) } -/// Tests garbage collection across all language test examples in parallel. +#[test] +#[ignore = "Additional stress test for GC. Run it locally when working on code that affects GC."] +fn garbage_collection_all_should_fail_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_should_fail_dir()) +} + +#[test] +#[ignore = "Additional stress test for GC. Run it locally when working on code that affects GC."] +fn garbage_collection_all_stdlib_tests() -> Result<(), String> { + run_garbage_collection_tests_from_projects_dir(e2e_stdlib_dir()) +} + +/// Parallel test runner for garbage collection tests across Sway projects defined by `tests`. +/// Each test in `tests` consists of a project name and the path to the file that will +/// be changed during the test (keystroke simulation will be in that file). /// /// # Overview /// This test suite takes a unique approach to handling test isolation and error reporting: @@ -2206,76 +2246,130 @@ fn garbage_collection_minimal_script() { /// examples need garbage collection fixes. /// /// # Implementation Details -/// - Uses std::process::Command to spawn each test in isolation -/// - Collects results through a thread-safe Mutex +/// - Uses [std::process::Command] to spawn each test in isolation +/// - Collects results through a thread-safe [Mutex] /// - Provides detailed error reporting for failed tests /// - Categorizes different types of failures (exit codes vs signals) -// #[test] -#[allow(dead_code)] -fn run_all_garbage_collection_tests() { - let base_dir = sway_workspace_dir().join(e2e_language_dir()); - let entries: Vec<_> = std::fs::read_dir(base_dir) - .unwrap() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) - .collect(); - - let results = Mutex::new(Vec::new()); - +fn run_garbage_collection_tests( + tests: &[(String, PathBuf)], + base_dir: Option, +) -> Result<(), String> { println!("\n=== Starting Garbage Collection Tests ===\n"); - entries.par_iter().for_each(|entry| { - let project_dir = entry.path(); - let project_name = project_dir - .file_name() - .unwrap() - .to_string_lossy() - .to_string(); - let main_file = project_dir.join("src/main.sw"); + match base_dir { + Some(base_dir) => { + println!("▶ Testing {} project(s) in '{base_dir}'\n", tests.len()); + } + None => { + println!("▶ Testing {} project(s):", tests.len()); + let max_project_name_len = tests + .iter() + .map(|(project_name, _)| project_name.len()) + .max() + .unwrap_or_default(); + tests.iter().for_each(|(project_name, test_file)| { + println!( + "- {project_name: 0 { - println!("\nFailed Projects:"); - for (name, _, error) in results.iter().filter(|r| !r.1) { - println!("- {} (Error: {})", name, error.as_ref().unwrap()); + println!("Failed projects:"); + for (project_name, test_file, _, error) in results.iter().filter(|r| !r.2) { + println!("- Project: {project_name}"); + println!(" Path: {test_file}"); + println!(" Error: {}", error.as_ref().unwrap()); } - panic!("{} projects failed garbage collection testing", failed); + println!(); + + Err(format!( + "{} project(s) failed garbage collection testing", + failed + )) + } else { + Ok(()) } } +/// Test runner for garbage collection tests across all Sway projects found in the `projects_dir`. +/// Tests run in parallel and include only the projects that have `src/main.sw` file. +fn run_garbage_collection_tests_from_projects_dir(projects_dir: PathBuf) -> Result<(), String> { + let base_dir = sway_workspace_dir().join(projects_dir); + let mut tests: Vec<_> = std::fs::read_dir(base_dir.clone()) + .unwrap() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().map(|ft| ft.is_dir()).unwrap_or(false)) + .map(|dir_entry| { + let project_dir = dir_entry.path(); + let project_name = project_dir + .file_name() + .unwrap() + .to_string_lossy() + .to_string(); + let main_file = project_dir.join("src/main.sw"); + (project_name, main_file) + }) + .filter(|(_, main_file)| main_file.exists()) + .collect(); + + tests.sort(); + + run_garbage_collection_tests(&tests, Some(base_dir.to_string_lossy().to_string())) +} + /// Individual test runner executed in a separate process for each test. /// /// This function is called by the main test runner through a new process invocation @@ -2287,12 +2381,11 @@ fn run_all_garbage_collection_tests() { /// 1. Tests are completely isolated from each other /// 2. Panics in one test don't affect others /// 3. Resource cleanup happens automatically on process exit -// #[tokio::test] -#[allow(dead_code)] -async fn test_single_project() { - if let Ok(file) = std::env::var("TEST_FILE") { - println!("Running single test for file: {}", file); - let path = PathBuf::from(file); +#[tokio::test] +#[ignore = "This test is meant to be run only indirectly through the tests that run GC in parallel."] +async fn test_single_garbage_collection_project() { + if let Ok(test_file) = std::env::var("TEST_FILE") { + let path = PathBuf::from(test_file); garbage_collection_runner(path).await; } else { panic!("TEST_FILE environment variable not set"); diff --git a/sway-lsp/tests/utils/src/lib.rs b/sway-lsp/tests/utils/src/lib.rs index be741f8798b..6f42b4d3f08 100644 --- a/sway-lsp/tests/utils/src/lib.rs +++ b/sway-lsp/tests/utils/src/lib.rs @@ -28,6 +28,18 @@ pub fn e2e_language_dir() -> PathBuf { PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass/language") } +pub fn e2e_should_pass_dir() -> PathBuf { + PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass") +} + +pub fn e2e_should_fail_dir() -> PathBuf { + PathBuf::from("test/src/e2e_vm_tests/test_programs/should_fail") +} + +pub fn e2e_stdlib_dir() -> PathBuf { + PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass/stdlib") +} + pub fn e2e_unit_dir() -> PathBuf { PathBuf::from("test/src/e2e_vm_tests/test_programs/should_pass/unit_tests") } diff --git a/sway-parse/src/attribute.rs b/sway-parse/src/attribute.rs index 84a174f3bf2..4b3d545eb8c 100644 --- a/sway-parse/src/attribute.rs +++ b/sway-parse/src/attribute.rs @@ -188,67 +188,121 @@ mod tests { fn main() { () } - "#,), @r###" + "#,), @r#" Annotated( attribute_list: [ AttributeDecl( hash_kind: Outer(HashToken( - span: (82, 108), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 82, + end: 108, + source_id: None, + ), )), attribute: SquareBrackets( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(Attribute( - name: Ident( - to_string: "doc-comment", - span: (82, 108), + name: BaseIdent( + name_override_opt: Some("doc-comment"), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 82, + end: 108, + source_id: None, + ), + is_raw_ident: false, ), args: Some(Parens( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(AttributeArg( - name: Ident( - to_string: " This is a doc comment.", - span: (85, 108), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 85, + end: 108, + source_id: None, + ), + is_raw_ident: false, ), value: None, )), ), - span: (85, 108), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 85, + end: 108, + source_id: None, + ), )), )), ), - span: (82, 108), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 82, + end: 108, + source_id: None, + ), ), ), AttributeDecl( hash_kind: Outer(HashToken( - span: (121, 122), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 121, + end: 122, + source_id: None, + ), )), attribute: SquareBrackets( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(Attribute( - name: Ident( - to_string: "storage", - span: (123, 130), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 123, + end: 130, + source_id: None, + ), + is_raw_ident: false, ), args: Some(Parens( inner: Punctuated( value_separator_pairs: [], final_value_opt: Some(AttributeArg( - name: Ident( - to_string: "read", - span: (131, 135), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 131, + end: 135, + source_id: None, + ), + is_raw_ident: false, ), value: None, )), ), - span: (130, 136), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 130, + end: 136, + source_id: None, + ), )), )), ), - span: (122, 137), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 122, + end: 137, + source_id: None, + ), ), ), ], @@ -256,11 +310,22 @@ mod tests { fn_signature: FnSignature( visibility: None, fn_token: FnToken( - span: (150, 152), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 150, + end: 152, + source_id: None, + ), ), - name: Ident( - to_string: "main", - span: (153, 157), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 153, + end: 157, + source_id: None, + ), + is_raw_ident: false, ), generics: None, arguments: Parens( @@ -268,7 +333,12 @@ mod tests { value_separator_pairs: [], final_value_opt: None, )), - span: (157, 159), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 157, + end: 159, + source_id: None, + ), ), return_type_opt: None, where_clause_opt: None, @@ -278,63 +348,122 @@ mod tests { statements: [], final_expr_opt: Some(Tuple(Parens( inner: Nil, - span: (178, 180), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 178, + end: 180, + source_id: None, + ), ))), - span: (161, 193), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 161, + end: 193, + source_id: None, + ), + ), + span: Span( + src: "\n // I will be ignored.\n //! I will be ignored.\n /// This is a doc comment.\n #[storage(read)]\n fn main() {\n ()\n }\n ", + start: 160, + end: 194, + source_id: None, ), - span: (160, 194), ), ), ) - "###); + "#); } #[test] fn parse_attribute() { assert_ron_snapshot!(parse::(r#" name(arg1, arg2 = "value", arg3) - "#,), @r###" + "#,), @r#" Attribute( - name: Ident( - to_string: "name", - span: (13, 17), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 13, + end: 17, + source_id: None, + ), + is_raw_ident: false, ), args: Some(Parens( inner: Punctuated( value_separator_pairs: [ (AttributeArg( - name: Ident( - to_string: "arg1", - span: (18, 22), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 18, + end: 22, + source_id: None, + ), + is_raw_ident: false, ), value: None, ), CommaToken( - span: (22, 23), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 22, + end: 23, + source_id: None, + ), )), (AttributeArg( - name: Ident( - to_string: "arg2", - span: (24, 28), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 24, + end: 28, + source_id: None, + ), + is_raw_ident: false, ), value: Some(String(LitString( - span: (31, 38), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 31, + end: 38, + source_id: None, + ), parsed: "value", ))), ), CommaToken( - span: (38, 39), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 38, + end: 39, + source_id: None, + ), )), ], final_value_opt: Some(AttributeArg( - name: Ident( - to_string: "arg3", - span: (40, 44), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 40, + end: 44, + source_id: None, + ), + is_raw_ident: false, ), value: None, )), ), - span: (17, 45), + span: Span( + src: "\n name(arg1, arg2 = \"value\", arg3)\n ", + start: 17, + end: 45, + source_id: None, + ), )), ) - "###); + "#); } } diff --git a/sway-parse/src/module.rs b/sway-parse/src/module.rs index 7936012e96a..05d97d82b42 100644 --- a/sway-parse/src/module.rs +++ b/sway-parse/src/module.rs @@ -87,17 +87,27 @@ mod tests { fn main() { () } - "#,), @r###" + "#,), @r#" Annotated( attribute_list: [], value: Module( kind: Script( script_token: ScriptToken( - span: (13, 19), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 13, + end: 19, + source_id: None, + ), ), ), semicolon_token: SemicolonToken( - span: (19, 20), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 19, + end: 20, + source_id: None, + ), ), items: [ Annotated( @@ -106,11 +116,22 @@ mod tests { fn_signature: FnSignature( visibility: None, fn_token: FnToken( - span: (42, 44), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 42, + end: 44, + source_id: None, + ), ), - name: Ident( - to_string: "main", - span: (45, 49), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 45, + end: 49, + source_id: None, + ), + is_raw_ident: false, ), generics: None, arguments: Parens( @@ -118,7 +139,12 @@ mod tests { value_separator_pairs: [], final_value_opt: None, )), - span: (49, 51), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 49, + end: 51, + source_id: None, + ), ), return_type_opt: None, where_clause_opt: None, @@ -128,17 +154,32 @@ mod tests { statements: [], final_expr_opt: Some(Tuple(Parens( inner: Nil, - span: (70, 72), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 70, + end: 72, + source_id: None, + ), ))), - span: (53, 85), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 53, + end: 85, + source_id: None, + ), + ), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 52, + end: 86, + source_id: None, ), - span: (52, 86), ), )), ), ], ), ) - "###); + "#); } } diff --git a/sway-parse/src/path.rs b/sway-parse/src/path.rs index a9bb8c3826a..4a2a57ac706 100644 --- a/sway-parse/src/path.rs +++ b/sway-parse/src/path.rs @@ -121,10 +121,7 @@ impl Parse for PathTypeSegment { impl Parse for QualifiedPathRoot { fn parse(parser: &mut Parser) -> ParseResult { let ty = parser.parse()?; - let as_trait = match parser.take() { - Some(as_token) => Some((as_token, parser.parse()?)), - None => None, - }; + let as_trait = (parser.parse()?, parser.parse()?); Ok(QualifiedPathRoot { ty, as_trait }) } } @@ -139,37 +136,65 @@ mod tests { fn parse_nested_path() { assert_ron_snapshot!(parse::(r#" std::vec::Vec - "#,), @r###" + "#,), @r#" PathExpr( root_opt: None, prefix: PathExprSegment( - name: Ident( - to_string: "std", - span: (13, 16), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n std::vec::Vec\n ", + start: 13, + end: 16, + source_id: None, + ), + is_raw_ident: false, ), generics_opt: None, ), suffix: [ (DoubleColonToken( - span: (16, 18), + span: Span( + src: "\n std::vec::Vec\n ", + start: 16, + end: 18, + source_id: None, + ), ), PathExprSegment( - name: Ident( - to_string: "vec", - span: (18, 21), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n std::vec::Vec\n ", + start: 18, + end: 21, + source_id: None, + ), + is_raw_ident: false, ), generics_opt: None, )), (DoubleColonToken( - span: (21, 23), + span: Span( + src: "\n std::vec::Vec\n ", + start: 21, + end: 23, + source_id: None, + ), ), PathExprSegment( - name: Ident( - to_string: "Vec", - span: (23, 26), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n std::vec::Vec\n ", + start: 23, + end: 26, + source_id: None, + ), + is_raw_ident: false, ), generics_opt: None, )), ], ) - "###); + "#); } } diff --git a/sway-parse/tests/noop_script.rs b/sway-parse/tests/noop_script.rs index fd3fe83cf0e..709da28de33 100644 --- a/sway-parse/tests/noop_script.rs +++ b/sway-parse/tests/noop_script.rs @@ -12,17 +12,27 @@ fn noop_script_file() { fn main() { () } - "#,), @r###" + "#,), @r#" Some(Annotated( attribute_list: [], value: Module( kind: Script( script_token: ScriptToken( - span: (7, 13), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 7, + end: 13, + source_id: None, + ), ), ), semicolon_token: SemicolonToken( - span: (13, 14), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 13, + end: 14, + source_id: None, + ), ), items: [ Annotated( @@ -31,11 +41,22 @@ fn noop_script_file() { fn_signature: FnSignature( visibility: None, fn_token: FnToken( - span: (28, 30), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 28, + end: 30, + source_id: None, + ), ), - name: Ident( - to_string: "main", - span: (31, 35), + name: BaseIdent( + name_override_opt: None, + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 31, + end: 35, + source_id: None, + ), + is_raw_ident: false, ), generics: None, arguments: Parens( @@ -43,7 +64,12 @@ fn noop_script_file() { value_separator_pairs: [], final_value_opt: None, )), - span: (35, 37), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 35, + end: 37, + source_id: None, + ), ), return_type_opt: None, where_clause_opt: None, @@ -53,16 +79,31 @@ fn noop_script_file() { statements: [], final_expr_opt: Some(Tuple(Parens( inner: Nil, - span: (48, 50), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 48, + end: 50, + source_id: None, + ), ))), - span: (39, 57), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 39, + end: 57, + source_id: None, + ), + ), + span: Span( + src: "\n script;\n \n fn main() {\n ()\n }\n ", + start: 38, + end: 58, + source_id: None, ), - span: (38, 58), ), )), ), ], ), )) - "###); + "#); } diff --git a/sway-types/Cargo.toml b/sway-types/Cargo.toml index aad3c5e52ac..89931ff9ab7 100644 --- a/sway-types/Cargo.toml +++ b/sway-types/Cargo.toml @@ -19,7 +19,7 @@ num-bigint.workspace = true num-traits.workspace = true parking_lot.workspace = true rustc-hash.workspace = true -serde = { workspace = true, features = ["derive"] } +serde = { workspace = true, features = ["derive", "std", "rc"] } sway-utils.workspace = true thiserror.workspace = true diff --git a/sway-types/src/ast.rs b/sway-types/src/ast.rs index b137ad9bd09..4db1c3b6c7c 100644 --- a/sway-types/src/ast.rs +++ b/sway-types/src/ast.rs @@ -6,14 +6,14 @@ pub enum Delimiter { } impl Delimiter { - pub fn as_open_char(self) -> char { + pub const fn as_open_char(self) -> char { match self { Delimiter::Parenthesis => '(', Delimiter::Brace => '{', Delimiter::Bracket => '[', } } - pub fn as_close_char(self) -> char { + pub const fn as_close_char(self) -> char { match self { Delimiter::Parenthesis => ')', Delimiter::Brace => '}', diff --git a/sway-types/src/ident.rs b/sway-types/src/ident.rs index f4aa577bc5d..ff1c168e9e6 100644 --- a/sway-types/src/ident.rs +++ b/sway-types/src/ident.rs @@ -1,7 +1,5 @@ -use serde::Serialize; - use crate::{span::Span, Spanned}; - +use serde::{Deserialize, Serialize}; use std::{ cmp::{Ord, Ordering}, fmt, @@ -13,7 +11,7 @@ pub trait Named { fn name(&self) -> &BaseIdent; } -#[derive(Clone)] +#[derive(Clone, Serialize, Deserialize)] pub struct BaseIdent { name_override_opt: Option>, span: Span, @@ -93,18 +91,6 @@ impl BaseIdent { /// often be different. pub type Ident = BaseIdent; -impl Serialize for Ident { - // Serialize an `Ident` struct with two fields: `to_string` and `span`. - fn serialize(&self, serializer: S) -> Result { - use serde::ser::SerializeStruct; - - let mut state = serializer.serialize_struct("Ident", 2)?; - state.serialize_field("to_string", &self.to_string())?; - state.serialize_field("span", &self.span)?; - state.end() - } -} - impl Hash for Ident { fn hash(&self, state: &mut H) { self.as_str().hash(state); diff --git a/sway-types/src/lib.rs b/sway-types/src/lib.rs index 5d8e1cf95c1..b45471dcba2 100644 --- a/sway-types/src/lib.rs +++ b/sway-types/src/lib.rs @@ -88,47 +88,34 @@ impl Instruction { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct ProgramId { - id: u16, -} +pub struct ProgramId(u16); impl ProgramId { pub fn new(id: u16) -> Self { - Self { id } + Self(id) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -pub struct SourceId { - id: u32, -} +pub struct SourceId(u32); impl SourceId { - const RESERVED: u16 = 0; const SOURCE_ID_BITS: u32 = 20; const SOURCE_ID_MASK: u32 = (1 << Self::SOURCE_ID_BITS) - 1; - /// Create a combined ID from module and source IDs. + /// Create a combined ID from program and source IDs. pub fn new(program_id: u16, source_id: u32) -> Self { - SourceId { - id: ((program_id as u32) << Self::SOURCE_ID_BITS) | source_id, - } - } - - /// Create a reserved source_id. This is assigned to internal types - /// that should not be cleared during garbage collection. - pub fn reserved() -> Self { - Self::new(Self::RESERVED, Self::RESERVED as u32) + SourceId(((program_id as u32) << Self::SOURCE_ID_BITS) | source_id) } - /// The program_id that this source_id was created from. + /// The [ProgramId] that this [SourceId] was created from. pub fn program_id(&self) -> ProgramId { - ProgramId::new((self.id >> Self::SOURCE_ID_BITS) as u16) + ProgramId::new((self.0 >> Self::SOURCE_ID_BITS) as u16) } - /// Id of the source file without the program_id component. + /// ID of the source file without the [ProgramId] component. pub fn source_id(&self) -> u32 { - self.id & Self::SOURCE_ID_MASK + self.0 & Self::SOURCE_ID_MASK } } diff --git a/sway-types/src/source_engine.rs b/sway-types/src/source_engine.rs index 95ea5d94775..7a3124a3de2 100644 --- a/sway-types/src/source_engine.rs +++ b/sway-types/src/source_engine.rs @@ -81,7 +81,7 @@ impl SourceEngine { } } - let source_id = SourceId::new(program_id.id, *self.next_source_id.read()); + let source_id = SourceId::new(program_id.0, *self.next_source_id.read()); { let mut next_id = self.next_source_id.write(); *next_id += 1; diff --git a/sway-types/src/span.rs b/sway-types/src/span.rs index c757fb523da..5ea94b3c2a0 100644 --- a/sway-types/src/span.rs +++ b/sway-types/src/span.rs @@ -1,12 +1,11 @@ -use std::fmt::Display; - -use serde::{Deserialize, Serialize}; - use crate::SourceId; - -use { - lazy_static::lazy_static, - std::{cmp, fmt, hash::Hash, sync::Arc}, +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use std::{ + cmp, + fmt::{self, Display}, + hash::Hash, + sync::Arc, }; lazy_static! { @@ -43,7 +42,7 @@ impl<'a> Position<'a> { } /// Represents a span of the source code in a specific file. -#[derive(Clone, Ord, PartialOrd)] +#[derive(Clone, Ord, PartialOrd, Serialize, Deserialize)] pub struct Span { // The original source code. src: Arc, @@ -71,18 +70,6 @@ impl PartialEq for Span { impl Eq for Span {} -impl Serialize for Span { - // Serialize a tuple two fields: `start` and `end`. - fn serialize(&self, serializer: S) -> Result { - use serde::ser::SerializeTuple; - - let mut state = serializer.serialize_tuple(2)?; - state.serialize_element(&self.start)?; - state.serialize_element(&self.end)?; - state.end() - } -} - impl From for std::ops::Range { fn from(value: Span) -> Self { Self { @@ -216,6 +203,10 @@ impl Span { pub fn is_dummy(&self) -> bool { self.eq(&DUMMY_SPAN) } + + pub fn is_empty(&self) -> bool { + self.start == self.end + } } impl fmt::Debug for Span { diff --git a/sway-types/src/u256.rs b/sway-types/src/u256.rs index e116308f169..2f42b43b0f3 100644 --- a/sway-types/src/u256.rs +++ b/sway-types/src/u256.rs @@ -1,10 +1,10 @@ -use std::ops::{Not, Shl, Shr}; - use num_bigint::{BigUint, ParseBigIntError, TryFromBigIntError}; use num_traits::Zero; +use serde::{Deserialize, Serialize}; +use std::ops::{Not, Shl, Shr}; use thiserror::Error; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Serialize, Deserialize)] pub struct U256(BigUint); impl U256 { diff --git a/sway-utils/src/constants.rs b/sway-utils/src/constants.rs index 00214945ed5..c0f8b6938a9 100644 --- a/sway-utils/src/constants.rs +++ b/sway-utils/src/constants.rs @@ -7,7 +7,8 @@ pub const USER_FORC_DIRECTORY: &str = ".forc"; pub const SRC_DIR: &str = "src"; pub const DEFAULT_NODE_URL: &str = "http://127.0.0.1:4000"; pub const LANGUAGE_NAME: &str = "Sway"; -pub const STORAGE_DOMAIN: &str = "storage"; +pub const STORAGE_DOMAIN: [u8; 1] = [0u8]; +pub const STORAGE_TOP_LEVEL_NAMESPACE: &str = "storage"; pub const STORAGE_NAMESPACE_SEPARATOR: &str = "::"; pub const STORAGE_FIELD_SEPARATOR: &str = "."; pub const STRUCT_FIELD_SEPARATOR: &str = "."; diff --git a/sway-utils/src/performance.rs b/sway-utils/src/performance.rs index cbf53cc5510..479c229c5e3 100644 --- a/sway-utils/src/performance.rs +++ b/sway-utils/src/performance.rs @@ -14,12 +14,28 @@ pub struct PerformanceData { pub reused_programs: u64, } +#[derive(serde::Serialize, Clone)] +pub struct FunctionEntryPoint { + /// The original entry point function name. + pub fn_name: String, + /// The immediate instruction offset at which the entry function begins. + pub imm: u64, + /// The function selector (only `Some` for contract ABI methods). + pub selector: Option<[u8; 4]>, +} + #[macro_export] // Time the given expression and print/save the result. macro_rules! time_expr { - ($description:expr, $key:expr, $expression:expr, $build_config:expr, $data:expr) => {{ + ($pkg_name:expr, $description:expr, $key:expr, $expression:expr, $build_config:expr, $data:expr) => {{ + use std::io::{BufRead, Read, Write}; if let Some(cfg) = $build_config { - if cfg.time_phases || cfg.metrics_outfile.is_some() { + if cfg.profile { + println!("/dyno start {} {}", $pkg_name, $description); + let output = { $expression }; + println!("/dyno stop {} {}", $pkg_name, $description); + output + } else if cfg.time_phases || cfg.metrics_outfile.is_some() { let expr_start = std::time::Instant::now(); let output = { $expression }; let elapsed = expr_start.elapsed(); diff --git a/swayfmt/Cargo.toml b/swayfmt/Cargo.toml index 475cbe5d1b2..71eb6d60824 100644 --- a/swayfmt/Cargo.toml +++ b/swayfmt/Cargo.toml @@ -16,7 +16,6 @@ ropey.workspace = true serde = { workspace = true, features = ["derive"] } serde_ignored.workspace = true sway-ast.workspace = true -sway-core.workspace = true sway-error.workspace = true sway-parse.workspace = true sway-types.workspace = true @@ -26,6 +25,6 @@ toml = { workspace = true, features = ["parse"] } [dev-dependencies] paste = "1.0" -prettydiff = "0.6" +prettydiff = "0.7" similar = "2.0" test-macros = { path = "test_macros" } diff --git a/swayfmt/src/comments.rs b/swayfmt/src/comments.rs index e891ca15666..dfd5590d7f7 100644 --- a/swayfmt/src/comments.rs +++ b/swayfmt/src/comments.rs @@ -76,15 +76,18 @@ fn write_trailing_comment( } /// Given a range, writes comments contained within the range. This function -/// removes comments that are written here from the CommentMap for later use. +/// removes comments that are written here from the [CommentMap] for later use. /// -/// Most comment formatting should be done using `rewrite_with_comments` in +/// Most comment formatting should be done using [rewrite_with_comments] in /// the context of the AST, but in some cases (eg. at the end of module) we require this function. /// /// Returns: /// `Ok(true)` on successful execution with comments written, /// `Ok(false)` on successful execution and if there are no comments within the given range, /// `Err` if a FormatterError was encountered. +/// +/// The `range` can be an empty [Range], or have its start being greater then its end. +/// This is to support formatting arbitrary lexed trees, that are not necessarily backed by source code. pub fn write_comments( formatted_code: &mut FormattedCode, range: Range, @@ -127,7 +130,7 @@ pub fn write_comments( // We do a trim and truncate here to ensure that only a single whitespace separates // the inlined comment from the previous token. formatted_code.truncate(formatted_code.trim_end().len()); - write!(formatted_code, " {} ", comment.span().as_str(),)?; + write!(formatted_code, " {} ", comment.span().as_str())?; } CommentKind::Multilined => { write!( @@ -157,6 +160,9 @@ pub fn write_comments( /// This takes a given AST node's unformatted span, its leaf spans and its formatted code (a string) and /// parses the equivalent formatted version to get its leaf spans. We traverse the spaces between both /// formatted and unformatted leaf spans to find possible comments and inserts them between. +/// +/// The `unformatted_span` can be an empty [Span]. This is to support formatting arbitrary lexed trees, +/// that are not necessarily backed by source code. pub fn rewrite_with_comments( formatter: &mut Formatter, unformatted_span: Span, diff --git a/swayfmt/src/formatter/mod.rs b/swayfmt/src/formatter/mod.rs index 96ead29f09d..0802d0c7727 100644 --- a/swayfmt/src/formatter/mod.rs +++ b/swayfmt/src/formatter/mod.rs @@ -8,7 +8,8 @@ pub use crate::{ error::{ConfigError, FormatterError}, }; use std::{borrow::Cow, fmt::Write, path::Path, sync::Arc}; -use sway_core::BuildConfig; +use sway_ast::attribute::Annotated; +use sway_ast::Module; use sway_types::{SourceEngine, Spanned}; pub(crate) mod shape; @@ -80,10 +81,14 @@ impl Formatter { Ok(self) } - pub fn format( + pub fn format(&mut self, src: Arc) -> Result { + let annotated_module = parse_file(src)?; + self.format_module(&annotated_module) + } + + pub fn format_module( &mut self, - src: Arc, - build_config: Option<&BuildConfig>, + annotated_module: &Annotated, ) -> Result { // apply the width heuristics settings from the `Config` self.shape.apply_width_heuristics( @@ -92,9 +97,11 @@ impl Formatter { .heuristics_pref .to_width_heuristics(self.config.whitespace.max_width), ); - let src = src.trim(); - let path = build_config.map(|build_config| build_config.canonical_root_module()); + // Get the original trimmed source code. + let module_kind_span = annotated_module.value.kind.span(); + let src = module_kind_span.src().trim(); + // Formatted code will be pushed here with raw newline style. // Which means newlines are not converted into system-specific versions until `apply_newline_style()`. // Use the length of src as a hint of the memory size needed for `raw_formatted_code`, @@ -103,7 +110,6 @@ impl Formatter { self.with_comments_context(src)?; - let annotated_module = parse_file(&self.source_engine, Arc::from(src), path.clone())?; annotated_module.format(&mut raw_formatted_code, self)?; let mut formatted_code = String::from(&raw_formatted_code); @@ -117,14 +123,13 @@ impl Formatter { // Add newline sequences handle_newlines( - &self.source_engine, Arc::from(src), &annotated_module.value, Arc::from(formatted_code.clone()), - path, &mut formatted_code, self, )?; + // Replace newlines with specified `NewlineStyle` apply_newline_style( self.config.whitespace.newline_style, @@ -137,6 +142,7 @@ impl Formatter { Ok(formatted_code) } + pub(crate) fn with_shape(&mut self, new_shape: Shape, f: F) -> O where F: FnOnce(&mut Self) -> O, diff --git a/swayfmt/src/formatter/shape.rs b/swayfmt/src/formatter/shape.rs index 0630c73e851..9c9def85548 100644 --- a/swayfmt/src/formatter/shape.rs +++ b/swayfmt/src/formatter/shape.rs @@ -163,6 +163,12 @@ pub(crate) enum LineStyle { Multiline, } +impl LineStyle { + pub fn is_multiline(&self) -> bool { + matches!(self, Self::Multiline) + } +} + impl Default for LineStyle { fn default() -> Self { Self::Normal diff --git a/swayfmt/src/items/item_abi/mod.rs b/swayfmt/src/items/item_abi/mod.rs index ddf1fabe22f..e47fa3b269d 100644 --- a/swayfmt/src/items/item_abi/mod.rs +++ b/swayfmt/src/items/item_abi/mod.rs @@ -8,7 +8,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemAbi}; +use sway_ast::{ + keywords::{AbiToken, ColonToken, Keyword, Token}, + ItemAbi, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -22,12 +25,12 @@ impl Format for ItemAbi { ) -> Result<(), FormatterError> { let start_len = formatted_code.len(); // `abi name` - write!(formatted_code, "{} ", self.abi_token.span().as_str())?; + write!(formatted_code, "{} ", AbiToken::AS_STR)?; self.name.format(formatted_code, formatter)?; // ` : super_trait + super_trait` - if let Some((colon_token, traits)) = &self.super_traits { - write!(formatted_code, " {} ", colon_token.ident().as_str())?; + if let Some((_colon_token, traits)) = &self.super_traits { + write!(formatted_code, " {} ", ColonToken::AS_STR)?; traits.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/items/item_configurable/mod.rs b/swayfmt/src/items/item_configurable/mod.rs index 550b8916d8d..c870b537a1d 100644 --- a/swayfmt/src/items/item_configurable/mod.rs +++ b/swayfmt/src/items/item_configurable/mod.rs @@ -10,7 +10,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ConfigurableField, ItemConfigurable}; +use sway_ast::{ + keywords::{ColonToken, ConfigurableToken, EqToken, Keyword, Token}, + CommaToken, ConfigurableField, ItemConfigurable, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -28,11 +31,7 @@ impl Format for ItemConfigurable { .with_code_line_from(LineStyle::Multiline, ExprKind::default()), |formatter| -> Result<(), FormatterError> { // Add configurable token - write!( - formatted_code, - "{}", - self.configurable_token.span().as_str() - )?; + write!(formatted_code, "{}", ConfigurableToken::AS_STR)?; let fields = self.fields.get(); // Handle opening brace @@ -44,19 +43,18 @@ impl Format for ItemConfigurable { match formatter.config.structures.field_alignment { FieldAlignment::AlignFields(configurable_field_align_threshold) => { writeln!(formatted_code)?; - let value_pairs = &fields + let configurable_fields = &fields .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them - .map(|(configurable_field, comma_token)| { - (&configurable_field.value, comma_token) - }) + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 + .map(|(configurable_field, _comma_token)| &configurable_field.value) .collect::>(); // In first iteration we are going to be collecting the lengths of the // struct fields. - let field_length: Vec = value_pairs + let field_length: Vec = configurable_fields .iter() - .map(|(configurable_field, _)| configurable_field.name.as_str().len()) + .map(|configurable_field| configurable_field.name.as_str().len()) .collect(); // Find the maximum length in the `field_length` vector that is still @@ -72,11 +70,10 @@ impl Format for ItemConfigurable { } }); - let value_pairs_iter = value_pairs.iter().enumerate(); - for (field_index, (configurable_field, comma_token)) in - value_pairs_iter.clone() + for (field_index, configurable_field) in + configurable_fields.iter().enumerate() { - write!(formatted_code, "{}", &formatter.indent_to_str()?)?; + write!(formatted_code, "{}", formatter.indent_to_str()?)?; // Add name configurable_field.name.format(formatted_code, formatter)?; @@ -94,24 +91,17 @@ impl Format for ItemConfigurable { } } // Add `:`, `ty` & `CommaToken` - write!( - formatted_code, - " {} ", - configurable_field.colon_token.ident().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; configurable_field.ty.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - configurable_field.eq_token.ident().as_str() - )?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; configurable_field .initializer .format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", comma_token.ident().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &fields.final_value_opt { final_value.format(formatted_code, formatter)?; + writeln!(formatted_code)?; } } FieldAlignment::Off => fields.format(formatted_code, formatter)?, diff --git a/swayfmt/src/items/item_const.rs b/swayfmt/src/items/item_const.rs index e853f2a97dc..0d78ef24eeb 100644 --- a/swayfmt/src/items/item_const.rs +++ b/swayfmt/src/items/item_const.rs @@ -4,7 +4,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemConst}; +use sway_ast::{ + keywords::{ColonToken, ConstToken, EqToken, Keyword, SemicolonToken, Token}, + ItemConst, PubToken, +}; use sway_types::Spanned; impl Format for ItemConst { @@ -17,26 +20,26 @@ impl Format for ItemConst { let start_len = formatted_code.len(); // Check if visibility token exists if so add it. - if let Some(visibility_token) = &self.visibility { - write!(formatted_code, "{} ", visibility_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add the const token - write!(formatted_code, "{} ", self.const_token.span().as_str())?; + write!(formatted_code, "{} ", ConstToken::AS_STR)?; // Add name of the const self.name.format(formatted_code, formatter)?; // Check if ty exists - if let Some((colon_token, ty)) = &self.ty_opt { + if let Some((_colon_token, ty)) = &self.ty_opt { // Add colon - write!(formatted_code, "{} ", colon_token.ident().as_str())?; + write!(formatted_code, "{} ", ColonToken::AS_STR)?; ty.format(formatted_code, formatter)?; } // Check if ` = ` exists - if let Some(eq_token) = &self.eq_token_opt { - write!(formatted_code, " {} ", eq_token.ident().as_str())?; + if self.eq_token_opt.is_some() { + write!(formatted_code, " {} ", EqToken::AS_STR)?; } // Check if expression exists @@ -44,7 +47,7 @@ impl Format for ItemConst { expr.format(formatted_code, formatter)?; } - write!(formatted_code, "{}", self.semicolon_token.ident().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; rewrite_with_comments::( formatter, diff --git a/swayfmt/src/items/item_enum/mod.rs b/swayfmt/src/items/item_enum/mod.rs index 561c2b436f6..11fa3d6c78d 100644 --- a/swayfmt/src/items/item_enum/mod.rs +++ b/swayfmt/src/items/item_enum/mod.rs @@ -11,11 +11,11 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::ItemEnum; -use sway_types::{ - ast::{Delimiter, PunctKind}, - Spanned, +use sway_ast::{ + keywords::{ColonToken, EnumToken, Keyword, Token}, + CommaToken, ItemEnum, PubToken, }; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; @@ -34,11 +34,11 @@ impl Format for ItemEnum { // Required for comment formatting let start_len = formatted_code.len(); // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &self.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add enum token and name - write!(formatted_code, "{} ", self.enum_token.span().as_str())?; + write!(formatted_code, "{} ", EnumToken::AS_STR)?; self.name.format(formatted_code, formatter)?; // Format `GenericParams`, if any if let Some(generics) = &self.generics { @@ -55,21 +55,22 @@ impl Format for ItemEnum { match formatter.config.structures.field_alignment { FieldAlignment::AlignFields(enum_variant_align_threshold) => { writeln!(formatted_code)?; - let value_pairs = &fields + let type_fields = &fields .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them - .map(|pair| (&pair.0.value, &pair.1)) + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 + .map(|(type_field, _comma_token)| &type_field.value) .collect::>(); // In first iteration we are going to be collecting the lengths of the enum variants. - let variant_length: Vec = value_pairs + let variants_lengths: Vec = type_fields .iter() - .map(|(type_field, _)| type_field.name.as_str().len()) + .map(|type_field| type_field.name.as_str().len()) .collect(); - // Find the maximum length in the variant_length vector that is still smaller than enum_field_align_threshold. + // Find the maximum length that is still smaller than the align threshold. let mut max_valid_variant_length = 0; - variant_length.iter().for_each(|length| { + variants_lengths.iter().for_each(|length| { if *length > max_valid_variant_length && *length < enum_variant_align_threshold { @@ -77,13 +78,12 @@ impl Format for ItemEnum { } }); - let value_pairs_iter = value_pairs.iter().enumerate(); - for (var_index, (type_field, comma_token)) in value_pairs_iter.clone() { - write!(formatted_code, "{}", &formatter.indent_to_str()?)?; + for (var_index, type_field) in type_fields.iter().enumerate() { + write!(formatted_code, "{}", formatter.indent_to_str()?)?; // Add name type_field.name.format(formatted_code, formatter)?; - let current_variant_length = variant_length[var_index]; + let current_variant_length = variants_lengths[var_index]; if current_variant_length < max_valid_variant_length { // We need to add alignment between : and ty // max_valid_variant_length: the length of the variant that we are taking as a reference to align @@ -96,23 +96,13 @@ impl Format for ItemEnum { } } // Add `:`, ty & `CommaToken` - write!( - formatted_code, - " {} ", - type_field.colon_token.span().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; type_field.ty.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", comma_token.span().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &fields.final_value_opt { - // TODO: Handle annotation - let final_value = &final_value.value; - writeln!( - formatted_code, - "{}{}", - final_value.span().as_str(), - PunctKind::Comma.as_char(), - )?; + final_value.format(formatted_code, formatter)?; + writeln!(formatted_code)?; } } FieldAlignment::Off => fields.format(formatted_code, formatter)?, @@ -164,6 +154,7 @@ impl CurlyBrace for ItemEnum { Ok(()) } } + impl LeafSpans for ItemEnum { fn leaf_spans(&self) -> Vec { let mut collected_spans = Vec::new(); diff --git a/swayfmt/src/items/item_fn/mod.rs b/swayfmt/src/items/item_fn/mod.rs index 596f37efad2..235fc5a2179 100644 --- a/swayfmt/src/items/item_fn/mod.rs +++ b/swayfmt/src/items/item_fn/mod.rs @@ -11,8 +11,10 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - keywords::{MutToken, RefToken, SelfToken, Token}, - FnArg, FnArgs, FnSignature, ItemFn, + keywords::{ + ColonToken, FnToken, Keyword, MutToken, RefToken, RightArrowToken, SelfToken, Token, + }, + CommaToken, FnArg, FnArgs, FnSignature, ItemFn, PubToken, }; use sway_types::{ast::Delimiter, Spanned}; @@ -152,11 +154,11 @@ fn format_fn_sig( formatter: &mut Formatter, ) -> Result<(), FormatterError> { // `pub ` - if let Some(visibility_token) = &fn_sig.visibility { - write!(formatted_code, "{} ", visibility_token.span().as_str())?; + if fn_sig.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // `fn ` + name - write!(formatted_code, "{} ", fn_sig.fn_token.span().as_str())?; + write!(formatted_code, "{} ", FnToken::AS_STR)?; fn_sig.name.format(formatted_code, formatter)?; // `` if let Some(generics) = &fn_sig.generics { @@ -169,12 +171,8 @@ fn format_fn_sig( // `)` FnSignature::close_parenthesis(formatted_code, formatter)?; // `return_type_opt` - if let Some((right_arrow, ty)) = &fn_sig.return_type_opt { - write!( - formatted_code, - " {} ", - right_arrow.ident().as_str() // `->` - )?; + if let Some((_right_arrow, ty)) = &fn_sig.return_type_opt { + write!(formatted_code, " {} ", RightArrowToken::AS_STR)?; ty.format(formatted_code, formatter)?; // `Ty` } // `WhereClause` @@ -196,7 +194,7 @@ fn format_fn_args( FnArgs::Static(args) => match formatter.shape.code_line.line_style { LineStyle::Multiline => { formatter.shape.code_line.update_expr_new_line(true); - if !args.value_separator_pairs.is_empty() || args.final_value_opt.is_some() { + if !args.is_empty() { formatter.indent(); args.format(formatted_code, formatter)?; formatter.unindent(); @@ -218,9 +216,9 @@ fn format_fn_args( write!(formatted_code, "\n{}", formatter.indent_to_str()?)?; format_self(self_token, ref_self, mutable_self, formatted_code)?; // `args_opt` - if let Some((comma, args)) = args_opt { + if let Some((_comma, args)) = args_opt { // `, ` - write!(formatted_code, "{}", comma.ident().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; // `Punctuated` args.format(formatted_code, formatter)?; } @@ -228,9 +226,9 @@ fn format_fn_args( _ => { format_self(self_token, ref_self, mutable_self, formatted_code)?; // `args_opt` - if let Some((comma, args)) = args_opt { + if let Some((_comma, args)) = args_opt { // `, ` - write!(formatted_code, "{} ", comma.ident().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; // `Punctuated` args.format(formatted_code, formatter)?; } @@ -243,21 +241,21 @@ fn format_fn_args( } fn format_self( - self_token: &SelfToken, + _self_token: &SelfToken, ref_self: &Option, mutable_self: &Option, formatted_code: &mut FormattedCode, ) -> Result<(), FormatterError> { // `ref ` - if let Some(ref_token) = ref_self { - write!(formatted_code, "{} ", ref_token.span().as_str())?; + if ref_self.is_some() { + write!(formatted_code, "{} ", RefToken::AS_STR)?; } // `mut ` - if let Some(mut_token) = mutable_self { - write!(formatted_code, "{} ", mut_token.span().as_str())?; + if mutable_self.is_some() { + write!(formatted_code, "{} ", MutToken::AS_STR)?; } // `self` - write!(formatted_code, "{}", self_token.span().as_str())?; + write!(formatted_code, "{}", SelfToken::AS_STR)?; Ok(()) } @@ -289,7 +287,7 @@ impl Format for FnArg { ) -> Result<(), FormatterError> { self.pattern.format(formatted_code, formatter)?; // `: ` - write!(formatted_code, "{} ", self.colon_token.span().as_str())?; + write!(formatted_code, "{} ", ColonToken::AS_STR)?; write_comments( formatted_code, diff --git a/swayfmt/src/items/item_impl/mod.rs b/swayfmt/src/items/item_impl/mod.rs index 164f157ba2c..fcadf3b040c 100644 --- a/swayfmt/src/items/item_impl/mod.rs +++ b/swayfmt/src/items/item_impl/mod.rs @@ -8,7 +8,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ItemImpl, ItemImplItem}; +use sway_ast::{ + keywords::{ForToken, ImplToken, Keyword}, + ItemImpl, ItemImplItem, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -23,14 +26,14 @@ impl Format for ItemImpl { // Required for comment formatting let start_len = formatted_code.len(); - write!(formatted_code, "{}", self.impl_token.span().as_str())?; + write!(formatted_code, "{}", ImplToken::AS_STR)?; if let Some(generic_params) = &self.generic_params_opt { generic_params.format(formatted_code, formatter)?; } write!(formatted_code, " ")?; - if let Some((path_type, for_token)) = &self.trait_opt { + if let Some((path_type, _for_token)) = &self.trait_opt { path_type.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", for_token.span().as_str())?; + write!(formatted_code, " {} ", ForToken::AS_STR)?; } self.ty.format(formatted_code, formatter)?; if let Some(where_clause) = &self.where_clause_opt { diff --git a/swayfmt/src/items/item_storage/mod.rs b/swayfmt/src/items/item_storage/mod.rs index c6fa0fdf189..acbcf5937c3 100644 --- a/swayfmt/src/items/item_storage/mod.rs +++ b/swayfmt/src/items/item_storage/mod.rs @@ -11,7 +11,10 @@ use crate::{ }, }; use std::{collections::HashMap, fmt::Write}; -use sway_ast::{keywords::Token, ItemStorage, StorageEntry, StorageField}; +use sway_ast::{ + keywords::{ColonToken, EqToken, Keyword, StorageToken, Token}, + CommaToken, ItemStorage, StorageEntry, StorageField, +}; use sway_types::{ast::Delimiter, IdentUnique, Spanned}; #[cfg(test)] @@ -32,7 +35,7 @@ impl Format for ItemStorage { let start_len = formatted_code.len(); // Add storage token - write!(formatted_code, "{}", self.storage_token.span().as_str())?; + write!(formatted_code, "{}", StorageToken::AS_STR)?; let entries = self.entries.get(); // Handle opening brace @@ -47,7 +50,8 @@ impl Format for ItemStorage { let value_pairs = &entries .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 .map(|(storage_field, comma_token)| (&storage_field.value, comma_token)) .collect::>(); // In first iteration we are going to be collecting the lengths of the @@ -114,7 +118,7 @@ impl Format for ItemStorage { ItemStorage::open_curly_brace(formatted_code, formatter)?; writeln!(formatted_code)?; - for (e, comma_token) in + for (e, _comma_token) in namespace.clone().into_inner().value_separator_pairs { format_entry( @@ -124,7 +128,7 @@ impl Format for ItemStorage { field_lengths, max_valid_field_length, )?; - writeln!(formatted_code, "{}", comma_token.ident().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &namespace.clone().into_inner().final_value_opt @@ -159,17 +163,9 @@ impl Format for ItemStorage { } } // Add `:`, `ty` & `CommaToken` - write!( - formatted_code, - " {} ", - storage_field.colon_token.ident().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; storage_field.ty.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - storage_field.eq_token.ident().as_str() - )?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; storage_field .initializer .format(formatted_code, formatter)?; @@ -177,7 +173,7 @@ impl Format for ItemStorage { Ok(()) } - for (storage_entry, comma_token) in value_pairs.iter().clone() { + for (storage_entry, _comma_token) in value_pairs.iter().clone() { format_entry( formatted_code, formatter, @@ -185,7 +181,7 @@ impl Format for ItemStorage { &field_lengths, max_valid_field_length, )?; - writeln!(formatted_code, "{}", comma_token.ident().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &entries.final_value_opt { format_entry( diff --git a/swayfmt/src/items/item_struct/mod.rs b/swayfmt/src/items/item_struct/mod.rs index 8ebefab2898..40946639ebb 100644 --- a/swayfmt/src/items/item_struct/mod.rs +++ b/swayfmt/src/items/item_struct/mod.rs @@ -11,7 +11,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::ItemStruct; +use sway_ast::{ + keywords::{ColonToken, Keyword, StructToken, Token}, + CommaToken, ItemStruct, PubToken, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -31,11 +34,11 @@ impl Format for ItemStruct { // Required for comment formatting let start_len = formatted_code.len(); // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &self.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add struct token and name - write!(formatted_code, "{} ", self.struct_token.span().as_str())?; + write!(formatted_code, "{} ", StructToken::AS_STR)?; self.name.format(formatted_code, formatter)?; // Format `GenericParams`, if any if let Some(generics) = &self.generics { @@ -52,7 +55,7 @@ impl Format for ItemStruct { // Handle opening brace Self::open_curly_brace(formatted_code, formatter)?; - if fields.final_value_opt.is_none() && fields.value_separator_pairs.is_empty() { + if fields.is_empty() { write_comments(formatted_code, self.span().into(), formatter)?; } @@ -60,74 +63,67 @@ impl Format for ItemStruct { // Determine alignment tactic match formatter.config.structures.field_alignment { - FieldAlignment::AlignFields(enum_variant_align_threshold) => { + FieldAlignment::AlignFields(struct_field_align_threshold) => { writeln!(formatted_code)?; - let value_pairs = &fields + let type_fields = &fields .value_separator_pairs .iter() - // TODO: Handle annotations instead of stripping them - .map(|(type_field, comma_token)| (&type_field.value, comma_token)) + // TODO: Handle annotations instead of stripping them. + // See: https://github.com/FuelLabs/sway/issues/6802 + .map(|(type_field, _comma_token)| &type_field.value) .collect::>(); - // In first iteration we are going to be collecting the lengths of the struct variants. + // In first iteration we are going to be collecting the lengths of the struct fields. // We need to include the `pub` keyword in the length, if the field is public, // together with one space character between the `pub` and the name. - let variant_length: Vec = value_pairs + let fields_lengths: Vec = type_fields .iter() - .map(|(type_field, _)| { + .map(|type_field| { type_field .visibility .as_ref() - // We don't want to hard code the token here to `pub` or just hardcode 4. - // This is in case we introduce e.g. `pub(crate)` one day. - .map_or(0, |token| token.span().as_str().len() + 1) + .map_or(0, |_pub_token| PubToken::AS_STR.len() + 1) + type_field.name.as_str().len() }) .collect(); - // Find the maximum length in the variant_length vector that is still smaller than struct_field_align_threshold. - let mut max_valid_variant_length = 0; - variant_length.iter().for_each(|length| { - if *length > max_valid_variant_length - && *length < enum_variant_align_threshold + // Find the maximum length that is still smaller than the align threshold. + let mut max_valid_field_length = 0; + fields_lengths.iter().for_each(|length| { + if *length > max_valid_field_length + && *length < struct_field_align_threshold { - max_valid_variant_length = *length; + max_valid_field_length = *length; } }); - let value_pairs_iter = value_pairs.iter().enumerate(); - for (var_index, (type_field, comma_token)) in value_pairs_iter.clone() { + for (var_index, type_field) in type_fields.iter().enumerate() { write!(formatted_code, "{}", formatter.indent_to_str()?)?; // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &type_field.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if type_field.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add name type_field.name.format(formatted_code, formatter)?; - let current_variant_length = variant_length[var_index]; - if current_variant_length < max_valid_variant_length { + let current_field_length = fields_lengths[var_index]; + if current_field_length < max_valid_field_length { // We need to add alignment between : and ty // max_valid_variant_length: the length of the variant that we are taking as a reference to align // current_variant_length: the length of the current variant that we are trying to format let mut required_alignment = - max_valid_variant_length - current_variant_length; + max_valid_field_length - current_field_length; while required_alignment != 0 { write!(formatted_code, " ")?; required_alignment -= 1; } } // Add `:`, ty & `CommaToken` - write!( - formatted_code, - " {} ", - type_field.colon_token.span().as_str(), - )?; + write!(formatted_code, " {} ", ColonToken::AS_STR)?; type_field.ty.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", comma_token.span().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &fields.final_value_opt { - // TODO: Handle annotation - let final_value = &final_value.value; - write!(formatted_code, "{}", final_value.span().as_str())?; + final_value.format(formatted_code, formatter)?; + writeln!(formatted_code)?; } } FieldAlignment::Off => { diff --git a/swayfmt/src/items/item_trait/mod.rs b/swayfmt/src/items/item_trait/mod.rs index 10f94eee8b4..32caff67128 100644 --- a/swayfmt/src/items/item_trait/mod.rs +++ b/swayfmt/src/items/item_trait/mod.rs @@ -8,7 +8,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemTrait, ItemTraitItem, Traits}; +use sway_ast::{ + keywords::{AddToken, ColonToken, Keyword, Token, TraitToken}, + ItemTrait, ItemTraitItem, PubToken, Traits, +}; use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] @@ -23,23 +26,23 @@ impl Format for ItemTrait { // Required for comment formatting let start_len = formatted_code.len(); // `pub ` - if let Some(pub_token) = &self.visibility { - write!(formatted_code, "{} ", pub_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // `trait name` write!( formatted_code, "{} {}", - self.trait_token.span().as_str(), - self.name.span().as_str() + TraitToken::AS_STR, + self.name.as_str(), )?; // `` if let Some(generics) = &self.generics { generics.format(formatted_code, formatter)?; } // `: super_trait + super_trait` - if let Some((colon_token, traits)) = &self.super_traits { - write!(formatted_code, "{} ", colon_token.ident().as_str())?; + if let Some((_colon_token, traits)) = &self.super_traits { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; traits.format(formatted_code, formatter)?; } // `where` @@ -145,8 +148,8 @@ impl Format for Traits { // additional `PathType`s // // ` + PathType` - for (add_token, path_type) in self.suffixes.iter() { - write!(formatted_code, " {} ", add_token.span().as_str())?; + for (_add_token, path_type) in self.suffixes.iter() { + write!(formatted_code, " {} ", AddToken::AS_STR)?; path_type.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/items/item_trait_type.rs b/swayfmt/src/items/item_trait_type.rs index f3af2251b2f..eb363c1ef7b 100644 --- a/swayfmt/src/items/item_trait_type.rs +++ b/swayfmt/src/items/item_trait_type.rs @@ -4,7 +4,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{keywords::Token, TraitType}; +use sway_ast::{ + keywords::{EqToken, Keyword, SemicolonToken, Token, TypeToken}, + TraitType, +}; use sway_types::Spanned; impl Format for TraitType { @@ -16,15 +19,15 @@ impl Format for TraitType { // Required for comment formatting let start_len = formatted_code.len(); - // Add the const token - write!(formatted_code, "{} ", self.type_token.span().as_str())?; + // Add the type token + write!(formatted_code, "{} ", TypeToken::AS_STR)?; - // Add name of the const + // Add name of the type self.name.format(formatted_code, formatter)?; // Check if ` = ` exists - if let Some(eq_token) = &self.eq_token_opt { - write!(formatted_code, " {} ", eq_token.ident().as_str())?; + if self.eq_token_opt.is_some() { + write!(formatted_code, " {} ", EqToken::AS_STR)?; } // Check if ty exists @@ -32,7 +35,7 @@ impl Format for TraitType { ty.format(formatted_code, formatter)?; } - write!(formatted_code, "{}", self.semicolon_token.ident().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; rewrite_with_comments::( formatter, diff --git a/swayfmt/src/items/item_type_alias.rs b/swayfmt/src/items/item_type_alias.rs index 4870baeb031..86221a70f5b 100644 --- a/swayfmt/src/items/item_type_alias.rs +++ b/swayfmt/src/items/item_type_alias.rs @@ -4,7 +4,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{keywords::Token, ItemTypeAlias}; +use sway_ast::{ + keywords::{EqToken, Keyword, SemicolonToken, Token, TypeToken}, + ItemTypeAlias, PubToken, +}; use sway_types::Spanned; impl Format for ItemTypeAlias { @@ -17,24 +20,24 @@ impl Format for ItemTypeAlias { let start_len = formatted_code.len(); // Check if visibility token exists if so add it. - if let Some(visibility_token) = &self.visibility { - write!(formatted_code, "{} ", visibility_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } // Add the `type` token - write!(formatted_code, "{} ", self.type_token.span().as_str())?; + write!(formatted_code, "{} ", TypeToken::AS_STR)?; // Add name of the type alias self.name.format(formatted_code, formatter)?; // Add the `=` token - write!(formatted_code, " {} ", self.eq_token.ident().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; // Format and add `ty` self.ty.format(formatted_code, formatter)?; // Add the `;` token - write!(formatted_code, "{}", self.semicolon_token.ident().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; rewrite_with_comments::( formatter, diff --git a/swayfmt/src/items/item_use/mod.rs b/swayfmt/src/items/item_use/mod.rs index ce304183495..838248fb1c7 100644 --- a/swayfmt/src/items/item_use/mod.rs +++ b/swayfmt/src/items/item_use/mod.rs @@ -9,11 +9,11 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{CommaToken, ItemUse, UseTree}; -use sway_types::{ - ast::{Delimiter, PunctKind}, - Spanned, +use sway_ast::{ + keywords::{AsToken, Keyword, SemicolonToken, StarToken, Token, UseToken}, + CommaToken, DoubleColonToken, ItemUse, PubToken, UseTree, }; +use sway_types::{ast::Delimiter, Spanned}; #[cfg(test)] mod tests; @@ -64,23 +64,40 @@ impl Format for UseTree { match self { Self::Group { imports } => { // check for only one import - if imports.inner.value_separator_pairs.is_empty() { + if imports.inner.value_separator_pairs.is_empty() + && !formatter.shape.code_line.line_style.is_multiline() + { + // we can have: path::{single_import} if let Some(single_import) = &imports.inner.final_value_opt { single_import.format(formatted_code, formatter)?; } + } else if imports.inner.value_separator_pairs.len() == 1 + && imports.inner.has_trailing_punctuation() + && !formatter.shape.code_line.line_style.is_multiline() + { + // but we can also have: path::{single_import,} + // note that in the case of multiline we want to keep the trailing comma + let single_import = &imports + .inner + .value_separator_pairs + .first() + .expect("the `if` condition ensures the existence of the first element") + .0; + single_import.format(formatted_code, formatter)?; } else { Self::open_curly_brace(formatted_code, formatter)?; // sort group imports let imports = imports.get(); let value_pairs = &imports.value_separator_pairs; - let mut commas: Vec<&CommaToken> = Vec::new(); + // track how many commas we have, to simplify checking for trailing element or trailing comma + let mut commas: Vec<()> = Vec::new(); let mut ord_vec: Vec = value_pairs .iter() .map( - |(use_tree, comma_token)| -> Result { + |(use_tree, _comma_token)| -> Result { let mut buf = FormattedCode::new(); use_tree.format(&mut buf, formatter)?; - commas.push(comma_token); + commas.push(()); // we have a comma token Ok(buf) }, ) @@ -102,15 +119,16 @@ impl Format for UseTree { a.to_lowercase().cmp(&b.to_lowercase()) } }); - for (use_tree, comma) in ord_vec.iter_mut().zip(commas.iter()) { - write!(use_tree, "{}", comma.span().as_str())?; + // zip will take only the parts of `ord_vec` before the last comma + for (use_tree, _) in ord_vec.iter_mut().zip(commas.iter()) { + write!(use_tree, "{}", CommaToken::AS_STR)?; } match formatter.shape.code_line.line_style { LineStyle::Multiline => { if imports.final_value_opt.is_some() { if let Some(last) = ord_vec.iter_mut().last() { - write!(last, "{}", PunctKind::Comma.as_char())?; + write!(last, "{}", CommaToken::AS_STR)?; } } @@ -122,39 +140,48 @@ impl Format for UseTree { )?; } _ => { - write!(formatted_code, "{}", ord_vec.join(" "))?; + if imports.has_trailing_punctuation() { + // remove the trailing punctuation + write!( + formatted_code, + "{}", + ord_vec.join(" ").trim_end_matches(',') + )?; + } else { + write!(formatted_code, "{}", ord_vec.join(" "))?; + } } } Self::close_curly_brace(formatted_code, formatter)?; } } - Self::Name { name } => write!(formatted_code, "{}", name.span().as_str())?, + Self::Name { name } => write!(formatted_code, "{}", name.as_str())?, Self::Rename { name, - as_token, + as_token: _, alias, } => { write!( formatted_code, "{} {} {}", - name.span().as_str(), - as_token.span().as_str(), - alias.span().as_str() + name.as_str(), + AsToken::AS_STR, + alias.as_str(), )?; } - Self::Glob { star_token } => { - write!(formatted_code, "{}", star_token.span().as_str())?; + Self::Glob { star_token: _ } => { + write!(formatted_code, "{}", StarToken::AS_STR)?; } Self::Path { prefix, - double_colon_token, + double_colon_token: _, suffix, } => { write!( formatted_code, "{}{}", - prefix.span().as_str(), - double_colon_token.span().as_str() + prefix.as_str(), + DoubleColonToken::AS_STR, )?; suffix.format(formatted_code, formatter)?; } @@ -208,19 +235,15 @@ fn format_use_stmt( formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some(pub_token) = &item_use.visibility { - write!(formatted_code, "{} ", pub_token.span().as_str())?; + if item_use.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } - write!(formatted_code, "{} ", item_use.use_token.span().as_str())?; - if let Some(root_import) = &item_use.root_import { - write!(formatted_code, "{}", root_import.span().as_str())?; + write!(formatted_code, "{} ", UseToken::AS_STR)?; + if item_use.root_import.is_some() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } item_use.tree.format(formatted_code, formatter)?; - write!( - formatted_code, - "{}", - item_use.semicolon_token.span().as_str() - )?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; Ok(()) } diff --git a/swayfmt/src/items/item_use/tests.rs b/swayfmt/src/items/item_use/tests.rs index 0b0a207bc37..64794080d65 100644 --- a/swayfmt/src/items/item_use/tests.rs +++ b/swayfmt/src/items/item_use/tests.rs @@ -10,6 +10,15 @@ fmt_test_item!(multiline "use foo::{ };", out_of_order "use foo::{yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, quux, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};" ); + +fmt_test_item!(multiline_with_trailing_comma "use foo::{ + quux, + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, + yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + out_of_order "use foo::{yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, quux, xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,};" +); + fmt_test_item!(multiline_nested "use foo::{ Quux::{ a, @@ -22,10 +31,42 @@ fmt_test_item!(multiline_nested "use foo::{ out_of_order "use foo::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, Quux::{b, a, C}, yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};" ); +fmt_test_item!(multiline_nested_with_trailing_comma "use foo::{ + Quux::{ + a, + b, + C, + }, + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, + yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + out_of_order "use foo::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, Quux::{b, a, C,}, yxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,};" +); + fmt_test_item!(single_line_sort "use foo::{bar, baz, Quux::{a, b, C}};", out_of_order "use foo::{baz, Quux::{b, a, C}, bar};" ); +fmt_test_item!(single_line_sort_with_trailing_comma "use foo::{bar, baz, Quux::{a, b, C}};", + out_of_order "use foo::{baz, Quux::{b, a, C,}, bar,};" +); + fmt_test_item!(single_import_without_braces "use std::tx::tx_id;", braced_single_import "use std::tx::{tx_id};" ); + +fmt_test_item!(single_import_without_braces_with_trailing_comma "use std::tx::tx_id;", + braced_single_import "use std::tx::{tx_id,};" +); + +fmt_test_item!(single_import_multiline_with_braces "use std::tx::{ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + braced_single_import "use std::tx::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx};" +); + +fmt_test_item!(single_import_multiline_with_braces_with_trailing_comma "use std::tx::{ + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, +};", + braced_single_import "use std::tx::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,};" +); diff --git a/swayfmt/src/module/mod.rs b/swayfmt/src/module/mod.rs index db49d4f806c..de95433281c 100644 --- a/swayfmt/src/module/mod.rs +++ b/swayfmt/src/module/mod.rs @@ -4,7 +4,12 @@ use crate::{ utils::map::byte_span::{self, ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{Item, ItemKind, Module, ModuleKind}; +use sway_ast::{ + keywords::{ + ContractToken, Keyword, LibraryToken, PredicateToken, ScriptToken, SemicolonToken, Token, + }, + Item, ItemKind, Module, ModuleKind, +}; use sway_types::Spanned; pub(crate) mod item; @@ -18,7 +23,7 @@ impl Format for Module { ) -> Result<(), FormatterError> { write_comments(formatted_code, 0..self.span().start(), formatter)?; self.kind.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; // Format comments between module kind declaration and rest of items if !self.items.is_empty() { @@ -69,17 +74,17 @@ impl Format for ModuleKind { _formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - ModuleKind::Script { script_token } => { - write!(formatted_code, "{}", script_token.span().as_str())? + ModuleKind::Script { script_token: _ } => { + write!(formatted_code, "{}", ScriptToken::AS_STR)? } - ModuleKind::Contract { contract_token } => { - write!(formatted_code, "{}", contract_token.span().as_str())? + ModuleKind::Contract { contract_token: _ } => { + write!(formatted_code, "{}", ContractToken::AS_STR)? } - ModuleKind::Predicate { predicate_token } => { - write!(formatted_code, "{}", predicate_token.span().as_str())? + ModuleKind::Predicate { predicate_token: _ } => { + write!(formatted_code, "{}", PredicateToken::AS_STR)? } - ModuleKind::Library { library_token } => { - write!(formatted_code, "{}", library_token.span().as_str())?; + ModuleKind::Library { library_token: _ } => { + write!(formatted_code, "{}", LibraryToken::AS_STR)?; } }; diff --git a/swayfmt/src/module/submodule.rs b/swayfmt/src/module/submodule.rs index 0c2a6c4d31b..6edb91ab574 100644 --- a/swayfmt/src/module/submodule.rs +++ b/swayfmt/src/module/submodule.rs @@ -3,7 +3,11 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::submodule::Submodule; +use sway_ast::{ + keywords::{Keyword, ModToken, SemicolonToken, Token}, + submodule::Submodule, + PubToken, +}; use sway_types::Spanned; impl Format for Submodule { @@ -12,12 +16,12 @@ impl Format for Submodule { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some(pub_token) = &self.visibility { - write!(formatted_code, "{} ", pub_token.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } - write!(formatted_code, "{} ", self.mod_token.span().as_str())?; + write!(formatted_code, "{} ", ModToken::AS_STR)?; self.name.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; Ok(()) } } diff --git a/swayfmt/src/parse.rs b/swayfmt/src/parse.rs index 9d4ccadbbfb..17befe22cc3 100644 --- a/swayfmt/src/parse.rs +++ b/swayfmt/src/parse.rs @@ -1,9 +1,7 @@ use crate::{error::ParseFileError, Formatter, FormatterError}; -use std::path::PathBuf; use std::sync::Arc; use sway_ast::{attribute::Annotated, token::CommentedTokenStream, Module}; use sway_error::handler::{ErrorEmitted, Handler}; -use sway_types::SourceEngine; fn with_handler( run: impl FnOnce(&Handler) -> Result, @@ -16,13 +14,8 @@ fn with_handler( .ok_or(ParseFileError(errors)) } -pub fn parse_file( - source_engine: &SourceEngine, - src: Arc, - path: Option>, -) -> Result, ParseFileError> { - let source_id = path.map(|p| source_engine.get_source_id(p.as_ref())); - with_handler(|h| sway_parse::parse_file(h, src, source_id)) +pub fn parse_file(src: Arc) -> Result, ParseFileError> { + with_handler(|h| sway_parse::parse_file(h, src, None)) } pub fn lex(input: &Arc) -> Result { diff --git a/swayfmt/src/utils/language/attribute.rs b/swayfmt/src/utils/language/attribute.rs index daa6b7e5611..b9662bf8d56 100644 --- a/swayfmt/src/utils/language/attribute.rs +++ b/swayfmt/src/utils/language/attribute.rs @@ -8,12 +8,12 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::attribute::{Annotated, Attribute, AttributeArg, AttributeDecl, AttributeHashKind}; -use sway_types::{ - ast::{Delimiter, PunctKind}, - constants::DOC_COMMENT_ATTRIBUTE_NAME, - Spanned, +use sway_ast::{ + attribute::{Annotated, Attribute, AttributeArg, AttributeDecl, AttributeHashKind}, + keywords::{HashToken, Token}, + CommaToken, }; +use sway_types::{ast::Delimiter, constants::DOC_COMMENT_ATTRIBUTE_NAME, Spanned}; impl Format for Annotated { fn format( @@ -56,11 +56,12 @@ impl Format for AttributeArg { fn format( &self, formatted_code: &mut FormattedCode, - _formatter: &mut Formatter, + formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.name.span().as_str())?; + write!(formatted_code, "{}", self.name.as_str())?; if let Some(value) = &self.value { - write!(formatted_code, " = {}", value.span().as_str())?; + write!(formatted_code, " = ")?; + value.format(formatted_code, formatter)?; } Ok(()) @@ -114,11 +115,12 @@ impl Format for AttributeDecl { // invariant: attribute lists cannot be empty // `#` - let hash_type_token_span = match &self.hash_kind { - AttributeHashKind::Inner(_) => Err(FormatterError::HashBangAttributeError), - AttributeHashKind::Outer(hash_token) => Ok(hash_token.span()), + match &self.hash_kind { + AttributeHashKind::Inner(_) => return Err(FormatterError::HashBangAttributeError), + AttributeHashKind::Outer(_hash_token) => { + write!(formatted_code, "{}", HashToken::AS_STR)?; + } }; - write!(formatted_code, "{}", hash_type_token_span?.as_str())?; // `[` Self::open_square_bracket(formatted_code, formatter)?; let mut regular_attrs = regular_attrs.iter().peekable(); @@ -127,7 +129,7 @@ impl Format for AttributeDecl { formatter.shape.with_default_code_line(), |formatter| -> Result<(), FormatterError> { // name e.g. `storage` - write!(formatted_code, "{}", attr.name.span().as_str())?; + write!(formatted_code, "{}", attr.name.as_str())?; if let Some(args) = &attr.args { // `(` Self::open_parenthesis(formatted_code, formatter)?; @@ -141,7 +143,7 @@ impl Format for AttributeDecl { )?; // do not put a separator after the last attribute if regular_attrs.peek().is_some() { - write!(formatted_code, "{} ", PunctKind::Comma.as_char())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; } } // `]\n` diff --git a/swayfmt/src/utils/language/expr/abi_cast.rs b/swayfmt/src/utils/language/expr/abi_cast.rs index 14493f3f4d3..5c6545891ab 100644 --- a/swayfmt/src/utils/language/expr/abi_cast.rs +++ b/swayfmt/src/utils/language/expr/abi_cast.rs @@ -6,7 +6,7 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::AbiCastArgs; +use sway_ast::{keywords::Token, AbiCastArgs, CommaToken}; use sway_types::{ast::Delimiter, Spanned}; impl Format for AbiCastArgs { @@ -17,7 +17,7 @@ impl Format for AbiCastArgs { ) -> Result<(), FormatterError> { Self::open_parenthesis(formatted_code, formatter)?; self.name.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", self.comma_token.span().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; self.address.format(formatted_code, formatter)?; Self::close_parenthesis(formatted_code, formatter)?; diff --git a/swayfmt/src/utils/language/expr/asm_block.rs b/swayfmt/src/utils/language/expr/asm_block.rs index 19f92f5ea68..458bfec669f 100644 --- a/swayfmt/src/utils/language/expr/asm_block.rs +++ b/swayfmt/src/utils/language/expr/asm_block.rs @@ -9,6 +9,7 @@ use crate::{ use std::fmt::Write; use sway_ast::{ expr::asm::{AsmBlock, AsmBlockContents, AsmFinalExpr, AsmRegisterDeclaration}, + keywords::{AsmToken, ColonToken, Keyword, SemicolonToken, Token}, Instruction, }; use sway_types::{ast::Delimiter, Spanned}; @@ -56,7 +57,7 @@ fn format_asm_block( formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", asm_block.asm_token.span().as_str())?; + write!(formatted_code, "{}", AsmToken::AS_STR)?; formatter.with_shape( formatter.shape.with_default_code_line(), @@ -174,8 +175,8 @@ impl Format for AsmRegisterDeclaration { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.register.format(formatted_code, formatter)?; - if let Some((colon_token, expr)) = &self.value_opt { - write!(formatted_code, "{} ", colon_token.span().as_str())?; + if let Some((_colon_token, expr)) = &self.value_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; expr.format(formatted_code, formatter)?; } @@ -189,7 +190,7 @@ impl Format for Instruction { formatted_code: &mut FormattedCode, _formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", &self.op_code_ident().as_str())?; + write!(formatted_code, "{}", self.op_code_as_str())?; for arg in self.register_arg_idents() { write!(formatted_code, " {}", arg.as_str())? } @@ -206,10 +207,10 @@ impl Format for AsmBlockContents { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - for (instruction, semicolon_token) in self.instructions.iter() { + for (instruction, _semicolon_token) in self.instructions.iter() { write!(formatted_code, "{}", formatter.indent_to_str()?)?; instruction.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", semicolon_token.span().as_str())? + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)? } if let Some(final_expr) = &self.final_expr_opt { if formatter.shape.code_line.line_style == LineStyle::Multiline { @@ -232,8 +233,8 @@ impl Format for AsmFinalExpr { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.register.format(formatted_code, formatter)?; - if let Some((colon_token, ty)) = &self.ty_opt { - write!(formatted_code, "{} ", colon_token.span().as_str())?; + if let Some((_colon_token, ty)) = &self.ty_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; ty.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/utils/language/expr/assignable.rs b/swayfmt/src/utils/language/expr/assignable.rs index b5e278464dd..1df99ad70cf 100644 --- a/swayfmt/src/utils/language/expr/assignable.rs +++ b/swayfmt/src/utils/language/expr/assignable.rs @@ -6,7 +6,12 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{assignable::ElementAccess, expr::ReassignmentOp, Assignable, Expr}; +use sway_ast::{ + assignable::ElementAccess, + expr::ReassignmentOp, + keywords::{DotToken, StarToken, Token}, + Assignable, Expr, +}; use sway_types::Spanned; impl Format for ElementAccess { @@ -27,26 +32,21 @@ impl Format for ElementAccess { } ElementAccess::FieldProjection { target, - dot_token, + dot_token: _, name, } => { target.format(formatted_code, formatter)?; - write!(formatted_code, "{}", dot_token.span().as_str())?; + write!(formatted_code, "{}", DotToken::AS_STR)?; name.format(formatted_code, formatter)?; } ElementAccess::TupleFieldProjection { target, - dot_token, - field: _, - field_span, + dot_token: _, + field, + field_span: _, } => { target.format(formatted_code, formatter)?; - write!( - formatted_code, - "{}{}", - dot_token.span().as_str(), - field_span.as_str() - )?; + write!(formatted_code, "{}{}", DotToken::AS_STR, field)?; } } Ok(()) @@ -63,8 +63,11 @@ impl Format for Assignable { Assignable::ElementAccess(element_access) => { element_access.format(formatted_code, formatter)? } - Assignable::Deref { star_token, expr } => { - write!(formatted_code, "{}", star_token.span().as_str())?; + Assignable::Deref { + star_token: _, + expr, + } => { + write!(formatted_code, "{}", StarToken::AS_STR)?; expr.format(formatted_code, formatter)?; } } @@ -78,7 +81,7 @@ impl Format for ReassignmentOp { formatted_code: &mut FormattedCode, _formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, " {} ", self.span.as_str())?; + write!(formatted_code, " {} ", self.variant.as_str())?; Ok(()) } } diff --git a/swayfmt/src/utils/language/expr/collections.rs b/swayfmt/src/utils/language/expr/collections.rs index f175329bbd9..af34214f21c 100644 --- a/swayfmt/src/utils/language/expr/collections.rs +++ b/swayfmt/src/utils/language/expr/collections.rs @@ -6,7 +6,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::{ExprArrayDescriptor, ExprTupleDescriptor}; +use sway_ast::{ + keywords::{SemicolonToken, Token}, + CommaToken, ExprArrayDescriptor, ExprTupleDescriptor, +}; use sway_types::{ast::Delimiter, Spanned}; impl Format for ExprTupleDescriptor { @@ -20,18 +23,18 @@ impl Format for ExprTupleDescriptor { Self::Nil => {} Self::Cons { head, - comma_token, + comma_token: _, tail, } => match formatter.shape.code_line.line_style { LineStyle::Multiline => { write!(formatted_code, "{}", formatter.indent_to_str()?)?; head.format(formatted_code, formatter)?; - write!(formatted_code, "{}", comma_token.span().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; tail.format(formatted_code, formatter)?; } _ => { head.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", comma_token.span().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; tail.format(formatted_code, formatter)?; } }, @@ -91,11 +94,11 @@ impl Format for ExprArrayDescriptor { } Self::Repeat { value, - semicolon_token, + semicolon_token: _, length, } => { value.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", semicolon_token.span().as_str())?; + write!(formatted_code, "{} ", SemicolonToken::AS_STR)?; length.format(formatted_code, formatter)?; } } diff --git a/swayfmt/src/utils/language/expr/conditional.rs b/swayfmt/src/utils/language/expr/conditional.rs index f21e71c133d..b97d5896c47 100644 --- a/swayfmt/src/utils/language/expr/conditional.rs +++ b/swayfmt/src/utils/language/expr/conditional.rs @@ -10,7 +10,11 @@ use crate::{ }, }; use std::{fmt::Write, ops::Range}; -use sway_ast::{expr::LoopControlFlow, IfCondition, IfExpr, MatchBranch, MatchBranchKind}; +use sway_ast::{ + expr::LoopControlFlow, + keywords::{ElseToken, EqToken, FatRightArrowToken, IfToken, Keyword, LetToken, Token}, + CommaToken, IfCondition, IfExpr, MatchBranch, MatchBranchKind, +}; use sway_types::{ast::Delimiter, Spanned}; impl Format for IfExpr { @@ -125,7 +129,7 @@ fn format_if_condition( formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{} ", if_expr.if_token.span().as_str())?; + write!(formatted_code, "{} ", IfToken::AS_STR)?; if formatter.shape.code_line.line_style == LineStyle::Multiline { formatter.indent(); if_expr.condition.format(formatted_code, formatter)?; @@ -181,11 +185,11 @@ fn format_else_opt( )?; if comments_written { - write!(else_if_str, "{}", formatter.indent_to_str()?,)?; + write!(else_if_str, "{}", formatter.indent_to_str()?)?; } else { write!(else_if_str, " ")?; } - write!(else_if_str, "{}", else_token.span().as_str())?; + write!(else_if_str, "{}", ElseToken::AS_STR)?; match &control_flow { LoopControlFlow::Continue(if_expr) => { write!(else_if_str, " ")?; @@ -263,14 +267,14 @@ impl Format for IfCondition { expr.format(formatted_code, formatter)?; } Self::Let { - let_token, + let_token: _, lhs, - eq_token, + eq_token: _, rhs, } => { - write!(formatted_code, "{} ", let_token.span().as_str())?; + write!(formatted_code, "{} ", LetToken::AS_STR)?; lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } } @@ -286,11 +290,7 @@ impl Format for MatchBranch { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.pattern.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - self.fat_right_arrow_token.span().as_str() - )?; + write!(formatted_code, " {} ", FatRightArrowToken::AS_STR)?; self.kind.format(formatted_code, formatter)?; Ok(()) @@ -348,13 +348,16 @@ impl Format for MatchBranchKind { write!(formatted_code, "{}", formatter.indent_to_str()?)?; } Self::close_curly_brace(formatted_code, formatter)?; - if let Some(comma_token) = comma_token_opt { - write!(formatted_code, "{}", comma_token.span().as_str())?; + if comma_token_opt.is_some() { + write!(formatted_code, "{}", CommaToken::AS_STR)?; } } - Self::Expr { expr, comma_token } => { + Self::Expr { + expr, + comma_token: _, + } => { expr.format(formatted_code, formatter)?; - write!(formatted_code, "{}", comma_token.span().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; } } diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index a65eb3bc527..95a53c01c30 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -10,11 +10,8 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - brackets::Parens, - keywords::{CommaToken, DotToken}, - punctuated::Punctuated, - Braces, CodeBlockContents, Expr, ExprStructField, IfExpr, MatchBranch, PathExpr, - PathExprSegment, + brackets::Parens, keywords::*, punctuated::Punctuated, Braces, CodeBlockContents, Expr, + ExprStructField, IfExpr, MatchBranch, PathExpr, PathExprSegment, }; use sway_types::{ast::Delimiter, Spanned}; @@ -79,7 +76,7 @@ fn two_parts_expr( )?; } _ => { - write!(formatted_code, " {} ", operator,)?; + write!(formatted_code, " {} ", operator)?; } } write!(formatted_code, "{}", rhs_code)?; @@ -99,8 +96,8 @@ impl Format for Expr { } Self::Path(path) => path.format(formatted_code, formatter)?, Self::Literal(lit) => lit.format(formatted_code, formatter)?, - Self::AbiCast { abi_token, args } => { - write!(formatted_code, "{}", abi_token.span().as_str())?; + Self::AbiCast { abi_token: _, args } => { + write!(formatted_code, "{}", AbiToken::AS_STR)?; args.get().format(formatted_code, formatter)?; } Self::Struct { path, fields } => { @@ -205,7 +202,7 @@ impl Format for Expr { .get_line_style(None, Some(body_width), &formatter.config); if formatter.shape.code_line.line_style == LineStyle::Multiline { - // Expr needs to be splitten into multiple lines + // Expr needs to be split into multiple lines array_descriptor.format(formatted_code, formatter)?; } else { // Expr fits in a single line @@ -218,10 +215,10 @@ impl Format for Expr { } Self::Asm(asm_block) => asm_block.format(formatted_code, formatter)?, Self::Return { - return_token, + return_token: _, expr_opt, } => { - write!(formatted_code, "{}", return_token.span().as_str())?; + write!(formatted_code, "{}", ReturnToken::AS_STR)?; if let Some(expr) = &expr_opt { write!(formatted_code, " ")?; expr.format(formatted_code, formatter)?; @@ -229,11 +226,11 @@ impl Format for Expr { } Self::If(if_expr) => if_expr.format(formatted_code, formatter)?, Self::Match { - match_token, + match_token: _, value, branches, } => { - write!(formatted_code, "{} ", match_token.span().as_str())?; + write!(formatted_code, "{} ", MatchToken::AS_STR)?; value.format(formatted_code, formatter)?; write!(formatted_code, " ")?; if !branches.get().is_empty() { @@ -250,7 +247,7 @@ impl Format for Expr { } } Self::While { - while_token, + while_token: _, condition, block, } => { @@ -259,7 +256,7 @@ impl Format for Expr { .shape .with_code_line_from(LineStyle::Normal, ExprKind::Function), |formatter| -> Result<(), FormatterError> { - write!(formatted_code, "{} ", while_token.span().as_str())?; + write!(formatted_code, "{} ", WhileToken::AS_STR)?; condition.format(formatted_code, formatter)?; IfExpr::open_curly_brace(formatted_code, formatter)?; block.get().format(formatted_code, formatter)?; @@ -269,8 +266,8 @@ impl Format for Expr { )?; } Self::For { - for_token, - in_token, + for_token: _, + in_token: _, value_pattern, iterator, block, @@ -280,9 +277,9 @@ impl Format for Expr { .shape .with_code_line_from(LineStyle::Normal, ExprKind::Function), |formatter| -> Result<(), FormatterError> { - write!(formatted_code, "{} ", for_token.span().as_str())?; + write!(formatted_code, "{} ", ForToken::AS_STR)?; value_pattern.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", in_token.span().as_str())?; + write!(formatted_code, " {} ", InToken::AS_STR)?; iterator.format(formatted_code, formatter)?; IfExpr::open_curly_brace(formatted_code, formatter)?; block.get().format(formatted_code, formatter)?; @@ -305,7 +302,7 @@ impl Format for Expr { Self::open_parenthesis(formatted_code, formatter)?; let (_, args_str) = write_function_call_arguments(args.get(), formatter)?; - write!(formatted_code, "{}", args_str,)?; + write!(formatted_code, "{}", args_str)?; Self::close_parenthesis(formatted_code, formatter)?; Ok(()) @@ -381,7 +378,7 @@ impl Format for Expr { } Self::FieldProjection { target, - dot_token, + dot_token: _, name, } => { let prev_length = formatted_code.len(); @@ -398,124 +395,124 @@ impl Format for Expr { formatted_code, "\n{}{}", formatter.indent_to_str()?, - dot_token.span().as_str() + DotToken::AS_STR, )?; name.format(formatted_code, formatter)?; formatter.unindent(); } else { - write!(formatted_code, "{}", dot_token.span().as_str())?; + write!(formatted_code, "{}", DotToken::AS_STR)?; name.format(formatted_code, formatter)?; } } Self::TupleFieldProjection { target, - dot_token, - field: _, - field_span, + dot_token: _, + field, + field_span: _, } => { target.format(formatted_code, formatter)?; - write!( - formatted_code, - "{}{}", - dot_token.span().as_str(), - field_span.as_str(), - )?; + write!(formatted_code, "{}{}", DotToken::AS_STR, field)?; } Self::Ref { - ampersand_token, + ampersand_token: _, mut_token, expr, } => { - // TODO-IG: Add unit tests. - write!(formatted_code, "{}", ampersand_token.span().as_str())?; - if let Some(mut_token) = mut_token { - write!(formatted_code, "{} ", mut_token.span().as_str())?; + write!(formatted_code, "{}", AmpersandToken::AS_STR)?; + if mut_token.is_some() { + write!(formatted_code, "{} ", MutToken::AS_STR)?; } expr.format(formatted_code, formatter)?; } - Self::Deref { star_token, expr } => { - write!(formatted_code, "{}", star_token.span().as_str())?; + Self::Deref { + star_token: _, + expr, + } => { + write!(formatted_code, "{}", StarToken::AS_STR)?; expr.format(formatted_code, formatter)?; } - Self::Not { bang_token, expr } => { - write!(formatted_code, "{}", bang_token.span().as_str())?; + Self::Not { + bang_token: _, + expr, + } => { + write!(formatted_code, "{}", BangToken::AS_STR)?; expr.format(formatted_code, formatter)?; } Self::Pow { lhs, - double_star_token, + double_star_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", double_star_token.span().as_str())?; + write!(formatted_code, " {} ", DoubleStarToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Mul { lhs, - star_token, + star_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", star_token.span().as_str())?; + write!(formatted_code, " {} ", StarToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Div { lhs, - forward_slash_token, + forward_slash_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", forward_slash_token.span().as_str())?; + write!(formatted_code, " {} ", ForwardSlashToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Modulo { lhs, - percent_token, + percent_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", percent_token.span().as_str())?; + write!(formatted_code, " {} ", PercentToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Add { lhs, - add_token, + add_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", add_token.span().as_str())?; + write!(formatted_code, " {} ", AddToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Sub { lhs, - sub_token, + sub_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", sub_token.span().as_str())?; + write!(formatted_code, " {} ", SubToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Shl { lhs, - shl_token, + shl_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", shl_token.span().as_str())?; + write!(formatted_code, " {} ", ShlToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::Shr { lhs, - shr_token, + shr_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", shr_token.span().as_str())?; + write!(formatted_code, " {} ", ShrToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::BitAnd { lhs, - ampersand_token, + ampersand_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; @@ -525,18 +522,18 @@ impl Format for Expr { formatted_code, "\n{}{} ", formatter.indent_to_str()?, - ampersand_token.span().as_str() + AmpersandToken::AS_STR, )?; } _ => { - write!(formatted_code, " {} ", ampersand_token.span().as_str())?; + write!(formatted_code, " {} ", AmpersandToken::AS_STR)?; } } rhs.format(formatted_code, formatter)?; } Self::BitXor { lhs, - caret_token, + caret_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; @@ -546,18 +543,18 @@ impl Format for Expr { formatted_code, "\n{}{} ", formatter.indent_to_str()?, - caret_token.span().as_str() + CaretToken::AS_STR, )?; } _ => { - write!(formatted_code, " {} ", caret_token.span().as_str())?; + write!(formatted_code, " {} ", CaretToken::AS_STR)?; } } rhs.format(formatted_code, formatter)?; } Self::BitOr { lhs, - pipe_token, + pipe_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; @@ -567,81 +564,77 @@ impl Format for Expr { formatted_code, "\n{}{} ", formatter.indent_to_str()?, - pipe_token.span().as_str() + PipeToken::AS_STR, )?; } _ => { - write!(formatted_code, " {} ", pipe_token.span().as_str())?; + write!(formatted_code, " {} ", PipeToken::AS_STR)?; } } rhs.format(formatted_code, formatter)?; } Self::Equal { lhs, - double_eq_token, + double_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", double_eq_token.span().as_str())?; + write!(formatted_code, " {} ", DoubleEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::NotEqual { lhs, - bang_eq_token, + bang_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", bang_eq_token.span().as_str())?; + write!(formatted_code, " {} ", BangEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::LessThan { lhs, - less_than_token, + less_than_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", less_than_token.span().as_str())?; + write!(formatted_code, " {} ", LessThanToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::GreaterThan { lhs, - greater_than_token, + greater_than_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", greater_than_token.span().as_str())?; + write!(formatted_code, " {} ", GreaterThanToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::LessThanEq { lhs, - less_than_eq_token, + less_than_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", less_than_eq_token.span().as_str())?; + write!(formatted_code, " {} ", LessThanEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::GreaterThanEq { lhs, - greater_than_eq_token, + greater_than_eq_token: _, rhs, } => { lhs.format(formatted_code, formatter)?; - write!( - formatted_code, - " {} ", - greater_than_eq_token.span().as_str() - )?; + write!(formatted_code, " {} ", GreaterThanEqToken::AS_STR)?; rhs.format(formatted_code, formatter)?; } Self::LogicalAnd { lhs, - double_ampersand_token, + double_ampersand_token: _, rhs, } => { two_parts_expr( lhs, - double_ampersand_token.span().as_str(), + DoubleAmpersandToken::AS_STR, rhs, formatted_code, formatter, @@ -649,16 +642,10 @@ impl Format for Expr { } Self::LogicalOr { lhs, - double_pipe_token, + double_pipe_token: _, rhs, } => { - two_parts_expr( - lhs, - double_pipe_token.span().as_str(), - rhs, - formatted_code, - formatter, - )?; + two_parts_expr(lhs, DoublePipeToken::AS_STR, rhs, formatted_code, formatter)?; } Self::Reassignment { assignable, @@ -669,11 +656,11 @@ impl Format for Expr { reassignment_op.format(formatted_code, formatter)?; expr.format(formatted_code, formatter)?; } - Self::Break { break_token } => { - write!(formatted_code, "{}", break_token.span().as_str())?; + Self::Break { break_token: _ } => { + write!(formatted_code, "{}", BreakToken::AS_STR)?; } - Self::Continue { continue_token } => { - write!(formatted_code, "{}", continue_token.span().as_str())?; + Self::Continue { continue_token: _ } => { + write!(formatted_code, "{}", ContinueToken::AS_STR)?; } } @@ -888,7 +875,7 @@ where fn format_method_call( target: &Expr, - dot_token: &DotToken, + _dot_token: &DotToken, path_seg: &PathExprSegment, contract_args_opt: &Option>>, args: &Parens>, @@ -906,7 +893,7 @@ fn format_method_call( write!(formatted_code, "\n{}", formatter.indent_to_str()?)?; } - write!(formatted_code, "{}", dot_token.span().as_str())?; + write!(formatted_code, "{}", DotToken::AS_STR)?; path_seg.format(formatted_code, formatter)?; if let Some(contract_args) = &contract_args_opt { @@ -927,7 +914,7 @@ fn format_method_call( Expr::open_parenthesis(formatted_code, formatter)?; let (args_inline, args_str) = write_function_call_arguments(args.get(), formatter)?; - write!(formatted_code, "{}", args_str,)?; + write!(formatted_code, "{}", args_str)?; Expr::close_parenthesis(formatted_code, formatter)?; if formatter.shape.code_line.expr_new_line { @@ -942,15 +929,15 @@ fn get_field_width( ) -> Result<(usize, usize), FormatterError> { let mut largest_field: usize = 0; let mut body_width: usize = 3; // this is taking into account the opening brace, the following space and the ending brace. - for (field, comma_token) in &fields.value_separator_pairs { + for (field, _comma_token) in &fields.value_separator_pairs { let mut field_length = field.field_name.as_str().chars().count(); - if let Some((colon_token, expr)) = &field.expr_opt { + if let Some((_colon_token, expr)) = &field.expr_opt { let mut buf = String::new(); - write!(buf, "{} ", colon_token.span().as_str())?; + write!(buf, "{} ", ColonToken::AS_STR)?; expr.format(&mut buf, formatter)?; field_length += buf.chars().count(); } - field_length += comma_token.span().as_str().chars().count(); + field_length += CommaToken::AS_STR.chars().count(); body_width += &field_length + 1; // accounting for the following space if field_length > largest_field { @@ -959,9 +946,9 @@ fn get_field_width( } if let Some(final_value) = &fields.final_value_opt { let mut field_length = final_value.field_name.as_str().chars().count(); - if let Some((colon_token, expr)) = &final_value.expr_opt { + if let Some((_colon_token, expr)) = &final_value.expr_opt { let mut buf = String::new(); - write!(buf, "{} ", colon_token.span().as_str())?; + write!(buf, "{} ", ColonToken::AS_STR)?; expr.format(&mut buf, formatter)?; field_length += buf.chars().count(); } diff --git a/swayfmt/src/utils/language/expr/struct_field.rs b/swayfmt/src/utils/language/expr/struct_field.rs index 0a51864cc6c..99764c34226 100644 --- a/swayfmt/src/utils/language/expr/struct_field.rs +++ b/swayfmt/src/utils/language/expr/struct_field.rs @@ -10,7 +10,10 @@ use crate::{ }, }; use std::fmt::Write; -use sway_ast::ExprStructField; +use sway_ast::{ + keywords::{ColonToken, Token}, + ExprStructField, +}; use sway_types::{ast::Delimiter, Spanned}; impl Format for ExprStructField { @@ -19,8 +22,8 @@ impl Format for ExprStructField { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.field_name.span().as_str())?; - if let Some((colon_token, expr)) = &self.expr_opt { + write!(formatted_code, "{}", self.field_name.as_str())?; + if let Some((_colon_token, expr)) = &self.expr_opt { formatter.with_shape( formatter .shape @@ -37,12 +40,7 @@ impl Format for ExprStructField { } else { expr_str }; - write!( - formatted_code, - "{} {}", - colon_token.span().as_str(), - expr_str - )?; + write!(formatted_code, "{} {}", ColonToken::AS_STR, expr_str)?; Ok(()) }, )?; diff --git a/swayfmt/src/utils/language/expr/tests.rs b/swayfmt/src/utils/language/expr/tests.rs index ef84d8b0c61..6472940e346 100644 --- a/swayfmt/src/utils/language/expr/tests.rs +++ b/swayfmt/src/utils/language/expr/tests.rs @@ -264,3 +264,13 @@ intermediate_whitespace "{ let i = 42; }"); + +fmt_test_expr!(basic_for_loop +"for iter in [0, 1, 7, 8, 15] { + let i = 42; +}", +intermediate_whitespace +"for iter in [0, 1, 7, 8, 15]{ +let i = 42; +}" +); diff --git a/swayfmt/src/utils/language/literal.rs b/swayfmt/src/utils/language/literal.rs index 3918f4de7f6..8fecedae9eb 100644 --- a/swayfmt/src/utils/language/literal.rs +++ b/swayfmt/src/utils/language/literal.rs @@ -3,7 +3,7 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::Literal; +use sway_ast::{literal::LitBoolType, LitIntType, Literal}; impl Format for Literal { fn format( @@ -12,16 +12,56 @@ impl Format for Literal { _formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - // TODO: do more digging into `Literal` and see if there is more formatting to do. - Self::String(lit_string) => write!(formatted_code, "{}", lit_string.span.as_str())?, - Self::Char(lit_char) => write!(formatted_code, "{}", lit_char.span.as_str())?, + Self::String(lit_string) => write!(formatted_code, "\"{}\"", lit_string.parsed)?, + Self::Char(lit_char) => write!(formatted_code, "\'{}\'", lit_char.parsed)?, Self::Int(lit_int) => { - write!(formatted_code, "{}", lit_int.span.as_str())?; - if let Some((_, ty_span)) = &lit_int.ty_opt { - write!(formatted_code, "{}", ty_span.as_str())?; + // It is tricky to support formatting of `LitInt` for an arbitrary `LitInt` + // that is potentially not backed by source code, but constructed in-memory. + // + // E.g., a constructed `LitInt` representing 1000 can have only the numeric value + // (LitInt::parsed) specified, in which case we can simply output the value. + // If it has the type specified (LitInt::ty_opt), we can output the type next to the + // value, e.g., 1000u16. + // But a `LitInt` backed by code can have an arbitrary representation that includes + // underscores. E.g., 1_00_00__u16. In that case we need to preserve the original + // representation. + // + // The taken approach is the following. If the length of the `LitInt::span` is zero, + // we assume that it is not backed by source code and render the canonical representation, + // 1000u16 in the above example. Otherwise, we assume that it is backed by source code + // and use the actual spans to obtain the strings. + + if lit_int.span.is_empty() { + write!(formatted_code, "{}", lit_int.parsed)?; + if let Some((int_type, _)) = &lit_int.ty_opt { + let int_type = match int_type { + LitIntType::U8 => "u8", + LitIntType::U16 => "u16", + LitIntType::U32 => "u32", + LitIntType::U64 => "u64", + LitIntType::U256 => "u256", + LitIntType::I8 => "i8", + LitIntType::I16 => "i16", + LitIntType::I32 => "i32", + LitIntType::I64 => "i64", + }; + write!(formatted_code, "{}", int_type)?; + } + } else { + write!(formatted_code, "{}", lit_int.span.as_str())?; + if let Some((_, ty_span)) = &lit_int.ty_opt { + write!(formatted_code, "{}", ty_span.as_str())?; + } } } - Self::Bool(lit_bool) => write!(formatted_code, "{}", lit_bool.span.as_str())?, + Self::Bool(lit_bool) => write!( + formatted_code, + "{}", + match lit_bool.kind { + LitBoolType::True => "true", + LitBoolType::False => "false", + } + )?, } Ok(()) } diff --git a/swayfmt/src/utils/language/path.rs b/swayfmt/src/utils/language/path.rs index 78711542b7f..6d5a84ded1d 100644 --- a/swayfmt/src/utils/language/path.rs +++ b/swayfmt/src/utils/language/path.rs @@ -7,7 +7,8 @@ use crate::{ }; use std::{fmt::Write, vec}; use sway_ast::{ - keywords::Token, PathExpr, PathExprSegment, PathType, PathTypeSegment, QualifiedPathRoot, + keywords::{AsToken, Keyword, Token}, + DoubleColonToken, PathExpr, PathExprSegment, PathType, PathTypeSegment, QualifiedPathRoot, }; use sway_types::Spanned; @@ -17,7 +18,7 @@ impl Format for PathExpr { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some((qualified_path_root, double_colon_token)) = &self.root_opt { + if let Some((qualified_path_root, _double_colon_token)) = &self.root_opt { if let Some(root) = &qualified_path_root { open_angle_bracket(formatted_code)?; root.clone() @@ -25,11 +26,11 @@ impl Format for PathExpr { .format(formatted_code, formatter)?; close_angle_bracket(formatted_code)?; } - write!(formatted_code, "{}", double_colon_token.ident().as_str())?; + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } self.prefix.format(formatted_code, formatter)?; - for (double_colon_token, path_expr_segment) in self.suffix.iter() { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + for (_double_colon_token, path_expr_segment) in self.suffix.iter() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; path_expr_segment.format(formatted_code, formatter)?; } @@ -46,8 +47,8 @@ impl Format for PathExprSegment { // name self.name.format(formatted_code, formatter)?; // generics `::` - if let Some((double_colon_token, generic_args)) = &self.generics_opt { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + if let Some((_double_colon_token, generic_args)) = &self.generics_opt { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; generic_args.format(formatted_code, formatter)?; } @@ -62,10 +63,9 @@ impl Format for QualifiedPathRoot { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.ty.format(formatted_code, formatter)?; - if let Some((as_token, path_type)) = &self.as_trait { - write!(formatted_code, " {} ", as_token.span().as_str())?; - path_type.format(formatted_code, formatter)?; - } + let (_as_token, path_type) = &self.as_trait; + write!(formatted_code, " {} ", AsToken::AS_STR)?; + path_type.format(formatted_code, formatter)?; Ok(()) } @@ -77,7 +77,7 @@ impl Format for PathType { formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if let Some((root_opt, double_colon_token)) = &self.root_opt { + if let Some((root_opt, _double_colon_token)) = &self.root_opt { if let Some(qualified_path_root) = &root_opt { open_angle_bracket(formatted_code)?; qualified_path_root @@ -86,11 +86,11 @@ impl Format for PathType { .format(formatted_code, formatter)?; close_angle_bracket(formatted_code)?; } - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } self.prefix.format(formatted_code, formatter)?; - for (double_colon_token, path_type_segment) in self.suffix.iter() { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + for (_double_colon_token, path_type_segment) in self.suffix.iter() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; path_type_segment.format(formatted_code, formatter)?; } @@ -105,11 +105,11 @@ impl Format for PathTypeSegment { formatter: &mut Formatter, ) -> Result<(), FormatterError> { // name - write!(formatted_code, "{}", self.name.span().as_str())?; + write!(formatted_code, "{}", self.name.as_str())?; // generics `::` if let Some((double_colon_opt, generic_args)) = &self.generics_opt { - if let Some(double_colon_token) = &double_colon_opt { - write!(formatted_code, "{}", double_colon_token.span().as_str())?; + if double_colon_opt.is_some() { + write!(formatted_code, "{}", DoubleColonToken::AS_STR)?; } generic_args.format(formatted_code, formatter)?; } diff --git a/swayfmt/src/utils/language/pattern.rs b/swayfmt/src/utils/language/pattern.rs index 5c95b2e0ba3..655db700939 100644 --- a/swayfmt/src/utils/language/pattern.rs +++ b/swayfmt/src/utils/language/pattern.rs @@ -10,6 +10,7 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ + keywords::{ColonToken, DoubleDotToken, Keyword, MutToken, RefToken, Token, UnderscoreToken}, Braces, CommaToken, ExprTupleDescriptor, PathExpr, Pattern, PatternStructField, Punctuated, }; use sway_types::{ast::Delimiter, Spanned}; @@ -30,19 +31,19 @@ impl Format for Pattern { formatted_code.push_str(" | "); rhs.format(formatted_code, formatter)?; } - Self::Wildcard { underscore_token } => { - formatted_code.push_str(underscore_token.span().as_str()) - } + Self::Wildcard { + underscore_token: _, + } => formatted_code.push_str(UnderscoreToken::AS_STR), Self::Var { reference, mutable, name, } => { - if let Some(ref_token) = reference { - write!(formatted_code, "{} ", ref_token.span().as_str())?; + if reference.is_some() { + write!(formatted_code, "{} ", RefToken::AS_STR)?; } - if let Some(mut_token) = mutable { - write!(formatted_code, "{} ", mut_token.span().as_str())?; + if mutable.is_some() { + write!(formatted_code, "{} ", MutToken::AS_STR)?; } name.format(formatted_code, formatter)?; } @@ -188,16 +189,16 @@ impl Format for PatternStructField { formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self { - Self::Rest { token } => { - write!(formatted_code, "{}", token.span().as_str())?; + Self::Rest { token: _ } => { + write!(formatted_code, "{}", DoubleDotToken::AS_STR)?; } Self::Field { field_name, pattern_opt, } => { - write!(formatted_code, "{}", field_name.span().as_str())?; - if let Some((colon_token, pattern)) = pattern_opt { - write!(formatted_code, "{} ", colon_token.span().as_str())?; + write!(formatted_code, "{}", field_name.as_str())?; + if let Some((_colon_token, pattern)) = pattern_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; pattern.format(formatted_code, formatter)?; } } @@ -213,12 +214,12 @@ fn get_field_width( ) -> Result<(usize, usize), FormatterError> { let mut largest_field: usize = 0; let mut body_width: usize = 3; // this is taking into account the opening brace, the following space and the ending brace. - for (field, comma_token) in &fields.value_separator_pairs { + for (field, _comma_token) in &fields.value_separator_pairs { let mut field_str = FormattedCode::new(); field.format(&mut field_str, formatter)?; let mut field_length = field_str.chars().count(); - field_length += comma_token.span().as_str().chars().count(); + field_length += CommaToken::AS_STR.chars().count(); body_width += &field_length + 1; // accounting for the following space if field_length > largest_field { diff --git a/swayfmt/src/utils/language/punctuated.rs b/swayfmt/src/utils/language/punctuated.rs index a06a6c68e55..ff488a60864 100644 --- a/swayfmt/src/utils/language/punctuated.rs +++ b/swayfmt/src/utils/language/punctuated.rs @@ -8,8 +8,9 @@ use crate::{ }; use std::fmt::Write; use sway_ast::{ - keywords::CommaToken, punctuated::Punctuated, ConfigurableField, ItemStorage, StorageEntry, - StorageField, TypeField, + keywords::{ColonToken, CommaToken, EqToken, InToken, Keyword, Token}, + punctuated::Punctuated, + ConfigurableField, ItemStorage, PubToken, StorageEntry, StorageField, TypeField, }; use sway_types::{ast::PunctKind, Ident, Spanned}; @@ -27,7 +28,7 @@ where formatted_code: &mut FormattedCode, formatter: &mut Formatter, ) -> Result<(), FormatterError> { - if !self.value_separator_pairs.is_empty() || self.final_value_opt.is_some() { + if !self.is_empty() { match formatter.shape.code_line.line_style { LineStyle::Normal => { write!( @@ -55,7 +56,7 @@ where if !formatted_code.ends_with('\n') { writeln!(formatted_code)?; } - if !self.value_separator_pairs.is_empty() || self.final_value_opt.is_some() { + if !self.is_empty() { formatter.write_indent_into_buffer(formatted_code)?; } @@ -191,8 +192,8 @@ impl Format for Ident { _formatter: &mut Formatter, ) -> Result<(), FormatterError> { match self.is_raw_ident() { - true => write!(formatted_code, "{}{}", RAW_MODIFIER, self.span().as_str())?, - false => write!(formatted_code, "{}", self.span().as_str())?, + true => write!(formatted_code, "{}{}", RAW_MODIFIER, self.as_str())?, + false => write!(formatted_code, "{}", self.as_str())?, } Ok(()) @@ -206,14 +207,14 @@ impl Format for TypeField { formatter: &mut Formatter, ) -> Result<(), FormatterError> { // If there is a visibility token add it to the formatted_code with a ` ` after it. - if let Some(visibility) = &self.visibility { - write!(formatted_code, "{} ", visibility.span().as_str())?; + if self.visibility.is_some() { + write!(formatted_code, "{} ", PubToken::AS_STR)?; } write!( formatted_code, "{}{} ", - self.name.span().as_str(), - self.colon_token.span().as_str(), + self.name.as_str(), + ColonToken::AS_STR, )?; self.ty.format(formatted_code, formatter)?; @@ -233,11 +234,11 @@ impl Format for ConfigurableField { write!( formatted_code, "{}{} ", - self.name.span().as_str(), - self.colon_token.span().as_str(), + self.name.as_str(), + ColonToken::AS_STR, )?; self.ty.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", self.eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; Ok(()) }, @@ -258,17 +259,17 @@ impl Format for StorageField { formatter.with_shape( formatter.shape.with_default_code_line(), |formatter| -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.name.span().as_str())?; - if let Some(in_token) = &self.in_token { - write!(formatted_code, " {}", in_token.span().as_str())?; + write!(formatted_code, "{}", self.name.as_str())?; + if self.in_token.is_some() { + write!(formatted_code, " {} ", InToken::AS_STR)?; } if let Some(key_expr) = &self.key_expr { - write!(formatted_code, " {}", key_expr.span().as_str())?; + key_expr.format(formatted_code, formatter)?; } - write!(formatted_code, "{} ", self.colon_token.span().as_str())?; + write!(formatted_code, "{} ", ColonToken::AS_STR)?; self.ty.format(formatted_code, formatter)?; - write!(formatted_code, " {} ", self.eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; Ok(()) }, @@ -328,7 +329,7 @@ impl Format for CommaToken { formatted_code: &mut FormattedCode, _formatter: &mut Formatter, ) -> Result<(), FormatterError> { - write!(formatted_code, "{}", self.span().as_str())?; + write!(formatted_code, "{}", CommaToken::AS_STR)?; Ok(()) } diff --git a/swayfmt/src/utils/language/statement.rs b/swayfmt/src/utils/language/statement.rs index ffbcd443f66..1359161bf2c 100644 --- a/swayfmt/src/utils/language/statement.rs +++ b/swayfmt/src/utils/language/statement.rs @@ -3,7 +3,10 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{Expr, Parens, Punctuated, Statement, StatementLet}; +use sway_ast::{ + keywords::{ColonToken, EqToken, Keyword, LetToken, SemicolonToken, Token}, + Expr, Parens, Punctuated, Statement, StatementLet, +}; use sway_types::{Span, Spanned}; impl Format for Statement { @@ -20,7 +23,7 @@ impl Format for Statement { } /// Remove arguments from the expression if the expression is a method call if -/// the method is a simple two path call (foo.bar()). This needed because in +/// the method is a simple two path call (foo.bar()). This is needed because in /// method calls of two parts they are never broke into multiple lines. /// Arguments however can be broken into multiple lines, and that is handled /// by `write_function_call_arguments` @@ -117,11 +120,11 @@ fn format_statement( } else { expr.format(formatted_code, formatter)?; } - if let Some(semicolon) = semicolon_token_opt { + if semicolon_token_opt.is_some() { if formatter.shape.code_line.line_style == LineStyle::Inline { - write!(formatted_code, "{}", semicolon.span().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; } else { - writeln!(formatted_code, "{}", semicolon.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; } } } @@ -140,24 +143,24 @@ impl Format for StatementLet { formatter: &mut Formatter, ) -> Result<(), FormatterError> { // `let ` - write!(formatted_code, "{} ", self.let_token.span().as_str())?; + write!(formatted_code, "{} ", LetToken::AS_STR)?; // pattern self.pattern.format(formatted_code, formatter)?; // `: Ty` - if let Some(ty) = &self.ty_opt { - write!(formatted_code, "{} ", ty.0.span().as_str())?; - ty.1.format(formatted_code, formatter)?; + if let Some((_colon_token, ty)) = &self.ty_opt { + write!(formatted_code, "{} ", ColonToken::AS_STR)?; + ty.format(formatted_code, formatter)?; } // ` = ` - write!(formatted_code, " {} ", self.eq_token.span().as_str())?; + write!(formatted_code, " {} ", EqToken::AS_STR)?; // expr self.expr.format(formatted_code, formatter)?; if formatter.shape.code_line.line_style == LineStyle::Inline { // `;` - write!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + write!(formatted_code, "{}", SemicolonToken::AS_STR)?; } else { // `;\n` - writeln!(formatted_code, "{}", self.semicolon_token.span().as_str())?; + writeln!(formatted_code, "{}", SemicolonToken::AS_STR)?; } Ok(()) diff --git a/swayfmt/src/utils/language/ty.rs b/swayfmt/src/utils/language/ty.rs index a509cca1567..327ed8165cc 100644 --- a/swayfmt/src/utils/language/ty.rs +++ b/swayfmt/src/utils/language/ty.rs @@ -6,8 +6,12 @@ use std::fmt::Write; use sway_ast::{ brackets::SquareBrackets, expr::Expr, - keywords::{AmpersandToken, MutToken, PtrToken, SliceToken, StrToken, Token, UnderscoreToken}, + keywords::{ + AmpersandToken, BangToken, Keyword, MutToken, PtrToken, SemicolonToken, SliceToken, + StrToken, Token, UnderscoreToken, + }, ty::{Ty, TyArrayDescriptor, TyTupleDescriptor}, + CommaToken, }; use sway_types::{ast::Delimiter, Spanned}; @@ -24,39 +28,35 @@ impl Format for Ty { write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; Ok(()) } - Self::Infer { underscore_token } => format_infer(formatted_code, underscore_token), + Self::Infer { + underscore_token: _, + } => format_infer(formatted_code), Self::Path(path_ty) => path_ty.format(formatted_code, formatter), Self::StringSlice(_) => { - write!(formatted_code, "str")?; + write!(formatted_code, "{}", StrToken::AS_STR)?; Ok(()) } - Self::StringArray { str_token, length } => { - format_str(formatted_code, str_token.clone(), length.clone()) - } + Self::StringArray { + str_token: _, + length, + } => format_str(formatted_code, formatter, length.clone()), Self::Tuple(tup_descriptor) => { write!(formatted_code, "{}", Delimiter::Parenthesis.as_open_char())?; tup_descriptor.get().format(formatted_code, formatter)?; write!(formatted_code, "{}", Delimiter::Parenthesis.as_close_char())?; Ok(()) } - Self::Ptr { ptr_token, ty } => { - format_ptr(formatted_code, ptr_token.clone(), ty.clone()) - } + Self::Ptr { ptr_token: _, ty } => format_ptr(formatted_code, formatter, ty.clone()), Self::Slice { slice_token, ty } => { - format_slice(formatted_code, slice_token.clone(), ty.clone()) + format_slice(formatted_code, formatter, slice_token, ty.clone()) } Self::Ref { - ampersand_token, + ampersand_token: _, mut_token, ty, - } => format_ref( - formatted_code, - ampersand_token.clone(), - mut_token.clone(), - ty.clone(), - ), - Self::Never { bang_token } => { - write!(formatted_code, "{}", bang_token.span().as_str(),)?; + } => format_ref(formatted_code, formatter, mut_token, ty), + Self::Never { bang_token: _ } => { + write!(formatted_code, "{}", BangToken::AS_STR)?; Ok(()) } } @@ -64,11 +64,9 @@ impl Format for Ty { } /// Simply inserts a `_` token to the `formatted_code`. -fn format_infer( - formatted_code: &mut FormattedCode, - underscore_token: &UnderscoreToken, -) -> Result<(), FormatterError> { - formatted_code.push_str(underscore_token.ident().as_str()); +fn format_infer(formatted_code: &mut FormattedCode) -> Result<(), FormatterError> { + formatted_code.push_str(UnderscoreToken::AS_STR); + Ok(()) } @@ -79,78 +77,73 @@ impl Format for TyArrayDescriptor { formatter: &mut Formatter, ) -> Result<(), FormatterError> { self.ty.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", self.semicolon_token.span().as_str())?; + write!(formatted_code, "{} ", SemicolonToken::AS_STR)?; self.length.format(formatted_code, formatter)?; + Ok(()) } } fn format_str( formatted_code: &mut FormattedCode, - str_token: StrToken, + formatter: &mut Formatter, length: SquareBrackets>, ) -> Result<(), FormatterError> { - write!( - formatted_code, - "{}{}{}{}", - str_token.span().as_str(), - Delimiter::Bracket.as_open_char(), - length.into_inner().span().as_str(), - Delimiter::Bracket.as_close_char() - )?; + write!(formatted_code, "{}", StrToken::AS_STR)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_open_char())?; + length.into_inner().format(formatted_code, formatter)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; + Ok(()) } fn format_ptr( formatted_code: &mut FormattedCode, - ptr_token: PtrToken, + formatter: &mut Formatter, ty: SquareBrackets>, ) -> Result<(), FormatterError> { - write!( - formatted_code, - "{}[{}]", - ptr_token.span().as_str(), - ty.into_inner().span().as_str() - )?; + write!(formatted_code, "{}", PtrToken::AS_STR)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_open_char())?; + ty.into_inner().format(formatted_code, formatter)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; + Ok(()) } fn format_slice( formatted_code: &mut FormattedCode, - slice_token: Option, + formatter: &mut Formatter, + slice_token: &Option, ty: SquareBrackets>, ) -> Result<(), FormatterError> { - if let Some(slice_token) = slice_token { - write!( - formatted_code, - "{}[{}]", - slice_token.span().as_str(), - ty.into_inner().span().as_str() - )?; - } else { - write!(formatted_code, "[{}]", ty.into_inner().span().as_str())?; + if slice_token.is_some() { + write!(formatted_code, "{}", SliceToken::AS_STR)?; } + write!(formatted_code, "{}", Delimiter::Bracket.as_open_char())?; + ty.into_inner().format(formatted_code, formatter)?; + write!(formatted_code, "{}", Delimiter::Bracket.as_close_char())?; Ok(()) } fn format_ref( formatted_code: &mut FormattedCode, - ampersand_token: AmpersandToken, - mut_token: Option, - ty: Box, + formatter: &mut Formatter, + mut_token: &Option, + ty: &Ty, ) -> Result<(), FormatterError> { write!( formatted_code, - "{}{}{}", - ampersand_token.span().as_str(), - if let Some(mut_token) = mut_token { - format!("{} ", mut_token.span().as_str()) + "{}{}", + AmpersandToken::AS_STR, + if mut_token.is_some() { + format!("{} ", MutToken::AS_STR) } else { "".to_string() }, - ty.span().as_str() )?; + ty.format(formatted_code, formatter)?; + Ok(()) } @@ -162,7 +155,7 @@ impl Format for TyTupleDescriptor { ) -> Result<(), FormatterError> { if let TyTupleDescriptor::Cons { head, - comma_token, + comma_token: _, tail, } = self { @@ -170,7 +163,7 @@ impl Format for TyTupleDescriptor { formatter.shape.with_default_code_line(), |formatter| -> Result<(), FormatterError> { head.format(formatted_code, formatter)?; - write!(formatted_code, "{} ", comma_token.ident().as_str())?; + write!(formatted_code, "{} ", CommaToken::AS_STR)?; tail.format(formatted_code, formatter)?; Ok(()) diff --git a/swayfmt/src/utils/language/where_clause.rs b/swayfmt/src/utils/language/where_clause.rs index 6a365370572..805bac01b86 100644 --- a/swayfmt/src/utils/language/where_clause.rs +++ b/swayfmt/src/utils/language/where_clause.rs @@ -3,8 +3,11 @@ use crate::{ utils::map::byte_span::{ByteSpan, LeafSpans}, }; use std::fmt::Write; -use sway_ast::{WhereBound, WhereClause}; -use sway_types::{ast::PunctKind, Spanned}; +use sway_ast::{ + keywords::{ColonToken, Keyword, Token, WhereToken}, + CommaToken, WhereBound, WhereClause, +}; +use sway_types::Spanned; impl Format for WhereClause { fn format( @@ -15,8 +18,8 @@ impl Format for WhereClause { writeln!( formatted_code, "{}{}", - &formatter.indent_to_str()?, - self.where_token.span().as_str(), + formatter.indent_to_str()?, + WhereToken::AS_STR, )?; formatter.indent(); // We should add a multiline field to `Shape` @@ -27,18 +30,19 @@ impl Format for WhereClause { // ``` // let value_pairs = self.bounds.value_separator_pairs.clone(); - for (bound, comma_token) in value_pairs.iter() { + for (bound, _comma_token) in value_pairs.iter() { // `WhereBound` bound.format(formatted_code, formatter)?; // `CommaToken` - writeln!(formatted_code, "{}", comma_token.span().as_str())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } if let Some(final_value) = &self.bounds.final_value_opt { final_value.format(formatted_code, formatter)?; - writeln!(formatted_code, "{}", PunctKind::Comma.as_char())?; + writeln!(formatted_code, "{}", CommaToken::AS_STR)?; } // reset indent formatter.unindent(); + Ok(()) } } @@ -52,11 +56,12 @@ impl Format for WhereBound { write!( formatted_code, "{}{}{} ", - &formatter.indent_to_str()?, // `Indent` - self.ty_name.span().as_str(), // `Ident` - self.colon_token.span().as_str(), // `ColonToken` + formatter.indent_to_str()?, + self.ty_name.as_str(), + ColonToken::AS_STR, )?; self.bounds.format(formatted_code, formatter)?; + Ok(()) } } diff --git a/swayfmt/src/utils/map/byte_span.rs b/swayfmt/src/utils/map/byte_span.rs index 36578739dcf..fec51afdc1c 100644 --- a/swayfmt/src/utils/map/byte_span.rs +++ b/swayfmt/src/utils/map/byte_span.rs @@ -49,8 +49,8 @@ impl ByteSpan { impl Ord for ByteSpan { fn cmp(&self, other: &Self) -> Ordering { - // If the starting position is the same encapsulatig span (i.e, wider one) should come - // first + // If the starting position is the same encapsulating span (i.e, wider one) should come + // first. match self.start.cmp(&other.start) { Ordering::Equal => other.end.cmp(&self.end), ord => ord, diff --git a/swayfmt/src/utils/map/newline.rs b/swayfmt/src/utils/map/newline.rs index 769b05e7ad3..9600248beee 100644 --- a/swayfmt/src/utils/map/newline.rs +++ b/swayfmt/src/utils/map/newline.rs @@ -1,8 +1,7 @@ use anyhow::Result; use ropey::{str_utils::byte_to_char_idx, Rope}; -use std::{collections::BTreeMap, fmt::Display, path::PathBuf, sync::Arc}; +use std::{collections::BTreeMap, fmt::Display, sync::Arc}; use sway_ast::Module; -use sway_types::SourceEngine; use crate::{ constants::NEW_LINE, @@ -106,11 +105,9 @@ fn newline_map_from_src(unformatted_input: &str) -> Result, unformatted_module: &Module, formatted_input: Arc, - path: Option>, formatted_code: &mut FormattedCode, formatter: &Formatter, ) -> Result<(), FormatterError> { @@ -123,7 +120,7 @@ pub fn handle_newlines( // formatting the code a second time will still produce the same result. let newline_map = newline_map_from_src(&unformatted_input)?; // After the formatting existing items should be the same (type of the item) but their spans will be changed since we applied formatting to them. - let formatted_module = parse_file(source_engine, formatted_input, path)?.value; + let formatted_module = parse_file(formatted_input)?.value; // Actually find & insert the newline sequences add_newlines( newline_map, diff --git a/swayfmt/test_macros/Cargo.toml b/swayfmt/test_macros/Cargo.toml index 89e0debe297..f08138e89dc 100644 --- a/swayfmt/test_macros/Cargo.toml +++ b/swayfmt/test_macros/Cargo.toml @@ -15,7 +15,7 @@ repository.workspace = true [dev-dependencies] paste = "1.0" -prettydiff = "0.6" +prettydiff = "0.7" [package.metadata.cargo-udeps.ignore] development = ["paste", "prettydiff"] diff --git a/swayfmt/tests/mod.rs b/swayfmt/tests/mod.rs index 890995ef338..75f46632b23 100644 --- a/swayfmt/tests/mod.rs +++ b/swayfmt/tests/mod.rs @@ -6,11 +6,11 @@ use test_macros::assert_eq_pretty; /// Takes a configured formatter as input and formats a given input and checks the actual output against an /// expected output. There are two format passes to ensure that the received output does not change on a second pass. fn check_with_formatter(unformatted: &str, expected: &str, formatter: &mut Formatter) { - let first_formatted = Formatter::format(formatter, Arc::from(unformatted), None).unwrap(); + let first_formatted = Formatter::format(formatter, Arc::from(unformatted)).unwrap(); assert_eq_pretty!(first_formatted, expected); let second_formatted = - Formatter::format(formatter, Arc::from(first_formatted.clone()), None).unwrap(); + Formatter::format(formatter, Arc::from(first_formatted.clone())).unwrap(); assert_eq_pretty!(second_formatted, first_formatted); } @@ -74,7 +74,33 @@ fn struct_alignment() { contract; pub struct Foo { barbazfoo: u64, - baz : bool, + baz : bool, + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + barbazfoo : u64, + baz : bool, + } + "#}, + &mut formatter, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn struct_alignment_without_trailing_comma() { + // The last struct field does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(40); + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + barbazfoo: u64, + baz : bool } "#}, indoc! {r#" @@ -98,7 +124,51 @@ fn struct_alignment_with_public_fields() { contract; pub struct Foo { barbazfoo: u64, - pub baz : bool, + pub baz : bool, + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + barbazfoo : u64, + pub baz : bool, + } + "#}, + &mut formatter, + ); + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + pub barbazfoo: u64, + baz : bool, + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + pub barbazfoo : u64, + baz : bool, + } + "#}, + &mut formatter, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn struct_alignment_with_public_fields_without_trailing_comma() { + // The last struct field does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(40); + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + barbazfoo: u64, + pub baz : bool } "#}, indoc! {r#" @@ -116,7 +186,7 @@ fn struct_alignment_with_public_fields() { contract; pub struct Foo { pub barbazfoo: u64, - baz : bool, + baz : bool } "#}, indoc! {r#" @@ -157,7 +227,34 @@ fn struct_public_fields() { } #[test] -fn struct_ending_comma() { +fn struct_public_fields_without_trailing_comma() { + // The last struct field does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::Off; + + check_with_formatter( + indoc! {r#" + contract; + pub struct Foo { + pub barbaz: T, + foo: u64, + pub baz : bool + } + "#}, + indoc! {r#" + contract; + pub struct Foo { + pub barbaz: T, + foo: u64, + pub baz: bool, + } + "#}, + &mut formatter, + ); +} + +#[test] +fn struct_add_ending_comma() { check( indoc! {r#" contract; @@ -183,10 +280,10 @@ fn enum_without_variant_alignment() { contract; enum Color { - Blue: (), Green: (), - Red: (), - Silver: (), - Grey: () } + Blue: (), Green: (), + Red: (), + Silver: () , + Grey: () , } "#}, indoc! {r#" contract; @@ -204,7 +301,6 @@ fn enum_without_variant_alignment() { #[test] fn enum_with_variant_alignment() { - // Creating a config with enum_variant_align_threshold that exceeds longest variant length let mut formatter = Formatter::default(); formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); check_with_formatter( @@ -212,10 +308,68 @@ fn enum_with_variant_alignment() { contract; enum Color { - Blue: (), Green: (), - Red: (), + Blue: (), Green: (), + Red: (), + Silver: () , + Grey: () , } + "#}, + indoc! {r#" + contract; + + enum Color { + Blue : (), + Green : (), + Red : (), + Silver : (), + Grey : (), + } + "#}, + &mut formatter, + ); +} + +#[test] +fn enum_without_variant_alignment_without_trailing_comma() { + // The last enum variant does not have trailing comma. + check( + indoc! {r#" + contract; + + enum Color { + Blue: (), Green : (), + Red : (), + Silver: () , + Grey: () } + "#}, + indoc! {r#" + contract; + + enum Color { + Blue: (), + Green: (), + Red: (), Silver: (), - Grey: (), } + Grey: (), + } + "#}, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn enum_with_variant_alignment_without_trailing_comma() { + // The last enum variant does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); + check_with_formatter( + indoc! {r#" + contract; + + enum Color { + Blue: (), Green : (), + Red : (), + Silver: () , + Grey: () } "#}, indoc! {r#" contract; @@ -232,6 +386,119 @@ fn enum_with_variant_alignment() { ); } +#[test] +fn configurable_without_alignment() { + check( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0, } + "#}, + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, + Green: u64 = 0, + Red: u64 = 0, + Silver: u64 = 0, + Grey: u64 = 0, + } + "#}, + ); +} + +#[test] +fn configurable_with_alignment() { + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); + check_with_formatter( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0, } + "#}, + indoc! {r#" + contract; + + configurable { + Blue : u64 = 0, + Green : u64 = 0, + Red : u64 = 0, + Silver : u64 = 0, + Grey : u64 = 0, + } + "#}, + &mut formatter, + ); +} + +#[test] +fn configurable_without_alignment_without_trailing_comma() { + // The last configurable does not have trailing comma. + check( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0 } + "#}, + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, + Green: u64 = 0, + Red: u64 = 0, + Silver: u64 = 0, + Grey: u64 = 0, + } + "#}, + ); +} + +#[test] +#[ignore = "Bug in `swayfmt`. Activate this test once https://github.com/FuelLabs/sway/issues/6805 is fixed."] +fn configurable_with_alignment_without_trailing_comma() { + // The last configurable does not have trailing comma. + let mut formatter = Formatter::default(); + formatter.config.structures.field_alignment = FieldAlignment::AlignFields(20); + check_with_formatter( + indoc! {r#" + contract; + + configurable { + Blue: u64 = 0, Green: u64 = 0, + Red: u64=0, + Silver: u64= 0, + Grey: u64 =0 } + "#}, + indoc! {r#" + contract; + + configurable { + Blue : u64 = 0, + Green : u64 = 0, + Red : u64 = 0, + Silver : u64 = 0, + Grey : u64 = 0, + } + "#}, + &mut formatter, + ); +} + #[test] fn item_abi_with_generics_and_attributes() { check( @@ -3155,3 +3422,70 @@ fn retain_in_keyword() { "#}, ); } + +#[test] +fn tuple_field_access() { + check( + indoc! {r#" + contract; + + fn fun() { + let t = (1, 1); + let a = t . 0; + let b = t + . + 1 + ; + } + "#}, + indoc! {r#" + contract; + + fn fun() { + let t = (1, 1); + let a = t.0; + let b = t.1; + } + "#}, + ); +} + +#[test] +fn contract_for_loop() { + check( + indoc! {r#" + contract; + + abi MyContract { + fn test_function() -> bool; + } + + impl MyContract for Contract { + fn test_function() -> bool { + let mut my_vec: Vec = Vec::new(); + for iter in my_vec.iter() { + + } + + true + } + } + "#}, + indoc! {r#" + contract; + + abi MyContract { + fn test_function() -> bool; + } + + impl MyContract for Contract { + fn test_function() -> bool { + let mut my_vec: Vec = Vec::new(); + for iter in my_vec.iter() { } + + true + } + } + "#}, + ); +} diff --git a/test/src/e2e_vm_tests/harness.rs b/test/src/e2e_vm_tests/harness.rs index 164d442e7bf..31dbcda4b48 100644 --- a/test/src/e2e_vm_tests/harness.rs +++ b/test/src/e2e_vm_tests/harness.rs @@ -398,22 +398,28 @@ pub(crate) fn test_json_abi( } if fs::metadata(oracle_path.clone()).is_err() { - bail!("JSON ABI oracle file does not exist for this test."); + bail!( + "JSON ABI oracle file does not exist for this test\nExpected oracle path: {}", + &oracle_path + ); } if fs::metadata(output_path.clone()).is_err() { - bail!("JSON ABI output file does not exist for this test."); + bail!( + "JSON ABI output file does not exist for this test\nExpected output path: {}", + &output_path + ); } - let oracle_contents = - fs::read_to_string(&oracle_path).expect("Something went wrong reading the file."); - let output_contents = - fs::read_to_string(&output_path).expect("Something went wrong reading the file."); + let oracle_contents = fs::read_to_string(&oracle_path) + .expect("Something went wrong reading the JSON ABI oracle file."); + let output_contents = fs::read_to_string(&output_path) + .expect("Something went wrong reading the JSON ABI output file."); if oracle_contents != output_contents { - println!("Mismatched ABI JSON output [{oracle_path}] versus [{output_path}]",); - println!( - "{}", + bail!( + "Mismatched ABI JSON output.\nOracle path: {}\nOutput path: {}\n{}", + oracle_path, + output_path, prettydiff::diff_lines(&oracle_contents, &output_contents) ); - bail!("Mismatched ABI JSON output."); } Ok(()) } @@ -435,29 +441,47 @@ fn emit_json_abi(file_name: &str, built_package: &BuiltPackage) -> Result<()> { Ok(()) } -pub(crate) fn test_json_storage_slots(file_name: &str, built_package: &BuiltPackage) -> Result<()> { +pub(crate) fn test_json_storage_slots( + file_name: &str, + built_package: &BuiltPackage, + suffix: &Option, +) -> Result<()> { emit_json_storage_slots(file_name, built_package)?; let manifest_dir = env!("CARGO_MANIFEST_DIR"); let oracle_path = format!( - "{}/src/e2e_vm_tests/test_programs/{}/{}", - manifest_dir, file_name, "json_storage_slots_oracle.json" + "{}/src/e2e_vm_tests/test_programs/{}/json_storage_slots_oracle.{}json", + manifest_dir, + file_name, + suffix + .as_ref() + .unwrap() + .strip_prefix("test") + .unwrap() + .strip_suffix("toml") + .unwrap() + .trim_start_matches('.') ); let output_path = format!( "{}/src/e2e_vm_tests/test_programs/{}/{}", manifest_dir, file_name, "json_storage_slots_output.json" ); if fs::metadata(oracle_path.clone()).is_err() { - bail!("JSON storage slots oracle file does not exist for this test."); + bail!("JSON storage slots oracle file does not exist for this test.\nExpected oracle path: {}", &oracle_path); } if fs::metadata(output_path.clone()).is_err() { - bail!("JSON storage slots output file does not exist for this test."); + bail!("JSON storage slots output file does not exist for this test.\nExpected output path: {}", &output_path); } - let oracle_contents = - fs::read_to_string(oracle_path).expect("Something went wrong reading the file."); - let output_contents = - fs::read_to_string(output_path).expect("Something went wrong reading the file."); + let oracle_contents = fs::read_to_string(oracle_path.clone()) + .expect("Something went wrong reading the JSON storage slots oracle file."); + let output_contents = fs::read_to_string(output_path.clone()) + .expect("Something went wrong reading the JSON storage slots output file."); if oracle_contents != output_contents { - bail!("Mismatched storage slots JSON output."); + bail!( + "Mismatched storage slots JSON output.\nOracle path: {}\nOutput path: {}\n{}", + oracle_path, + output_path, + prettydiff::diff_lines(&oracle_contents, &output_contents) + ); } Ok(()) } diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 62dc360fea1..725056b9ac7 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -515,7 +515,7 @@ impl TestContext { if validate_storage_slots { for (name, built_pkg) in &compiled_pkgs { let (result, out) = run_and_capture_output(|| async { - harness::test_json_storage_slots(name, built_pkg) + harness::test_json_storage_slots(name, built_pkg, &suffix) }) .await; result?; @@ -602,7 +602,15 @@ impl TestContext { ))); } } - _ => todo!(), + TestResult::ReturnData(_) => { + todo!("Test result `ReturnData` is currently not implemented.") + } + TestResult::Return(_) => { + todo!("Test result `Return` is currently not implemented.") + } + TestResult::Revert(_) => { + todo!("Test result `Revert` is currently not implemented.") + } }, Receipt::ReturnData { data, .. } => match expected_result.unwrap() { TestResult::ReturnData(v) => { @@ -612,7 +620,15 @@ impl TestContext { ))); } } - _ => todo!(), + TestResult::Result(_) => { + todo!("Test result `Result` is currently not implemented.") + } + TestResult::Return(_) => { + todo!("Test result `Return` is currently not implemented.") + } + TestResult::Revert(_) => { + todo!("Test result `Revert` is currently not implemented.") + } }, _ => {} }; diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock new file mode 100644 index 00000000000..7f8a3338563 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "array_oob_reassignment" +source = "member" +dependencies = ["core"] + +[[package]] +name = "core" +source = "path+from-root-CC73096846C1E083" diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml new file mode 100644 index 00000000000..cc38134eea8 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "array_oob_reassignment" +entry = "main.sw" +implicit-std = false + +[dependencies] +core = { path = "../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw new file mode 100644 index 00000000000..cd5d7979225 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/src/main.sw @@ -0,0 +1,16 @@ +script; + +fn main() { + let mut a = [u64; 0]; + a[0] = 1; + + + let mut b = [[u64; 1]; 1]; + b[0][1] = 1; + + + b[1][0] = 1; + + + a[0] = return; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml new file mode 100644 index 00000000000..e3c8288e736 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/array_oob_reassignment/test.toml @@ -0,0 +1,19 @@ +category = "fail" + +# check: $()let mut a = [u64; 0]; +# nextln: $()This declaration is never used. + +# check: $()let mut b = [[u64; 1]; 1]; +# nextln: $()This declaration is never used. + +# check: $()a[0] = 1; +# nextln: $()Index out of bounds; the length is 0 but the index is 0. + +# check: $()b[0][1] = 1; +# nextln: $()Index out of bounds; the length is 1 but the index is 1. + +# check: $()b[1][0] = 1; +# nextln: $()Index out of bounds; the length is 1 but the index is 1. + +# check: $()a[0] = return; +# nextln: $()Index out of bounds; the length is 0 but the index is 0. \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock new file mode 100644 index 00000000000..cc167580e1e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-FF35018BB7DF2595" + +[[package]] +name = "for_loop_error" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-FF35018BB7DF2595" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml new file mode 100644 index 00000000000..700b97ff4e3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +name = "for_loop_error" +entry = "main.sw" + +[dependencies] +std = { path = "../../../reduced_std_libs/sway-lib-std-vec" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/json_abi_oracle.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw new file mode 100644 index 00000000000..5c3f883c10d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/src/main.sw @@ -0,0 +1,12 @@ +script; + +fn main() { + let mut v : Vec = Vec::new(); + v.push(1); + v.push(2); + v.push(3); + for elem in v.iter() { + log(elem); + 3 + }; +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml new file mode 100644 index 00000000000..e738a23e98e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/for_loop_error/test.toml @@ -0,0 +1,13 @@ +category = "fail" + +# check: $()3 +# nextln: $()Mismatched types. +# nextln: $()expected: () +# nextln: $()found: numeric. +# nextln: $()Implicit return must match up with block's type. + +# check: $()3 +# nextln: $()Mismatched types. +# nextln: $()expected: () +# nextln: $()found: numeric. +# nextln: $()A for loop's loop body cannot implicitly return a value. Try assigning it to a mutable variable declared outside of the loop instead. \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap index fee2b903ecd..84c0fa58caf 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap +++ b/test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap @@ -11,7 +11,7 @@ warning | 1 | predicate; 2 | #[cfg(c)] a - | --- Unexpected attribute value: "c" for attribute: "cfg" expected value "target" or "program_type" or "experimental_new_encoding" + | --- Unexpected attribute value: "c" for attribute: "cfg" expected value "target" or "program_type" or "experimental_new_encoding" or "experimental_storage_domains" | ____ diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock new file mode 100644 index 00000000000..f9932679777 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-E4EB5F90E61EC58F" + +[[package]] +name = "transmute" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml new file mode 100644 index 00000000000..457f84ef26a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +entry = "main.sw" +name = "transmute" + +[dependencies] +core = { path = "../../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json new file mode 100644 index 00000000000..c42f6cefac2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-abi.json @@ -0,0 +1,28 @@ +{ + "programType": "script", + "specVersion": "1", + "encodingVersion": "1", + "concreteTypes": [ + { + "type": "u64", + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypes": [], + "functions": [ + { + "inputs": [], + "name": "main", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "attributes": null + } + ], + "loggedTypes": [ + { + "logId": "1515152261580153489", + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "messagesTypes": [], + "configurables": [] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash new file mode 100644 index 00000000000..86a358e416a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute-bin-hash @@ -0,0 +1 @@ +0x82d76771fa3e7e2cc3c0f9904b45673c9066384f3077cd97e20892c965a096db \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute.bin b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute.bin new file mode 100644 index 00000000000..4c9d69d93cb Binary files /dev/null and b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/debug/transmute.bin differ diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/snapshot.toml b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/snapshot.toml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw new file mode 100644 index 00000000000..6873ab62973 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw @@ -0,0 +1,16 @@ +script; + +fn main() { + // Missing type arguments + let _ = __transmute(1u64); + let _ = __transmute::(1u64); + + // Wrong source type + let _ = __transmute::(1u32); + + // Different sizes + let _ = __transmute::(1u64); + + // Invalid types + let _ = __transmute::<&u64, &u8>(&1u64); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap new file mode 100644 index 00000000000..70f758a10e0 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/stdout.snap @@ -0,0 +1,62 @@ +--- +source: test/tests/tests.rs +snapshot_kind: text +--- +> forc build --path test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute +exit status: 1 +output: + Building test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute + Compiling library core (sway-lib-core) + Compiling script transmute (test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute) +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:5:13 + | +3 | fn main() { +4 | // Missing type arguments +5 | let _ = __transmute(1u64); + | ^^^^^^^^^^^^^^^^^ Call to "transmute" expects 2 type arguments +6 | let _ = __transmute::(1u64); +7 | + | +____ + +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:6:13 + | +4 | // Missing type arguments +5 | let _ = __transmute(1u64); +6 | let _ = __transmute::(1u64); + | ^^^^^^^^^^^^^^^^^^^^^^^^ Call to "transmute" expects 2 type arguments +7 | +8 | // Wrong source type + | +____ + +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:9:36 + | + 7 | + 8 | // Wrong source type + 9 | let _ = __transmute::(1u32); + | ^^^^ Mismatched types. +expected: u64 +found: u32. + +10 | +11 | // Different sizes + | +____ + +error + --> test/src/e2e_vm_tests/test_programs/should_fail/language/intrinsics/transmute/src/main.sw:15:27 + | +13 | +14 | // Invalid types +15 | let _ = __transmute::<&u64, &u8>(&1u64); + | ^^^^ references, pointers, slices, string slices or types containing any of these are not allowed. +16 | } + | +____ + + Aborting due to 4 errors. +error: Failed to compile transmute diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw index d84157a1bce..a8597cf626a 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/aliases/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1; // Aliased item reexports of items_1 -mod items_2; -mod lib_2; // Aliased item reexports of items_2 -mod items_3; -mod lib_3; // Aliased item reexports of items_3 -mod items_4; -mod lib_4_1; // Aliased item reexports of items_4 -mod lib_4_2; // Aliased item reexports of lib_4_1 -mod items_5; -mod lib_5_1; // Aliased trait reexports from items_5 -mod lib_5_2; // Aliased trait reexports from items_5 +pub mod items_1; +pub mod lib_1; // Aliased item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Aliased item reexports of items_2 +pub mod items_3; +pub mod lib_3; // Aliased item reexports of items_3 +pub mod items_4; +pub mod lib_4_1; // Aliased item reexports of items_4 +pub mod lib_4_2; // Aliased item reexports of lib_4_1 +pub mod items_5; +pub mod lib_5_1; // Aliased trait reexports from items_5 +pub mod lib_5_2; // Aliased trait reexports from items_5 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw index c4f06aaf84f..29853e98b33 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/multiple_imports_of_same_reexport/src/main.sw @@ -1,8 +1,8 @@ script; -mod items_1; -mod lib_1_1; // Item reexports of items_1 -mod lib_1_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1_1; // Item reexports of items_1 +pub mod lib_1_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw index a2961173628..c0290b47faf 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/shadowing_in_reexporting_module/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2_1; -mod items_2_2; -mod lib_2; // Item reexports of items_2_1 and items_2_2 -mod items_3_1; -mod lib_3; // Item reexports of items_3_1 and items_3_2 -mod items_4_1; -mod items_4_2; -mod items_4_3; -mod items_4_4; -mod lib_4; // Item reexports of items_4_1 and items_4_2 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2_1; +pub mod items_2_2; +pub mod lib_2; // Item reexports of items_2_1 and items_2_2 +pub mod items_3_1; +pub mod lib_3; // Item reexports of items_3_1 and items_3_2 +pub mod items_4_1; +pub mod items_4_2; +pub mod items_4_3; +pub mod items_4_4; +pub mod lib_4; // Item reexports of items_4_1 and items_4_2 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw index 57262307323..fe1ea19f9c1 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_glob_import/src/main.sw @@ -1,9 +1,9 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw index 57262307323..8856faf59f6 100755 --- a/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_fail/language/reexport/simple_item_import/src/main.sw @@ -1,9 +1,11 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_2 +pub mod items_3; +pub mod lib_3; // Item reexports of items_3 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock new file mode 100644 index 00000000000..e319a387961 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-3A3AB9F18BDA9100" + +[[package]] +name = "parser_generic_turbo_fish_prefix" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-3A3AB9F18BDA9100" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml new file mode 100644 index 00000000000..22143b9b5eb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "parser_generic_turbo_fish_prefix" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw new file mode 100644 index 00000000000..af437cc603e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/src/main.sw @@ -0,0 +1,9 @@ +script; + +struct S { + x: T, +} + +fn main() { + let x: ::S:: = S::{x: 8}; +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml new file mode 100644 index 00000000000..cfb2e0f1a93 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/parser_generic_turbo_fish_prefix/test.toml @@ -0,0 +1,4 @@ +category = "fail" + +# check: $()let x: ::S:: = S::{x: 8}; +# nextln: $()Expected `as`. diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock new file mode 100644 index 00000000000..58699a84e7e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-722DFCAB6A209427" + +[[package]] +name = "self_return_type" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml new file mode 100644 index 00000000000..40a91e8b7b5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/Forc.toml @@ -0,0 +1,9 @@ +[project] +name = "self_return_type" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +implicit-std = false + +[dependencies] +core = { path = "../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw new file mode 100644 index 00000000000..659207244d6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/src/main.sw @@ -0,0 +1,13 @@ +script; +trait MyTrait { + fn foo(self, other: Self) -> Self; +} +impl MyTrait for u8 { + fn foo(self, other: Self) -> self { + self + } +} +fn main() -> () { + let a = 1u8; + let _ = a.foo(2u8); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml new file mode 100644 index 00000000000..3bd3d799fb2 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/self_return_type/test.toml @@ -0,0 +1,4 @@ +category = "fail" + +# check: $()fn foo(self, other: Self) -> self { +# nextln: $()Unknown type name "self". A self type with a similar name exists (notice the capitalization): `Self` \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock new file mode 100644 index 00000000000..6024e958c64 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-C0C563B172E50A8D" + +[[package]] +name = "storage_invalid_storage_key_type" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml new file mode 100644 index 00000000000..18a5527966d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "storage_invalid_storage_key_type" +implicit-std = false + +[dependencies] +core = { path = "../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw new file mode 100644 index 00000000000..18a4f599f52 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/src/main.sw @@ -0,0 +1,9 @@ +contract; + +fn get_u256() -> u256 { + 0x0u256 +} + +storage { + field in get_u256(): u64 = 0, +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml new file mode 100644 index 00000000000..150a184e449 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/storage_invalid_storage_key_type/test.toml @@ -0,0 +1,17 @@ +category = "fail" + +#check: $()error +#check: $()field in get_u256(): u64 = 0, +#nextln: $()Mismatched types. +#nextln: $()expected: b256 +#nextln: $()found: u256. +#nextln: $()Function return type does not match up with local type annotation. + +#check: $()error +#check: $()field in get_u256(): u64 = 0, +#nextln: $()Mismatched types. +#nextln: $()expected: b256 +#nextln: $()found: u256. +#nextln: $()Storage keys must have type "b256". + +#check: $()2 errors. \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw index ef39fb605a9..5fc24d795cf 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_enum/src/main.sw @@ -1,6 +1,6 @@ script; -mod r#enum; +pub mod r#enum; mod utils; fn main() { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw index 2607dbb987a..7a95e67d0a5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/dca/unused_trait/src/main.sw @@ -1,6 +1,6 @@ script; -mod r#trait; +pub mod r#trait; mod utils; use r#trait::Trait; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml b/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml deleted file mode 100644 index b9151f7a736..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/snapshot.toml +++ /dev/null @@ -1,16 +0,0 @@ -cmds = [ - "forc addr2line -h", - "forc build -h", - "forc check -h", - "forc clean -h", - "forc completions -h", - "forc new -h", - "forc init -h", - "forc parse-bytecode -h", - "forc test -h", - "forc update -h", - "forc plugins -h", - "forc template -h", - "forc contract-id -h", - "forc predicate-root -h", -] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap deleted file mode 100644 index 8dd4a804aae..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/forc/help/stdout.snap +++ /dev/null @@ -1,597 +0,0 @@ ---- -source: test/tests/tests.rs ---- -> forc addr2line -h -exit status: 0 -output: -Show location and context of an opcode address in its source file - -Usage: forc addr2line [OPTIONS] --sourcemap-path --opcode-index - -Options: - -S, --search-dir Where to search for the project root [default: .] - -g, --sourcemap-path Source file mapping in JSON format - -c, --context How many lines of context to show [default: 2] - -i, --opcode-index Opcode index - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -> forc build -h -exit status: 0 -output: -Compile the current or target project - -Usage: forc build [OPTIONS] - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - --reverse-order - Output build errors and warnings in reverse order - --metrics-outfile - Output compilation metrics into the specified file - -v, --verbose... - Use verbose output - --json-abi - Minify JSON ABI files - -s, --silent - Silence all output - --json-storage-slots - Minify JSON storage slot files - -L, --log-level - Set the log level - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --build-target - Build target to use for code generation [default: fuel] [possible values: fuel, evm] - --tests - Also build all tests within the project - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Compile the current projectx - forc build - - # Compile the current project from a different path - forc build --path - - # Compile the current project without updating dependencies - forc build --path --locked - -> forc check -h -exit status: 0 -output: -Check the current or target project and all of its dependencies for errors - -Usage: forc check [OPTIONS] [BUILD_TARGET] - -Arguments: - [BUILD_TARGET] Build target to use for code generation [default: fuel] [possible values: fuel, evm] - -Options: - -p, --path - Path to the project, if not specified, current working directory will be used - --offline - Offline mode, prevents Forc from using the network when managing dependencies. Meaning it will only try to use previously downloaded dependencies - --locked - Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs to be updated, Forc will exit with an error - -t, --terse - Terse mode. Limited warning and error output - --disable-tests - Disable checking unit tests - --ipfs-node - The IPFS Node to use for fetching IPFS sources - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -v, --verbose... - Use verbose output - -s, --silent - Silence all output - -L, --log-level - Set the log level - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Check the current project - forc check - - # Check the current project with a different path - forc check --path - - # Check the current project without updating dependencies - forc check --locked - -> forc clean -h -exit status: 0 -output: -Removes the default forc compiler output artifact directory, i.e. `/out` - -Usage: forc clean [OPTIONS] - -Options: - -p, --path Path to the project, if not specified, current working directory will be used - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Clean project - forc clean - - # Clean project with a custom path - forc clean --path - -> forc completions -h -exit status: 0 -output: -Generate tab-completion scripts for your shell - -Usage: forc completions [OPTIONS] --target - -Options: - -T, --target Specify shell to enable tab-completion for [possible values: bash, elvish, fish, power-shell, zsh, fig] - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help (see more with '--help') - -> forc new -h -exit status: 0 -output: -Create a new Forc project at `` - -Usage: forc new [OPTIONS] - -Arguments: - The path at which the project directory will be created - -Options: - --contract The default program type. Excluding all flags or adding this flag creates a basic contract program - --script Adding this flag creates an empty script program - --predicate Adding this flag creates an empty predicate program - --library Adding this flag creates an empty library program - --workspace Adding this flag creates an empty workspace - --name Set the package name. Defaults to the directory name - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Create a new project - forc new --contract --name my_project - - # Create a new workspace - forc new --workspace --name my_workspace - - # Create a new Forc project with a predicate - forc new --predicate - - # Create a new Forc library project - forc new --library - -> forc init -h -exit status: 0 -output: -Create a new Forc project in an existing directory - -Usage: forc init [OPTIONS] - -Options: - --path The directory in which the forc project will be initialized - --contract The default program type, excluding all flags or adding this flag creates a basic contract program - --script Create a package with a script target (src/main.sw) - --predicate Create a package with a predicate target (src/predicate.rs) - --library Create a package with a library target (src/lib.sw) - --workspace Adding this flag creates an empty workspace - --name Set the package name. Defaults to the directory name - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Initialize a new Forc project - forc init --path - - # Initialize a new Forc project as workspace - forc init --path --workspace - - # Initialize a new Forc project with a predicate - forc init --path --predicate - - # Initialize a new Forc library project - forc init --path --library - -> forc parse-bytecode -h -exit status: 0 -output: -Parse bytecode file into a debug format - -Usage: forc parse-bytecode [OPTIONS] - -Arguments: - - -Options: - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Parse bytecode - forc parse-bytecode - -> forc test -h -exit status: 0 -output: -Run the Sway unit tests for the current project - -Usage: forc test [OPTIONS] [FILTER] - -Arguments: - [FILTER] When specified, only tests containing the given string will be executed - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - --reverse-order - Output build errors and warnings in reverse order - --metrics-outfile - Output compilation metrics into the specified file - -v, --verbose... - Use verbose output - --json-abi - Minify JSON ABI files - -s, --silent - Silence all output - --json-storage-slots - Minify JSON storage slot files - -L, --log-level - Set the log level - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --build-target - Build target to use for code generation [default: fuel] [possible values: fuel, evm] - --pretty - Pretty-print the logs emitted from tests - -l, --logs - Print `Log` and `LogData` receipts for tests - --raw-logs - Print the raw logs for tests - --filter-exact - When specified, only the test exactly matching the given string will be executed - --test-threads - Number of threads to utilize when running the tests. By default, this is the number of threads available in your system - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Run test - forc test - - # Run test with a filter - forc test $filter - - # Run test without any output - forc test --silent - - # Run test without creating or update the lock file - forc test --locked - -> forc update -h -exit status: 0 -output: -Update dependencies in the Forc dependencies directory - -Usage: forc update [OPTIONS] - -Options: - -p, --path Path to the project, if not specified, current working directory will be used - -d Dependency to be updated. If not set, all dependencies will be updated - -c, --check Checks if the dependencies have newer versions. Won't actually perform the update, will output which ones are up-to-date and outdated - --ipfs-node The IPFS Node to use for fetching IPFS sources - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help (see more with '--help') - -V, --version Print version - -EXAMPLES: - # Update dependencies - forc update - - # Update a specific dependency - forc update -d std - - # Check if dependencies have newer versions - forc update --check - -> forc plugins -h -exit status: 0 -output: -List all forc plugins - -Usage: forc plugins [OPTIONS] - -Options: - -p, --paths Prints the absolute path to each discovered plugin - -d, --describe Prints the long description associated with each listed plugin - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help (see more with '--help') - -V, --version Print version - -EXAMPLES: - # List all plugins - forc plugins - - # List all plugins with their paths - forc plugins --paths - - # List all plugins with their descriptions - forc plugins --describe - - # List all plugins with their paths and descriptions - forc plugins --paths --describe - -> forc template -h -exit status: 0 -output: -Create a new Forc project from a git template - -Usage: forc template [OPTIONS] - -Arguments: - The name of the project that will be created - -Options: - -u, --url The template url, should be a git repo [default: https://github.com/fuellabs/sway] - -t, --template-name The name of the template that needs to be fetched and used from git repo provided - -v, --verbose... Use verbose output - -s, --silent Silence all output - -L, --log-level Set the log level - -h, --help Print help - -V, --version Print version - -EXAMPLES: - # Create a new Forc project from an option template - forc template new-path --template-name option - -> forc contract-id -h -exit status: 0 -output: -Determine contract-id for a contract. For workspaces outputs all contract ids in the workspace - -Usage: forc contract-id [OPTIONS] - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --json-abi - Minify JSON ABI files - --json-storage-slots - Minify JSON storage slot files - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - -v, --verbose... - Use verbose output - --reverse-order - Output build errors and warnings in reverse order - -s, --silent - Silence all output - -L, --log-level - Set the log level - --metrics-outfile - Output compilation metrics into the specified file - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --salt - Added salt used to derive the contract ID - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Get contract id - forc contract-id - - # Get contract id from a different path - forc contract-id --path - -> forc predicate-root -h -exit status: 0 -output: -Determine predicate-root for a predicate. For workspaces outputs all predicate roots in the workspace - -Usage: forc predicate-root [OPTIONS] - -Options: - -p, --path - Path to the project - --offline - Offline mode - -t, --terse - Terse mode - --output-directory - The directory in which Forc output artifacts are placed - --locked - Requires that the Forc.lock file is up-to-date - --ipfs-node - The IPFS node to use for fetching IPFS sources - --json-abi - Minify JSON ABI files - --json-storage-slots - Minify JSON storage slot files - --ast - Print the generated Sway AST (Abstract Syntax Tree) - --dca-graph - Print the computed Sway DCA (Dead Code Analysis) graph - --dca-graph-url-format - URL format to be used in the generated DCA graph .dot file. - --asm ... - Print the generated ASM (assembler). [possible values: virtual, allocated, abstract, final, all] - --bytecode - Print the bytecode - --ir ... - Print the generated Sway IR (Intermediate Representation). [possible values: initial, final, all, modified, inline, simplify-cfg, sroa, dce, fn-dce, fn-dedup-release, fn-dedup-debug, mem2reg, memcpyopt, const-folding, arg-demotion, const-demotion, ret-demotion, misc-demotion] - --time-phases - Output the time elapsed over each part of the compilation process - -v, --verbose... - Use verbose output - --reverse-order - Output build errors and warnings in reverse order - -s, --silent - Silence all output - -L, --log-level - Set the log level - --metrics-outfile - Output compilation metrics into the specified file - -o, --output-bin - Create a binary file at the provided path representing the final bytecode - -g, --output-debug - Create a file at the provided path containing debug information - --build-profile - The name of the build profile to use [default: debug] - --release - Use the release build profile - --error-on-warnings - Treat warnings as errors - --experimental - Comma separated list of all experimental features that will be enabled [possible values: new_encoding] - --no-experimental - Comma separated list of all experimental features that will be disabled [possible values: new_encoding] - -h, --help - Print help (see more with '--help') - -V, --version - Print version - -EXAMPLES: - # Get predicate root - forc predicate-root diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw index 6f08f7204de..2058833a235 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/abi_cast_nested_method/src/main.sw @@ -3,6 +3,7 @@ script; abi AMM { fn pool() -> Option; } + abi Exchange { fn swap_exact_output(); } @@ -12,9 +13,6 @@ fn main() { let exchange_contract_id = amm_contract.pool(); - // let a = exchange_contract_id.unwrap().into(); - // let exchange_contract = abi(Exchange, a); - let exchange_contract = abi(Exchange, exchange_contract_id.unwrap().into()); exchange_contract.swap_exact_output(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw index 4486078f32b..ec8dab4f17b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/associated_const_abi/src/main.sw @@ -2,15 +2,12 @@ contract; abi A { const A_WITH_DEFAULT: u32 = 3; - // TODO: Uncomment this case when https://github.com/FuelLabs/sway/issues/6348 is fixed. - // const A_NO_DEFAULT: u32; + const A_NO_DEFAULT: u32; const COMMON_1: u32 = 5; - // TODO: Uncomment this version (without default) when https://github.com/FuelLabs/sway/issues/6348 is fixed. - // const COMMON_2: u32; - const COMMON_2: u32 = 111; // TODO: Remove this one in favor of the one without default. + const COMMON_2: u32; fn a_with_default() -> u32; - // fn a_no_default() -> u32; + fn a_no_default() -> u32; fn common_1() -> u32; fn common_2() -> u32; @@ -34,9 +31,7 @@ abi A { } abi B { - // TODO: Uncomment this version (without default) when https://github.com/FuelLabs/sway/issues/6348 is fixed. - // const COMMON_1: u32; - const COMMON_1: u32 = 111; // TODO: Remove this one in favor of the one without default. + const COMMON_1: u32; const COMMON_2: u32 = 7; fn common_1() -> u32; @@ -54,7 +49,7 @@ abi B { impl A for Contract { const A_WITH_DEFAULT: u32 = 13; - // const A_NO_DEFAULT: u32 = 133; + const A_NO_DEFAULT: u32 = 133; const COMMON_1: u32 = 15; const COMMON_2: u32 = 155; @@ -62,9 +57,9 @@ impl A for Contract { Self::A_WITH_DEFAULT } - // fn a_no_default() -> u32 { - // Self::A_NO_DEFAULT - // } + fn a_no_default() -> u32 { + Self::A_NO_DEFAULT + } fn common_1() -> u32 { Self::COMMON_1 @@ -92,14 +87,12 @@ impl B for Contract { fn test() { let a = abi(A, CONTRACT_ID); // TODO: Enable these asserts once these bugs are fixed: - // https://github.com/FuelLabs/sway/issues/6310 // https://github.com/FuelLabs/sway/issues/6306 - // https://github.com/FuelLabs/sway/issues/6348 - // assert_eq(13, a.a_with_default()); + assert_eq(13, a.a_with_default()); // assert_eq(13, a.a_implemented_with_default()); - // assert_eq(133, a.a_no_default()); + assert_eq(133, a.a_no_default()); // assert_eq(133, a.a_implemented_no_default()); // assert_eq(15, a.common_1()); @@ -110,9 +103,9 @@ fn test() { let b = abi(B, CONTRACT_ID); - // assert_eq(177, b.common_1()); + assert_eq(177, b.common_1()); // assert_eq(177, b.b_implemented_common_1()); - // assert_eq(17, b.common_2()); + assert_eq(17, b.common_2()); // assert_eq(17, b.b_implemented_common_2()); } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json index 2daeaffdc6a..71cf1f22ff7 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json @@ -62,82 +62,82 @@ { "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", "name": "BOOL", - "offset": 6896 + "offset": 7048 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "U8", - "offset": 7088 + "offset": 7240 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "ANOTHER_U8", - "offset": 6824 + "offset": 6976 }, { "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", "name": "U16", - "offset": 7032 + "offset": 7184 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U32", - "offset": 7072 + "offset": 7224 }, { "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", "name": "U64", - "offset": 7080 + "offset": 7232 }, { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "U256", - "offset": 7040 + "offset": 7192 }, { "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", "name": "B256", - "offset": 6864 + "offset": 7016 }, { "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", "name": "CONFIGURABLE_STRUCT", - "offset": 6984 + "offset": 7136 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_A", - "offset": 6904 + "offset": 7056 }, { "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", "name": "CONFIGURABLE_ENUM_B", - "offset": 6944 + "offset": 7096 }, { "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", "name": "ARRAY_BOOL", - "offset": 6832 + "offset": 6984 }, { "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", "name": "ARRAY_U64", - "offset": 6840 + "offset": 6992 }, { "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", "name": "TUPLE_BOOL_U64", - "offset": 7016 + "offset": 7168 }, { "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", "name": "STR_4", - "offset": 7008 + "offset": 7160 }, { "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", "name": "NOT_USED", - "offset": 7000 + "offset": 7152 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml index 784ff71e177..adfffceffad 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/snapshot.toml @@ -1 +1 @@ -cmds = ["forc build --path {root} --release --ir final"] +cmds = ["forc build --path {root} --release --ir final --asm final"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap index 8e825421dd7..6af5fcc2f13 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode/stdout.snap @@ -2,7 +2,7 @@ source: test/tests/tests.rs snapshot_kind: text --- -> forc build --path test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode --release --ir final +> forc build --path test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode --release --ir final --asm final exit status: 0 output: Building test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_dedup_decode @@ -361,4 +361,194 @@ script { !128 = fn_call_path_span !0 235 236 !129 = (!127 !128) - Finished release [optimized + fuel] target(s) [744 B] in ??? +;; ASM: Final program +;; Program kind: Script +.program: +move $$tmp $pc +jmpf $zero i4 +DATA_SECTION_OFFSET[0..32] +DATA_SECTION_OFFSET[32..64] +CONFIGURABLES_OFFSET[0..32] +CONFIGURABLES_OFFSET[32..64] +lw $$ds $$tmp i1 +add $$ds $$ds $$tmp +cfei i16 ; allocate stack space for globals +addr $$arg0 data_Configurable_0; get pointer to configurable TUPLE default value +addi $$arg1 $zero i8 ; get length of configurable TUPLE default value +addi $$arg2 $ssp i0 ; get pointer to configurable TUPLE stack address +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; set new return address +jmpf $zero i93 ; decode configurable TUPLE +addr $$arg0 data_Configurable_1; get pointer to configurable WRAPPED default value +addi $$arg1 $zero i8 ; get length of configurable WRAPPED default value +addi $$arg2 $ssp i8 ; get pointer to configurable WRAPPED stack address +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; set new return address +jmpf $zero i85 ; decode configurable WRAPPED +move $$locbase $sp ; save locals base register for function __entry +cfei i360 ; allocate 360 bytes for locals and 0 slots for call arguments +addi $r6 $$locbase i320 ; get offset to local +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; [call]: set new return address +jmpf $zero i140 ; [call]: call main_8 +move $r0 $$retv ; [call]: copy the return value +movi $r1 i1024 ; initialize constant into register +aloc $r1 +move $r1 $hp ; return value from ASM block with return register hp +addi $r2 $$locbase i112 ; get offset to local +sw $$locbase $r1 i14 ; store word +movi $r1 i1024 ; initialize constant into register +sw $$locbase $r1 i15 ; store word +sw $$locbase $zero i16 ; store word +movi $r1 i24 ; get data length for memory copy +mcp $$locbase $r2 $r1 ; copy memory +addi $r1 $$locbase i184 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $$locbase $r2 ; copy memory +addi $r2 $$locbase i272 ; get offset to local +movi $r3 i24 ; get data length for memory copy +mcp $r2 $r1 $r3 ; copy memory +addi $r1 $$locbase i24 ; get offset to local +movi $r3 i24 ; get data length for memory copy +mcp $r1 $r2 $r3 ; copy memory +addi $r2 $$locbase i136 ; get offset to local +movi $r3 i24 ; get data length for memory copy +mcp $r2 $r1 $r3 ; copy memory +lw $r5 $$locbase i17 ; load word +lw $r4 $$locbase i18 ; load word +lw $r1 $$locbase i19 ; load word +movi $r2 i8 ; initialize constant into register +add $r2 $r1 $r2 +gt $r3 $r2 $r4 +jnzf $r3 $zero i1 +jmpf $zero i7 +movi $r3 i2 ; initialize constant into register +mul $r3 $r4 $r3 +movi $r4 i8 ; initialize constant into register +add $r4 $r3 $r4 +aloc $r4 +mcp $hp $r5 $r1 +move $r5 $hp ; return value from ASM block with return register hp +add $r1 $r5 $r1 +sw $r1 $r0 i0 ; store word +addi $r0 $$locbase i208 ; get offset to local +sw $$locbase $r5 i26 ; store word +sw $$locbase $r4 i27 ; store word +sw $$locbase $r2 i28 ; store word +addi $r1 $$locbase i48 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +addi $r0 $$locbase i248 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r0 $r1 $r2 ; copy memory +addi $r1 $$locbase i336 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +addi $r0 $$locbase i336 ; get offset to local +addi $r1 $$locbase i296 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +addi $r0 $$locbase i72 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r0 $r1 $r2 ; copy memory +addi $r1 $$locbase i160 ; get offset to local +movi $r2 i24 ; get data length for memory copy +mcp $r1 $r0 $r2 ; copy memory +lw $r0 $$locbase i20 ; load word +addi $r1 $r1 i16 ; get offset to aggregate element +addi $r2 $$locbase i232 ; get offset to local +sw $$locbase $r0 i29 ; store word +addi $r0 $r2 i8 ; get offset to aggregate element +movi $r3 i8 ; get data length for memory copy +mcp $r0 $r1 $r3 ; copy memory +addi $r0 $$locbase i96 ; get offset to local +movi $r1 i16 ; get data length for memory copy +mcp $r0 $r2 $r1 ; copy memory +movi $r1 i16 ; get data length for memory copy +mcp $r6 $r0 $r1 ; copy memory +lw $r0 $r6 i1 ; load size of returned slice +lw $r6 $r6 i0 ; load pointer to returned slice +retd $r6 $r0 +pshl i15 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function abi_decode_in_place_0 +cfei i24 ; allocate 24 bytes for locals and 0 slots for call arguments +move $r0 $$arg0 ; save argument 0 (ptr) +move $r1 $$arg1 ; save argument 1 (len) +move $r2 $$arg2 ; save argument 2 (target) +move $r3 $$reta ; save return address +move $$arg0 $r0 ; [call]: pass argument 0 +move $$arg1 $r1 ; [call]: pass argument 1 +move $$arg2 $$locbase ; [call]: pass argument 2 +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; [call]: set new return address +jmpf $zero i19 ; [call]: call from_parts_1 +lw $r0 $$retv i0 ; load word +sw $$locbase $r0 i1 ; store word +addi $r0 $$locbase i8 ; get offset to local +move $$arg0 $r0 ; [call]: pass argument 0 +sub $$reta $pc $is ; get current instruction offset from instructions start ($is) +srli $$reta $$reta i2 ; get current instruction offset in 32-bit words +addi $$reta $$reta i4 ; [call]: set new return address +jmpf $zero i23 ; [call]: call abi_decode_3 +move $r0 $$retv ; [call]: copy the return value +sw $$locbase $r0 i2 ; store word +addi $r0 $$locbase i16 ; get offset to local +movi $r1 i8 ; initialize constant into register +mcp $r2 $r0 $r1 ; mcp target temp size +move $$retv $zero ; set return value +cfsi i24 ; free 24 bytes for locals and 0 slots for extra call arguments +move $$reta $r3 ; restore return address +poph i524288 ; restore registers 40..64 +popl i15 ; restore registers 16..40 +jmp $$reta ; return from call +pshl i7 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function from_parts_1 +move $r0 $$arg0 ; save argument 0 (ptr) +move $r1 $$arg2 ; save argument 2 (__ret_value) +move $r2 $$reta ; save return address +sw $r1 $r0 i0 ; store word +move $$retv $r1 ; set return value +move $$reta $r2 ; restore return address +poph i524288 ; restore registers 40..64 +popl i7 ; restore registers 16..40 +jmp $$reta ; return from call +pshl i31 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function abi_decode_3 +move $r0 $$arg0 ; save argument 0 (buffer) +move $r1 $$reta ; save return address +lw $r2 $r0 i0 ; load word +lw $r2 $r2 i0 ; lw val ptr i0 +lw $r3 $r0 i0 ; load word +movi $r4 i8 ; initialize constant into register +add $r3 $r3 $r4 +sw $r0 $r3 i0 ; store word +move $$retv $r2 ; set return value +move $$reta $r1 ; restore return address +poph i524288 ; restore registers 40..64 +popl i31 ; restore registers 16..40 +jmp $$reta ; return from call +pshl i7 ; save registers 16..40 +pshh i524288 ; save registers 40..64 +move $$locbase $sp ; save locals base register for function main_8 +move $r2 $$reta ; save return address +lw $r0 $ssp i1 ; load word +lw $r1 $ssp i0 ; load word +add $r0 $r0 $r1 +move $$retv $r0 ; set return value +move $$reta $r2 ; restore return address +poph i524288 ; restore registers 40..64 +popl i7 ; restore registers 16..40 +jmp $$reta ; return from call +.data: +data__0 .bytes[8] 00 00 00 00 00 00 00 02 ........ +data__1 .bytes[8] 00 00 00 00 00 00 00 01 ........ + + + Finished release [optimized + fuel] target(s) [752 B] in ??? diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock new file mode 100644 index 00000000000..688eb152964 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "configurable_tests" +source = "member" +dependencies = ["std"] + +[[package]] +name = "core" +source = "path+from-root-CEAD1EF3DC39BB76" + +[[package]] +name = "std" +source = "path+from-root-CEAD1EF3DC39BB76" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml new file mode 100644 index 00000000000..7fff3f8b575 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "configurable_tests" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json new file mode 100644 index 00000000000..096b1d487c9 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle.json @@ -0,0 +1,284 @@ +{ + "configurables": [ + { + "configurableType": { + "name": "", + "type": 5, + "typeArguments": null + }, + "name": "BOOL", + "offset": 3392 + }, + { + "configurableType": { + "name": "", + "type": 13, + "typeArguments": null + }, + "name": "U8", + "offset": 3528 + }, + { + "configurableType": { + "name": "", + "type": 13, + "typeArguments": null + }, + "name": "ANOTHER_U8", + "offset": 3320 + }, + { + "configurableType": { + "name": "", + "type": 9, + "typeArguments": null + }, + "name": "U16", + "offset": 3472 + }, + { + "configurableType": { + "name": "", + "type": 11, + "typeArguments": null + }, + "name": "U32", + "offset": 3512 + }, + { + "configurableType": { + "name": "", + "type": 11, + "typeArguments": null + }, + "name": "U64", + "offset": 3520 + }, + { + "configurableType": { + "name": "", + "type": 10, + "typeArguments": null + }, + "name": "U256", + "offset": 3480 + }, + { + "configurableType": { + "name": "", + "type": 4, + "typeArguments": null + }, + "name": "B256", + "offset": 3360 + }, + { + "configurableType": { + "name": "", + "type": 8, + "typeArguments": [] + }, + "name": "CONFIGURABLE_STRUCT", + "offset": 3432 + }, + { + "configurableType": { + "name": "", + "type": 6, + "typeArguments": [] + }, + "name": "CONFIGURABLE_ENUM_A", + "offset": 3400 + }, + { + "configurableType": { + "name": "", + "type": 6, + "typeArguments": [] + }, + "name": "CONFIGURABLE_ENUM_B", + "offset": 3416 + }, + { + "configurableType": { + "name": "", + "type": 2, + "typeArguments": null + }, + "name": "ARRAY_BOOL", + "offset": 3328 + }, + { + "configurableType": { + "name": "", + "type": 3, + "typeArguments": null + }, + "name": "ARRAY_U64", + "offset": 3336 + }, + { + "configurableType": { + "name": "", + "type": 1, + "typeArguments": null + }, + "name": "TUPLE_BOOL_U64", + "offset": 3456 + }, + { + "configurableType": { + "name": "", + "type": 7, + "typeArguments": null + }, + "name": "STR_4", + "offset": 3448 + } + ], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "messagesTypes": [], + "types": [ + { + "components": [], + "type": "()", + "typeId": 0, + "typeParameters": null + }, + { + "components": [ + { + "name": "__tuple_element", + "type": 5, + "typeArguments": null + }, + { + "name": "__tuple_element", + "type": 12, + "typeArguments": null + } + ], + "type": "(_, _)", + "typeId": 1, + "typeParameters": null + }, + { + "components": [ + { + "name": "__array_element", + "type": 5, + "typeArguments": null + } + ], + "type": "[_; 3]", + "typeId": 2, + "typeParameters": null + }, + { + "components": [ + { + "name": "__array_element", + "type": 12, + "typeArguments": null + } + ], + "type": "[_; 3]", + "typeId": 3, + "typeParameters": null + }, + { + "components": null, + "type": "b256", + "typeId": 4, + "typeParameters": null + }, + { + "components": null, + "type": "bool", + "typeId": 5, + "typeParameters": null + }, + { + "components": [ + { + "name": "A", + "type": 5, + "typeArguments": null + }, + { + "name": "B", + "type": 12, + "typeArguments": null + } + ], + "type": "enum ConfigurableEnum", + "typeId": 6, + "typeParameters": null + }, + { + "components": null, + "type": "str[4]", + "typeId": 7, + "typeParameters": null + }, + { + "components": [ + { + "name": "a", + "type": 5, + "typeArguments": null + }, + { + "name": "b", + "type": 12, + "typeArguments": null + } + ], + "type": "struct ConfigurableStruct", + "typeId": 8, + "typeParameters": null + }, + { + "components": null, + "type": "u16", + "typeId": 9, + "typeParameters": null + }, + { + "components": null, + "type": "u256", + "typeId": 10, + "typeParameters": null + }, + { + "components": null, + "type": "u32", + "typeId": 11, + "typeParameters": null + }, + { + "components": null, + "type": "u64", + "typeId": 12, + "typeParameters": null + }, + { + "components": null, + "type": "u8", + "typeId": 13, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..2daeaffdc6a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/json_abi_oracle_new_encoding.json @@ -0,0 +1,228 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", + "metadataTypeId": 0, + "type": "(bool, u64)" + }, + { + "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", + "metadataTypeId": 1, + "type": "[bool; 3]" + }, + { + "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", + "metadataTypeId": 2, + "type": "[u64; 3]" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "type": "bool" + }, + { + "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", + "metadataTypeId": 3, + "type": "enum ConfigurableEnum" + }, + { + "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", + "type": "str[4]" + }, + { + "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", + "metadataTypeId": 4, + "type": "struct ConfigurableStruct" + }, + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "type": "u16" + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "type": "u256" + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "type": "u32" + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "type": "u8" + } + ], + "configurables": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "name": "BOOL", + "offset": 6896 + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "U8", + "offset": 7088 + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "ANOTHER_U8", + "offset": 6824 + }, + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "name": "U16", + "offset": 7032 + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "U32", + "offset": 7072 + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "U64", + "offset": 7080 + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "name": "U256", + "offset": 7040 + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "B256", + "offset": 6864 + }, + { + "concreteTypeId": "81fc10c4681a3271cf2d66b2ec6fbc8ed007a442652930844fcf11818c295bff", + "name": "CONFIGURABLE_STRUCT", + "offset": 6984 + }, + { + "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", + "name": "CONFIGURABLE_ENUM_A", + "offset": 6904 + }, + { + "concreteTypeId": "a2922861f03be8a650595dd76455b95383a61b46dd418f02607fa2e00dc39d5c", + "name": "CONFIGURABLE_ENUM_B", + "offset": 6944 + }, + { + "concreteTypeId": "4926d35d1a5157936b0a29bc126b8aace6d911209a5c130e9b716b0c73643ea6", + "name": "ARRAY_BOOL", + "offset": 6832 + }, + { + "concreteTypeId": "776fb5a3824169d6736138565fdc20aad684d9111266a5ff6d5c675280b7e199", + "name": "ARRAY_U64", + "offset": 6840 + }, + { + "concreteTypeId": "c998ca9a5f221fe7b5c66ae70c8a9562b86d964408b00d17f883c906bc1fe4be", + "name": "TUPLE_BOOL_U64", + "offset": 7016 + }, + { + "concreteTypeId": "94f0fa95c830be5e4f711963e83259fe7e8bc723278ab6ec34449e791a99b53a", + "name": "STR_4", + "offset": 7008 + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "NOT_USED", + "offset": 7000 + } + ], + "encodingVersion": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "__tuple_element", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "__tuple_element", + "typeId": 5 + } + ], + "metadataTypeId": 0, + "type": "(_, _)" + }, + { + "components": [ + { + "name": "__array_element", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + } + ], + "metadataTypeId": 1, + "type": "[_; 3]" + }, + { + "components": [ + { + "name": "__array_element", + "typeId": 5 + } + ], + "metadataTypeId": 2, + "type": "[_; 3]" + }, + { + "components": [ + { + "name": "A", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "B", + "typeId": 5 + }, + { + "name": "C", + "typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + } + ], + "metadataTypeId": 3, + "type": "enum ConfigurableEnum" + }, + { + "components": [ + { + "name": "a", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "b", + "typeId": 5 + } + ], + "metadataTypeId": 4, + "type": "struct ConfigurableStruct" + }, + { + "metadataTypeId": 5, + "type": "u64" + } + ], + "programType": "script", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw new file mode 100644 index 00000000000..a0e5d11a345 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/src/main.sw @@ -0,0 +1,83 @@ +script; + +use std::hash::*; + +struct ConfigurableStruct { + a: bool, + b: u64, +} + +enum ConfigurableEnum { + A: bool, + B: u64, + C: b256 +} + +impl core::ops::Eq for ConfigurableEnum { + fn eq(self, other: ConfigurableEnum) -> bool { + match (self, other) { + (ConfigurableEnum::A(inner1), ConfigurableEnum::A(inner2)) => inner1 == inner2, + (ConfigurableEnum::B(inner1), ConfigurableEnum::B(inner2)) => inner1 == inner2, + _ => false, + } + } +} + +type AnotherU8 = u8; + +configurable { + BOOL: bool = true, + U8: u8 = 1, + ANOTHER_U8: AnotherU8 = 3, + U16: u16 = 2, + U32: u32 = 3, + U64: u32 = 4, + U256: u256 = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu256, + B256: b256 = 0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB, + CONFIGURABLE_STRUCT: ConfigurableStruct = ConfigurableStruct { a: true, b: 5 }, + CONFIGURABLE_ENUM_A: ConfigurableEnum = ConfigurableEnum::A(true), + CONFIGURABLE_ENUM_B: ConfigurableEnum = ConfigurableEnum::B(12), + ARRAY_BOOL: [bool; 3] = [true, false, true], + ARRAY_U64: [u64; 3] = [9, 8, 7], + TUPLE_BOOL_U64: (bool, u64) = (true, 11), + STR_4: str[4] = __to_str_array("abcd"), + + NOT_USED: u8 = 1 +} + +fn main() { +} + +#[test] +fn t() { + assert(BOOL == true); + assert(U8 == 1); + assert(ANOTHER_U8 == 3); + assert(U16 == 2); + assert(U32 == 3); + assert(U64 == 4); + assert(U256 == 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu256); + assert(B256 == 0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB); + assert(CONFIGURABLE_STRUCT.a == true); + assert(CONFIGURABLE_STRUCT.b == 5); + assert(CONFIGURABLE_ENUM_A == ConfigurableEnum::A(true)); + assert(CONFIGURABLE_ENUM_B == ConfigurableEnum::B(12)); + assert(ARRAY_BOOL[0] == true); + assert(ARRAY_BOOL[1] == false); + assert(ARRAY_BOOL[2] == true); + assert(ARRAY_U64[0] == 9); + assert(ARRAY_U64[1] == 8); + assert(ARRAY_U64[2] == 7); + assert(TUPLE_BOOL_U64.0 == true); + assert(TUPLE_BOOL_U64.1 == 11); + assert(sha256_str_array(STR_4) == sha256("abcd")); + + // Assert address do not change + let addr_1 = asm(addr: __addr_of(&BOOL)) { + addr: u64 + }; + let addr_2 = asm(addr: __addr_of(&BOOL)) { + addr: u64 + }; + assert(addr_1 == addr_2); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml new file mode 100644 index 00000000000..0f3f6d7e866 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_tests/test.toml @@ -0,0 +1 @@ +category = "unit_tests_pass" diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw index 54c8ccf3246..2bfa29631e6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/src/main.sw @@ -2,12 +2,24 @@ contract; storage { f1:u64 = 1, + #[cfg(experimental_storage_domains = true)] + f2 in 0xcecf0a910789de762c699a85a66835df1662df633238cbb25804b7f78640747b: u64 = 2, + #[cfg(experimental_storage_domains = false)] f2 in 0x36389d1013642dcb070193fc48b0316e9dfdfef1860096dc5957e3eb44430b83: u64 = 2, ns1 { f3 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, }, ns2 { f4 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, - } + }, + ns3 { + #[cfg(experimental_storage_domains = true)] + f5 in 0x41e70e0fdfa49becc40cbfd5c057ab0540e8844f3d737fa3b1ab21a564b48069: u64 = 3, + #[cfg(experimental_storage_domains = false)] + f5 in 0xa49ebab6739a90f7658bbbdc2ed139942bd0b7be2e89aa8d90a953c45bf7a211: u64 = 3, + }, + ns4 { + f6: u64 = 4, + }, } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml new file mode 100644 index 00000000000..4e181f7e13d --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.storage_domains.toml @@ -0,0 +1,30 @@ +category = "compile" +experimental = { storage_domains = true } + +# check: $()Two storage fields have the same storage key +# check: $()f1:u64 = 1, +# nextln: $()"storage.f1" has the same storage key as "storage.f2". +# check: $()f2 in 0xcecf0a910789de762c699a85a66835df1662df633238cbb25804b7f78640747b: u64 = 2, +# nextln: $()"storage.f2" is declared here. +# check: $()The key of "storage.f1" is generated by the compiler using the following formula: +# nextln: $()sha256((0u8, "storage.f1")) +# nextln: $()The common key is: 0xcecf0a910789de762c699a85a66835df1662df633238cbb25804b7f78640747b. + +# check: $()Two storage fields have the same storage key +# check: $()f3 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns1.f3" has the same storage key as "storage::ns2.f4". +# check: $()f4 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns2.f4" is declared here. +# check: $()Both keys are explicitly defined by using the `in` keyword. +# nextln: $()The common key is: 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca. + +# check: $()Two storage fields have the same storage key +# check: $()f5 in 0x41e70e0fdfa49becc40cbfd5c057ab0540e8844f3d737fa3b1ab21a564b48069: u64 = 3, +# nextln: $()"storage::ns3.f5" has the same storage key as "storage::ns4.f6". +# check: $()f6: u64 = 4, +# nextln: $()"storage::ns4.f6" is declared here. +# check: $()The key of "storage::ns4.f6" is generated by the compiler using the following formula: +# nextln: $()sha256((0u8, "storage::ns4.f6")) +# nextln: $()The common key is: 0x41e70e0fdfa49becc40cbfd5c057ab0540e8844f3d737fa3b1ab21a564b48069. + +expected_warnings = 9 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml index 8e5e7a86ef3..30c36d8b5f8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/duplicated_storage_keys/test.toml @@ -1,13 +1,29 @@ category = "compile" -# check: $()Two storage fields are using the same storage key. -# nextln: $()First field: storage.f1 -# nextln: $()Second field: storage.f2 -# nextln: $()Key: 36389D1013642DCB070193FC48B0316E9DFDFEF1860096DC5957E3EB44430B83 +# check: $()Two storage fields have the same storage key +# check: $()f1:u64 = 1, +# nextln: $()"storage.f1" has the same storage key as "storage.f2". +# check: $()f2 in 0x36389d1013642dcb070193fc48b0316e9dfdfef1860096dc5957e3eb44430b83: u64 = 2, +# nextln: $()"storage.f2" is declared here. +# check: $()The key of "storage.f1" is generated by the compiler using the following formula: +# nextln: $()sha256("storage.f1") +# nextln: $()The common key is: 0x36389d1013642dcb070193fc48b0316e9dfdfef1860096dc5957e3eb44430b83. -# check: $()Two storage fields are using the same storage key. -# nextln: $()First field: storage::ns1.f3 -# nextln: $()Second field: storage::ns2.f4 -# nextln: $()Key: 5F4C20CE4BD128E5393A4C2B82007DAC795FA0006D01ACF8DB4C42632BC680CA +# check: $()Two storage fields have the same storage key +# check: $()f3 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns1.f3" has the same storage key as "storage::ns2.f4". +# check: $()f4 in 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca: u64 = 2, +# nextln: $()"storage::ns2.f4" is declared here. +# check: $()Both keys are explicitly defined by using the `in` keyword. +# nextln: $()The common key is: 0x5f4c20ce4bd128e5393a4c2b82007dac795fa0006d01acf8db4c42632bc680ca. -expected_warnings = 6 +# check: $()Two storage fields have the same storage key +# check: $()f5 in 0xa49ebab6739a90f7658bbbdc2ed139942bd0b7be2e89aa8d90a953c45bf7a211: u64 = 3, +# nextln: $()"storage::ns3.f5" has the same storage key as "storage::ns4.f6". +# check: $()f6: u64 = 4, +# nextln: $()"storage::ns4.f6" is declared here. +# check: $()The key of "storage::ns4.f6" is generated by the compiler using the following formula: +# nextln: $()sha256("storage::ns4.f6") +# nextln: $()The common key is: 0xa49ebab6739a90f7658bbbdc2ed139942bd0b7be2e89aa8d90a953c45bf7a211. + +expected_warnings = 9 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw index 3e5e72a76e3..f050a4cc0fc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/generic_traits/src/main.sw @@ -4,9 +4,9 @@ script; // but until then, multiple methods with the same name is undefined behavior. // https://doc.rust-lang.org/rust-by-example/trait/disambiguating.html -mod my_double; +pub mod my_double; mod my_point; -mod my_triple; +pub mod my_triple; use my_point::MyPoint; use my_triple::MyTriple; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw index 136515fc5c3..1f0fbad59be 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_method_from_other_file/src/main.sw @@ -1,7 +1,7 @@ script; mod context; -mod asset; +pub mod asset; mod utils; use context::Context; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw index 29e6fe78ddf..d672a617d81 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/import_with_different_callpaths/src/main.sw @@ -1,6 +1,6 @@ script; -mod data_structures; +pub mod data_structures; mod eq_impls; use eq_impls::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore new file mode 100644 index 00000000000..77d3844f58c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock new file mode 100644 index 00000000000..f9932679777 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.lock @@ -0,0 +1,8 @@ +[[package]] +name = "core" +source = "path+from-root-E4EB5F90E61EC58F" + +[[package]] +name = "transmute" +source = "member" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml new file mode 100644 index 00000000000..457f84ef26a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +license = "Apache-2.0" +entry = "main.sw" +name = "transmute" + +[dependencies] +core = { path = "../../../../../../../../sway-lib-core" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json new file mode 100644 index 00000000000..7ebeae3ddd5 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/json_abi_oracle_new_encoding.json @@ -0,0 +1,28 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "logId": "1515152261580153489" + } + ], + "messagesTypes": [], + "metadataTypes": [], + "programType": "script", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw new file mode 100644 index 00000000000..9bad6776dcc --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/src/main.sw @@ -0,0 +1,121 @@ +script; + +fn assert(v: bool) { + if !v { + __revert(0); + } +} + +enum SomeEnum { + A: u64, + B: u64 +} + +pub struct SomeStruct { + #[allow(dead_code)] + tag: u64, + #[allow(dead_code)] + value: u64 +} + +fn const_transmute() { + // u16 needs 8 bytes as u64 + const U8ARRAY_U16 = __transmute::<[u8; 8], u16>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8]); + assert(U8ARRAY_U16 == 0x0102u16); + + // u32 needs 8 bytes as u64 + const U8ARRAY_U32 = __transmute::<[u8; 8], u32>([0u8, 0u8, 0u8, 0u8, 1u8, 2u8, 3u8, 4u8]); + assert(U8ARRAY_U32 == 0x01020304u32); + + const U8ARRAY_U64 = __transmute::<[u8; 8], u64>([1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8]); + assert(U8ARRAY_U64 == 0x0102030405060708u64); + + // u32 <-> u64 + const U32_U64 = __transmute::(1u32); + assert(U32_U64 == 0x0000000000000001u64); + + const U64_U32 = __transmute::(1u64); + assert(U64_U32 == 0x00000001u32); +} + +fn main() { + const_transmute(); + + // Check transmute work as nop + let u8_u8 = __transmute::(1); + assert(u8_u8 == 1); + + let u16_u16 = __transmute::(1); + assert(u16_u16 == 1); + + let u32_u32 = __transmute::(1); + assert(u32_u32 == 1); + + let u64_u64 = __transmute::(1); + assert(u64_u64 == 1); + + // Check transmute arrays + let u8array_u8 = __transmute::<[u8; 1], u8>([1u8]); + assert(u8array_u8 == 1); + + // u16 needs 8 bytes as u64 + let u8array_u16 = __transmute::<[u8; 8], u64>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]); + assert(u8array_u16 == 1); + + // u32 needs 8 bytes as u64 + let u8array_u32 = __transmute::<[u8; 8], u32>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]); + assert(u8array_u32 == 1); + + let u8array_u64 = __transmute::<[u8; 8], u64>([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8]); + assert(u8array_u64 == 1); + + // u32 <-> u64 + let u32_u64 = __transmute::(1u32); + assert(u32_u64 == 0x0000000000000001u64); + + let u64_u32 = __transmute::(1u64); + assert(u64_u32 == 0x00000001u32); + + // check u256 and b256 are transmutable + let u256_b256 = __transmute::(u256::max()); + assert(u256_b256 == b256::max()); + + // b256 to arrays of u64 and back + let b256_u64array = __transmute::(b256::max()); + assert(b256_u64array[0] == u64::max()); + assert(b256_u64array[1] == u64::max()); + assert(b256_u64array[2] == u64::max()); + assert(b256_u64array[3] == u64::max()); + let u64array_b256 = __transmute::<[u64; 4], b256>(b256_u64array); + assert(u64array_b256 == b256::max()); + + // Check tuples + let b256_tuple_u64 = __transmute::(b256::max()); + assert(b256_tuple_u64.0 == u64::max()); + assert(b256_tuple_u64.1 == u64::max()); + assert(b256_tuple_u64.2 == u64::max()); + assert(b256_tuple_u64.3 == u64::max()); + let tuple_u64_b256 = __transmute::<(u64, u64, u64, u64), b256>(b256_tuple_u64); + assert(tuple_u64_b256 == b256::max()); + + // u16 is actually as big as a u64 + // even inside "structs" + let tuple_u8_u6_u8 = __transmute::<(u8, u16, u8), (u8, u64, u8)>((1, 2, 3)); + assert(tuple_u8_u6_u8.0 == 1); + assert(tuple_u8_u6_u8.1 == 2); + assert(tuple_u8_u6_u8.2 == 3); + + // Check struct to enum + let some_struct: SomeStruct = SomeStruct { tag: 0, value: 1 }; + let some_enum = __transmute::(some_struct); + match some_enum { + SomeEnum::A(v) => assert(v == 1), + _ => {} + }; + + // check enum to struct + let some_enum = SomeEnum::B(1); + let some_struct = __transmute::(some_enum); + assert(some_struct.tag == 1); + assert(some_struct.value == 1); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml new file mode 100644 index 00000000000..f656259dc91 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/intrinsics/transmute/test.toml @@ -0,0 +1,4 @@ +category = "run" +expected_result = { action = "return", value = 0 } +expected_result_new_encoding = { action = "return_data", value = "" } + diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml index a06f647ef58..79e3031d8bd 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/Forc.toml @@ -5,4 +5,4 @@ license = "Apache-2.0" name = "main_args_various_types" [dependencies] -std = { path = "../../../../../reduced_std_libs/sway-lib-std-assert" } +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json index 6d95b04580f..ee7cb119623 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/json_abi_oracle_new_encoding.json @@ -6,8 +6,8 @@ "type": "[(struct OpName, enum SignedNum); 2]" }, { - "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", - "type": "u64" + "concreteTypeId": "d489af6a272dc02bb98c58446e5250345c65721ecfef3f43b26c263819725668", + "type": "generic AliasedS" } ], "configurables": [], @@ -22,7 +22,7 @@ } ], "name": "main", - "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + "output": "d489af6a272dc02bb98c58446e5250345c65721ecfef3f43b26c263819725668" } ], "loggedTypes": [ @@ -61,11 +61,11 @@ "components": [ { "name": "Positive", - "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + "typeId": 5 }, { "name": "Negative", - "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + "typeId": 5 } ], "metadataTypeId": 2, @@ -84,6 +84,10 @@ ], "metadataTypeId": 4, "type": "struct OpName" + }, + { + "metadataTypeId": 5, + "type": "u64" } ], "programType": "script", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw index cf8cb142ee1..55cf6bae4d3 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/main.sw @@ -1,5 +1,9 @@ script; +mod types; + +use types::{S as AliasedS}; + fn eq_str_3(a: str[3], b: str) -> bool { let ptr_b = b.as_ptr(); asm(a: a, b: ptr_b, len: 3, r) { @@ -17,7 +21,7 @@ struct OpName { val: str[3] } -fn main(ops: [(OpName, SignedNum); 2]) -> u64 { +fn main(ops: [(OpName, SignedNum); 2]) -> AliasedS { __log(ops); assert(eq_str_3(ops[0].0.val, "set")); assert(match ops[0].1 { @@ -31,5 +35,7 @@ fn main(ops: [(OpName, SignedNum); 2]) -> u64 { _ => revert(2), } == 1); - 1 + AliasedS{ + v: 1 + } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw new file mode 100644 index 00000000000..8e5e9741521 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/main_args/main_args_various_types/src/types.sw @@ -0,0 +1,5 @@ +library; + +pub struct S { + pub v: u64 +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw index ffa92ace5e7..df1535977a6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_constants/src/main.sw @@ -1,6 +1,6 @@ script; -mod lib; +pub mod lib; mod top_level; mod in_structs; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml index 2a24c489834..1d19796346b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/match_expressions_or/test.toml @@ -2,4 +2,4 @@ category = "run" expected_result = { action = "return", value = 42 } expected_result_new_encoding = { action = "return_data", value = "000000000000002A" } validate_abi = true -expected_warnings = 7 #TODO: Set number of warnings to minimum once TODOs in tests are solved. +expected_warnings = 7 #TODO: Set number of warnings to minimum once TODOs in tests are solved. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw index e59f07dba62..94d40f22f5b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep/src/lib.sw @@ -1,7 +1,7 @@ library; -mod a; -mod b; +pub mod a; +pub mod b; fn main() -> u32 { 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw index 06ceb2f6e8b..db23337b474 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/module_dep_multiple/src/lib.sw @@ -1,8 +1,8 @@ library; mod c; -mod a; -mod b; +pub mod a; +pub mod b; fn main() -> u32 { 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw index 18a842fa725..b1a1ee9b298 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/aliases/src/main.sw @@ -1,15 +1,15 @@ script; -mod items_1; -mod lib_1; // Aliased item reexports of items_1 -mod items_2; -mod lib_2; // Aliased item reexports of items_2 -mod items_3; -mod lib_3_1; // Aliased item reexports of items_3 -mod lib_3_2; // Aliased item reexports of lib_3_1 -mod items_4; -mod lib_4_1; // Aliased item reexports of items_4 -mod lib_4_2; // Aliased item reexports of items_4 with different aliases +pub mod items_1; +pub mod lib_1; // Aliased item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Aliased item reexports of items_2 +pub mod items_3; +pub mod lib_3_1; // Aliased item reexports of items_3 +pub mod lib_3_2; // Aliased item reexports of lib_3_1 +pub mod items_4; +pub mod lib_4_1; // Aliased item reexports of items_4 +pub mod lib_4_2; // Aliased item reexports of items_4 with different aliases mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw index 4ae46fbab15..01cd29bb68c 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/multiple_imports_of_same_reexport/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1_1; // Item reexports of items_1 -mod lib_1_2; // Item reexports of items_1 -mod items_2; -mod lib_2_1; // Star reexports of items_2 -mod lib_2_2; // Star reexports of items_2 -mod items_3; -mod lib_3_1; // Star reexports of items_3 -mod lib_3_2; // Item reexports of items_3 -mod items_4; -mod lib_4_1; // Item reexports of items_4 -mod lib_4_2; // Star reexports of items_4 +pub mod items_1; +pub mod lib_1_1; // Item reexports of items_1 +pub mod lib_1_2; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2_1; // Star reexports of items_2 +pub mod lib_2_2; // Star reexports of items_2 +pub mod items_3; +pub mod lib_3_1; // Star reexports of items_3 +pub mod lib_3_2; // Item reexports of items_3 +pub mod items_4; +pub mod lib_4_1; // Item reexports of items_4 +pub mod lib_4_2; // Star reexports of items_4 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw index 84a4dffa3df..738e0d7b893 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/reexport_paths/src/main.sw @@ -1,15 +1,15 @@ script; -mod items_1; -mod lib_1_1; // Reexports of items_1 -mod lib_1_2; // Reexports of lib_1_1 -mod lib_2; // Reexports of std::hash::Hasher, which is not part of the std prelude -mod lib_3_1; // Reexports of std::hash::Hash, which is not part of the std prelude -mod lib_3_2; // Reexports of std::hash::Hash, which is not part of the std prelude -mod lib_4; // Reexport of std::registers::global_gas -mod lib_5; // Reexport of core::codec::* -//mod lib_6_1; // Reexports of std::address::Address from the std prelude -mod lib_6_2; // Reexports of std::address::Address directly from std::address +pub mod items_1; +pub mod lib_1_1; // Reexports of items_1 +pub mod lib_1_2; // Reexports of lib_1_1 +pub mod lib_2; // Reexports of std::hash::Hasher, which is not part of the std prelude +pub mod lib_3_1; // Reexports of std::hash::Hash, which is not part of the std prelude +pub mod lib_3_2; // Reexports of std::hash::Hash, which is not part of the std prelude +pub mod lib_4; // Reexport of std::registers::global_gas +pub mod lib_5; // Reexport of core::codec::* +//pub mod lib_6_1; // Reexports of std::address::Address from the std prelude +pub mod lib_6_2; // Reexports of std::address::Address directly from std::address mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw index a2961173628..c0290b47faf 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/shadowing_in_reexporting_module/src/main.sw @@ -1,17 +1,17 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2_1; -mod items_2_2; -mod lib_2; // Item reexports of items_2_1 and items_2_2 -mod items_3_1; -mod lib_3; // Item reexports of items_3_1 and items_3_2 -mod items_4_1; -mod items_4_2; -mod items_4_3; -mod items_4_4; -mod lib_4; // Item reexports of items_4_1 and items_4_2 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2_1; +pub mod items_2_2; +pub mod lib_2; // Item reexports of items_2_1 and items_2_2 +pub mod items_3_1; +pub mod lib_3; // Item reexports of items_3_1 and items_3_2 +pub mod items_4_1; +pub mod items_4_2; +pub mod items_4_3; +pub mod items_4_4; +pub mod lib_4; // Item reexports of items_4_1 and items_4_2 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw index 57262307323..fe1ea19f9c1 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_glob_import/src/main.sw @@ -1,9 +1,9 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw index 0b3777176d7..6470ef09668 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/simple_item_import/src/main.sw @@ -1,9 +1,9 @@ script; -mod items_1; -mod lib_1; // Item reexports of items_1 -mod items_2; -mod lib_2; // Item reexports of items_2 +pub mod items_1; +pub mod lib_1; // Item reexports of items_1 +pub mod items_2; +pub mod lib_2; // Item reexports of items_2 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw index 078a2114541..55d7e81f033 100755 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/reexport/visibility/src/main.sw @@ -1,11 +1,11 @@ script; -mod items_1; -mod lib_1_1; // Item reexports of items_1 -mod lib_1_2; // Item imports without reexport of items_1 -mod items_2; -mod lib_2_1; // Item imports without reexport of items_1 -mod lib_2_2; // Item reexports of items_1 +pub mod items_1; +pub mod lib_1_1; // Item reexports of items_1 +pub mod lib_1_2; // Item imports without reexport of items_1 +pub mod items_2; +pub mod lib_2_1; // Item imports without reexport of items_1 +pub mod lib_2_2; // Item reexports of items_1 mod tests; // All tests diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock new file mode 100644 index 00000000000..e52d486e352 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-1F6D5E67DD060824" + +[[package]] +name = "mutability_of_references_memcpy_bug" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-1F6D5E67DD060824" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml new file mode 100644 index 00000000000..66e2ad87de3 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "mutability_of_references_memcpy_bug" + +[dependencies] +std = { path = "../../../../../reduced_std_libs/sway-lib-std-assert" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw new file mode 100644 index 00000000000..88c1bfa547f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/lib.sw @@ -0,0 +1,19 @@ +library; + +#[inline(never)] +pub fn unit(b: u256) -> u256 { + b +} + +#[inline(never)] +pub fn weird(_b: u256) { + let mut b = _b; // b = _b = 2 + + log(b); + + let mut b_tmp = b; // b_tmp = b = 2 + + b = 0x03u256; // b = a = 1 + + assert(unit(b_tmp) == 0x02u256); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw new file mode 100644 index 00000000000..91454432859 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/src/main.sw @@ -0,0 +1,27 @@ +contract; + +pub mod lib; + +use ::lib::weird; + +abi MyContract { + fn test_function(b: u256) -> u256; +} + +impl MyContract for Contract { + + fn test_function(_b: u256) -> u256 { + weird(_b); + 0x00u256 + } +} + + + +#[test] +fn test() { + let caller = abi(MyContract, CONTRACT_ID); + let b = 0x02u256; + + let _ = caller.test_function(b); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml new file mode 100644 index 00000000000..ad1782559e7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/references/mutability_of_references_memcpy_bug/test.toml @@ -0,0 +1,3 @@ +category = "unit_tests_pass" +validate_abi = false +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json index 49a75d8d5c1..c58838960ad 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json @@ -9,7 +9,7 @@ { "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", "name": "SOME_U256", - "offset": 816 + "offset": 872 } ], "encodingVersion": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw index ce2c888d964..4dd52fdef97 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/use_absolute_path/src/main.sw @@ -1,6 +1,6 @@ script; -mod r#trait; +pub mod r#trait; mod foo; use ::foo::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw index ffc9dcbe016..8d0a9e93e2c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x14ed3cd06c2947248f69d54bfa681fe40d26267be84df7e19e253622b7921bbe; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xdf53a7533a12c5ee3df459fc424f51807fc9740f13080a725f5f66408ede1186; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release +const CONTRACT_ID = 0xe0c85555f3d94e58cc23830deb6dc193e1f173761a4fc5d56d3e07a5a1db0378; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release fn get_address() -> Option { Some(CONTRACT_ID.into()) diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw index 5459da78f0c..6da541af0b8 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw @@ -9,12 +9,12 @@ use test_fuel_coin_abi::*; #[cfg(experimental_new_encoding = false)] const FUEL_COIN_CONTRACT_ID = 0xec2277ebe007ade87e3d797c3b1e070dcd542d5ef8f038b471f262ef9cebc87c; #[cfg(experimental_new_encoding = true)] -const FUEL_COIN_CONTRACT_ID = 0xf2fecff29038dab2ef571397ea5507359265c9154608e7de36ccbea20ed5c8aa; +const FUEL_COIN_CONTRACT_ID = 0xcdb572031a0779e09beea1e93e21630d104766c90cc8ce90c8dfd0abdd0ce5b2; // AUTO-CONTRACT-ID ../../test_contracts/test_fuel_coin_contract --release #[cfg(experimental_new_encoding = false)] const BALANCE_CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const BALANCE_CONTRACT_ID = 0xaa4e3d9c953790384f76dcad07e21d6973ae8df79432e48bbed76ccb6437a9a7; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release +const BALANCE_CONTRACT_ID = 0xb770fa56f665d6fbdbdceecce21b7b61878f650981ac7f21c052613015937034; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let default_gas = 1_000_000_000_000; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml index a653725436b..ebf2e18c854 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/test.toml @@ -1,5 +1,8 @@ category = "run_on_node" expected_result = { action = "result", value = 1 } expected_result_new_encoding = { action = "return_data", value = "01" } -contracts = ["should_pass/test_contracts/balance_test_contract", "should_pass/test_contracts/test_fuel_coin_contract"] -unsupported_profiles = ["debug"] \ No newline at end of file +contracts = [ + "should_pass/test_contracts/balance_test_contract", + "should_pass/test_contracts/test_fuel_coin_contract", +] +unsupported_profiles = ["debug"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw index 365a489a3dd..638541084b4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw @@ -5,7 +5,7 @@ use balance_test_abi::BalanceTest; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xaa4e3d9c953790384f76dcad07e21d6973ae8df79432e48bbed76ccb6437a9a7; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release +const CONTRACT_ID = 0xb770fa56f665d6fbdbdceecce21b7b61878f650981ac7f21c052613015937034; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let balance_test_contract = abi(BalanceTest, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw index b0a18868637..9a078ca2bbc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw @@ -6,7 +6,7 @@ use abi_with_tuples::{MyContract, Location, Person}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xfdc14550c8aee742cd556d0ab7f378b7be0d3b1e6e086c097352e94590d4ed02; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xe21bdb5e019c073978f5bd6eee1339a0e68ab38b913d8a00ff1286e9e5eb894d; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release +const CONTRACT_ID = 0xcc679c89d2950879d4f8fb3b99770f93dfde3335fff574cbf0588691fbcefde3; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release fn main() -> bool { let the_abi = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index 1ed97f22e9d..d6a56b1b07e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -4,7 +4,7 @@ use basic_storage_abi::{BasicStorage, Quad}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x94db39f409a31b9f2ebcadeea44378e419208c20de90f5d8e1e33dc1523754cb; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xb48002b23e2861d62237348199ff111e310f5dd10298a01562e3a4d41cb6aae6; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release +const CONTRACT_ID = 0x52954afa6e6020d78b4daa89bc2bfceb31a7b85a97f55a49946f67d4e03b66c0; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release fn main() -> u64 { let addr = abi(BasicStorage, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw index eab00cc7b7c..7dc873bf458 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw @@ -5,7 +5,7 @@ use contract_with_type_aliases_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x0cbeb6efe3104b460be769bdc4ea101ebf16ccc16f2d7b667ec3e1c7f5ce35b5; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x8b400005d6178d7ceaccac502a021abad28a899ab8692099c0bfa5e70853d573; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release +const CONTRACT_ID = 0x5f2d9be937ca4a0de3404d1165d0faed6f8c440ab9ba7c6c046904e28761f7f7; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release fn main() { let caller = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index 28089f44fa3..28218e97054 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -6,7 +6,7 @@ use dynamic_contract_call::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xd1b4047af7ef111c023ab71069e01dc2abfde487c0a0ce1268e4f447e6c6e4c2; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xe1dbd25c5d2ccb547ce1f592d04a407dec80cc715255c358dfb32ccf9ca0f926; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release +const CONTRACT_ID = 0xc2694e6a397883ae59ea2e807c0ba3714865d0c4bf16571893d632b3bd7ec6f7; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release fn main() -> bool { let the_abi = abi(Incrementor, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index af5bdc4cd47..b8060557890 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -5,7 +5,7 @@ use storage_enum_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc601d11767195485a6654d566c67774134668863d8c797a8c69e8778fb1f89e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x434f5f10c3270134e51a1963f610286466e448c1c6109e4f20502939c7a3d429; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release +const CONTRACT_ID = 0xd9247267148944e3f541347c65705af8798b257e8acda1e89e220c4bdf9298fc; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release fn main() -> u64 { let caller = abi(StorageEnum, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw index ae8dc25bd57..ea5fb5c74e5 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw @@ -5,7 +5,7 @@ use auth_testing_abi::AuthTesting; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc2eec20491b53aab7232cbd27c31d15417b4e9daf0b89c74cc242ef1295f681f; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x507e5e609fdb2a085da8d681519b6bb6b738f2beb0321600c1e3497db3114a37; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release +const CONTRACT_ID = 0xcdc67c314d13752e5c3e10aa1de6615e1ec6864e0461317b5f26eef3320a9a8e; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release // should be false in the case of a script fn main() -> bool { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw index 4a0c2e86a63..64dec655d14 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw @@ -6,7 +6,7 @@ use context_testing_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x6054c11cda000f5990373a4d61929396165be4dfdd61d5b7bd26da60ab0d8577; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xb80ada1b7018cd6cb45dac7e0dfc1b17fc2931439facc55bd784523410e31449; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release +const CONTRACT_ID = 0xecf511a0e2f4022c17413625d69c390d51d0740424d6886cbbe9ca60acd0606b; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release fn main() -> bool { let gas: u64 = u64::max(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw index 69da3b33161..1364b7aa4b4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw @@ -5,7 +5,7 @@ use nested_struct_args_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xe63d33a1b3a6903808b379f6a41a72fa8a370e8b76626775e7d9d2f9c4c5da40; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xc4f40cab476f1e705db3cdb22367eb20ebb180213801918db9b2030db56a0542; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release +const CONTRACT_ID = 0x27e6a749a1773f65f850b36e4e61afdbfe72ba4189cd518c16e06cf0c04a1fa9; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release fn main() -> bool { let caller = abi(NestedStructArgs, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index 7850cbec2ad..181a7fd980a 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x3bc28acd66d327b8c1b9624c1fabfc07e9ffa1b5d71c2832c3bfaaf8f4b805e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xa8eb4bf19964abcc5fdeac8daa1e5816326f728e9883f0287cf4c404527291a8; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release +const CONTRACT_ID = 0x03ad85f37b515247a0481ba4d1448a5592b8684312e7f2626d4403ab9fec2acc; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release fn main() -> bool { let caller = abi(StorageAccess, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw index f37ed2f5bff..ea66b079683 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/option/src/main.sw @@ -1,6 +1,6 @@ script; -mod data_structures; +pub mod data_structures; mod tests; use tests::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw index f37ed2f5bff..ea66b079683 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/stdlib/result/src/main.sw @@ -1,6 +1,6 @@ script; -mod data_structures; +pub mod data_structures; mod tests; use tests::*; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock new file mode 100644 index 00000000000..fe96407a20f --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-90F1067CD9AC8A94" + +[[package]] +name = "std" +source = "path+from-root-90F1067CD9AC8A94" +dependencies = ["core"] + +[[package]] +name = "storage_slot_key_calculation" +source = "member" +dependencies = ["std"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml new file mode 100644 index 00000000000..cb479a470ea --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/Forc.toml @@ -0,0 +1,8 @@ +[project] +name = "storage_slot_key_calculation" +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw new file mode 100644 index 00000000000..a4810dff242 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/src/main.sw @@ -0,0 +1,53 @@ +contract; + +use std::hash::*; + +storage { + a: u8 = 0, + b: u8 = 0, + ns1 { + a: u8 = 0, + b: u8 = 0, + }, + ns2 { + ns3 { + a: u8 = 0, + b: u8 = 0, + }, + }, +} + +abi TestStorageKeyCalculation { + #[storage(read)] + fn test_storage_key_calculation(); +} + +impl TestStorageKeyCalculation for Contract { + #[cfg(experimental_storage_domains = false)] + #[storage(read)] + fn test_storage_key_calculation() { + assert_eq(storage.a.slot(), sha256("storage.a")); + assert_eq(storage.b.slot(), sha256("storage.b")); + assert_eq(storage::ns1.a.slot(), sha256("storage::ns1.a")); + assert_eq(storage::ns1.b.slot(), sha256("storage::ns1.b")); + assert_eq(storage::ns2::ns3.a.slot(), sha256("storage::ns2::ns3.a")); + assert_eq(storage::ns2::ns3.b.slot(), sha256("storage::ns2::ns3.b")); + } + + #[cfg(experimental_storage_domains = true)] + #[storage(read)] + fn test_storage_key_calculation() { + assert_eq(storage.a.slot(), sha256((0u8, "storage.a"))); + assert_eq(storage.b.slot(), sha256((0u8, "storage.b"))); + assert_eq(storage::ns1.a.slot(), sha256((0u8, "storage::ns1.a"))); + assert_eq(storage::ns1.b.slot(), sha256((0u8, "storage::ns1.b"))); + assert_eq(storage::ns2::ns3.a.slot(), sha256((0u8, "storage::ns2::ns3.a"))); + assert_eq(storage::ns2::ns3.b.slot(), sha256((0u8, "storage::ns2::ns3.b"))); + } +} + +#[test] +fn test() { + let caller = abi(TestStorageKeyCalculation, CONTRACT_ID); + caller.test_storage_key_calculation(); +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml new file mode 100644 index 00000000000..0890b8a8510 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml new file mode 100644 index 00000000000..c82484373af --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/storage_slot_key_calculation/test.toml @@ -0,0 +1,2 @@ +category = "unit_tests_pass" +expected_warnings = 1 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..2f821ed58f1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_abi_oracle.storage_domains.json @@ -0,0 +1,297 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeArguments": [ + "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + ] + }, + { + "concreteTypeId": "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6", + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeArguments": [ + "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6" + ] + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "type": "u256" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "type": "u8" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "storage_key" + } + ], + "name": "get_u64", + "output": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "slots" + } + ], + "name": "intrinsic_load_quad", + "output": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + } + ], + "name": "intrinsic_load_word", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "name": "values" + } + ], + "name": "intrinsic_store_quad", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "intrinsic_store_word", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "store_u64", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "test_storage_exhaustive", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "logId": "14454674236531057292" + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "logId": "1970142151624111756" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "logId": "8961848586872524460" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "logId": "1515152261580153489" + } + ], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "None", + "typeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "name": "Some", + "typeId": 1 + } + ], + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeParameters": [ + 1 + ] + }, + { + "metadataTypeId": 1, + "type": "generic T" + }, + { + "metadataTypeId": 2, + "type": "raw untyped ptr" + }, + { + "components": [ + { + "name": "v1", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v2", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v3", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v4", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "components": [ + { + "name": "ptr", + "typeId": 2 + }, + { + "name": "cap", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 4, + "type": "struct std::vec::RawVec", + "typeParameters": [ + 1 + ] + }, + { + "components": [ + { + "name": "buf", + "typeArguments": [ + { + "name": "", + "typeId": 1 + } + ], + "typeId": 4 + }, + { + "name": "len", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeParameters": [ + 1 + ] + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..8c0169567bb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,58 @@ +[ + { + "key": "040f131e97eaba9c2d25f5c1d6ea9489ce530940dd87d486f8cd9c7ff5360f6c", + "value": "6161616161000000000000000000000000000000000000000000000000000000" + }, + { + "key": "077f64b0ca598a020551265c0faf95f8e860b45700f27c06af3640a123818b17", + "value": "6161000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "2b46310c8d886cf7d9e4339837ecc696ecfaf2c431e56e725c552b92b11c3bc8", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "30226b031f925fbb2a1ad161ce31b798a684c6f52ed49cf84e244d324eceaf58", + "value": "6161616100000000000000000000000000000000000000000000000000000000" + }, + { + "key": "42e97a774f87c61347e7283755a043a5a896d37e801045e8f5ce538b6d1ce8c8", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "78dabd24c80fc40f05bae92654874f2f77bd13ef803fd55ccf014ff5849cdfd0", + "value": "6161616161610000000000000000000000000000000000000000000000000000" + }, + { + "key": "848a0a618b9c374a4b1b47c59ef2f0a01f5c42bb5e805ffd669412ce283b992a", + "value": "6161616161616161000000000000000000000000000000000000000000000000" + }, + { + "key": "84e44dc0900861559343f0fc02dc0d92f7e87872a50e730a85740b701b162863", + "value": "6161616161616100000000000000000000000000000000000000000000000000" + }, + { + "key": "933a534d4af4c376b0b569e8d8a2c62e635e26f403e124cb91d9c42e83d54373", + "value": "0100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "976540acfef542cb328d6679def3e281cdb1a5bbaca7d9e59a30aa74f3952d90", + "value": "6100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "9d3f8eb1f2d99b97a2fd6fa68fe7e5a9c5b6734739f8dd84f2ae3da221206a80", + "value": "0000000000000002000000000000000000000000000000000000000000000000" + }, + { + "key": "a42ed3ecc6aaf8d594f165e6c60cdaf172d59436167556f954e6559036736ceb", + "value": "6161610000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "d33763008c92b260fc4381d53aa5976de2b5f991798799fa5edf300bb4a40e02", + "value": "6161616161616161616100000000000000000000000000000000000000000000" + }, + { + "key": "f8fde9e56bb5ab545fdfe17edabb876e6f4cd1b3296d92b266d4acb9ca0b5f79", + "value": "6161616161616161610000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw index 532709bfed7..251577caf5b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/src/main.sw @@ -296,8 +296,6 @@ fn test_storage() { assert_eq(storage::ns1::ns2.c1.read(), NS1_NS2_C1); assert_eq(storage.c1.slot(), C1KEY); - assert_eq(storage.const_b256.slot(), sha256("storage.const_b256")); - assert_eq(storage::ns1::ns2.c1.slot(), sha256("storage::ns1::ns2.c1")); } // If these comparisons are done inline just above then it blows out the register allocator due to diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml new file mode 100644 index 00000000000..0890b8a8510 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml index 8bce24f6a24..c1349fc15dc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/basic_storage/test.toml @@ -1,4 +1,4 @@ category = "compile" validate_abi = true validate_storage_slots = true -expected_warnings = 3 +expected_warnings = 2 # TODO-DCA: Set to zero once https://github.com/FuelLabs/sway/issues/5921 is fixed. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..edd98a1f3d1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_abi_oracle.storage_domains.json @@ -0,0 +1,102 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "metadataTypeId": 1, + "type": "enum std::option::Option", + "typeArguments": [ + "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + ] + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "increment_by" + } + ], + "name": "increment", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "name": "initial_value" + } + ], + "name": "increment_or_not", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [ + { + "metadataTypeId": 0, + "type": "()" + }, + { + "components": [ + { + "name": "None", + "typeId": 0 + }, + { + "name": "Some", + "typeId": 2 + } + ], + "metadataTypeId": 1, + "type": "enum std::option::Option", + "typeParameters": [ + 2 + ] + }, + { + "metadataTypeId": 2, + "type": "generic T" + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..efa6132760a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,6 @@ +[ + { + "key": "d810923c0d6cc6ed49622594d7368eb1e124753474e3ebd52a66c6c2ecb42642", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/increment_contract/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock new file mode 100644 index 00000000000..efaec2f6f2a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = "core" +source = "path+from-root-2A7B279266ACFF97" + +[[package]] +name = "issue_6335_repro" +source = "member" +dependencies = ["std"] + +[[package]] +name = "std" +source = "path+from-root-2A7B279266ACFF97" +dependencies = ["core"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml new file mode 100644 index 00000000000..5f7f8ed6230 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/Forc.toml @@ -0,0 +1,9 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +implicit-std = false +license = "Apache-2.0" +name = "issue_6335_repro" + +[dependencies] +std = { path = "../../../../reduced_std_libs/sway-lib-std-conversions" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw new file mode 100644 index 00000000000..36c95885603 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/src/main.sw @@ -0,0 +1,25 @@ +contract; + +use std::bytes::*; + +abi MyAbi { + fn test() -> u64; +} + +abi FakeAbi { + fn test() -> Bytes; +} + +impl MyAbi for Contract { + fn test() -> u64 { + 64 + } +} + +#[test] +fn test() { + let caller = abi(FakeAbi, CONTRACT_ID); + let res = caller.test(); + assert(res.len() == 64); + let s: str[30] = abi_decode(res.as_raw_slice()); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml new file mode 100644 index 00000000000..526e7df8fdb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/issue_6335_repro/test.toml @@ -0,0 +1,4 @@ +category = "compile" +validate_abi = false +validate_storage_slots = false +expected_warnings = 0 diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw index 1dd7e0293ea..92e93915701 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/return_struct/src/main.sw @@ -1,6 +1,6 @@ contract; -mod data_structures; +pub mod data_structures; mod interface; use interface::MyContract; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..9a1f9ebd31e --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_abi_oracle.storage_domains.json @@ -0,0 +1,769 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "type": "bool" + }, + { + "concreteTypeId": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15", + "metadataTypeId": 0, + "type": "enum storage_access_abi::E" + }, + { + "concreteTypeId": "893a66eb2f595d7e0cc15e2253da1b6e53fd634ad542b2f1a198a8ae3d8d92b2", + "type": "str[40]" + }, + { + "concreteTypeId": "427fd62288add8763eb5e0c4facf553d877489a3038b29a8a1045e9a853660f0", + "metadataTypeId": 1, + "type": "struct storage_access_abi::S" + }, + { + "concreteTypeId": "74df8abb4a65a07ec7420c0f167703fc6e26c9e43b8036ffacb89d399f13db73", + "metadataTypeId": 2, + "type": "struct storage_access_abi::T" + }, + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "type": "u16" + }, + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "type": "u32" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + }, + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "type": "u8" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_boolean", + "output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_e", + "output": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_e2", + "output": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_int16", + "output": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_int32", + "output": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_int8", + "output": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s", + "output": "427fd62288add8763eb5e0c4facf553d877489a3038b29a8a1045e9a853660f0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t", + "output": "74df8abb4a65a07ec7420c0f167703fc6e26c9e43b8036ffacb89d399f13db73" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_boolean", + "output": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_int16", + "output": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_int32", + "output": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_int8", + "output": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_x", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_y", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_t_dot_z", + "output": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_x", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_y", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_s_dot_z", + "output": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_string", + "output": "893a66eb2f595d7e0cc15e2253da1b6e53fd634ad542b2f1a198a8ae3d8d92b2" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_x", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "get_y", + "output": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "name": "boolean" + } + ], + "name": "set_boolean", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "35b24140807b67d1f1675de36775d5d6c62b04f3721f616a9adee739e24c9c15", + "name": "e" + } + ], + "name": "set_e", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "name": "int16" + } + ], + "name": "set_int16", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "int32" + } + ], + "name": "set_int32", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "int8" + } + ], + "name": "set_int8", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "427fd62288add8763eb5e0c4facf553d877489a3038b29a8a1045e9a853660f0", + "name": "s" + } + ], + "name": "set_s", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "74df8abb4a65a07ec7420c0f167703fc6e26c9e43b8036ffacb89d399f13db73", + "name": "t" + } + ], + "name": "set_s_dot_t", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "name": "boolean" + } + ], + "name": "set_s_dot_t_dot_boolean", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef", + "name": "int16" + } + ], + "name": "set_s_dot_t_dot_int16", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc", + "name": "int32" + } + ], + "name": "set_s_dot_t_dot_int32", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b", + "name": "int8" + } + ], + "name": "set_s_dot_t_dot_int8", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "x" + } + ], + "name": "set_s_dot_t_dot_x", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "y" + } + ], + "name": "set_s_dot_t_dot_y", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "z" + } + ], + "name": "set_s_dot_t_dot_z", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "x" + } + ], + "name": "set_s_dot_x", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "y" + } + ], + "name": "set_s_dot_y", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "z" + } + ], + "name": "set_s_dot_z", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "893a66eb2f595d7e0cc15e2253da1b6e53fd634ad542b2f1a198a8ae3d8d92b2", + "name": "string" + } + ], + "name": "set_string", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "x" + } + ], + "name": "set_x", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "y" + } + ], + "name": "set_y", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903", + "logId": "13213829929622723620" + } + ], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "A", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "B", + "typeId": 2 + } + ], + "metadataTypeId": 0, + "type": "enum storage_access_abi::E" + }, + { + "components": [ + { + "name": "x", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "y", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "z", + "typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "name": "t", + "typeId": 2 + } + ], + "metadataTypeId": 1, + "type": "struct storage_access_abi::S" + }, + { + "components": [ + { + "name": "x", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "y", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "z", + "typeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b" + }, + { + "name": "boolean", + "typeId": "b760f44fa5965c2474a3b471467a22c43185152129295af588b022ae50b50903" + }, + { + "name": "int8", + "typeId": "c89951a24c6ca28c13fd1cfdc646b2b656d69e61a92b91023be7eb58eb914b6b" + }, + { + "name": "int16", + "typeId": "29881aad8730c5ab11d275376323d8e4ff4179aae8ccb6c13fe4902137e162ef" + }, + { + "name": "int32", + "typeId": "d7649d428b9ff33d188ecbf38a7e4d8fd167fa01b2e10fe9a8f9308e52f1d7cc" + } + ], + "metadataTypeId": 2, + "type": "struct storage_access_abi::T" + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..ff1eae7956b --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,74 @@ +[ + { + "key": "419b1120ea993203d7e223dfbe76184322453d6f8de946e827a8669102ab395b", + "value": "0000000000000040000000000000000000000000000000000000000000000000" + }, + { + "key": "4b06f7ce27bc88217a7c9d4300619d2900cef25ecb29a790ec869b02e4191275", + "value": "4141414141414141414141414141414141414141414141414141414141414141" + }, + { + "key": "4b06f7ce27bc88217a7c9d4300619d2900cef25ecb29a790ec869b02e4191276", + "value": "4141414141414141000000000000000000000000000000000000000000000000" + }, + { + "key": "7299da45c4430837636de04fb23f3343a80d88c1dc0455562b3066913f0d7745", + "value": "0000000000000020000000000000000000000000000000000000000000000000" + }, + { + "key": "865b6b6b53f4babe503029163d7076d649da88a10c4ed333d19c645d271f495c", + "value": "0000000000000010000000000000000000000000000000000000000000000000" + }, + { + "key": "8e06966f123f8d6e298f853c70d34036061474c4674b7960119ac4a08a557f0c", + "value": "0000000000000001000000000000000100000000000000020000000000000000" + }, + { + "key": "8e06966f123f8d6e298f853c70d34036061474c4674b7960119ac4a08a557f0d", + "value": "0000000000000000000000000000000000000000000000030100000000000000" + }, + { + "key": "8e06966f123f8d6e298f853c70d34036061474c4674b7960119ac4a08a557f0e", + "value": "0400000000000000000000000000000500000000000000060000000000000000" + }, + { + "key": "9538bea0a4c2601b6bd45782e4c10df5728427e310421d9a5d93f85a1f3704f2", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "9538bea0a4c2601b6bd45782e4c10df5728427e310421d9a5d93f85a1f3704f3", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "9538bea0a4c2601b6bd45782e4c10df5728427e310421d9a5d93f85a1f3704f4", + "value": "0000000000000000000000000000000000000000000003090000000000000000" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c86", + "value": "0000000000000001000000000000000200000000000000000000000000000000" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c87", + "value": "0000000000000000000000000000000300000000000000040000000000000005" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c88", + "value": "0000000000000000000000000000000000000000000000000000000000000006" + }, + { + "key": "ae10a55cca3f364be094340b109ccf393d12c2c07417ff2e719b1816ac793c89", + "value": "0100000000000000070000000000000000000000000000080000000000000009" + }, + { + "key": "d871d81721e9905a5cafe5b82dfde0ddb930f96a8e6deb44f92a8c9ce4d24ac1", + "value": "0800000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "e8aaf9a6b72b4eee2bcb2315773bc50e9166ff05c4221843637e25f0424a5dd5", + "value": "0100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "eb390d9f85c8c849ff8aeb05c865ca66b37ba69a7bec8489b1c467f029b650af", + "value": "0101010101010101010101010101010101010101010101010101010101010101" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_access_contract/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..32bd4e374ca --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_abi_oracle.storage_domains.json @@ -0,0 +1,31 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "read_write_enums", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "loggedTypes": [], + "messagesTypes": [], + "metadataTypes": [], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..f2d1ca396cb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,62 @@ +[ + { + "key": "12f9e955b5b2b5a00c0ebd1320f2cbd0e66c39396b3b3d7ff95c87f4b6e48c0d", + "value": "000000000000000000000000000000cd00000000000000000000000000000000" + }, + { + "key": "23e09d7a09a27d7d9c5c9d0f5191084c19a0a668c60b804a94e99234e6069c7b", + "value": "0000000000000001000000000000aa00000000000000bb00000000000000cc00" + }, + { + "key": "2e7251f5b28dbe052a7f5113d45f3cc2faccf7c955cbc0966089aa0d0059beab", + "value": "0000000000000001000000000000ab00000000000000bc00000000000000cd00" + }, + { + "key": "2e7251f5b28dbe052a7f5113d45f3cc2faccf7c955cbc0966089aa0d0059beac", + "value": "000000000000de00000000000000ef0000000000000000000000000000000000" + }, + { + "key": "2f02e964cd75fddf505a740d9daa11fef5f09b4d17058f893fc0f4e8b2244f53", + "value": "0000000000000000000000000000000100000000000000000000000000000000" + }, + { + "key": "50010301032c3383ef066fbb9ac7c25e3de42bdd5ccaec2d6e0bd26b6531bb0f", + "value": "0000000000000000000000000000000100000000000000000000000000000000" + }, + { + "key": "6b765908aa8ec7bc3a1d73cd252e40fb055de29fb0e9486a16e388cba9fa7c9f", + "value": "00000000000000000000000000000000000000000000000000000000000000ee" + }, + { + "key": "728df923e281e7cb9793c2c2d6419b735161b5e1b8d5ca2065569611418fc194", + "value": "000000000000000100000000000000cd00000000000000000000000000000000" + }, + { + "key": "7ddacb90e6ff09ed9aa4fde095854476123392aab8c73165cc65097b0a2a2578", + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "7ddacb90e6ff09ed9aa4fde095854476123392aab8c73165cc65097b0a2a2579", + "value": "000000000000000000000000000000ff00000000000000000000000000000000" + }, + { + "key": "c20357da738934c36211a22c69d4c44bc7a3b500b07d9e7328c3f0a7c2c426c0", + "value": "0000000000000002000000000000000000000000000000000000000000000000" + }, + { + "key": "d60810fb854958d678015228bfbd5a23a3e1763c1ff90f6790f69fbb85b413c6", + "value": "000000000000000000000000000000ab00000000000000000000000000000000" + }, + { + "key": "d71ff2e9ac87ec91301ee89d18b1dc8991b79753f004ce0810661bd5bfa92bd2", + "value": "0000000000000001000000000000bb0000000000000000000000000000000000" + }, + { + "key": "d9149ae8e217ec10a045c9f83c5bc9d227285fe76b9bcdc8245e6a57a23d0229", + "value": "000000000000000000000000000000aa00000000000000000000000000000000" + }, + { + "key": "e7af73ebbf0ab36c9e30283a504e1326febe010a1b2d0deae9252af8302526a1", + "value": "0000000000000002000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw index e604563d4e2..597bed643ce 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/src/main.sw @@ -117,10 +117,6 @@ fn check_s_u8_a(expected: u8) -> u8 { assert(i == expected); return i; }, - _ => { - assert(false); - return 99; - } } } @@ -132,10 +128,6 @@ fn check_s_u64_a(expected: u64) -> u64 { assert(i == expected); return i; }, - _ => { - assert(false); - return 9999; - } } } @@ -147,10 +139,6 @@ fn check_s_bool_a(expected: bool) -> u64 { assert(i == expected); return 171; }, - _ => { - assert(false); - return 9999; - } } } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_enum_contract/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json new file mode 100644 index 00000000000..a7b039e5eeb --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_abi_oracle.storage_domains.json @@ -0,0 +1,289 @@ +{ + "concreteTypes": [ + { + "concreteTypeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d", + "type": "()" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "type": "b256" + }, + { + "concreteTypeId": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d", + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeArguments": [ + "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + ] + }, + { + "concreteTypeId": "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6", + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeArguments": [ + "6906df92e2e485dde893b7d719d621b8910422e7c468f99caa5920e6ac19d9c6" + ] + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "type": "u256" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "type": "u64" + } + ], + "configurables": [], + "encodingVersion": "1", + "functions": [ + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "storage_key" + } + ], + "name": "get_u64", + "output": "d852149004cc9ec0bbe7dc4e37bffea1d41469b759512b6136f2e865a4c06e7d" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "slots" + } + ], + "name": "intrinsic_load_quad", + "output": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff" + }, + { + "attributes": [ + { + "arguments": [ + "read" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + } + ], + "name": "intrinsic_load_word", + "output": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "7880d311d30802b48bd6a100a31adb5af17f94bff12daee556d4f02c1ac5b2ff", + "name": "values" + } + ], + "name": "intrinsic_store_quad", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "intrinsic_store_word", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "write" + ], + "name": "storage" + } + ], + "inputs": [ + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "name": "key" + }, + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "name": "value" + } + ], + "name": "store_u64", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "attributes": [ + { + "arguments": [ + "read", + "write" + ], + "name": "storage" + } + ], + "inputs": [], + "name": "test_storage_exhaustive", + "output": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + } + ], + "loggedTypes": [ + { + "concreteTypeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0", + "logId": "1515152261580153489" + }, + { + "concreteTypeId": "1b5759d94094368cfd443019e7ca5ec4074300e544e5ea993a979f5da627261e", + "logId": "1970142151624111756" + }, + { + "concreteTypeId": "7c5ee1cecf5f8eacd1284feb5f0bf2bdea533a51e2f0c9aabe9236d335989f3b", + "logId": "8961848586872524460" + } + ], + "messagesTypes": [], + "metadataTypes": [ + { + "components": [ + { + "name": "None", + "typeId": "2e38e77b22c314a449e91fafed92a43826ac6aa403ae6a8acb6cf58239fbaf5d" + }, + { + "name": "Some", + "typeId": 1 + } + ], + "metadataTypeId": 0, + "type": "enum std::option::Option", + "typeParameters": [ + 1 + ] + }, + { + "metadataTypeId": 1, + "type": "generic T" + }, + { + "metadataTypeId": 2, + "type": "raw untyped ptr" + }, + { + "components": [ + { + "name": "v1", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v2", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v3", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + }, + { + "name": "v4", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 3, + "type": "struct basic_storage_abi::Quad" + }, + { + "components": [ + { + "name": "ptr", + "typeId": 2 + }, + { + "name": "cap", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 4, + "type": "struct std::vec::RawVec", + "typeParameters": [ + 1 + ] + }, + { + "components": [ + { + "name": "buf", + "typeArguments": [ + { + "name": "", + "typeId": 1 + } + ], + "typeId": 4 + }, + { + "name": "len", + "typeId": "1506e6f44c1d6291cdf46395a8e573276a4fa79e8ace3fc891e092ef32d1b0a0" + } + ], + "metadataTypeId": 5, + "type": "struct std::vec::Vec", + "typeParameters": [ + 1 + ] + } + ], + "programType": "contract", + "specVersion": "1" +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json new file mode 100644 index 00000000000..30e9e240f7c --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/json_storage_slots_oracle.storage_domains.json @@ -0,0 +1,54 @@ +[ + { + "key": "130875c838ab7f4f039a63d56d8173198d6edade9a61967c93b9d32d93547979", + "value": "6161000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "1997c0b14a3944421bc909d65cdb7f96023661790725e7a06d0bdf211002f9c0", + "value": "6161610000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "1cb08489095e2318cabf34c2c00b0f2b78c151bf4e3caf2a1762778c1b79c052", + "value": "0000000000000001000000000000000000000000000000000000000000000000" + }, + { + "key": "35338f6734c20524ba70780eae61e4dc5398122eab4a3cad9509a3d3ddc1551b", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "55279c57558d3bb1938f803552769ed7dcb3efacd74d9a16cf71d0cfbaab6c0a", + "value": "6161616161616161616100000000000000000000000000000000000000000000" + }, + { + "key": "5d5895256cdf173ecc135c1a18de5133b00b36e5caae538407a883dd44cc0dac", + "value": "0000000000000000000000000000000000000000000000000000000001234567" + }, + { + "key": "5dbeb0e7fc4c2fa3b01b9873d2a4e23488fb486046b6074b4ae463b7bbacbe89", + "value": "6161616161000000000000000000000000000000000000000000000000000000" + }, + { + "key": "659790a8d5d87a599ab69d1a3e6f48ff00c850fb7d24ccd782b209a52e4be83c", + "value": "6161616161616100000000000000000000000000000000000000000000000000" + }, + { + "key": "7aac1eb5fdc9d977b39721c2ccddb3ae405eecac0d8570e3be2d70fe677db4bd", + "value": "6161616161616161610000000000000000000000000000000000000000000000" + }, + { + "key": "8449d22802f944884dd98b791627c4265f4303014d1975f3da48fde003d77936", + "value": "6161616161616161000000000000000000000000000000000000000000000000" + }, + { + "key": "c2f546e9b4a2a37895f7f563be4610aa580468ddd8ba5d3544513965d79eac8a", + "value": "6100000000000000000000000000000000000000000000000000000000000000" + }, + { + "key": "e1ba0adcc27d3a21cfe72cc296e282f1c4b9f6798f89ac4e4b8ac95e3ee16d81", + "value": "6161616161610000000000000000000000000000000000000000000000000000" + }, + { + "key": "fdcf008347ae968111d6837c46f05f1a9943e76f6998d51ee1220b4069709a51", + "value": "6161616100000000000000000000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml new file mode 100644 index 00000000000..24be96bbf31 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.storage_domains.toml @@ -0,0 +1 @@ +experimental = { storage_domains = true } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml index 94671fb72d4..a235275de20 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/storage_namespace/test.toml @@ -1,4 +1,4 @@ category = "compile" validate_abi = true validate_storage_slots = true -expected_warnings = 1 +expected_warnings = 1 # TODO-DCA: Set to zero once https://github.com/FuelLabs/sway/issues/5921 is fixed. diff --git a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw index 65597943ef7..e32d25da40b 100644 --- a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw @@ -779,6 +779,7 @@ fn bytes_append_to_empty() { }; } +#[test()] fn bytes_append_self() { let (mut bytes, a, b, c) = setup(); assert(bytes.len() == 3); @@ -797,6 +798,7 @@ fn bytes_append_self() { assert(bytes.get(5).unwrap() == c); } +#[test()] fn bytes_append_empty_self() { let mut empty_bytes = Bytes::new(); diff --git a/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw index c2641d71272..7a320860c83 100644 --- a/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/math_inline_tests/src/main.sw @@ -1,5 +1,7 @@ library; +mod modulo; + use std::{flags::{disable_panic_on_overflow, disable_panic_on_unsafe_math}, registers::flags}; #[test] diff --git a/test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw b/test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw new file mode 100644 index 00000000000..43187e0b69d --- /dev/null +++ b/test/src/in_language_tests/test_programs/math_inline_tests/src/modulo.sw @@ -0,0 +1,147 @@ +library; + +use std::flags::disable_panic_on_unsafe_math; + +// u8 +#[test] +pub fn u8_modulo() { + let u8_max = u8::max(); + + assert(0u8 % 1u8 == 0u8); + assert(0u8 % 2u8 == 0u8); + assert(1u8 % 1u8 == 0u8); + assert(1u8 % 2u8 == 1u8); + + assert(u8_max % 1u8 == 0u8); + assert(u8_max % 2u8 == 1u8); + assert(u8_max % u8_max == 0u8); + assert(254u8 % u8_max == 254u8); +} + +#[test(should_revert)] +pub fn u8_modulo_panic_on_undefined_math() { + log(1u8 % 0u8); +} + +#[test] +pub fn u8_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u8 % 0u8 == 0u8); + assert(1u8 % 0u8 == 0u8); + assert(u8::max() % 0u8 == 0u8); +} + +// u16 +#[test] +pub fn u16_modulo() { + let u16_max = u16::max(); + + assert(0u16 % 1u16 == 0u16); + assert(0u16 % 2u16 == 0u16); + assert(1u16 % 1u16 == 0u16); + assert(1u16 % 2u16 == 1u16); + + assert(u16_max % 1u16 == 0u16); + assert(u16_max % 2u16 == 1u16); + assert(u16_max % u16_max == 0u16); + assert((u16_max - 1u16) % u16_max == (u16_max - 1u16)); +} + +#[test(should_revert)] +pub fn u16_modulo_panic_on_undefined_math() { + log(1u16 % 0u16); +} + +#[test] +pub fn u16_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u16 % 0u16 == 0u16); + assert(1u16 % 0u16 == 0u16); + assert(u16::max() % 0u16 == 0u16); +} + +// u32 +#[test] +pub fn u32_modulo() { + let u32_max = u32::max(); + + assert(0u32 % 1u32 == 0u32); + assert(0u32 % 2u32 == 0u32); + assert(1u32 % 1u32 == 0u32); + assert(1u32 % 2u32 == 1u32); + + assert(u32_max % 1u32 == 0u32); + assert(u32_max % 2u32 == 1u32); + assert(u32_max % u32_max == 0u32); + assert((u32_max - 1u32) % u32_max == (u32_max - 1u32)); +} + +#[test(should_revert)] +pub fn u32_modulo_panic_on_undefined_math() { + log(1u32 % 0u32); +} + +#[test] +pub fn u32_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u32 % 0u32 == 0u32); + assert(1u32 % 0u32 == 0u32); + assert(u32::max() % 0u32 == 0u32); +} + +// u64 +#[test] +pub fn u64_modulo() { + let u64_max = u64::max(); + + assert(0u64 % 1u64 == 0u64); + assert(0u64 % 2u64 == 0u64); + assert(1u64 % 1u64 == 0u64); + assert(1u64 % 2u64 == 1u64); + + assert(u64_max % 1u64 == 0u64); + assert(u64_max % 2u64 == 1u64); + assert(u64_max % u64_max == 0u64); + assert((u64_max - 1u64) % u64_max == (u64_max - 1u64)); +} + +#[test(should_revert)] +pub fn u64_modulo_panic_on_undefined_math() { + log(1u64 % 0u64); +} + +#[test] +pub fn u64_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0u64 % 0u64 == 0u64); + assert(1u64 % 0u64 == 0u64); + assert(u64::max() % 0u64 == 0u64); +} + +// u256 +#[test] +pub fn u256_modulo() { + let u256_max = u256::max(); + + assert(0x0u256 % 0x1u256 == 0x0u256); + assert(0x1u256 % 0x1u256 == 0x0u256); + assert(0x1u256 % 0x2u256 == 0x1u256); + + assert(u256_max % 0x1u256 == 0x0u256); + assert(u256_max % 0x2u256 == 0x1u256); + assert(u256_max % u256_max == 0x0u256); + assert((u256_max - 0x1u256) % u256_max == (u256_max - 0x1u256)); +} + +#[test(should_revert)] +pub fn u256_modulo_panic_on_undefined_math() { + log(0x1u256 % 0x0u256); +} + +#[test] +pub fn u256_modulo_unsafe_math() { + disable_panic_on_unsafe_math(); + assert(0x0u256 % 0x0u256 == 0x0u256); + assert(0x1u256 % 0x0u256 == 0x0u256); + assert(u256::max() % 0x0u256 == 0x0u256); +} diff --git a/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw index cff1e49fc0e..e11a6f413cd 100644 --- a/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/revert_inline_tests/src/main.sw @@ -14,3 +14,8 @@ fn revert_revert_require() { fn pass_revert_require() { require(true, "error"); } + +#[test(should_revert)] +fn revert_revert_with_log() { + revert_with_log("error") +} diff --git a/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw index 4d7acda31fb..584a1716ad4 100644 --- a/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/u128_inline_tests/src/main.sw @@ -1,6 +1,14 @@ library; -use std::{u128::U128, registers::flags, flags::{set_flags, disable_panic_on_unsafe_math, disable_panic_on_overflow}}; +use std::{ + flags::{ + disable_panic_on_overflow, + disable_panic_on_unsafe_math, + set_flags, + }, + registers::flags, + u128::U128, +}; #[test] fn u128_from_u8() { @@ -686,6 +694,60 @@ fn u128_root() { assert(root_of_u_128 == U128::from((0, 1))); } +#[test] +fn u128_mod() { + let u128_zero = U128::zero(); + let u128_1 = U128::from((0, 1)); + let u128_2 = U128::from((0, 2)); + let u128_3 = U128::from((0, 3)); + let u128_max = U128::max(); + + assert(u128_zero % u128_1 == u128_zero); + assert(u128_zero % u128_2 == u128_zero); + assert(u128_zero % u128_3 == u128_zero); + assert(u128_zero % u128_max == u128_zero); + + assert(u128_1 % u128_1 == u128_zero); + assert(U128::from((0, 10)) % u128_1 == u128_zero); + assert(U128::from((0, 10000)) % u128_1 == u128_zero); + assert(u128_max % u128_1 == u128_zero); + + assert(u128_2 % u128_2 == u128_zero); + assert(u128_3 % u128_2 == u128_1); + assert(U128::from((0, 10)) % u128_2 == u128_zero); + assert(U128::from((0, 10000)) % u128_2 == u128_zero); + assert(U128::from((0, 10001)) % u128_2 == u128_1); + assert(U128::from((0, u64::max())) % u128_2 == u128_1); + assert(U128::from((u64::max(), 0)) % u128_2 == u128_zero); + assert(U128::from((u64::max(), 1)) % u128_2 == u128_1); + assert(u128_max % u128_2 == u128_1); + + assert(u128_3 % u128_3 == u128_zero); + assert(u128_2 % u128_3 == u128_2); + assert(u128_1 % u128_3 == u128_1); + assert(U128::from((0, 30000)) % u128_3 == u128_zero); + assert(U128::from((0, 30001)) % u128_3 == u128_1); + assert(U128::from((0, 30002)) % u128_3 == u128_2); + assert(U128::from((u64::max(), 0)) % u128_3 == u128_zero); + assert(U128::from((u64::max(), 1)) % u128_3 == u128_1); + assert(U128::from((u64::max(), 2)) % u128_3 == u128_2); + assert(u128_max % u128_3 == u128_zero); + + assert(U128::from((u64::max(), 0)) % U128::from((u64::max(), 0)) == u128_zero); + assert(U128::from((u64::max(), 1)) % U128::from((u64::max(), 0)) == u128_1); + assert(U128::from((u64::max(), 2)) % U128::from((u64::max(), 0)) == u128_2); + assert(U128::from((u64::max(), 3)) % U128::from((u64::max(), 0)) == u128_3); + assert(u128_max % U128::from((u64::max(), 0)) == U128::from((0, u64::max()))); +} + +#[test(should_revert)] +fn revert_u128_mod_zero() { + let a = U128::from((0, 1)); + let b = U128::zero(); + + let result = a % b; +} + #[test] fn u128_log() { let prior_flags = flags(); @@ -781,228 +843,272 @@ fn parity_u128_log_with_ruint() { // Failure cases found by comparing parity with ruint implementation of U128 // https://docs.rs/ruint/latest/src/ruint/log.rs.html#45-89 let a = [ - 2, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, - 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 29, - 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, - 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 60, 60, - 60, 60, 61, 61, 61, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, - 100, 100, 100, 100, + 2, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, + 14, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, + 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 29, 29, 29, + 29, 29, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, + 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, 60, 60, 60, + 60, 61, 61, 61, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, ]; let b = [ - 3, 3, 5, 6, 7, 3, 6, 7, 3, 7, 3, 3, 9, 10, 11, 12, 13, 14, 15, 3, 10, 11, 12, 13, 14, 15, - 3, 11, 12, 13, 14, 15, 3, 12, 13, 14, 15, 3, 13, 14, 15, 3, 14, 15, 3, 15, 3, 3, 5, 6, 7, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 3, 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, - 6, 7, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, - 6, 7, 25, 26, 27, 28, 29, 30, 31, 3, 6, 7, 26, 27, 28, 29, 30, 31, 3, 6, 7, 27, 28, 29, 30, - 31, 3, 6, 7, 28, 29, 30, 31, 3, 6, 7, 29, 30, 31, 3, 6, 7, 30, 31, 3, 6, 7, 31, 3, 6, 7, 3, - 6, 7, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, 7, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, 7, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 3, 6, 7, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 3, 7, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 3, 7, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 3, 7, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 3, 7, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 3, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 56, 57, 58, - 59, 60, 61, 62, 63, 3, 57, 58, 59, 60, 61, 62, 63, 3, 58, 59, 60, 61, 62, 63, 3, 59, 60, - 61, 62, 63, 3, 60, 61, 62, 63, 3, 61, 62, 63, 3, 62, 63, 3, 63, 3, 3, 5, 6, 7, 9, 10, 11, - 12, 13, 14, 15, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, - 12, 13, 14, 15, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, - 13, 14, 15, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, - 15, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, - 10, 11, 12, 13, 14, 15, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, - 11, 12, 13, 14, 15, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, - 7, 9, 10, 11, 12, 13, 14, 15, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, - 10, 11, 12, 13, 14, 15, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, - 7, 10, 11, 12, 13, 14, 15, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, - 14, 15, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, - 12, 13, 14, 15, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, - 11, 12, 13, 14, 15, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, - 11, 12, 13, 14, 15, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, - 12, 13, 14, 15, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, - 14, 15, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 93, 94, 95, 96, 97, - 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, - 10, 11, 12, 13, 14, 15, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 96, - 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, - 12, 13, 14, 15, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 99, 100, 3, 5, 6, 7, 10, - 11, 12, 13, 14, 15, 100, 3, 5, 6, 7, 11, 12, 13, 14, 15, + 3, 3, 5, 6, 7, 3, 6, 7, 3, 7, 3, 3, 9, 10, 11, 12, 13, 14, 15, 3, 10, 11, + 12, 13, 14, 15, 3, 11, 12, 13, 14, 15, 3, 12, 13, 14, 15, 3, 13, 14, 15, 3, + 14, 15, 3, 15, 3, 3, 5, 6, 7, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 3, 5, 6, 7, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 3, 5, 6, 7, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, + 5, 6, 7, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 3, 5, 6, 7, 23, 24, 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 24, + 25, 26, 27, 28, 29, 30, 31, 3, 5, 6, 7, 25, 26, 27, 28, 29, 30, 31, 3, 6, + 7, 26, 27, 28, 29, 30, 31, 3, 6, 7, 27, 28, 29, 30, 31, 3, 6, 7, 28, 29, 30, + 31, 3, 6, 7, 29, 30, 31, 3, 6, 7, 30, 31, 3, 6, 7, 31, 3, 6, 7, 3, 6, 7, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, 7, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 3, 6, 7, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 6, + 7, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 3, 7, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, + 7, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 3, 7, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 3, 7, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 3, 7, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 3, 7, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 3, 7, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 3, 7, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 3, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 3, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 3, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 3, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 3, 56, 57, 58, 59, 60, 61, 62, 63, 3, 57, 58, 59, 60, 61, + 62, 63, 3, 58, 59, 60, 61, 62, 63, 3, 59, 60, 61, 62, 63, 3, 60, 61, 62, 63, + 3, 61, 62, 63, 3, 62, 63, 3, 63, 3, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, + 6, 7, 9, 10, 11, 12, 13, 14, 15, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, + 14, 15, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, + 7, 9, 10, 11, 12, 13, 14, 15, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, + 6, 7, 9, 10, 11, 12, 13, 14, 15, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, + 13, 14, 15, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, + 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, + 11, 12, 13, 14, 15, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, + 15, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, + 7, 10, 11, 12, 13, 14, 15, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, + 5, 6, 7, 10, 11, 12, 13, 14, 15, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 92, 93, 94, 95, 96, 97, 98, 99, 100, 3, + 5, 6, 7, 10, 11, 12, 13, 14, 15, 93, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, + 7, 10, 11, 12, 13, 14, 15, 94, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, + 12, 13, 14, 15, 95, 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, + 96, 97, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 97, 98, 99, 100, + 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 98, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, + 14, 15, 99, 100, 3, 5, 6, 7, 10, 11, 12, 13, 14, 15, 100, 3, 5, 6, 7, 11, + 12, 13, 14, 15, ]; let expected = [ - 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 3, 1, 1, 0, - 0, 0, 3, 1, 1, 0, 0, 3, 1, 1, 0, 3, 1, 1, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 3, 0, 3, 3, 2, 2, 2, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, - 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 2, 2, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 3, + 1, 1, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 3, 1, 1, 0, 0, 3, 1, 1, 0, 3, 1, 1, 3, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 3, 0, 3, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 4, 2, 2, 2, 1, 1, 1, 1, 1, ]; @@ -1065,7 +1171,7 @@ fn u128_overflowing_pow() { let a = U128::max(); let res = a.pow(2); - + assert(res == U128::from((0, 0))); set_flags(prior_flags); @@ -1081,4 +1187,4 @@ fn u128_unsafemath_log2() { assert(res == U128::zero()); set_flags(prior_flags); -} \ No newline at end of file +} diff --git a/test/src/ir_generation/mod.rs b/test/src/ir_generation/mod.rs index 8313845fe39..6969ef1c689 100644 --- a/test/src/ir_generation/mod.rs +++ b/test/src/ir_generation/mod.rs @@ -223,7 +223,9 @@ pub(super) async fn run( tracing::info!("Testing {} ...", test_file_name.bold()); let experimental = ExperimentalFeatures { - new_encoding: false, // IR tests still need encoding v1 off + new_encoding: false, // IR tests still need encoding v1 off. + // TODO: Properly support experimental features in IR tests. + ..Default::default() }; // Compile to AST. We need to provide a faux build config otherwise the IR will have diff --git a/test/src/sdk-harness/Cargo.lock b/test/src/sdk-harness/Cargo.lock index dad11fa0e14..54d09476c97 100644 --- a/test/src/sdk-harness/Cargo.lock +++ b/test/src/sdk-harness/Cargo.lock @@ -14,18 +14,18 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli", + "gimli 0.31.1", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -85,9 +85,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "android-tzdata" @@ -106,9 +106,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -121,61 +121,61 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -185,9 +185,9 @@ checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "asn1-rs" -version = "0.5.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -201,25 +201,25 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", - "synstructure 0.12.6", + "syn 2.0.87", + "synstructure", ] [[package]] name = "asn1-rs-impl" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -251,7 +251,7 @@ dependencies = [ "futures-timer", "futures-util", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "mime", "multer", "num-traits", @@ -280,7 +280,7 @@ dependencies = [ "proc-macro2", "quote", "strum 0.26.3", - "syn 2.0.63", + "syn 2.0.87", "thiserror", ] @@ -303,16 +303,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5ec94176a12a8cbe985cd73f2e54dc9c702c88c766bdef12f1f3a67cedbee1" dependencies = [ "bytes", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_json", ] [[package]] name = "async-io" -version = "2.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -324,14 +324,14 @@ dependencies = [ "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener", "event-listener-strategy", @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -351,24 +351,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -419,9 +419,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" @@ -472,18 +472,18 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.32.2", + "object", "rustc-demangle", "serde", + "windows-targets 0.52.6", ] [[package]] @@ -536,9 +536,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -606,22 +606,22 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.0.97" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -630,6 +630,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chacha20" version = "0.9.1" @@ -666,7 +672,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -682,9 +688,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -692,9 +698,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -704,21 +710,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "cobs" @@ -780,9 +786,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -871,9 +877,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -895,27 +901,27 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" dependencies = [ "libc", ] [[package]] name = "cranelift-bforest" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305d51c180ebdc46ef61bc60c54ae6512db3bc9a05842a1f1e762e45977019ab" +checksum = "4a41b85213deedf877555a7878ca9fb680ccba8183611c4bb8030ed281b2ad83" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3247afacd9b13d620033f3190d9e49d1beefc1acb33d5604a249956c9c13709" +checksum = "690d8ae6c73748e5ce3d8fe59034dceadb8823e6c8994ba324141c5eae909b0e" dependencies = [ "serde", "serde_derive", @@ -923,9 +929,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7ca95e831c18d1356da783765c344207cbdffea91e13e47fa9327dbb2e0719" +checksum = "0ce027a7b16f8b86f60ff6819615273635186d607a0c225ee6ac340d7d18f978" dependencies = [ "bumpalo", "cranelift-bforest", @@ -935,44 +941,44 @@ dependencies = [ "cranelift-control", "cranelift-entity", "cranelift-isle", - "gimli", + "gimli 0.28.1", "hashbrown 0.14.5", "log", "regalloc2", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "450c105fa1e51bfba4e95a86e926504a867ad5639d63f31d43fe3b7ec1f1c9ef" +checksum = "f0a2d2ab65e6cbf91f81781d8da65ec2005510f18300eff21a99526ed6785863" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479117cd1266881479908d383086561cee37e49affbea9b1e6b594cc21cc220" +checksum = "efcff860573cf3db9ae98fbd949240d78b319df686cc306872e7fab60e9c84d7" [[package]] name = "cranelift-control" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34378804f0abfdd22c068a741cfeed86938b92375b2a96fb0b42c878e0141bfb" +checksum = "69d70e5b75c2d5541ef80a99966ccd97aaa54d2a6af19ea31759a28538e1685a" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a48cb0a194c9ba82fec35a1e492055388d89b2e3c03dee9dcf2488892be8004d" +checksum = "d21d3089714278920030321829090d9482c91e5ff2339f2f697f8425bffdcba3" dependencies = [ "cranelift-bitset", "serde", @@ -981,9 +987,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8327afc6c1c05f4be62fefce5b439fa83521c65363a322e86ea32c85e7ceaf64" +checksum = "7308482930f2a2fad4fe25a06054f6f9a4ee1ab97264308c661b037cb60001a3" dependencies = [ "cranelift-codegen", "log", @@ -993,15 +999,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b08621c00321efcfa3eee6a3179adc009e21ea8d24ca7adc3c326184bc3f48" +checksum = "ab4c59e259dab0e6958dabcc536b30845574f027ba6e5000498cdaf7e7ed2d30" [[package]] name = "cranelift-native" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51180b147c8557c1196c77b098f04140c91962e135ea152cd2fcabf40cf365c" +checksum = "d77ac3dfb61ef3159998105116acdfeaec75e4296c43ee2dcc4ea39838c0080e" dependencies = [ "cranelift-codegen", "libc", @@ -1010,9 +1016,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.110.2" +version = "0.110.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "019e3dccb7f15e0bc14f0ddc034ec608a66df8e05c9e1e16f75a7716f8461799" +checksum = "1d883f1b8d3d1dab4797407117bc8a1824f4a1fe86654aee2ee3205613f77d3e" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1035,9 +1041,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-deque" @@ -1060,9 +1066,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1114,16 +1120,15 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.1.2" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "platforms", "rustc_version", "subtle", "zeroize", @@ -1137,7 +1142,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1225,7 +1230,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1247,7 +1252,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1288,9 +1293,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.2.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ "asn1-rs", "displaydoc", @@ -1323,15 +1328,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.87", ] [[package]] @@ -1390,13 +1395,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1452,9 +1457,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -1481,6 +1486,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1489,23 +1500,23 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1525,7 +1536,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -1574,9 +1585,9 @@ checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" [[package]] name = "event-listener" -version = "4.0.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -1585,9 +1596,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener", "pin-project-lite", @@ -1617,9 +1628,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "ff" @@ -1667,6 +1678,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1695,7 +1712,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.63", + "syn 2.0.87", "thiserror", ] @@ -1705,7 +1722,7 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122c27ab46707017063bf1c6e0b4f3de881e22e81b4059750a0dc95033d9cc26" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "fuel-types 0.56.0", "serde", "strum 0.24.1", @@ -1717,7 +1734,7 @@ version = "0.58.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f325971bf9047ec70004f80a989e03456316bc19cbef3ff3a39a38b192ab56e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "fuel-types 0.58.2", "serde", "strum 0.24.1", @@ -1783,7 +1800,7 @@ dependencies = [ "tower", "tower-http 0.4.4", "tracing", - "uuid 1.8.0", + "uuid 1.11.0", ] [[package]] @@ -2189,8 +2206,8 @@ checksum = "3f49fdbfc1615d88d2849650afc2b0ac2fecd69661ebadd31a073d8416747764" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", - "synstructure 0.13.1", + "syn 2.0.87", + "synstructure", ] [[package]] @@ -2201,8 +2218,8 @@ checksum = "ab0bc46a3552964bae5169e79b383761a54bd115ea66951a1a7a229edcefa55a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", - "synstructure 0.13.1", + "syn 2.0.87", + "synstructure", ] [[package]] @@ -2263,7 +2280,7 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aae44611588d199dd119e4a0ebd8eb7ae4cde6bf8b4d12715610b1f5e5b731" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "fuel-asm 0.56.0", @@ -2285,7 +2302,7 @@ version = "0.58.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6723bb8710ba2b70516ac94d34459593225870c937670fb3afaf82e0354667ac" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "fuel-asm 0.58.2", @@ -2333,7 +2350,7 @@ checksum = "64fc4695efac9207276f6229f2dd9811848b328a13604a698f7bce1d452bd986" dependencies = [ "async-trait", "backtrace", - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "ethnum", @@ -2365,7 +2382,7 @@ dependencies = [ "anyhow", "async-trait", "backtrace", - "bitflags 2.5.0", + "bitflags 2.6.0", "derivative", "derive_more", "ethnum", @@ -2393,9 +2410,9 @@ dependencies = [ [[package]] name = "fuels" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed08053e72bdb285d5a167c27a7a0d10f1dc4e27d1e6e5296dd2a67813bd13f" +checksum = "25bf359dceffcbab4163bca473a03658b912686c3aa81a223f828260729dd474" dependencies = [ "fuel-core-client", "fuel-crypto 0.58.2", @@ -2409,9 +2426,9 @@ dependencies = [ [[package]] name = "fuels-accounts" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fee90e8f3a4fc9392a6cde3010c561fa50da0f805d66fdb659eaa4d5d8a504" +checksum = "4b0b09d6ce3a12196f6944c74bdd795c39950d32ebaaf56b2943741a5e4308a1" dependencies = [ "async-trait", "chrono", @@ -2435,9 +2452,9 @@ dependencies = [ [[package]] name = "fuels-code-gen" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f857b7ff658400506ca6be57bb84fedda44b566e78f5f0a8d0782242f41615c0" +checksum = "78bf5f7b37ec598514fb3767abdae5372a9fa0919d350703f5d627ec2eb33456" dependencies = [ "Inflector", "fuel-abi-types", @@ -2446,14 +2463,14 @@ dependencies = [ "quote", "regex", "serde_json", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "fuels-core" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baccbdd81e624f57950dcb136b32b853c520dd954badf26b9f58de33f3d71c7e" +checksum = "ab66cdf52fa6ef98dbc9cc7b4ce19c6a340b2a4710c5d5f87eae39ffb868bad7" dependencies = [ "async-trait", "bech32", @@ -2480,22 +2497,22 @@ dependencies = [ [[package]] name = "fuels-macros" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da75294c5e9da312bdc49239736699ee84ea9c5bfbc19a61a8ee588a1247aa1" +checksum = "1471d221453d13d4643c9a698212781f0e8ac40f515a8566538db87409e30752" dependencies = [ "fuels-code-gen", "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "fuels-programs" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32675ed1c08edd28ddb648dfae0c60a1946d4368a69ddfa6434f2316e33f0520" +checksum = "7a854561a68ef4088972119cf31023d2d1afd58584da203bcb7dfbd1e84dd8fc" dependencies = [ "async-trait", "fuel-abi-types", @@ -2512,9 +2529,9 @@ dependencies = [ [[package]] name = "fuels-test-helpers" -version = "0.66.9" +version = "0.66.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02176c0fb1bf8cf58b8a9e5372efb650324740abcd4847b45bd0b041a0f133a2" +checksum = "5a7b428c35a54e4d667343b4051f07a7397e6039bd110411c37647db4478086e" dependencies = [ "fuel-core", "fuel-core-chain-config", @@ -2543,9 +2560,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -2558,9 +2575,9 @@ dependencies = [ [[package]] name = "futures-bounded" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e2774cc104e198ef3d3e1ff4ab40f86fa3245d6cb6a3a46174f21463cee173" +checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e" dependencies = [ "futures-timer", "futures-util", @@ -2568,9 +2585,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -2578,15 +2595,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -2596,15 +2613,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "futures-core", "pin-project-lite", @@ -2612,36 +2629,37 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "futures-rustls" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" +checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls", + "rustls 0.23.16", + "rustls-pki-types", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-ticker" @@ -2662,9 +2680,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -2717,10 +2735,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator", - "indexmap 2.2.6", + "indexmap 2.6.0", "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "graphql-parser" version = "0.4.0" @@ -2754,7 +2778,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2796,6 +2820,17 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "heapless" version = "0.7.17" @@ -2828,6 +2863,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -2989,9 +3030,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -3001,9 +3042,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -3033,7 +3074,7 @@ dependencies = [ "http 0.2.12", "hyper", "log", - "rustls", + "rustls 0.21.12", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3054,9 +3095,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3075,6 +3116,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -3109,12 +3268,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -3167,26 +3337,26 @@ dependencies = [ [[package]] name = "impl-tools" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82c305b1081f1a99fda262883c788e50ab57d36c00830bdd7e0a82894ad965c" +checksum = "8a84bc8d2baf8da56e93b4247067d918e1a44829bbbe3e4b875aaf8d7d3c7bc9" dependencies = [ "autocfg", "impl-tools-lib", - "proc-macro-error", - "syn 2.0.63", + "proc-macro-error2", + "syn 2.0.87", ] [[package]] name = "impl-tools-lib" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85d3946d886eaab0702fa0c6585adcced581513223fa9df7ccfabbd9fa331a88" +checksum = "a795a1e201125947a063b967c79de6ae152143ab522f481d4f493c44835ba37a" dependencies = [ - "proc-macro-error", + "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -3202,12 +3372,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "serde", ] @@ -3235,9 +3405,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -3262,15 +3432,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -3307,18 +3477,18 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -3339,9 +3509,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "leb128" @@ -3351,15 +3521,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libp2p" @@ -3423,15 +3593,14 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.41.2" +version = "0.41.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8130a8269e65a2554d55131c770bdf4bcd94d2b8d4efb24ca23699be65066c05" +checksum = "a5a8920cbd8540059a01950c1e5c96ea8d89eb50c51cd366fc18bdf540a6e48f" dependencies = [ "either", "fnv", "futures", "futures-timer", - "instant", "libp2p-identity", "multiaddr", "multihash", @@ -3447,6 +3616,7 @@ dependencies = [ "tracing", "unsigned-varint 0.8.0", "void", + "web-time", ] [[package]] @@ -3521,9 +3691,9 @@ dependencies = [ [[package]] name = "libp2p-identity" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ec70441b2fb35355076726a6bc466c932e9bdc66f6a11c6c0aa17c7ab9be0" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ "asn1_der", "bs58", @@ -3654,9 +3824,9 @@ dependencies = [ [[package]] name = "libp2p-quic" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0375cdfee57b47b313ef1f0fdb625b78aed770d33a40cf1c294a371ff5e6666" +checksum = "c67296ad4e092e23f92aea3d2bdb6f24eab79c0929ed816dfb460ea2f4567d2b" dependencies = [ "bytes", "futures", @@ -3668,8 +3838,8 @@ dependencies = [ "parking_lot", "quinn", "rand", - "ring 0.16.20", - "rustls", + "ring 0.17.8", + "rustls 0.23.16", "socket2", "thiserror", "tokio", @@ -3678,9 +3848,9 @@ dependencies = [ [[package]] name = "libp2p-request-response" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6946e5456240b3173187cc37a17cb40c3cd1f7138c76e2c773e0d792a42a8de1" +checksum = "c314fe28368da5e3a262553fb0ad575c1c8934c461e10de10265551478163836" dependencies = [ "async-trait", "futures", @@ -3729,7 +3899,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -3751,18 +3921,18 @@ dependencies = [ [[package]] name = "libp2p-tls" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ce7e3c2e7569d685d08ec795157981722ff96e9e9f9eae75df3c29d02b07a5" +checksum = "72b7b831e55ce2aa6c354e6861a85fdd4dd0a2b97d5e276fabac0e4810a71776" dependencies = [ "futures", "futures-rustls", "libp2p-core", "libp2p-identity", "rcgen", - "ring 0.16.20", - "rustls", - "rustls-webpki", + "ring 0.17.8", + "rustls 0.23.16", + "rustls-webpki 0.101.7", "thiserror", "x509-parser", "yasna", @@ -3786,9 +3956,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.43.0" +version = "0.43.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4846d51afd08180e164291c3754ba30dd4fbac6fac65571be56403c16431a5e" +checksum = "85b953b6803a1f3161a989538974d72511c4e48a4af355337b6fb90723c56c05" dependencies = [ "either", "futures", @@ -3799,6 +3969,7 @@ dependencies = [ "pin-project-lite", "rw-stream-sink", "soketto", + "thiserror", "tracing", "url", "webpki-roots", @@ -3806,9 +3977,9 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.45.1" +version = "0.45.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200cbe50349a44760927d50b431d77bed79b9c0a3959de1af8d24a63434b71e5" +checksum = "ddd5265f6b80f94d48a3963541aad183cc598a645755d2f1805a373e41e0716b" dependencies = [ "either", "futures", @@ -3816,7 +3987,7 @@ dependencies = [ "thiserror", "tracing", "yamux 0.12.1", - "yamux 0.13.2", + "yamux 0.13.3", ] [[package]] @@ -3825,7 +3996,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -3885,9 +4056,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" @@ -3901,17 +4078,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.1", ] [[package]] @@ -3946,9 +4123,9 @@ checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" @@ -3973,22 +4150,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -4037,9 +4215,9 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", @@ -4050,7 +4228,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", "url", ] @@ -4067,12 +4245,12 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" dependencies = [ "core2", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", ] [[package]] @@ -4190,9 +4368,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -4239,29 +4417,29 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] [[package]] name = "num_enum" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -4272,39 +4450,30 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", - "hashbrown 0.14.5", - "indexmap 2.2.6", + "hashbrown 0.15.1", + "indexmap 2.6.0", "memchr", ] [[package]] name = "oid-registry" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ "asn1-rs", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -4332,15 +4501,15 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -4356,7 +4525,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4402,9 +4571,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -4418,34 +4587,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.6.0", ] [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -4465,29 +4634,23 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "platforms" -version = "3.4.0" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polling" -version = "3.7.0" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4515,9 +4678,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "portpicker" @@ -4530,12 +4693,13 @@ dependencies = [ [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "heapless", "serde", ] @@ -4548,9 +4712,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" @@ -4568,15 +4735,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -4584,9 +4751,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -4613,50 +4780,48 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro-error-attr2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", "quote", - "version_check", ] [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus-client" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ca959da22a332509f2a73ae9e5f23f9dcfc31fd3a54d71f159495bd5909baa" +checksum = "504ee9ff529add891127c4827eb481bd69dc0ebc72e9a682e187db4caa60c3ca" dependencies = [ "dtoa", "itoa", @@ -4672,7 +4837,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -4730,17 +4895,18 @@ dependencies = [ [[package]] name = "quinn" -version = "0.10.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", - "rustls", + "rustc-hash 2.0.0", + "rustls 0.23.16", + "socket2", "thiserror", "tokio", "tracing", @@ -4748,15 +4914,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.10.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", - "ring 0.16.20", - "rustc-hash", - "rustls", + "ring 0.17.8", + "rustc-hash 2.0.0", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -4765,22 +4931,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.4.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ - "bytes", + "cfg_aliases", "libc", + "once_cell", "socket2", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -4855,11 +5022,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -4881,16 +5048,16 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", - "rustc-hash", + "rustc-hash 1.1.0", "slice-group-by", "smallvec", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -4900,9 +5067,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -4911,9 +5078,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -4940,7 +5107,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.12", "rustls-pemfile", "serde", "serde_json", @@ -5044,11 +5211,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -5064,11 +5237,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -5083,10 +5256,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +dependencies = [ + "once_cell", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -5108,6 +5295,12 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -5118,11 +5311,22 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rw-stream-sink" @@ -5152,11 +5356,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5257,11 +5461,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -5270,9 +5474,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" dependencies = [ "core-foundation-sys", "libc", @@ -5286,40 +5490,41 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.201" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -5338,15 +5543,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -5356,27 +5561,25 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] -name = "sha-1" -version = "0.9.8" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest 0.10.7", ] [[package]] @@ -5413,6 +5616,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -5485,17 +5694,17 @@ dependencies = [ [[package]] name = "soketto" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "bytes", "futures", "httparse", "log", "rand", - "sha-1", + "sha1", ] [[package]] @@ -5609,7 +5818,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5622,14 +5831,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -5644,9 +5853,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -5659,18 +5868,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "synstructure" version = "0.13.1" @@ -5679,7 +5876,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5705,9 +5902,9 @@ dependencies = [ [[package]] name = "tai64" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7401421025f4132e6c1f7af5e7f8287383969f36e6628016cd509b8d3da9dc" +checksum = "014639506e4f425c78e823eabf56e71c093f940ae55b43e58f682e7bc2f5887a" dependencies = [ "serde", ] @@ -5726,14 +5923,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5772,22 +5970,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5821,11 +6019,21 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -5838,21 +6046,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5867,13 +6074,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -5892,15 +6099,15 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -5910,9 +6117,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -5923,47 +6130,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" -dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow", ] [[package]] @@ -6008,7 +6204,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bytes", "futures-core", "futures-util", @@ -6024,15 +6220,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -6054,7 +6250,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] @@ -6092,9 +6288,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -6110,36 +6306,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -6190,20 +6386,32 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -6217,18 +6425,18 @@ dependencies = [ [[package]] name = "uuid" -version = "1.8.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", ] [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -6253,34 +6461,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -6290,9 +6499,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6300,22 +6509,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-encoder" @@ -6333,9 +6542,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d28bc49ba1e5c5b61ffa7a2eace10820443c4b7d1c0b144109261d14570fdf8" dependencies = [ "ahash", - "bitflags 2.5.0", + "bitflags 2.6.0", "hashbrown 0.14.5", - "indexmap 2.2.6", + "indexmap 2.6.0", "semver", "serde", ] @@ -6353,23 +6562,23 @@ dependencies = [ [[package]] name = "wasmtime" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07232e0b473af36112da7348f51e73fa8b11047a6cb546096da3812930b7c93a" +checksum = "fe501caefeb9f7b15360bdd7e47ad96e20223846f1c7db485ae5820ba5acc3d2" dependencies = [ "anyhow", - "bitflags 2.5.0", + "bitflags 2.6.0", "bumpalo", "cc", "cfg-if", "hashbrown 0.14.5", - "indexmap 2.2.6", + "indexmap 2.6.0", "libc", "libm", "log", "mach2", "memfd", - "object 0.36.4", + "object", "once_cell", "paste", "postcard", @@ -6395,18 +6604,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a9c42562d879c749288d9a26acc0d95d2ca069e30c2ec2efce84461c4d62b3" +checksum = "c904a057d74bfa0ad9369a3fd99231d81ba0345f059d03c9148c3bb2abbf310f" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d5d5aac98c8ae87cf5244495da7722e3fa022aa6f3f4fcd5e3d6e5699ce422" +checksum = "8dff4d467d6b5bd0d137f5426f45178222e40b59e49ab3a7361420262b9f00df" dependencies = [ "anyhow", "base64 0.21.7", @@ -6424,14 +6633,14 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c3f57c4bc96f9b4a6ff4d6cb6e837913eff32e98d09e2b6d79b5c4647b415b" +checksum = "3a96185dab1c14ffb986ff2b3a2185d15acf2b801ca7895aa35ee80328e2ce38" dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser", @@ -6439,15 +6648,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1da707969bc31a565da9b32d087eb2370c95c6f2087c5539a15f2e3b27e77203" +checksum = "71a40200d42a8985edadb4007a0ed320756cbe28065b83e0027e39524c1b1b22" [[package]] name = "wasmtime-cranelift" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cb6135ec46994299be711b78b03acaa9480de3715f827d450f0c947a84977c" +checksum = "b099ef9b7808fa8d18cad32243e78e9c07a4a8aacfa913d88dc08704b1643c49" dependencies = [ "anyhow", "cfg-if", @@ -6457,9 +6666,9 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli", + "gimli 0.28.1", "log", - "object 0.36.4", + "object", "target-lexicon", "thiserror", "wasmparser", @@ -6469,17 +6678,17 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bcaa3b42a0718e9123da7fb75e8e13fc95df7db2a7e32e2f2f4f0d3333b7d6f" +checksum = "e2f1765f6ca1a166927bee13ad4aed7bf18269f34c0cd7d6d523889a0b52e6ee" dependencies = [ "anyhow", "cranelift-bitset", "cranelift-entity", - "gimli", - "indexmap 2.2.6", + "gimli 0.28.1", + "indexmap 2.6.0", "log", - "object 0.36.4", + "object", "postcard", "serde", "serde_derive", @@ -6492,9 +6701,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfee42dac5148fc2664ab1f5cb8d7fa77a28d1a2cf1d9483abc2c3d751a58b9" +checksum = "1e1a826e4ccd0803b2f7463289cad104f40d09d06bc8acf1a614230a47b4d96f" dependencies = [ "anyhow", "cfg-if", @@ -6504,15 +6713,15 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42eb8f6515708ec67974998c3e644101db4186308985f5ef7c2ef324ff33c948" +checksum = "f92a137c17c992eb5eaacfa0f0590353471e49dbb4bdbdf9cf7536d66109e63a" [[package]] name = "wasmtime-types" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046873fb8fb3e9652f3fd76fe99c8c8129007695c3d73b2e307fdae40f6e324c" +checksum = "a6072ac3267866d99ca726b6a4f157df9b733aac8082e902d527368f07c303ba" dependencies = [ "anyhow", "cranelift-entity", @@ -6524,32 +6733,42 @@ dependencies = [ [[package]] name = "wasmtime-versioned-export-macros" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c02af2e9dbeb427304d1a08787d70ed0dbfec1af2236616f84c9f1f03e7969" +checksum = "a2bde986038b819bc43a21fef0610aeb47aabfe3ea09ca3533a7b81023b84ec6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", ] [[package]] name = "wasmtime-wit-bindgen" -version = "23.0.2" +version = "23.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f528f8b8a2376a3dacaf497d960216dd466d324425361e1e00e26de0a7705c" +checksum = "8f88e49a9b81746ec0cede5505e40a4012c92cb5054cd7ef4300dc57c36f26b1" dependencies = [ "anyhow", "heck 0.4.1", - "indexmap 2.2.6", + "indexmap 2.6.0", "wit-parser", ] [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -6563,9 +6782,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "which" -version = "6.0.1" +version = "6.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", @@ -6601,7 +6820,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -6635,7 +6854,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -6653,7 +6872,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -6673,18 +6901,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -6695,9 +6923,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -6707,9 +6935,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -6719,15 +6947,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -6737,9 +6965,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -6749,9 +6977,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -6761,9 +6989,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -6773,24 +7001,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "winnow" -version = "0.5.40" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6819,7 +7038,7 @@ checksum = "ceeb0424aa8679f3fcf2d6e3cfa381f3d6fa6179976a2c05a6249dd2bb426716" dependencies = [ "anyhow", "id-arena", - "indexmap 2.2.6", + "indexmap 2.6.0", "log", "semver", "serde", @@ -6829,6 +7048,18 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -6852,9 +7083,9 @@ dependencies = [ [[package]] name = "x509-parser" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ "asn1-rs", "data-encoding", @@ -6869,9 +7100,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "af310deaae937e48a26602b730250b4949e125f468f11e6990be3e5304ddd96f" [[package]] name = "xmltree" @@ -6899,25 +7130,25 @@ dependencies = [ [[package]] name = "yamux" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f97202f6b125031b95d83e01dc57292b529384f80bfae4677e4bbc10178cf72" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" dependencies = [ "futures", - "instant", "log", "nohash-hasher", "parking_lot", "pin-project", "rand", "static_assertions", + "web-time", ] [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yasna" @@ -6928,31 +7159,77 @@ dependencies = [ "time", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", + "synstructure", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -6965,7 +7242,29 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.87", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] diff --git a/test/src/sdk-harness/Cargo.toml b/test/src/sdk-harness/Cargo.toml index 3d28c7b1506..7a2a74da1f1 100644 --- a/test/src/sdk-harness/Cargo.toml +++ b/test/src/sdk-harness/Cargo.toml @@ -18,7 +18,7 @@ fuel-core-client = { version = "0.40.0", default-features = false } fuel-vm = { version = "0.58", features = ["random"] } # Dependencies from the `fuels-rs` repository: -fuels = { version = "0.66.9", features = ["fuel-core-lib"] } +fuels = { version = "0.66.10", features = ["fuel-core-lib"] } hex = "0.4" paste = "1.0" diff --git a/test/src/sdk-harness/Forc.lock b/test/src/sdk-harness/Forc.lock index b05cb399826..ee70e29936a 100644 --- a/test/src/sdk-harness/Forc.lock +++ b/test/src/sdk-harness/Forc.lock @@ -251,11 +251,21 @@ name = "run_external_proxy" source = "member" dependencies = ["std"] +[[package]] +name = "run_external_proxy_with_storage" +source = "member" +dependencies = ["std"] + [[package]] name = "run_external_target" source = "member" dependencies = ["std"] +[[package]] +name = "run_external_target_with_storage" +source = "member" +dependencies = ["std"] + [[package]] name = "script_bytecode" source = "member" @@ -410,7 +420,7 @@ source = "member" dependencies = ["std"] [[package]] -name = "tx_output_change_contract" +name = "tx_output_contract" source = "member" dependencies = ["std"] diff --git a/test/src/sdk-harness/Forc.toml b/test/src/sdk-harness/Forc.toml index 97a7001d7da..2f4dd422291 100644 --- a/test/src/sdk-harness/Forc.toml +++ b/test/src/sdk-harness/Forc.toml @@ -29,6 +29,8 @@ members = [ "test_projects/result_option_expect", "test_projects/run_external_proxy", "test_projects/run_external_target", + "test_projects/run_external_proxy_with_storage", + "test_projects/run_external_target_with_storage", "test_projects/script_bytecode", "test_projects/script_data", "test_projects/storage", @@ -76,7 +78,7 @@ members = [ "test_artifacts/storage_vec/svec_u64", "test_artifacts/tx_contract", "test_artifacts/tx_input_count_predicate", - "test_artifacts/tx_output_change_contract", + "test_artifacts/tx_output_contract", "test_artifacts/tx_output_contract_creation_predicate", "test_artifacts/tx_output_count_predicate", "test_artifacts/tx_output_predicate", diff --git a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw index ed80700620c..bce0730c604 100644 --- a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw @@ -135,7 +135,8 @@ impl TxContractTest for Contract { let mut iter = 0; while iter < expected_data_bytes.len() { - if data.get(iter).unwrap() != expected_data_bytes.get(iter).unwrap() { + if data.get(iter).unwrap() != expected_data_bytes.get(iter).unwrap() + { return false } iter += 1; diff --git a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw deleted file mode 100644 index 32aeeb5e7c9..00000000000 --- a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/src/main.sw +++ /dev/null @@ -1,13 +0,0 @@ -contract; - -use std::asset::transfer; - -abi TxOutputChangeContract { - fn send_assets(to: Address, asset: AssetId, amount: u64); -} - -impl TxOutputChangeContract for Contract { - fn send_assets(to: Address, asset: AssetId, amount: u64) { - transfer(Identity::Address(to), asset, amount); - } -} diff --git a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/Forc.toml b/test/src/sdk-harness/test_artifacts/tx_output_contract/Forc.toml similarity index 81% rename from test/src/sdk-harness/test_artifacts/tx_output_change_contract/Forc.toml rename to test/src/sdk-harness/test_artifacts/tx_output_contract/Forc.toml index 5a053f78b77..824dbc61360 100644 --- a/test/src/sdk-harness/test_artifacts/tx_output_change_contract/Forc.toml +++ b/test/src/sdk-harness/test_artifacts/tx_output_contract/Forc.toml @@ -2,7 +2,7 @@ authors = ["Fuel Labs "] entry = "main.sw" license = "Apache-2.0" -name = "tx_output_change_contract" +name = "tx_output_contract" [dependencies] std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw new file mode 100644 index 00000000000..3682db6ea9b --- /dev/null +++ b/test/src/sdk-harness/test_artifacts/tx_output_contract/src/main.sw @@ -0,0 +1,35 @@ +contract; + +use std::asset::transfer; +use std::outputs::*; + +abi TxOutputContract { + fn send_assets_change(to: Address, asset: AssetId, amount: u64); + fn send_assets_variable(to: Address, asset: AssetId, index: u64) -> (Address, AssetId, u64); +} + +impl TxOutputContract for Contract { + fn send_assets_change(to: Address, asset: AssetId, amount: u64) { + transfer(Identity::Address(to), asset, amount); + } + + fn send_assets_variable(to: Address, asset: AssetId, index: u64) -> (Address, AssetId, u64) { + transfer(Identity::Address(to), asset, 1); + + get_variable_tx_params(index) + } +} + +fn get_variable_tx_params(index: u64) -> (Address, AssetId, u64) { + let tx_asset_id = output_asset_id(index); + let tx_to = output_asset_to(index); + let tx_amount = output_amount(index); + + let tx_output_type = output_type(index); + assert(tx_output_type.is_some() && tx_output_type.unwrap() == Output::Variable); + ( + tx_to.unwrap_or(Address::zero()), + tx_asset_id.unwrap_or(AssetId::zero()), + tx_amount.unwrap_or(0), + ) +} diff --git a/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw index e639bd11833..6f6495c9a42 100644 --- a/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_output_predicate/src/main.sw @@ -1,6 +1,6 @@ predicate; -use std::outputs::{output_asset_id, output_asset_to, output_type, Output}; +use std::outputs::{Output, output_asset_id, output_asset_to, output_type}; fn main(index: u64, asset_id: b256, to: b256, expected_type: Output) -> bool { let tx_asset_id = output_asset_id(index); diff --git a/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw index 59bd4f10714..44938b3c833 100644 --- a/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_type_predicate/src/main.sw @@ -1,6 +1,6 @@ predicate; -use std::tx::{tx_type, Transaction}; +use std::tx::{Transaction, tx_type}; fn main(expected_type: Transaction) -> bool { tx_type() == expected_type diff --git a/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw index adb0ea9dbc9..294051eb0cb 100644 --- a/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_witness_predicate/src/main.sw @@ -1,8 +1,13 @@ predicate; -use std::tx::{tx_witnesses_count, tx_witness_data_length, tx_witness_data}; +use std::tx::{tx_witness_data, tx_witness_data_length, tx_witnesses_count}; -fn main(index: u64, expected_count: u64, expected_length: u64, expected_data: [u8; 64]) -> bool { +fn main( + index: u64, + expected_count: u64, + expected_length: u64, + expected_data: [u8; 64], +) -> bool { let count: u64 = tx_witnesses_count(); let length: Option = tx_witness_data_length(index); let data: Option<[u8; 64]> = tx_witness_data(index); @@ -11,7 +16,7 @@ fn main(index: u64, expected_count: u64, expected_length: u64, expected_data: [u assert(length.is_some() && length.unwrap() == expected_length); assert(data.is_some()); - let data = data.unwrap(); + let data = data.unwrap(); let mut iter = 0; while iter < 64 { assert(data[iter] == expected_data[iter]); diff --git a/test/src/sdk-harness/test_projects/auth/mod.rs b/test/src/sdk-harness/test_projects/auth/mod.rs index 2fefd28f8c8..5c167a1d927 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -624,7 +624,7 @@ async fn can_get_predicate_address() { // Setup predicate. let hex_predicate_address: &str = - "0x5dcc82a88eebb07fb628db93d11ec38f085cbf36453a7135fea41b93cc44e118"; + "0x8b300a68337368654e71c65ae93c3d9eb3b9837d0c11d770cbf8740a6a5a8631"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); @@ -750,7 +750,7 @@ async fn when_incorrect_predicate_address_passed() { async fn can_get_predicate_address_in_message() { // Setup predicate address. let hex_predicate_address: &str = - "0x5dcc82a88eebb07fb628db93d11ec38f085cbf36453a7135fea41b93cc44e118"; + "0x8b300a68337368654e71c65ae93c3d9eb3b9837d0c11d770cbf8740a6a5a8631"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); diff --git a/test/src/sdk-harness/test_projects/harness.rs b/test/src/sdk-harness/test_projects/harness.rs index bc01e3cbc5b..6f297b67ad9 100644 --- a/test/src/sdk-harness/test_projects/harness.rs +++ b/test/src/sdk-harness/test_projects/harness.rs @@ -31,6 +31,7 @@ mod registers; mod result_in_abi; mod result_option_expect; mod run_external_proxy; +mod run_external_proxy_with_storage; mod script_data; mod storage; mod storage_access; diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock new file mode 100644 index 00000000000..c0e7ac7bd1a --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-37E4B1588712FA61' + +[[package]] +name = 'std' +source = 'path+from-root-37E4B1588712FA61' +dependencies = ['core'] + +[[package]] +name = 'run_external_proxy' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml new file mode 100644 index 00000000000..77108416623 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "run_external_proxy_with_storage" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs new file mode 100644 index 00000000000..39e70a5fcc4 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/mod.rs @@ -0,0 +1,106 @@ +use fuels::{prelude::*, types::Bits256}; + +abigen!(Contract( + name = "RunExternalProxyContract", + abi = "test_projects/run_external_proxy_with_storage/out/release/run_external_proxy_with_storage-abi.json", +)); + +#[tokio::test] +async fn run_external_can_proxy_call() { + let wallet = launch_provider_and_get_wallet().await.unwrap(); + + let storage_configuration = + StorageConfiguration::default().add_slot_overrides_from_file("test_projects/run_external_target_with_storage/out/release/run_external_target_with_storage-storage_slots.json").unwrap(); + + let target_id = Contract::load_from( + "test_projects/run_external_target_with_storage/out/release/run_external_target_with_storage.bin", + LoadConfiguration::default() + .with_storage_configuration(storage_configuration.clone()), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + + let configurables = RunExternalProxyContractConfigurables::default() + .with_TARGET(target_id.clone().into()) + .unwrap(); + let id = Contract::load_from( + "test_projects/run_external_proxy_with_storage/out/release/run_external_proxy_with_storage.bin", + LoadConfiguration::default().with_configurables(configurables).with_storage_configuration(storage_configuration), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + let instance = RunExternalProxyContract::new(id.clone(), wallet); + // Call "large_value" + // Will call run_external_proxy::large_value + // that will call run_external_target::large_value + // and return the value doubled. + let result = instance + .methods() + .large_value() + .with_contract_ids(&[target_id.clone().into()]) + .call() + .await + .unwrap(); + for r in result.receipts.iter() { + match r { + Receipt::LogData { data, .. } => { + if let Some(data) = data { + if data.len() > 8 { + if let Ok(s) = std::str::from_utf8(&data[8..]) { + print!("{:?} ", s); + } + } + println!("{:?}", data); + } + } + _ => {} + } + } + let expected_large = + Bits256::from_hex_str("0x00000000000000000000000059F2f1fCfE2474fD5F0b9BA1E73ca90b143Eb8d0") + .unwrap(); + assert_eq!(result.value, expected_large); + // Call "double_value" + // Will call run_external_proxy::double_value + // that will call run_external_target::double_value + // and return the value doubled. + let result = instance + .methods() + .double_value(42) + .with_contract_ids(&[target_id.clone().into()]) + .call() + .await + .unwrap(); + for r in result.receipts.iter() { + match r { + Receipt::LogData { data, .. } => { + if let Some(data) = data { + if data.len() > 8 { + if let Ok(s) = std::str::from_utf8(&data[8..]) { + print!("{:?} ", s); + } + } + println!("{:?}", data); + } + } + _ => {} + } + } + assert_eq!(result.value, 84); + // Call "does_not_exist_in_the_target" + // Will call run_external_proxy::does_not_exist_in_the_target + // it will proxy the call to run_external_target, + // and endup in the fallback, fn that will triple the input value + let result = instance + .methods() + .does_not_exist_in_the_target(42) + .with_contract_ids(&[target_id.into()]) + .call() + .await + .unwrap(); + assert_eq!(result.value, 126); +} diff --git a/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw new file mode 100644 index 00000000000..05dc44f0473 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_proxy_with_storage/src/main.sw @@ -0,0 +1,29 @@ +contract; + +use std::execution::run_external; + +configurable { + TARGET: ContractId = ContractId::zero(), +} + +abi RunExternalTest { + fn double_value(foo: u64) -> u64; + fn large_value() -> b256; + fn does_not_exist_in_the_target(foo: u64) -> u64; +} +impl RunExternalTest for Contract { + fn double_value(_foo: u64) -> u64 { + __log(1); + run_external(TARGET) + } + + fn large_value() -> b256 { + run_external(TARGET) + } + + // ANCHOR: does_not_exist_in_the_target + fn does_not_exist_in_the_target(_foo: u64) -> u64 { + run_external(TARGET) + } + // ANCHOR_END: does_not_exist_in_the_target +} \ No newline at end of file diff --git a/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock new file mode 100644 index 00000000000..05131a01155 --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-37E4B1588712FA61' + +[[package]] +name = 'std' +source = 'path+from-root-37E4B1588712FA61' +dependencies = ['core'] + +[[package]] +name = 'run_external_target' +source = 'member' +dependencies = ['std'] diff --git a/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml new file mode 100644 index 00000000000..130715dae8c --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_target_with_storage/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "run_external_target_with_storage" + +[dependencies] +std = { path = "../../../../../sway-lib-std" } diff --git a/test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw b/test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw new file mode 100644 index 00000000000..ab7d770ccef --- /dev/null +++ b/test/src/sdk-harness/test_projects/run_external_target_with_storage/src/main.sw @@ -0,0 +1,38 @@ +contract; + +use std::constants::ZERO_B256; + +storage { + owner: Identity = Identity::Address(Address::from(ZERO_B256)), + simple_value: u64 = 0, +} + +abi RunExternalTest { + fn double_value(foo: u64) -> u64; + fn large_value() -> b256; +} + +impl RunExternalTest for Contract { + fn double_value(foo: u64) -> u64 { + __log(2); + foo * 2 + } + fn large_value() -> b256 { + 0x00000000000000000000000059F2f1fCfE2474fD5F0b9BA1E73ca90b143Eb8d0 + } +} + +// ANCHOR: fallback +#[fallback, storage(read, write)] +fn fallback() -> u64 { + let iden = storage.owner.read(); + + use std::call_frames::*; + __log(3); + __log(called_method()); + __log("double_value"); + __log(called_method() == "double_value"); + let foo = called_args::(); + foo * 3 +} +// ANCHOR_END: fallback diff --git a/test/src/sdk-harness/test_projects/tx_fields/mod.rs b/test/src/sdk-harness/test_projects/tx_fields/mod.rs index 0ac934999c7..f7e7308737d 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -14,8 +14,8 @@ const MESSAGE_DATA: [u8; 3] = [1u8, 2u8, 3u8]; const TX_CONTRACT_BYTECODE_PATH: &str = "test_artifacts/tx_contract/out/release/tx_contract.bin"; const TX_OUTPUT_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_predicate/out/release/tx_output_predicate.bin"; -const TX_OUTPUT_CHANGE_CONTRACT_BYTECODE_PATH: &str = - "test_artifacts/tx_output_change_contract/out/release/tx_output_change_contract.bin"; +const TX_OUTPUT_CONTRACT_BYTECODE_PATH: &str = + "test_artifacts/tx_output_contract/out/release/tx_output_contract.bin"; const TX_FIELDS_PREDICATE_BYTECODE_PATH: &str = "test_projects/tx_fields/out/release/tx_fields.bin"; const TX_CONTRACT_CREATION_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_contract_creation_predicate/out/release/tx_output_contract_creation_predicate.bin"; @@ -28,8 +28,8 @@ const TX_INPUT_COUNT_PREDICATE_BYTECODE_PATH: &str = const TX_OUTPUT_COUNT_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_count_predicate/out/release/tx_output_count_predicate.bin"; -use crate::tx_fields::Transaction as SwayTransaction; use crate::tx_fields::Output as SwayOutput; +use crate::tx_fields::Transaction as SwayTransaction; abigen!( Contract( @@ -37,8 +37,8 @@ abigen!( abi = "test_artifacts/tx_contract/out/release/tx_contract-abi.json", ), Contract( - name = "TxOutputChangeContract", - abi = "test_artifacts/tx_output_change_contract/out/release/tx_output_change_contract-abi.json", + name = "TxOutputContract", + abi = "test_artifacts/tx_output_contract/out/release/tx_output_contract-abi.json", ), Predicate( name = "TestPredicate", @@ -172,7 +172,10 @@ async fn generate_predicate_inputs( (predicate_code, predicate_input, predicate_message) } -async fn setup_output_predicate(index: u64, expected_output_type: SwayOutput) -> (WalletUnlocked, WalletUnlocked, Predicate, AssetId, AssetId) { +async fn setup_output_predicate( + index: u64, + expected_output_type: SwayOutput, +) -> (WalletUnlocked, WalletUnlocked, Predicate, AssetId, AssetId) { let asset_id1 = AssetId::default(); let asset_id2 = AssetId::new([2u8; 32]); let wallets_config = WalletsConfig::new_multiple_assets( @@ -201,7 +204,12 @@ async fn setup_output_predicate(index: u64, expected_output_type: SwayOutput) -> let wallet2 = wallets.pop().unwrap(); let predicate_data = TestOutputPredicateEncoder::default() - .encode_data(index, Bits256([0u8; 32]), Bits256(*wallet1.address().hash()), expected_output_type) + .encode_data( + index, + Bits256([0u8; 32]), + Bits256(*wallet1.address().hash()), + expected_output_type, + ) .unwrap(); let predicate = Predicate::load_from(TX_OUTPUT_PREDICATE_BYTECODE_PATH) @@ -1547,7 +1555,8 @@ mod outputs { #[tokio::test] async fn can_get_tx_output_details() { - let (wallet, _, predicate, asset_id, _) = setup_output_predicate(0, SwayOutput::Coin).await; + let (wallet, _, predicate, asset_id, _) = + setup_output_predicate(0, SwayOutput::Coin).await; let balance = predicate.get_asset_balance(&asset_id).await.unwrap(); @@ -1678,32 +1687,39 @@ mod outputs { assert_eq!(predicate_balance, 0); } } - + #[tokio::test] async fn can_get_tx_output_change_details() { // Prepare predicate - let (wallet, _, predicate, asset_id, _) = setup_output_predicate(2, SwayOutput::Change).await; + let (wallet, _, predicate, asset_id, _) = + setup_output_predicate(2, SwayOutput::Change).await; let provider = wallet.try_provider().unwrap().clone(); let balance = predicate.get_asset_balance(&asset_id).await.unwrap(); // Deploy contract - let contract_id = Contract::load_from(TX_OUTPUT_CHANGE_CONTRACT_BYTECODE_PATH, LoadConfiguration::default()) - .unwrap() - .deploy(&wallet, TxPolicies::default()) - .await - .unwrap(); - - let instance = TxOutputChangeContract::new(contract_id.clone(), wallet.clone()); + let contract_id = Contract::load_from( + TX_OUTPUT_CONTRACT_BYTECODE_PATH, + LoadConfiguration::default(), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + + let instance = TxOutputContract::new(contract_id.clone(), wallet.clone()); // Send tokens to the contract let _ = wallet .force_transfer_to_contract(&contract_id, 10, asset_id, TxPolicies::default()) - .await - .unwrap(); + .await + .unwrap(); // Build transaction - let call_handler = instance.methods().send_assets(wallet.clone().address(), asset_id, 10); + let call_handler = + instance + .methods() + .send_assets_change(wallet.clone().address(), asset_id, 10); let mut tb = call_handler.transaction_builder().await.unwrap(); // Inputs for predicate @@ -1714,20 +1730,21 @@ mod outputs { .unwrap(); // Outputs for predicate - let predicate_output = wallet.get_asset_outputs_for_amount( - &wallet.address(), - asset_id, - transfer_amount, - ); + let predicate_output = + wallet.get_asset_outputs_for_amount(&wallet.address(), asset_id, transfer_amount); // Append the inputs and outputs to the transaction tb.inputs.push(predicate_input.get(0).unwrap().clone()); tb.outputs.push(predicate_output.get(0).unwrap().clone()); - tb.outputs.push(SdkOutput::Change{to: wallet.address().into(), amount: 0, asset_id}); + tb.outputs.push(SdkOutput::Change { + to: wallet.address().into(), + amount: 0, + asset_id, + }); wallet.adjust_for_fee(&mut tb, 0).await.unwrap(); tb.add_signer(wallet.clone()).unwrap(); - + let tx = tb.build(provider.clone()).await.unwrap(); let _tx_id = provider.send_transaction(tx).await.unwrap(); @@ -1735,6 +1752,44 @@ mod outputs { let new_balance = predicate.get_asset_balance(&asset_id).await.unwrap(); assert!(balance - transfer_amount == new_balance); } + + #[tokio::test] + async fn can_get_tx_output_variable_details() { + // Prepare wallet + let (wallet, _, _, asset_id, _) = setup_output_predicate(1, SwayOutput::Variable).await; + + // Deploy contract + let contract_id = Contract::load_from( + TX_OUTPUT_CONTRACT_BYTECODE_PATH, + LoadConfiguration::default(), + ) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); + + let instance = TxOutputContract::new(contract_id.clone(), wallet.clone()); + + // Send tokens to the contract + let _ = wallet + .force_transfer_to_contract(&contract_id, 10, asset_id, TxPolicies::default()) + .await + .unwrap(); + + // Run transaction with variable output + let (tx_to, tx_asset_id, tx_amount) = instance + .methods() + .send_assets_variable(wallet.clone().address(), asset_id, 2) + .with_variable_output_policy(VariableOutputPolicy::Exactly(1)) + .call() + .await + .unwrap() + .value; + + assert_eq!(tx_to, wallet.clone().address().into()); + assert_eq!(tx_asset_id, asset_id); + assert_eq!(tx_amount, 1); + } } mod revert { @@ -1743,7 +1798,8 @@ mod outputs { #[tokio::test] #[should_panic] async fn fails_output_predicate_when_incorrect_asset() { - let (wallet1, _, predicate, _, asset_id2) = setup_output_predicate(0, SwayOutput::Coin).await; + let (wallet1, _, predicate, _, asset_id2) = + setup_output_predicate(0, SwayOutput::Coin).await; let transfer_amount = 10; predicate @@ -1760,7 +1816,8 @@ mod outputs { #[tokio::test] #[should_panic] async fn fails_output_predicate_when_incorrect_to() { - let (_, wallet2, predicate, asset_id1, _) = setup_output_predicate(0, SwayOutput::Coin).await; + let (_, wallet2, predicate, asset_id1, _) = + setup_output_predicate(0, SwayOutput::Coin).await; let transfer_amount = 10; predicate