diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index a302e23781..d5951a9420 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,10 @@ # prettier format f247090558c9ba3c551566eae5882b7ca865225f + +# subtree syncs +932d85b52946d917deab2c23ead552f7f713b828 +3e358a6827d83e8d6473913a5e304734aadfed04 +9d2cb42a413e51deb50b36794a2e1605381878fc +f532576ac53ddcc666bc8d59e0b6437065e2f599 +c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a10345a706..87a1729d2b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,15 +63,15 @@ jobs: - name: Install Rust toolchain run: | rustup update --no-self-update ${{ env.RUST_CHANNEL }} - rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src rustup default ${{ env.RUST_CHANNEL }} + rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json - name: Install Rust Problem Matcher if: matrix.os == 'ubuntu-latest' run: echo "::add-matcher::.github/rust.json" - name: Cache Dependencies - uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012 + uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 with: key: ${{ env.RUST_CHANNEL }} @@ -140,7 +140,7 @@ jobs: rustup target add ${{ env.targets }} ${{ env.targets_ide }} - name: Cache Dependencies - uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012 + uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609 - name: Check run: | diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml index b6cd4a795a..a4146d6021 100644 --- a/.github/workflows/metrics.yaml +++ b/.github/workflows/metrics.yaml @@ -11,34 +11,21 @@ env: RUSTUP_MAX_RETRIES: 10 jobs: - setup_cargo: + build_metrics: if: github.repository == 'rust-lang/rust-analyzer' runs-on: ubuntu-latest + steps: - name: Install Rust toolchain run: | rustup update --no-self-update stable - rustup component add rustfmt rust-src rustup default stable - - name: Cache cargo - uses: actions/cache@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - key: ${{ runner.os }}-cargo-${{ github.sha }} + rustup component add --toolchain stable rust-src - build_metrics: - runs-on: ubuntu-latest - needs: setup_cargo - - steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Restore cargo cache + - name: Cache cargo uses: actions/cache@v4 with: path: | @@ -69,22 +56,18 @@ jobs: matrix: names: [self, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18] runs-on: ubuntu-latest - needs: [setup_cargo, build_metrics] + needs: build_metrics steps: + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup default stable + rustup component add --toolchain stable rust-src + - name: Checkout repository uses: actions/checkout@v4 - - name: Restore cargo cache - uses: actions/cache@v4 - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - key: ${{ runner.os }}-cargo-${{ github.sha }} - - name: Restore target cache uses: actions/cache@v4 with: diff --git a/.github/workflows/rustdoc.yaml b/.github/workflows/rustdoc.yaml index 12a1a791fd..f975bbaa51 100644 --- a/.github/workflows/rustdoc.yaml +++ b/.github/workflows/rustdoc.yaml @@ -26,7 +26,7 @@ jobs: run: cargo doc --all --no-deps - name: Deploy Docs - uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_branch: gh-pages diff --git a/Cargo.lock b/Cargo.lock index a6e460134f..8eb872514a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "arbitrary" @@ -46,15 +46,15 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -91,9 +91,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "byteorder" @@ -112,9 +112,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -135,9 +135,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg" @@ -159,6 +159,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chalk-derive" version = "0.97.0" @@ -177,7 +183,7 @@ version = "0.97.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "chalk-derive", ] @@ -282,11 +288,11 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "ctrlc" -version = "3.4.2" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" dependencies = [ - "nix 0.27.1", + "nix 0.28.0", "windows-sys 0.52.0", ] @@ -324,10 +330,31 @@ dependencies = [ ] [[package]] -name = "dissimilar" -version = "1.0.7" +name = "directories" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dissimilar" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" [[package]] name = "dot" @@ -343,15 +370,15 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] @@ -364,9 +391,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "expect-test" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3" +checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0" dependencies = [ "dissimilar", "once_cell", @@ -380,7 +407,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "windows-sys 0.52.0", ] @@ -392,9 +419,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -442,9 +469,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -459,9 +486,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -504,7 +531,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg", "cov-mark", "dashmap", @@ -568,7 +595,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.4.2", + "bitflags 2.5.0", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -589,7 +616,7 @@ dependencies = [ "oorandom", "project-model", "ra-ap-rustc_abi", - "ra-ap-rustc_index", + "ra-ap-rustc_index 0.53.0", "ra-ap-rustc_pattern_analysis", "rustc-hash", "scoped-tls", @@ -695,7 +722,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.4.2", + "bitflags 2.5.0", "cov-mark", "crossbeam-channel", "either", @@ -776,9 +803,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -826,9 +853,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jod-thread" @@ -874,9 +901,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -885,19 +912,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] name = "libmimalloc-sys" -version = "0.1.35" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" +checksum = "81eb4061c0582dedea1cbc7aff2240300dd6982e0239d1c99e65c1dbf4a30ba7" dependencies = [ "cc", "libc", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + [[package]] name = "limit" version = "0.0.0" @@ -948,9 +985,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1001,9 +1038,9 @@ dependencies = [ [[package]] name = "lz4_flex" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" [[package]] name = "mbe" @@ -1023,9 +1060,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -1038,18 +1075,18 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "mimalloc" -version = "0.1.39" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" +checksum = "9f41a2280ded0da56c8cf898babb86e8f10651a34adcfff190ae9a1159c6908d" dependencies = [ "libmimalloc-sys", ] @@ -1097,12 +1134,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", + "cfg_aliases", "libc", ] @@ -1118,7 +1156,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "crossbeam-channel", "filetime", "fsevent-sys", @@ -1187,10 +1225,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] -name = "parking_lot" -version = "0.12.1" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking_lot" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -1198,15 +1242,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -1224,9 +1268,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "paths" @@ -1262,9 +1306,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap", @@ -1272,9 +1316,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "powerfmt" @@ -1346,9 +1390,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -1365,7 +1409,7 @@ dependencies = [ "perf-event", "tikv-jemalloc-ctl", "tracing", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -1417,7 +1461,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "memchr", "unicase", ] @@ -1433,21 +1477,21 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "ra-ap-rustc_abi" -version = "0.44.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8709df2a746f055316bc0c62bd30948695a25e734863bf6e1f9755403e010ab" +checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46" dependencies = [ - "bitflags 2.4.2", - "ra-ap-rustc_index", + "bitflags 2.5.0", + "ra-ap-rustc_index 0.53.0", "tracing", ] @@ -1458,7 +1502,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20" dependencies = [ "arrayvec", - "ra-ap-rustc_index_macros", + "ra-ap-rustc_index_macros 0.44.0", + "smallvec", +] + +[[package]] +name = "ra-ap-rustc_index" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9" +dependencies = [ + "arrayvec", + "ra-ap-rustc_index_macros 0.53.0", "smallvec", ] @@ -1475,10 +1530,22 @@ dependencies = [ ] [[package]] -name = "ra-ap-rustc_lexer" -version = "0.44.0" +name = "ra-ap-rustc_index_macros" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab683fc8579d09eb72033bd5dc9ba6d701aa9645b5fed087ef19af71184dff3" +checksum = "82f3d6dcb30a66905388e14756b8f2216131d9f8004922c07f13335840e058d1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "ra-ap-rustc_lexer" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd8a2b0bdcba9892cbce0b25f6c953d31b0febc1f3420fc692884fce5a23ad8" dependencies = [ "unicode-properties", "unicode-xid", @@ -1486,11 +1553,11 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.44.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bcf9ff5edbf784b67b8ad5e03a068f1300fcc24062c0d476b3018965135d933" +checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135" dependencies = [ - "ra-ap-rustc_index", + "ra-ap-rustc_index 0.53.0", "ra-ap-rustc_lexer", ] @@ -1500,7 +1567,7 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334" dependencies = [ - "ra-ap-rustc_index", + "ra-ap-rustc_index 0.44.0", "rustc-hash", "rustc_apfloat", "smallvec", @@ -1539,9 +1606,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -1566,6 +1633,26 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "rowan" version = "0.15.15" @@ -1634,16 +1721,16 @@ dependencies = [ "vfs", "vfs-notify", "walkdir", - "winapi", + "windows-sys 0.52.0", "xflags", "xshell", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -1663,9 +1750,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "salsa" @@ -1729,27 +1816,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", @@ -1758,9 +1845,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "indexmap", "itoa", @@ -1770,9 +1857,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", @@ -1799,9 +1886,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smol_str" @@ -1856,14 +1943,14 @@ dependencies = [ "jod-thread", "libc", "miow", - "winapi", + "windows-sys 0.52.0", ] [[package]] name = "syn" -version = "2.0.52" +version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ "proc-macro2", "quote", @@ -1946,18 +2033,18 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", @@ -2007,9 +2094,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "num-conv", @@ -2041,9 +2128,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", @@ -2062,9 +2149,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ "indexmap", "serde", @@ -2255,6 +2342,7 @@ dependencies = [ "paths", "rustc-hash", "stdx", + "tracing", ] [[package]] @@ -2304,11 +2392,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2332,7 +2420,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2352,17 +2440,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "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", ] [[package]] @@ -2373,9 +2462,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2385,9 +2474,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2397,9 +2486,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2409,9 +2504,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2421,9 +2516,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2433,9 +2528,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2445,15 +2540,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.5.32" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] @@ -2481,24 +2576,25 @@ checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155" [[package]] name = "xshell" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad" +checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437" dependencies = [ "xshell-macros", ] [[package]] name = "xshell-macros" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e" +checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" [[package]] name = "xtask" version = "0.1.0" dependencies = [ "anyhow", + "directories", "flate2", "itertools", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index f7e3ae51df..3108c1b3df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"] resolver = "2" [workspace.package] -rust-version = "1.76" +rust-version = "1.78" edition = "2021" license = "MIT OR Apache-2.0" authors = ["rust-analyzer team"] @@ -85,10 +85,10 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.44.0", default-features = false } -ra-ap-rustc_parse_format = { version = "0.44.0", default-features = false } -ra-ap-rustc_index = { version = "0.44.0", default-features = false } -ra-ap-rustc_abi = { version = "0.44.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.53.0", default-features = false } +ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false } +ra-ap-rustc_index = { version = "0.53.0", default-features = false } +ra-ap-rustc_abi = { version = "0.53.0", default-features = false } ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false } # local crates that aren't published to crates.io. These should not have versions. diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs index f202a885e2..927b2108a6 100644 --- a/crates/base-db/src/change.rs +++ b/crates/base-db/src/change.rs @@ -51,7 +51,7 @@ impl FileChange { } pub fn apply(self, db: &mut dyn SourceDatabaseExt) { - let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered(); + let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered(); if let Some(roots) = self.roots { for (idx, root) in roots.into_iter().enumerate() { let root_id = SourceRootId(idx as u32); diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 240af7925c..b2c3f38ab4 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -324,21 +324,27 @@ pub struct Dependency { pub crate_id: CrateId, pub name: CrateName, prelude: bool, + sysroot: bool, } impl Dependency { pub fn new(name: CrateName, crate_id: CrateId) -> Self { - Self { name, crate_id, prelude: true } + Self { name, crate_id, prelude: true, sysroot: false } } - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self { - Self { name, crate_id, prelude } + pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool, sysroot: bool) -> Self { + Self { name, crate_id, prelude, sysroot } } /// Whether this dependency is to be added to the depending crate's extern prelude. pub fn is_prelude(&self) -> bool { self.prelude } + + /// Whether this dependency is a sysroot injected one. + pub fn is_sysroot(&self) -> bool { + self.sysroot + } } impl CrateGraph { diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 2b64a07a5a..2c13eed56c 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -8,7 +8,7 @@ mod input; use std::panic; use salsa::Durability; -use syntax::{ast, Parse, SourceFile}; +use syntax::{ast, Parse, SourceFile, SyntaxError}; use triomphe::Arc; pub use crate::{ @@ -51,6 +51,7 @@ pub trait FileLoader { /// Text of the file. fn file_text(&self, file_id: FileId) -> Arc; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option; + /// Crates whose root's source root is the same as the source root of `file_id` fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>; } @@ -61,6 +62,9 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { /// Parses the file into the syntax tree. fn parse(&self, file_id: FileId) -> Parse; + /// Returns the set of errors obtained from parsing the file including validation errors. + fn parse_errors(&self, file_id: FileId) -> Option>; + /// The crate graph. #[salsa::input] fn crate_graph(&self) -> Arc; @@ -81,12 +85,20 @@ fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option Parse { - let _p = tracing::span!(tracing::Level::INFO, "parse_query", ?file_id).entered(); + let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered(); let text = db.file_text(file_id); // FIXME: Edition based parsing SourceFile::parse(&text, span::Edition::CURRENT) } +fn parse_errors(db: &dyn SourceDatabase, file_id: FileId) -> Option> { + let errors = db.parse(file_id).errors(); + match &*errors { + [] => None, + [..] => Some(errors.into()), + } +} + /// We don't want to give HIR knowledge of source roots, hence we extract these /// methods into a separate DB. #[salsa::query_group(SourceDatabaseExtStorage)] @@ -104,6 +116,7 @@ pub trait SourceDatabaseExt: SourceDatabase { #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; + /// Crates whose root fool is in `id`. fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; } diff --git a/crates/cfg/src/tests.rs b/crates/cfg/src/tests.rs index a1ae15fcdd..dddaf2cce1 100644 --- a/crates/cfg/src/tests.rs +++ b/crates/cfg/src/tests.rs @@ -1,6 +1,6 @@ use arbitrary::{Arbitrary, Unstructured}; use expect_test::{expect, Expect}; -use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY}; +use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY}; use syntax::{ast, AstNode, Edition}; use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; @@ -8,7 +8,12 @@ use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; fn assert_parse_result(input: &str, expected: CfgExpr) { let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap(); let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY); + let tt = syntax_node_to_token_tree( + tt.syntax(), + DummyTestSpanMap, + DUMMY, + DocCommentDesugarMode::ProcMacro, + ); let cfg = CfgExpr::parse(&tt); assert_eq!(cfg, expected); } @@ -16,7 +21,12 @@ fn assert_parse_result(input: &str, expected: CfgExpr) { fn check_dnf(input: &str, expect: Expect) { let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap(); let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY); + let tt = syntax_node_to_token_tree( + tt.syntax(), + DummyTestSpanMap, + DUMMY, + DocCommentDesugarMode::ProcMacro, + ); let cfg = CfgExpr::parse(&tt); let actual = format!("#![cfg({})]", DnfExpr::new(cfg)); expect.assert_eq(&actual); @@ -25,7 +35,12 @@ fn check_dnf(input: &str, expect: Expect) { fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) { let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap(); let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY); + let tt = syntax_node_to_token_tree( + tt.syntax(), + DummyTestSpanMap, + DUMMY, + DocCommentDesugarMode::ProcMacro, + ); let cfg = CfgExpr::parse(&tt); let dnf = DnfExpr::new(cfg); let why_inactive = dnf.why_inactive(opts).unwrap().to_string(); @@ -36,7 +51,12 @@ fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) { fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) { let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap(); let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY); + let tt = syntax_node_to_token_tree( + tt.syntax(), + DummyTestSpanMap, + DUMMY, + DocCommentDesugarMode::ProcMacro, + ); let cfg = CfgExpr::parse(&tt); let dnf = DnfExpr::new(cfg); let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::>(); diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 5dfaaf7742..6d5ca8321e 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -125,8 +125,10 @@ impl FlycheckHandle { config: FlycheckConfig, sysroot_root: Option, workspace_root: AbsPathBuf, + manifest_path: Option, ) -> FlycheckHandle { - let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root); + let actor = + FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path); let (sender, receiver) = unbounded::(); let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) .name("Flycheck".to_owned()) @@ -205,6 +207,7 @@ struct FlycheckActor { id: usize, sender: Box, config: FlycheckConfig, + manifest_path: Option, /// Either the workspace root of the workspace we are flychecking, /// or the project root of the project. root: AbsPathBuf, @@ -233,6 +236,7 @@ impl FlycheckActor { config: FlycheckConfig, sysroot_root: Option, workspace_root: AbsPathBuf, + manifest_path: Option, ) -> FlycheckActor { tracing::info!(%id, ?workspace_root, "Spawning flycheck"); FlycheckActor { @@ -241,6 +245,7 @@ impl FlycheckActor { config, sysroot_root, root: workspace_root, + manifest_path, command_handle: None, command_receiver: None, } @@ -388,8 +393,13 @@ impl FlycheckActor { "--message-format=json" }); - cmd.arg("--manifest-path"); - cmd.arg(self.root.join("Cargo.toml")); + if let Some(manifest_path) = &self.manifest_path { + cmd.arg("--manifest-path"); + cmd.arg(manifest_path); + if manifest_path.extension().map_or(false, |ext| ext == "rs") { + cmd.arg("-Zscript"); + } + } options.apply_on_command(&mut cmd); (cmd, options.extra_args.clone()) diff --git a/crates/hir-def/src/attr/tests.rs b/crates/hir-def/src/attr/tests.rs index 9b68797fbf..727f442980 100644 --- a/crates/hir-def/src/attr/tests.rs +++ b/crates/hir-def/src/attr/tests.rs @@ -5,7 +5,7 @@ use triomphe::Arc; use base_db::FileId; use hir_expand::span_map::{RealSpanMap, SpanMap}; -use mbe::syntax_node_to_token_tree; +use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode}; use syntax::{ast, AstNode, TextRange}; use crate::attr::{DocAtom, DocExpr}; @@ -18,6 +18,7 @@ fn assert_parse_result(input: &str, expected: DocExpr) { tt.syntax(), map.as_ref(), map.span_for_range(TextRange::empty(0.into())), + DocCommentDesugarMode::ProcMacro, ); let cfg = DocExpr::parse(&tt); assert_eq!(cfg, expected); diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index c9f1add275..d2f4d7b7e5 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -10,9 +10,10 @@ use std::ops::Index; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::{name::Name, HirFileId, InFile}; +use hir_expand::{name::Name, InFile}; use la_arena::{Arena, ArenaMap}; use rustc_hash::FxHashMap; +use span::MacroFileId; use syntax::{ast, AstPtr, SyntaxNodePtr}; use triomphe::Arc; @@ -98,7 +99,7 @@ pub struct BodySourceMap { format_args_template_map: FxHashMap>, - expansions: FxHashMap>, HirFileId>, + expansions: FxHashMap>, MacroFileId>, /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in /// the source map (since they're just as volatile). @@ -349,11 +350,17 @@ impl BodySourceMap { self.expr_map.get(&src).cloned() } - pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option { + pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option { let src = node.map(AstPtr::new); self.expansions.get(&src).cloned() } + pub fn macro_calls( + &self, + ) -> impl Iterator>, MacroFileId)> + '_ { + self.expansions.iter().map(|(&a, &b)| (a, b)) + } + pub fn pat_syntax(&self, pat: PatId) -> Result { self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) } diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 340e95dbc2..82f89393ad 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1006,7 +1006,9 @@ impl ExprCollector<'_> { Some((mark, expansion)) => { // Keep collecting even with expansion errors so we can provide completions and // other services in incomplete macro expressions. - self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id()); + self.source_map + .expansions + .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap()); let prev_ast_id_map = mem::replace( &mut self.ast_id_map, self.db.ast_id_map(self.expander.current_file_id()), @@ -1869,42 +1871,45 @@ impl ExprCollector<'_> { ) -> ExprId { match count { Some(FormatCount::Literal(n)) => { - match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) { - Some(count_is) => { - let count_is = self.alloc_expr_desugared(Expr::Path(count_is)); - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - *n as u128, - Some(BuiltinUint::Usize), - ))); - self.alloc_expr_desugared(Expr::Call { - callee: count_is, - args: Box::new([args]), - is_assignee_expr: false, - }) - } - None => self.missing_expr(), - } + let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + *n as u128, + Some(BuiltinUint::Usize), + ))); + let count_is = + match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) { + Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)), + None => self.missing_expr(), + }; + self.alloc_expr_desugared(Expr::Call { + callee: count_is, + args: Box::new([args]), + is_assignee_expr: false, + }) } Some(FormatCount::Argument(arg)) => { if let Ok(arg_index) = arg.index { let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); - match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) { - Some(count_param) => { - let count_param = self.alloc_expr_desugared(Expr::Path(count_param)); - let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( - i as u128, - Some(BuiltinUint::Usize), - ))); - self.alloc_expr_desugared(Expr::Call { - callee: count_param, - args: Box::new([args]), - is_assignee_expr: false, - }) - } + let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint( + i as u128, + Some(BuiltinUint::Usize), + ))); + let count_param = match LangItem::FormatCount.ty_rel_path( + self.db, + self.krate, + name![Param], + ) { + Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)), None => self.missing_expr(), - } + }; + self.alloc_expr_desugared(Expr::Call { + callee: count_param, + args: Box::new([args]), + is_assignee_expr: false, + }) } else { + // FIXME: This drops arg causing it to potentially not be resolved/type checked + // when typing? self.missing_expr() } } @@ -1925,7 +1930,8 @@ impl ExprCollector<'_> { fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId { use ArgumentType::*; use FormatTrait::*; - match LangItem::FormatArgument.ty_rel_path( + + let new_fn = match LangItem::FormatArgument.ty_rel_path( self.db, self.krate, match ty { @@ -1941,16 +1947,14 @@ impl ExprCollector<'_> { Usize => name![from_usize], }, ) { - Some(new_fn) => { - let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn)); - self.alloc_expr_desugared(Expr::Call { - callee: new_fn, - args: Box::new([arg]), - is_assignee_expr: false, - }) - } + Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)), None => self.missing_expr(), - } + }; + self.alloc_expr_desugared(Expr::Call { + callee: new_fn, + args: Box::new([arg]), + is_assignee_expr: false, + }) } // endregion: format } diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index 0020e4eac3..fd685235e1 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -7,7 +7,7 @@ use crate::{ body::Body, db::DefDatabase, hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement}, - BlockId, DefWithBodyId, + BlockId, ConstBlockId, DefWithBodyId, }; pub type ScopeId = Idx; @@ -46,7 +46,9 @@ pub struct ScopeData { impl ExprScopes { pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { let body = db.body(def); - let mut scopes = ExprScopes::new(&body); + let mut scopes = ExprScopes::new(&body, |const_block| { + db.lookup_intern_anonymous_const(const_block).root + }); scopes.shrink_to_fit(); Arc::new(scopes) } @@ -89,7 +91,10 @@ fn empty_entries(idx: usize) -> IdxRange { } impl ExprScopes { - fn new(body: &Body) -> ExprScopes { + fn new( + body: &Body, + resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy, + ) -> ExprScopes { let mut scopes = ExprScopes { scopes: Arena::default(), scope_entries: Arena::default(), @@ -100,7 +105,7 @@ impl ExprScopes { scopes.add_bindings(body, root, self_param); } scopes.add_params_bindings(body, root, &body.params); - compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); + compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block); scopes } @@ -183,35 +188,46 @@ fn compute_block_scopes( body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId, + resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy, ) { for stmt in statements { match stmt { Statement::Let { pat, initializer, else_branch, .. } => { if let Some(expr) = initializer { - compute_expr_scopes(*expr, body, scopes, scope); + compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block); } if let Some(expr) = else_branch { - compute_expr_scopes(*expr, body, scopes, scope); + compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block); } *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(body, *scope, *pat); } Statement::Expr { expr, .. } => { - compute_expr_scopes(*expr, body, scopes, scope); + compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block); } Statement::Item => (), } } if let Some(expr) = tail { - compute_expr_scopes(expr, body, scopes, scope); + compute_expr_scopes(expr, body, scopes, scope, resolve_const_block); } } -fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) { +fn compute_expr_scopes( + expr: ExprId, + body: &Body, + scopes: &mut ExprScopes, + scope: &mut ScopeId, + resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy, +) { let make_label = |label: &Option| label.map(|label| (label, body.labels[label].name.clone())); + let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| { + compute_expr_scopes(expr, body, scopes, scope, resolve_const_block) + }; + scopes.set_scope(expr, *scope); match &body[expr] { Expr::Block { statements, tail, id, label } => { @@ -219,53 +235,54 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope // Overwrite the old scope for the block expr, so that every block scope can be found // via the block itself (important for blocks that only contain items, no expressions). scopes.set_scope(expr, scope); - compute_block_scopes(statements, *tail, body, scopes, &mut scope); + compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block); } - Expr::Const(_) => { - // FIXME: This is broken. + Expr::Const(id) => { + let mut scope = scopes.root_scope(); + compute_expr_scopes(scopes, resolve_const_block(*id), &mut scope); } Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => { let mut scope = scopes.new_block_scope(*scope, *id, None); // Overwrite the old scope for the block expr, so that every block scope can be found // via the block itself (important for blocks that only contain items, no expressions). scopes.set_scope(expr, scope); - compute_block_scopes(statements, *tail, body, scopes, &mut scope); + compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block); } Expr::Loop { body: body_expr, label } => { let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); - compute_expr_scopes(*body_expr, body, scopes, &mut scope); + compute_expr_scopes(scopes, *body_expr, &mut scope); } Expr::Closure { args, body: body_expr, .. } => { let mut scope = scopes.new_scope(*scope); scopes.add_params_bindings(body, scope, args); - compute_expr_scopes(*body_expr, body, scopes, &mut scope); + compute_expr_scopes(scopes, *body_expr, &mut scope); } Expr::Match { expr, arms } => { - compute_expr_scopes(*expr, body, scopes, scope); + compute_expr_scopes(scopes, *expr, scope); for arm in arms.iter() { let mut scope = scopes.new_scope(*scope); scopes.add_pat_bindings(body, scope, arm.pat); if let Some(guard) = arm.guard { scope = scopes.new_scope(scope); - compute_expr_scopes(guard, body, scopes, &mut scope); + compute_expr_scopes(scopes, guard, &mut scope); } - compute_expr_scopes(arm.expr, body, scopes, &mut scope); + compute_expr_scopes(scopes, arm.expr, &mut scope); } } &Expr::If { condition, then_branch, else_branch } => { let mut then_branch_scope = scopes.new_scope(*scope); - compute_expr_scopes(condition, body, scopes, &mut then_branch_scope); - compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope); + compute_expr_scopes(scopes, condition, &mut then_branch_scope); + compute_expr_scopes(scopes, then_branch, &mut then_branch_scope); if let Some(else_branch) = else_branch { - compute_expr_scopes(else_branch, body, scopes, scope); + compute_expr_scopes(scopes, else_branch, scope); } } &Expr::Let { pat, expr } => { - compute_expr_scopes(expr, body, scopes, scope); + compute_expr_scopes(scopes, expr, scope); *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(body, *scope, pat); } - e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), + e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)), }; } diff --git a/crates/hir-def/src/body/tests.rs b/crates/hir-def/src/body/tests.rs index a27ffe2167..4c8a54f7c8 100644 --- a/crates/hir-def/src/body/tests.rs +++ b/crates/hir-def/src/body/tests.rs @@ -318,18 +318,20 @@ fn f() { expect![[r#" fn f() { - $crate::panicking::panic_fmt( - builtin#lang(Arguments::new_v1_formatted)( - &[ - "cc", - ], - &[], - &[], - unsafe { - builtin#lang(UnsafeArg::new)() - }, - ), - ); + { + $crate::panicking::panic_fmt( + builtin#lang(Arguments::new_v1_formatted)( + &[ + "cc", + ], + &[], + &[], + unsafe { + builtin#lang(UnsafeArg::new)() + }, + ), + ); + }; }"#]] .assert_eq(&body.pretty_print(&db, def)) } diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index e3d750d33c..51a4dd6f42 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -229,7 +229,7 @@ pub struct TraitData { /// method calls to this trait's methods when the receiver is an array and the crate edition is /// 2015 or 2018. // box it as the vec is usually empty anyways - pub attribute_calls: Option, MacroCallId)>>>, + pub macro_calls: Option, MacroCallId)>>>, } impl TraitData { @@ -258,12 +258,12 @@ impl TraitData { let mut collector = AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); - let (items, attribute_calls, diagnostics) = collector.finish(); + let (items, macro_calls, diagnostics) = collector.finish(); ( Arc::new(TraitData { name, - attribute_calls, + macro_calls, items, is_auto, is_unsafe, @@ -298,7 +298,7 @@ impl TraitData { } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { - self.attribute_calls.iter().flat_map(|it| it.iter()).copied() + self.macro_calls.iter().flat_map(|it| it.iter()).copied() } } @@ -319,7 +319,7 @@ impl TraitAliasData { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct ImplData { pub target_trait: Option>, pub self_ty: Interned, @@ -327,7 +327,7 @@ pub struct ImplData { pub is_negative: bool, pub is_unsafe: bool, // box it as the vec is usually empty anyways - pub attribute_calls: Option, MacroCallId)>>>, + pub macro_calls: Option, MacroCallId)>>>, } impl ImplData { @@ -354,7 +354,7 @@ impl ImplData { AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id)); collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items); - let (items, attribute_calls, diagnostics) = collector.finish(); + let (items, macro_calls, diagnostics) = collector.finish(); let items = items.into_iter().map(|(_, item)| item).collect(); ( @@ -364,14 +364,14 @@ impl ImplData { items, is_negative, is_unsafe, - attribute_calls, + macro_calls, }), DefDiagnostics::new(diagnostics), ) } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { - self.attribute_calls.iter().flat_map(|it| it.iter()).copied() + self.macro_calls.iter().flat_map(|it| it.iter()).copied() } } @@ -573,7 +573,7 @@ struct AssocItemCollector<'a> { expander: Expander, items: Vec<(Name, AssocItemId)>, - attr_calls: Vec<(AstId, MacroCallId)>, + macro_calls: Vec<(AstId, MacroCallId)>, } impl<'a> AssocItemCollector<'a> { @@ -590,7 +590,7 @@ impl<'a> AssocItemCollector<'a> { container, expander: Expander::new(db, file_id, module_id), items: Vec::new(), - attr_calls: Vec::new(), + macro_calls: Vec::new(), diagnostics: Vec::new(), } } @@ -604,7 +604,7 @@ impl<'a> AssocItemCollector<'a> { ) { ( self.items, - if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) }, + if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) }, self.diagnostics, ) } @@ -662,11 +662,11 @@ impl<'a> AssocItemCollector<'a> { } } - self.attr_calls.push((ast_id, call_id)); + self.macro_calls.push((ast_id, call_id)); let res = self.expander.enter_expand_id::(self.db, call_id); - self.collect_macro_items(res, &|| loc.kind.clone()); + self.collect_macro_items(res); continue 'items; } Ok(_) => (), @@ -698,24 +698,22 @@ impl<'a> AssocItemCollector<'a> { match item { AssocItem::Function(id) => { let item = &item_tree[id]; - let def = FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); self.items.push((item.name.clone(), def.into())); } + AssocItem::TypeAlias(id) => { + let item = &item_tree[id]; + let def = + TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); + self.items.push((item.name.clone(), def.into())); + } AssocItem::Const(id) => { let item = &item_tree[id]; let Some(name) = item.name.clone() else { return }; let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); self.items.push((name, def.into())); } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; - - let def = - TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db); - self.items.push((item.name.clone(), def.into())); - } AssocItem::MacroCall(call) => { let file_id = self.expander.current_file_id(); let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; @@ -745,11 +743,8 @@ impl<'a> AssocItemCollector<'a> { Ok(Some(call_id)) => { let res = self.expander.enter_expand_id::(self.db, call_id); - self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike { - ast_id: InFile::new(file_id, ast_id), - expand_to: hir_expand::ExpandTo::Items, - eager: None, - }); + self.macro_calls.push((InFile::new(file_id, ast_id.upcast()), call_id)); + self.collect_macro_items(res); } Ok(None) => (), Err(_) => { @@ -768,39 +763,8 @@ impl<'a> AssocItemCollector<'a> { } } - fn collect_macro_items( - &mut self, - ExpandResult { value, err }: ExpandResult)>>, - error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind, - ) { - let Some((mark, parse)) = value else { return }; - - if let Some(err) = err { - let diag = match err { - // why is this reported here? - hir_expand::ExpandError::UnresolvedProcMacro(krate) => { - DefDiagnostic::unresolved_proc_macro( - self.module_id.local_id, - error_call_kind(), - krate, - ) - } - _ => DefDiagnostic::macro_error( - self.module_id.local_id, - error_call_kind(), - err.to_string(), - ), - }; - self.diagnostics.push(diag); - } - let errors = parse.errors(); - if !errors.is_empty() { - self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error( - self.module_id.local_id, - error_call_kind(), - errors.into_boxed_slice(), - )); - } + fn collect_macro_items(&mut self, res: ExpandResult)>>) { + let Some((mark, _parse)) = res.value else { return }; let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None); let item_tree = tree_id.item_tree(self.db); diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index bf728a7107..4e57845a69 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -1177,6 +1177,8 @@ pub mod fmt { //- /main.rs crate:main deps:alloc,std #![no_std] +extern crate alloc; + $0 //- /std.rs crate:std deps:alloc diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index acc60e1d9e..10a1d65bb9 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -20,7 +20,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, expander::Expander, - item_tree::{GenericsItemTreeNode, ItemTree}, + item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree}, lower::LowerCtx, nameres::{DefMap, MacroSubNs}, type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef}, @@ -339,6 +339,7 @@ impl GenericParamsCollector { target: Either, ) { let bound = TypeBound::from_ast(lower_ctx, bound); + self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds()); let predicate = match (target, bound) { (Either::Left(type_ref), bound) => match hrtb_lifetimes { Some(hrtb_lifetimes) => WherePredicate::ForLifetime { @@ -359,7 +360,24 @@ impl GenericParamsCollector { self.where_predicates.push(predicate); } - pub(crate) fn fill_implicit_impl_trait_args( + fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec>>) { + for bounds in impl_bounds { + let param = TypeParamData { + name: None, + default: None, + provenance: TypeParamProvenance::ArgumentImplTrait, + }; + let param_id = self.type_or_consts.alloc(param.into()); + for bound in bounds { + self.where_predicates.push(WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeOrConstParam(param_id), + bound, + }); + } + } + } + + fn fill_implicit_impl_trait_args( &mut self, db: &dyn DefDatabase, exp: &mut Lazy<(Arc, Expander), impl FnOnce() -> (Arc, Expander)>, @@ -456,56 +474,67 @@ impl GenericParams { let cfg_options = &cfg_options[krate].cfg_options; // Returns the generic parameters that are enabled under the current `#[cfg]` options - let enabled_params = |params: &Interned, item_tree: &ItemTree| { - let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + let enabled_params = + |params: &Interned, item_tree: &ItemTree, parent: GenericModItem| { + let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param); + let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); - // In the common case, no parameters will by disabled by `#[cfg]` attributes. - // Therefore, make a first pass to check if all parameters are enabled and, if so, - // clone the `Interned` instead of recreating an identical copy. - let all_type_or_consts_enabled = - params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into())); - let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into())); + // In the common case, no parameters will by disabled by `#[cfg]` attributes. + // Therefore, make a first pass to check if all parameters are enabled and, if so, + // clone the `Interned` instead of recreating an identical copy. + let all_type_or_consts_enabled = + params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx))); + let all_lifetimes_enabled = + params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx))); - if all_type_or_consts_enabled && all_lifetimes_enabled { - params.clone() - } else { - Interned::new(GenericParams { - type_or_consts: all_type_or_consts_enabled - .then(|| params.type_or_consts.clone()) - .unwrap_or_else(|| { - params - .type_or_consts - .iter() - .filter(|(idx, _)| enabled((*idx).into())) - .map(|(_, param)| param.clone()) - .collect() - }), - lifetimes: all_lifetimes_enabled - .then(|| params.lifetimes.clone()) - .unwrap_or_else(|| { - params - .lifetimes - .iter() - .filter(|(idx, _)| enabled((*idx).into())) - .map(|(_, param)| param.clone()) - .collect() - }), - where_predicates: params.where_predicates.clone(), - }) - } - }; + if all_type_or_consts_enabled && all_lifetimes_enabled { + params.clone() + } else { + Interned::new(GenericParams { + type_or_consts: all_type_or_consts_enabled + .then(|| params.type_or_consts.clone()) + .unwrap_or_else(|| { + params + .type_or_consts + .iter() + .filter(|&(idx, _)| enabled(attr_owner_ct(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + lifetimes: all_lifetimes_enabled + .then(|| params.lifetimes.clone()) + .unwrap_or_else(|| { + params + .lifetimes + .iter() + .filter(|&(idx, _)| enabled(attr_owner_lt(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + where_predicates: params.where_predicates.clone(), + }) + } + }; fn id_to_generics( db: &dyn DefDatabase, id: impl for<'db> Lookup< Database<'db> = dyn DefDatabase + 'db, Data = impl ItemTreeLoc, >, - enabled_params: impl Fn(&Interned, &ItemTree) -> Interned, - ) -> Interned { + enabled_params: impl Fn( + &Interned, + &ItemTree, + GenericModItem, + ) -> Interned, + ) -> Interned + where + FileItemTreeId: Into, + { let id = id.lookup(db).item_tree_id(); let tree = id.item_tree(db); let item = &tree[id.value]; - enabled_params(item.generic_params(), &tree) + enabled_params(item.generic_params(), &tree, id.value.into()) } match def { @@ -514,7 +543,8 @@ impl GenericParams { let tree = loc.id.item_tree(db); let item = &tree[loc.id.value]; - let enabled_params = enabled_params(&item.explicit_generic_params, &tree); + let enabled_params = + enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into()); let module = loc.container.module(db); let func_data = db.function_data(id); diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index ac0caaf0dc..2f7ebbfec1 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -136,15 +136,15 @@ impl From for Literal { Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty) } LiteralKind::ByteString(bs) => { - let text = bs.value().map(Box::from).unwrap_or_else(Default::default); + let text = bs.value().map_or_else(|_| Default::default(), Box::from); Literal::ByteString(text) } LiteralKind::String(s) => { - let text = s.value().map(Box::from).unwrap_or_else(Default::default); + let text = s.value().map_or_else(|_| Default::default(), Box::from); Literal::String(text) } LiteralKind::CString(s) => { - let text = s.value().map(Box::from).unwrap_or_else(Default::default); + let text = s.value().map_or_else(|_| Default::default(), Box::from); Literal::CString(text) } LiteralKind::Byte(b) => { diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index a60b9f9f3a..54cd57110e 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -234,6 +234,14 @@ impl ItemScope { self.impls.iter().copied() } + pub fn all_macro_calls(&self) -> impl Iterator + '_ { + self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain( + self.derive_macros.values().flat_map(|it| { + it.iter().flat_map(|it| it.derive_call_ids.iter().copied().flatten()) + }), + ) + } + pub(crate) fn modules_in_scope(&self) -> impl Iterator + '_ { self.types.values().copied().filter_map(|(def, vis, _)| match def { ModuleDefId::ModuleId(module) => Some((module, vis)), diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 610480736c..acda64c41f 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -29,6 +29,7 @@ //! //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its //! surface syntax. +#![allow(unexpected_cfgs)] mod lower; mod pretty; @@ -57,21 +58,21 @@ use triomphe::Arc; use crate::{ attr::Attrs, db::DefDatabase, - generics::{GenericParams, LifetimeParamData, TypeOrConstParamData}, + generics::GenericParams, path::{GenericArgs, ImportAlias, ModPath, Path, PathKind}, type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, visibility::{RawVisibility, VisibilityExplicitness}, - BlockId, Lookup, + BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, }; #[derive(Copy, Clone, Eq, PartialEq)] pub struct RawVisibilityId(u32); impl RawVisibilityId { - pub const PUB: Self = RawVisibilityId(u32::max_value()); - pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1); - pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2); - pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3); + pub const PUB: Self = RawVisibilityId(u32::MAX); + pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1); + pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2); + pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3); } impl fmt::Debug for RawVisibilityId { @@ -293,8 +294,8 @@ pub enum AttrOwner { Variant(FileItemTreeId), Field(Idx), Param(Idx), - TypeOrConstParamData(Idx), - LifetimeParamData(Idx), + TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId), + LifetimeParamData(GenericModItem, LocalLifetimeParamId), } macro_rules! from_attrs { @@ -314,8 +315,6 @@ from_attrs!( Variant(FileItemTreeId), Field(Idx), Param(Idx), - TypeOrConstParamData(Idx), - LifetimeParamData(Idx), ); /// Trait implemented by all nodes in the item tree. @@ -465,12 +464,49 @@ macro_rules! mod_items { )+ } + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] + pub enum GenericModItem { + $( + $( + #[cfg_attr(ignore_fragment, $generic_params)] + $typ(FileItemTreeId<$typ>), + )? + )+ + } + + impl From for ModItem { + fn from(id: GenericModItem) -> ModItem { + match id { + $( + $( + #[cfg_attr(ignore_fragment, $generic_params)] + GenericModItem::$typ(id) => ModItem::$typ(id), + )? + )+ + } + } + } + + impl From for AttrOwner { + fn from(t: GenericModItem) -> AttrOwner { + AttrOwner::ModItem(t.into()) + } + } + $( impl From> for ModItem { fn from(id: FileItemTreeId<$typ>) -> ModItem { ModItem::$typ(id) } } + $( + #[cfg_attr(ignore_fragment, $generic_params)] + impl From> for GenericModItem { + fn from(id: FileItemTreeId<$typ>) -> GenericModItem { + GenericModItem::$typ(id) + } + } + )? )+ $( diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 4b5ef56d78..199b8daa37 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -4,6 +4,7 @@ use std::collections::hash_map::Entry; use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId}; use la_arena::Arena; +use rustc_hash::FxHashMap; use span::{AstIdMap, SyntaxContextId}; use syntax::{ ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString}, @@ -16,11 +17,11 @@ use crate::{ generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, item_tree::{ AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId, - Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias, - Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, - ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs, - RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, - Use, UseTree, UseTreeKind, Variant, + Fields, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, IdxRange, + Impl, ImportAlias, Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, + MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, + Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, + TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, }, path::AssociatedTypeBinding, type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef}, @@ -36,6 +37,8 @@ pub(super) struct Ctx<'a> { db: &'a dyn DefDatabase, tree: ItemTree, source_ast_id_map: Arc, + generic_param_attr_buffer: + FxHashMap, RawAttrs>, body_ctx: crate::lower::LowerCtx<'a>, } @@ -44,6 +47,7 @@ impl<'a> Ctx<'a> { Self { db, tree: ItemTree::default(), + generic_param_attr_buffer: FxHashMap::default(), source_ast_id_map: db.ast_id_map(file), body_ctx: crate::lower::LowerCtx::new(db, file), } @@ -56,6 +60,7 @@ impl<'a> Ctx<'a> { pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree { self.tree.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect(); + assert!(self.generic_param_attr_buffer.is_empty()); self.tree } @@ -89,6 +94,7 @@ impl<'a> Ctx<'a> { } } + assert!(self.generic_param_attr_buffer.is_empty()); self.tree } @@ -117,6 +123,7 @@ impl<'a> Ctx<'a> { } } + assert!(self.generic_param_attr_buffer.is_empty()); self.tree } @@ -185,10 +192,12 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(strukt); let name = strukt.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(strukt); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let fields = self.lower_fields(&strukt.kind()); + let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt); let res = Struct { name, visibility, generic_params, fields, ast_id }; - Some(id(self.data().structs.alloc(res))) + let id = id(self.data().structs.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields { @@ -252,28 +261,32 @@ impl<'a> Ctx<'a> { let visibility = self.lower_visibility(union); let name = union.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(union); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let fields = match union.record_field_list() { Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)), None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())), }; + let generic_params = self.lower_generic_params(HasImplicitSelf::No, union); let res = Union { name, visibility, generic_params, fields, ast_id }; - Some(id(self.data().unions.alloc(res))) + let id = id(self.data().unions.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_enum(&mut self, enum_: &ast::Enum) -> Option> { let visibility = self.lower_visibility(enum_); let name = enum_.name()?.as_name(); let ast_id = self.source_ast_id_map.ast_id(enum_); - let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let variants = match &enum_.variant_list() { Some(variant_list) => self.lower_variants(variant_list), None => { FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx()) } }; + let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_); let res = Enum { name, visibility, generic_params, variants, ast_id }; - Some(id(self.data().enums.alloc(res))) + let id = id(self.data().enums.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_variants(&mut self, variants: &ast::VariantList) -> Range> { @@ -414,7 +427,9 @@ impl<'a> Ctx<'a> { flags, }; - Some(id(self.data().functions.alloc(res))) + let id = id(self.data().functions.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_type_alias( @@ -428,7 +443,9 @@ impl<'a> Ctx<'a> { let ast_id = self.source_ast_id_map.ast_id(type_alias); let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias); let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id }; - Some(id(self.data().type_aliases.alloc(res))) + let id = id(self.data().type_aliases.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_static(&mut self, static_: &ast::Static) -> Option> { @@ -475,8 +492,6 @@ impl<'a> Ctx<'a> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); let ast_id = self.source_ast_id_map.ast_id(trait_def); - let generic_params = - self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let is_auto = trait_def.auto_token().is_some(); let is_unsafe = trait_def.unsafe_token().is_some(); @@ -487,8 +502,12 @@ impl<'a> Ctx<'a> { .filter_map(|item_node| self.lower_assoc_item(&item_node)) .collect(); + let generic_params = + self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def); let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; - Some(id(self.data().traits.alloc(def))) + let id = id(self.data().traits.alloc(def)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_trait_alias( @@ -504,19 +523,18 @@ impl<'a> Ctx<'a> { ); let alias = TraitAlias { name, visibility, generic_params, ast_id }; - Some(id(self.data().trait_aliases.alloc(alias))) + let id = id(self.data().trait_aliases.alloc(alias)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option> { let ast_id = self.source_ast_id_map.ast_id(impl_def); - // Note that trait impls don't get implicit `Self` unlike traits, because here they are a - // type alias rather than a type parameter, so this is handled by the resolver. - let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only // equals itself. - let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); let self_ty = self.lower_type_ref(&impl_def.self_ty()?); + let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); let is_negative = impl_def.excl_token().is_some(); let is_unsafe = impl_def.unsafe_token().is_some(); @@ -527,9 +545,14 @@ impl<'a> Ctx<'a> { .flat_map(|it| it.assoc_items()) .filter_map(|item| self.lower_assoc_item(&item)) .collect(); + // Note that trait impls don't get implicit `Self` unlike traits, because here they are a + // type alias rather than a type parameter, so this is handled by the resolver. + let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def); let res = Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id }; - Some(id(self.data().impls.alloc(res))) + let id = id(self.data().impls.alloc(res)); + self.write_generic_params_attributes(id.into()); + Some(id) } fn lower_use(&mut self, use_item: &ast::Use) -> Option> { @@ -616,11 +639,30 @@ impl<'a> Ctx<'a> { id(self.data().extern_blocks.alloc(res)) } + fn write_generic_params_attributes(&mut self, parent: GenericModItem) { + self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| { + self.tree.attrs.insert( + match idx { + Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id), + Either::Right(id) => AttrOwner::LifetimeParamData(parent, id), + }, + attrs, + ); + }) + } + fn lower_generic_params( &mut self, has_implicit_self: HasImplicitSelf, node: &dyn ast::HasGenericParams, ) -> Interned { + debug_assert!(self.generic_param_attr_buffer.is_empty(),); + let add_param_attrs = |item: Either, + param| { + let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map()); + debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none()); + }; + self.body_ctx.take_impl_traits_bounds(); let mut generics = GenericParamsCollector::default(); if let HasImplicitSelf::Yes(bounds) = has_implicit_self { @@ -635,28 +677,13 @@ impl<'a> Ctx<'a> { ); // add super traits as bounds on Self // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar` - let self_param = TypeRef::Path(name![Self].into()); - generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param)); + generics.fill_bounds( + &self.body_ctx, + bounds, + Either::Left(TypeRef::Path(name![Self].into())), + ); } - let add_param_attrs = |item: Either, - param| { - let attrs = RawAttrs::new(self.db.upcast(), ¶m, self.body_ctx.span_map()); - // This is identical to the body of `Ctx::add_attrs()` but we can't call that here - // because it requires `&mut self` and the call to `generics.fill()` below also - // references `self`. - match self.tree.attrs.entry(match item { - Either::Right(id) => id.into(), - Either::Left(id) => id.into(), - }) { - Entry::Occupied(mut entry) => { - *entry.get_mut() = entry.get().merge(attrs); - } - Entry::Vacant(entry) => { - entry.insert(attrs); - } - } - }; generics.fill(&self.body_ctx, node, add_param_attrs); Interned::new(generics.finish()) diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index cef2a3fb86..2803678a33 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -8,8 +8,8 @@ use crate::{ generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, item_tree::{ AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields, - FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2, - MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs, + FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, Interned, ItemTree, + Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union, Use, UseTree, UseTreeKind, Variant, }, @@ -276,7 +276,7 @@ impl Printer<'_> { w!(self, "extern \"{}\" ", abi); } w!(self, "fn {}", name.display(self.db.upcast())); - self.print_generic_params(explicit_generic_params); + self.print_generic_params(explicit_generic_params, it.into()); w!(self, "("); if !params.is_empty() { self.indented(|this| { @@ -316,7 +316,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "struct {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { wln!(self); @@ -329,7 +329,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "union {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { wln!(self); @@ -342,7 +342,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "enum {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for variant in FileItemTreeId::range_iter(variants.clone()) { @@ -394,7 +394,7 @@ impl Printer<'_> { w!(self, "auto "); } w!(self, "trait {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for item in &**items { @@ -408,7 +408,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "trait {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); w!(self, " = "); self.print_where_clause(generic_params); w!(self, ";"); @@ -429,7 +429,7 @@ impl Printer<'_> { w!(self, "unsafe"); } w!(self, "impl"); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); w!(self, " "); if *is_negative { w!(self, "!"); @@ -453,7 +453,7 @@ impl Printer<'_> { self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); w!(self, "type {}", name.display(self.db.upcast())); - self.print_generic_params(generic_params); + self.print_generic_params(generic_params, it.into()); if !bounds.is_empty() { w!(self, ": "); self.print_type_bounds(bounds); @@ -525,7 +525,7 @@ impl Printer<'_> { print_path(self.db, path, self).unwrap(); } - fn print_generic_params(&mut self, params: &GenericParams) { + fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) { if params.is_empty() { return; } @@ -537,7 +537,7 @@ impl Printer<'_> { w!(self, ", "); } first = false; - self.print_attrs_of(idx, " "); + self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " "); w!(self, "{}", lt.name.display(self.db.upcast())); } for (idx, x) in params.type_or_consts.iter() { @@ -545,7 +545,7 @@ impl Printer<'_> { w!(self, ", "); } first = false; - self.print_attrs_of(idx, " "); + self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " "); match x { TypeOrConstParamData::TypeParamData(ty) => match &ty.name { Some(name) => w!(self, "{}", name.display(self.db.upcast())), diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs index 48da876ac1..79bab11998 100644 --- a/crates/hir-def/src/item_tree/tests.rs +++ b/crates/hir-def/src/item_tree/tests.rs @@ -427,10 +427,18 @@ fn generics_with_attributes() { check( r#" struct S<#[cfg(never)] T>; +struct S; +struct S; "#, expect![[r#" // AstId: 1 pub(self) struct S<#[cfg(never)] T>; + + // AstId: 2 + pub(self) struct S; + + // AstId: 3 + pub(self) struct S; "#]], ) } diff --git a/crates/hir-def/src/lower.rs b/crates/hir-def/src/lower.rs index d574d80a8e..ecd8d79f20 100644 --- a/crates/hir-def/src/lower.rs +++ b/crates/hir-def/src/lower.rs @@ -1,26 +1,34 @@ //! Context for lowering paths. -use std::cell::OnceCell; +use std::cell::{OnceCell, RefCell}; use hir_expand::{ span_map::{SpanMap, SpanMapRef}, AstId, HirFileId, InFile, }; +use intern::Interned; use span::{AstIdMap, AstIdNode}; use syntax::ast; use triomphe::Arc; -use crate::{db::DefDatabase, path::Path}; +use crate::{db::DefDatabase, path::Path, type_ref::TypeBound}; pub struct LowerCtx<'a> { pub db: &'a dyn DefDatabase, file_id: HirFileId, span_map: OnceCell, ast_id_map: OnceCell>, + impl_trait_bounds: RefCell>>>, } impl<'a> LowerCtx<'a> { pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { - LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() } + LowerCtx { + db, + file_id, + span_map: OnceCell::new(), + ast_id_map: OnceCell::new(), + impl_trait_bounds: RefCell::new(Vec::new()), + } } pub fn with_span_map_cell( @@ -28,7 +36,13 @@ impl<'a> LowerCtx<'a> { file_id: HirFileId, span_map: OnceCell, ) -> Self { - LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() } + LowerCtx { + db, + file_id, + span_map, + ast_id_map: OnceCell::new(), + impl_trait_bounds: RefCell::new(Vec::new()), + } } pub(crate) fn span_map(&self) -> SpanMapRef<'_> { @@ -45,4 +59,12 @@ impl<'a> LowerCtx<'a> { self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item), ) } + + pub fn update_impl_traits_bounds(&self, bounds: Vec>) { + self.impl_trait_bounds.borrow_mut().push(bounds); + } + + pub fn take_impl_traits_bounds(&self) -> Vec>> { + self.impl_trait_bounds.take() + } } diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index a4864c74d7..6f605c0cb3 100644 --- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -186,3 +186,33 @@ fn#0:1@45..47#0# foo#0:1@48..51#0#(#0:1@51..52#0#�:1@52..53#0#self#0:1@53..57# }#0:1@76..77#0#"#]], ); } + +#[test] +fn attribute_macro_doc_desugaring() { + check( + r#" +//- proc_macros: identity +#[proc_macros::identity] +/// doc string \n with newline +/** + MultiLines Doc + MultiLines Doc +*/ +#[doc = "doc attr"] +struct S; +"#, + expect![[r##" +#[proc_macros::identity] +/// doc string \n with newline +/** + MultiLines Doc + MultiLines Doc +*/ +#[doc = "doc attr"] +struct S; + +#[doc = " doc string \\n with newline"] +#[doc = "\n MultiLines Doc\n MultiLines Doc\n"] +#[doc = "doc attr"] struct S;"##]], + ); +} diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 0a6cd0fe9e..262bc538b9 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -5,7 +5,7 @@ use std::{cmp::Ordering, iter, mem, ops::Not}; -use base_db::{CrateId, Dependency, FileId}; +use base_db::{CrateId, CrateOrigin, Dependency, FileId, LangCrateOrigin}; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -15,15 +15,13 @@ use hir_expand::{ builtin_fn_macro::find_builtin_macro, name::{name, AsName, Name}, proc_macro::CustomProcMacroExpander, - ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, - MacroDefId, MacroDefKind, + ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId}; -use stdx::always; use syntax::ast; use triomphe::Arc; @@ -279,7 +277,8 @@ impl DefCollector<'_> { fn seed_with_top_level(&mut self) { let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered(); - let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id; + let crate_graph = self.db.crate_graph(); + let file_id = crate_graph[self.def_map.krate].root_file_id; let item_tree = self.db.file_item_tree(file_id.into()); let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); @@ -288,19 +287,14 @@ impl DefCollector<'_> { crate_data.proc_macro_loading_error = Some(e.clone()); } - for (name, dep) in &self.deps { - if dep.is_prelude() { - crate_data - .extern_prelude - .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None)); - } - } + let mut process = true; // Process other crate-level attributes. for attr in &*attrs { if let Some(cfg) = attr.cfg() { if self.cfg_options.check(&cfg) == Some(false) { - return; + process = false; + break; } } let Some(attr_name) = attr.path.as_ident() else { continue }; @@ -350,9 +344,38 @@ impl DefCollector<'_> { } } - crate_data.shrink_to_fit(); + for (name, dep) in &self.deps { + if dep.is_prelude() { + // This is a bit confusing but the gist is that `no_core` and `no_std` remove the + // sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly + // constructed with them in place no matter what though, since at that point we + // don't do pre-configured attribute resolution yet. + // So here check if we are no_core / no_std and we are trying to add the + // corresponding dep from the sysroot + let skip = match crate_graph[dep.crate_id].origin { + CrateOrigin::Lang(LangCrateOrigin::Core) => { + crate_data.no_core && dep.is_sysroot() + } + CrateOrigin::Lang(LangCrateOrigin::Std) => { + crate_data.no_std && dep.is_sysroot() + } + _ => false, + }; + if skip { + continue; + } + crate_data + .extern_prelude + .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None)); + } + } + self.inject_prelude(); + if !process { + return; + } + ModCollector { def_collector: self, macro_depth: 0, @@ -362,6 +385,7 @@ impl DefCollector<'_> { mod_dir: ModDir::root(), } .collect_in_top_module(item_tree.top_level_items()); + Arc::get_mut(&mut self.def_map.data).unwrap().shrink_to_fit(); } fn seed_with_inner(&mut self, tree_id: TreeId) { @@ -519,15 +543,12 @@ impl DefCollector<'_> { let krate = if self.def_map.data.no_std { name![core] + } else if self.def_map.extern_prelude().any(|(name, _)| *name == name![std]) { + name![std] } else { - let std = name![std]; - if self.def_map.extern_prelude().any(|(name, _)| *name == std) { - std - } else { - // If `std` does not exist for some reason, fall back to core. This mostly helps - // keep r-a's own tests minimal. - name![core] - } + // If `std` does not exist for some reason, fall back to core. This mostly helps + // keep r-a's own tests minimal. + name![core] }; let edition = match self.def_map.data.edition { @@ -1389,31 +1410,6 @@ impl DefCollector<'_> { } let file_id = macro_call_id.as_file(); - // First, fetch the raw expansion result for purposes of error reporting. This goes through - // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve - // incrementality). - // FIXME: This kind of error fetching feels a bit odd? - let ExpandResult { value: errors, err } = - self.db.parse_macro_expansion_error(macro_call_id); - if let Some(err) = err { - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); - let diag = match err { - // why is this reported here? - hir_expand::ExpandError::UnresolvedProcMacro(krate) => { - always!(krate == loc.def.krate); - DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate) - } - _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()), - }; - - self.def_map.diagnostics.push(diag); - } - if !errors.is_empty() { - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); - let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors); - self.def_map.diagnostics.push(diag); - } - // Then, fetch and process the item tree. This will reuse the expansion result from above. let item_tree = self.db.file_item_tree(file_id); diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 8c7fdaaf58..523a4c107b 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -6,7 +6,7 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind}; use la_arena::Idx; -use syntax::{ast, SyntaxError}; +use syntax::ast; use crate::{ item_tree::{self, ItemTreeId}, @@ -23,8 +23,6 @@ pub enum DefDiagnosticKind { UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, - MacroError { ast: MacroCallKind, message: String }, - MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> }, UnimplementedBuiltinMacro { ast: AstId }, InvalidDeriveTarget { ast: AstId, id: usize }, MalformedDerive { ast: AstId, id: usize }, @@ -98,7 +96,7 @@ impl DefDiagnostic { // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this // struct loses all that information! - pub(crate) fn unresolved_proc_macro( + pub fn unresolved_proc_macro( container: LocalModuleId, ast: MacroCallKind, krate: CrateId, @@ -106,25 +104,6 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } } } - pub(crate) fn macro_error( - container: LocalModuleId, - ast: MacroCallKind, - message: String, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } } - } - - pub(crate) fn macro_expansion_parse_error( - container: LocalModuleId, - ast: MacroCallKind, - errors: Box<[SyntaxError]>, - ) -> Self { - Self { - in_module: container, - kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors }, - } - } - // FIXME: Whats the difference between this and unresolved_proc_macro pub(crate) fn unresolved_macro_call( container: LocalModuleId, diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index b3c41a073c..6af5261411 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -208,6 +208,13 @@ pub(super) fn lower_generic_args( .and_then(|args| lower_generic_args(lower_ctx, args)) .map(Interned::new); let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); + let type_ref = type_ref.inspect(|tr| { + tr.walk(&mut |tr| { + if let TypeRef::ImplTrait(bounds) = tr { + lower_ctx.update_impl_traits_bounds(bounds.clone()); + } + }); + }); let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { l.bounds() .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))) diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index fadab858aa..1602b17385 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -1,5 +1,5 @@ //! Name resolution façade. -use std::{fmt, hash::BuildHasherDefault, mem}; +use std::{fmt, hash::BuildHasherDefault, iter, mem}; use base_db::CrateId; use hir_expand::{ @@ -591,13 +591,13 @@ impl Resolver { pub fn where_predicates_in_scope( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.scopes() .filter_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(params), + Scope::GenericParams { params, def } => Some((params, def)), _ => None, }) - .flat_map(|params| params.where_predicates.iter()) + .flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def))) } pub fn generic_def(&self) -> Option { diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index f8bf88d83c..85ec02ae07 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -5,7 +5,7 @@ use base_db::CrateId; use cfg::CfgExpr; use either::Either; use intern::Interned; -use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; +use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct}; use smallvec::{smallvec, SmallVec}; use span::{Span, SyntaxContextId}; use syntax::unescape; @@ -239,7 +239,12 @@ impl Attr { span, }))) } else if let Some(tt) = ast.token_tree() { - let tree = syntax_node_to_token_tree(tt.syntax(), span_map, span); + let tree = syntax_node_to_token_tree( + tt.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); Some(Interned::new(AttrInput::TokenTree(Box::new(tree)))) } else { None @@ -247,8 +252,18 @@ impl Attr { Some(Attr { id, path, input, ctxt: span.ctx }) } - fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option { - let ctxt = tt.first()?.first_span().ctx; + fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option { + if matches!(tt, + [tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, .. })), ..] + if text == "unsafe" + ) { + match tt.get(1) { + Some(tt::TokenTree::Subtree(subtree)) => tt = &subtree.token_trees, + _ => return None, + } + } + let first = &tt.first()?; + let ctxt = first.first_span().ctx; let path_end = tt .iter() .position(|tt| { @@ -430,7 +445,7 @@ fn inner_attributes( // Input subtree is: `(cfg, $(attr),+)` // Split it up into a `cfg` subtree and the `attr` subtrees. -pub fn parse_cfg_attr_input( +fn parse_cfg_attr_input( subtree: &Subtree, ) -> Option<(&[tt::TokenTree], impl Iterator)> { let mut parts = subtree diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 94681b42a9..c7cdc5e922 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -1,6 +1,7 @@ //! Builtin derives. use itertools::izip; +use mbe::DocCommentDesugarMode; use rustc_hash::FxHashSet; use span::{MacroCallId, Span}; use stdx::never; @@ -262,7 +263,12 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result { param_type_set.insert(it.as_name()); - mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site) + mbe::syntax_node_to_token_tree( + it.syntax(), + tm, + call_site, + DocCommentDesugarMode::ProcMacro, + ) } None => { tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site }) @@ -270,15 +276,27 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result it - .type_bound_list() - .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)), + ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| { + mbe::syntax_node_to_token_tree( + it.syntax(), + tm, + call_site, + DocCommentDesugarMode::ProcMacro, + ) + }), ast::TypeOrConstParam::Const(_) => None, }; let ty = if let ast::TypeOrConstParam::Const(param) = param { let ty = param .ty() - .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax(), tm, call_site)) + .map(|ty| { + mbe::syntax_node_to_token_tree( + ty.syntax(), + tm, + call_site, + DocCommentDesugarMode::ProcMacro, + ) + }) .unwrap_or_else(|| { tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site }) }); @@ -292,7 +310,14 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result Result Option<(String, Span)> { let span = lit.span; let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::String::cast(lit)?; - token.value().map(|it| (it.into_owned(), span)) + token.value().ok().map(|it| (it.into_owned(), span)) } fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> { let span = lit.span; let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::Char::cast(lit)?; - token.value().zip(Some(span)) + token.value().ok().zip(Some(span)) } fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec, Span)> { let span = lit.span; let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::ByteString::cast(lit)?; - token.value().map(|it| (it.into_owned(), span)) + token.value().ok().map(|it| (it.into_owned(), span)) } fn compile_error_expand( diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index d7233a8923..2e5fa6131a 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -3,7 +3,7 @@ use base_db::{salsa, CrateId, FileId, SourceDatabase}; use either::Either; use limit::Limit; -use mbe::{syntax_node_to_token_tree, MatchedArmIndex}; +use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, MatchedArmIndex}; use rustc_hash::FxHashSet; use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId}; use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T}; @@ -132,7 +132,7 @@ pub trait ExpandDatabase: SourceDatabase { fn parse_macro_expansion_error( &self, macro_call: MacroCallId, - ) -> ExpandResult>; + ) -> Option>>>; } /// This expands the given macro call, but with different arguments. This is @@ -156,11 +156,25 @@ pub fn expand_speculative( // Build the subtree and token mapping for the speculative args let (mut tt, undo_info) = match loc.kind { MacroCallKind::FnLike { .. } => ( - mbe::syntax_node_to_token_tree(speculative_args, span_map, span), + mbe::syntax_node_to_token_tree( + speculative_args, + span_map, + span, + if loc.def.is_proc_macro() { + DocCommentDesugarMode::ProcMacro + } else { + DocCommentDesugarMode::Mbe + }, + ), SyntaxFixupUndoInfo::NONE, ), MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => ( - mbe::syntax_node_to_token_tree(speculative_args, span_map, span), + mbe::syntax_node_to_token_tree( + speculative_args, + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ), SyntaxFixupUndoInfo::NONE, ), MacroCallKind::Derive { derive_attr_index: index, .. } @@ -176,7 +190,12 @@ pub fn expand_speculative( let censor_cfg = cfg_process::process_cfg_attrs(db, speculative_args, &loc).unwrap_or_default(); - let mut fixups = fixup::fixup_syntax(span_map, speculative_args, span); + let mut fixups = fixup::fixup_syntax( + span_map, + speculative_args, + span, + DocCommentDesugarMode::ProcMacro, + ); fixups.append.retain(|it, _| match it { syntax::NodeOrToken::Token(_) => true, it => !censor.contains(it) && !censor_cfg.contains(it), @@ -191,6 +210,7 @@ pub fn expand_speculative( fixups.append, fixups.remove, span, + DocCommentDesugarMode::ProcMacro, ), fixups.undo_info, ) @@ -212,7 +232,12 @@ pub fn expand_speculative( }?; match attr.token_tree() { Some(token_tree) => { - let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map, span); + let mut tree = syntax_node_to_token_tree( + token_tree.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); tree.delimiter = tt::Delimiter::invisible_spanned(span); Some(tree) @@ -332,9 +357,14 @@ fn parse_macro_expansion( fn parse_macro_expansion_error( db: &dyn ExpandDatabase, macro_call_id: MacroCallId, -) -> ExpandResult> { - db.parse_macro_expansion(MacroFileId { macro_call_id }) - .map(|it| it.0.errors().into_boxed_slice()) +) -> Option>>> { + let e: ExpandResult> = + db.parse_macro_expansion(MacroFileId { macro_call_id }).map(|it| Arc::from(it.0.errors())); + if e.value.is_empty() && e.err.is_none() { + None + } else { + Some(Arc::new(e)) + } } pub(crate) fn parse_with_map( @@ -432,7 +462,16 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { return dummy_tt(kind); } - let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), span); + let mut tt = mbe::syntax_node_to_token_tree( + tt.syntax(), + map.as_ref(), + span, + if loc.def.is_proc_macro() { + DocCommentDesugarMode::ProcMacro + } else { + DocCommentDesugarMode::Mbe + }, + ); if loc.def.is_proc_macro() { // proc macros expect their inputs without parentheses, MBEs expect it with them included tt.delimiter.kind = tt::DelimiterKind::Invisible; @@ -469,7 +508,8 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { let (mut tt, undo_info) = { let syntax = item_node.syntax(); let censor_cfg = cfg_process::process_cfg_attrs(db, syntax, &loc).unwrap_or_default(); - let mut fixups = fixup::fixup_syntax(map.as_ref(), syntax, span); + let mut fixups = + fixup::fixup_syntax(map.as_ref(), syntax, span, DocCommentDesugarMode::ProcMacro); fixups.append.retain(|it, _| match it { syntax::NodeOrToken::Token(_) => true, it => !censor.contains(it) && !censor_cfg.contains(it), @@ -484,6 +524,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { fixups.append, fixups.remove, span, + DocCommentDesugarMode::ProcMacro, ), fixups.undo_info, ) diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs index 66465ce600..7c3bf995b1 100644 --- a/crates/hir-expand/src/declarative.rs +++ b/crates/hir-expand/src/declarative.rs @@ -2,6 +2,7 @@ use std::sync::OnceLock; use base_db::{CrateId, VersionReq}; +use mbe::DocCommentDesugarMode; use span::{Edition, MacroCallId, Span, SyntaxContextId}; use stdx::TupleExt; use syntax::{ast, AstNode}; @@ -158,6 +159,7 @@ impl DeclarativeMacroExpander { map.span_for_range( macro_rules.macro_rules_token().unwrap().text_range(), ), + DocCommentDesugarMode::Mbe, ); mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars) @@ -175,6 +177,7 @@ impl DeclarativeMacroExpander { arg.syntax(), map.as_ref(), map.span_for_range(macro_def.macro_token().unwrap().text_range()), + DocCommentDesugarMode::Mbe, ); mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars) diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs index 8b147c88c1..64e04bc08f 100644 --- a/crates/hir-expand/src/eager.rs +++ b/crates/hir-expand/src/eager.rs @@ -19,6 +19,7 @@ //! //! See the full discussion : use base_db::CrateId; +use mbe::DocCommentDesugarMode; use span::SyntaxContextId; use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent}; use triomphe::Arc; @@ -80,7 +81,12 @@ pub fn expand_eager_macro_input( return ExpandResult { value: None, err }; }; - let mut subtree = mbe::syntax_node_to_token_tree(&expanded_eager_input, arg_map, span); + let mut subtree = mbe::syntax_node_to_token_tree( + &expanded_eager_input, + arg_map, + span, + DocCommentDesugarMode::Mbe, + ); subtree.delimiter.kind = crate::tt::DelimiterKind::Invisible; diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 711acfeb3d..9ec2a83162 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -1,6 +1,7 @@ //! To make attribute macros work reliably when typing, we need to take care to //! fix up syntax errors in the code we're passing to them. +use mbe::DocCommentDesugarMode; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER}; @@ -49,6 +50,7 @@ pub(crate) fn fixup_syntax( span_map: SpanMapRef<'_>, node: &SyntaxNode, call_site: Span, + mode: DocCommentDesugarMode, ) -> SyntaxFixups { let mut append = FxHashMap::::default(); let mut remove = FxHashSet::::default(); @@ -70,7 +72,7 @@ pub(crate) fn fixup_syntax( if can_handle_error(&node) && has_error_to_handle(&node) { remove.insert(node.clone().into()); // the node contains an error node, we have to completely replace it by something valid - let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site); + let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site, mode); let idx = original.len() as u32; original.push(original_tree); let span = span_map.span_for_range(node_range); @@ -360,6 +362,7 @@ fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) { mod tests { use base_db::FileId; use expect_test::{expect, Expect}; + use mbe::DocCommentDesugarMode; use syntax::TextRange; use triomphe::Arc; @@ -402,6 +405,7 @@ mod tests { span_map.as_ref(), &parsed.syntax_node(), span_map.span_for_range(TextRange::empty(0.into())), + DocCommentDesugarMode::Mbe, ); let mut tt = mbe::syntax_node_to_token_tree_modified( &parsed.syntax_node(), @@ -409,6 +413,7 @@ mod tests { fixups.append, fixups.remove, span_map.span_for_range(TextRange::empty(0.into())), + DocCommentDesugarMode::Mbe, ); let actual = format!("{tt}\n"); @@ -436,6 +441,7 @@ mod tests { &parsed.syntax_node(), span_map.as_ref(), span_map.span_for_range(TextRange::empty(0.into())), + DocCommentDesugarMode::Mbe, ); assert!( check_subtree_eq(&tt, &original_as_tt), diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 338bd25ede..4ab989bec2 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -132,13 +132,13 @@ pub enum ExpandError { MacroDefinition, Mbe(mbe::ExpandError), RecursionOverflow, - Other(Box>), - ProcMacroPanic(Box>), + Other(Arc>), + ProcMacroPanic(Arc>), } impl ExpandError { pub fn other(msg: impl Into>) -> Self { - ExpandError::Other(Box::new(msg.into())) + ExpandError::Other(Arc::new(msg.into())) } } diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index abed16fecd..def2578b0e 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -8,6 +8,7 @@ use rustc_hash::FxHashMap; use span::Span; use stdx::never; use syntax::SmolStr; +use triomphe::Arc; use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult}; @@ -157,7 +158,7 @@ impl CustomProcMacroExpander { ProcMacroExpansionError::System(text) | ProcMacroExpansionError::Panic(text) => ExpandResult::new( tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), - ExpandError::ProcMacroPanic(Box::new(text.into_boxed_str())), + ExpandError::ProcMacroPanic(Arc::new(text.into_boxed_str())), ), }, } diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 46612242b0..84ac8740ec 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -806,7 +806,7 @@ pub(crate) fn impl_datum_query( krate: CrateId, impl_id: ImplId, ) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "impl_datum").entered(); + let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered(); debug!("impl_datum {:?}", impl_id); let impl_: hir_def::ImplId = from_chalk(db, impl_id); impl_def_datum(db, krate, impl_id, impl_) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index 0bf01b0bc6..d99ef6679e 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -27,6 +27,7 @@ pub trait TyExt { fn is_scalar(&self) -> bool; fn is_floating_point(&self) -> bool; fn is_never(&self) -> bool; + fn is_str(&self) -> bool; fn is_unknown(&self) -> bool; fn contains_unknown(&self) -> bool; fn is_ty_var(&self) -> bool; @@ -87,6 +88,10 @@ impl TyExt for Ty { matches!(self.kind(Interner), TyKind::Never) } + fn is_str(&self) -> bool { + matches!(self.kind(Interner), TyKind::Str) + } + fn is_unknown(&self) -> bool { matches!(self.kind(Interner), TyKind::Error) } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index a357e85035..c010f5d22b 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -797,8 +797,20 @@ impl HirDisplay for Ty { c.hir_fmt(f)?; write!(f, "]")?; } - TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => { - if matches!(self.kind(Interner), TyKind::Raw(..)) { + kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => { + if let TyKind::Ref(_, l, _) = kind { + f.write_char('&')?; + if cfg!(test) { + // rendering these unconditionally is probably too much (at least for inlay + // hints) so we gate it to testing only for the time being + l.hir_fmt(f)?; + f.write_char(' ')?; + } + match m { + Mutability::Not => (), + Mutability::Mut => f.write_str("mut ")?, + } + } else { write!( f, "*{}", @@ -807,15 +819,6 @@ impl HirDisplay for Ty { Mutability::Mut => "mut ", } )?; - } else { - write!( - f, - "&{}", - match m { - Mutability::Not => "", - Mutability::Mut => "mut ", - } - )?; } // FIXME: all this just to decide whether to use parentheses... @@ -1330,7 +1333,18 @@ fn hir_fmt_generics( } let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters); - if !parameters_to_write.is_empty() { + + // FIXME: Remote this + // most of our lifetimes will be errors as we lack elision and inference + // so don't render them for now + let only_err_lifetimes = !cfg!(test) + && parameters_to_write.iter().all(|arg| { + matches!( + arg.data(Interner), + chalk_ir::GenericArgData::Lifetime(it) if *it.data(Interner) == LifetimeData::Error + ) + }); + if !parameters_to_write.is_empty() && !only_err_lifetimes { write!(f, "<")?; hir_fmt_generic_arguments(f, parameters_to_write)?; write!(f, ">")?; @@ -1403,6 +1417,18 @@ fn hir_fmt_generic_arguments( None => (parameters, &[][..]), }; for generic_arg in lifetimes.iter().chain(ty_or_const) { + // FIXME: Remove this + // most of our lifetimes will be errors as we lack elision and inference + // so don't render them for now + if !cfg!(test) + && matches!( + generic_arg.lifetime(Interner), + Some(l) if ***l.interned() == LifetimeData::Error + ) + { + continue; + } + if !first { write!(f, ", ")?; } @@ -1728,9 +1754,9 @@ impl HirDisplay for LifetimeData { LifetimeData::BoundVar(idx) => idx.hir_fmt(f), LifetimeData::InferenceVar(_) => write!(f, "_"), LifetimeData::Static => write!(f, "'static"), - LifetimeData::Error => write!(f, "'{{error}}"), - LifetimeData::Erased => Ok(()), - LifetimeData::Phantom(_, _) => Ok(()), + LifetimeData::Error => write!(f, "'?"), + LifetimeData::Erased => write!(f, "'"), + LifetimeData::Phantom(void, _) => match *void {}, } } } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 281386e136..6f2f70dd40 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -198,6 +198,7 @@ pub enum InferenceDiagnostic { NoSuchField { field: ExprOrPatId, private: bool, + variant: VariantId, }, PrivateField { expr: ExprId, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index d011a62e77..38076fce8f 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -563,6 +563,7 @@ impl InferenceContext<'_> { InferenceDiagnostic::NoSuchField { field: field.expr.into(), private: true, + variant: def, }, ); } @@ -572,6 +573,7 @@ impl InferenceContext<'_> { self.push_diagnostic(InferenceDiagnostic::NoSuchField { field: field.expr.into(), private: false, + variant: def, }); None } diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 1b354935a5..dac5a5ea69 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -177,6 +177,7 @@ impl InferenceContext<'_> { self.push_diagnostic(InferenceDiagnostic::NoSuchField { field: inner.into(), private: true, + variant: def, }); } let f = field_types[local_id].clone(); @@ -190,6 +191,7 @@ impl InferenceContext<'_> { self.push_diagnostic(InferenceDiagnostic::NoSuchField { field: inner.into(), private: false, + variant: def, }); self.err_ty() } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 4d0516ead6..04ace38202 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -345,51 +345,47 @@ impl<'a> TyLoweringContext<'a> { } ImplTraitLoweringState::Param(counter) => { let idx = counter.get(); - // FIXME we're probably doing something wrong here + // Count the number of `impl Trait` things that appear within our bounds. + // Since t hose have been emitted as implicit type args already. counter.set(idx + count_impl_traits(type_ref) as u16); - if let Some(generics) = self.generics() { - let param = generics - .iter() - .filter(|(_, data)| { - matches!( - data, - GenericParamDataRef::TypeParamData(data) - if data.provenance == TypeParamProvenance::ArgumentImplTrait - ) - }) - .nth(idx as usize) - .map_or(TyKind::Error, |(id, _)| { - if let GenericParamId::TypeParamId(id) = id { - TyKind::Placeholder(to_placeholder_idx(self.db, id.into())) - } else { - // we just filtered them out - unreachable!("Unexpected lifetime or const argument"); - } - }); - param.intern(Interner) - } else { - TyKind::Error.intern(Interner) - } + let kind = self + .generics() + .expect("param impl trait lowering must be in a generic def") + .iter() + .filter_map(|(id, data)| match (id, data) { + ( + GenericParamId::TypeParamId(id), + GenericParamDataRef::TypeParamData(data), + ) if data.provenance == TypeParamProvenance::ArgumentImplTrait => { + Some(id) + } + _ => None, + }) + .nth(idx as usize) + .map_or(TyKind::Error, |id| { + TyKind::Placeholder(to_placeholder_idx(self.db, id.into())) + }); + kind.intern(Interner) } ImplTraitLoweringState::Variable(counter) => { let idx = counter.get(); - // FIXME we're probably doing something wrong here + // Count the number of `impl Trait` things that appear within our bounds. + // Since t hose have been emitted as implicit type args already. counter.set(idx + count_impl_traits(type_ref) as u16); let ( _parent_params, self_params, - list_params, + type_params, const_params, _impl_trait_params, _lifetime_params, - ) = if let Some(generics) = self.generics() { - generics.provenance_split() - } else { - (0, 0, 0, 0, 0, 0) - }; + ) = self + .generics() + .expect("variable impl trait lowering must be in a generic def") + .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_params + list_params + const_params, + idx as usize + self_params + type_params + const_params, )) .intern(Interner) } @@ -1010,6 +1006,7 @@ impl<'a> TyLoweringContext<'a> { pub(crate) fn lower_where_predicate<'b>( &'b self, where_predicate: &'b WherePredicate, + &def: &GenericDefId, ignore_bindings: bool, ) -> impl Iterator + 'b { match where_predicate { @@ -1018,7 +1015,6 @@ impl<'a> TyLoweringContext<'a> { let self_ty = match target { WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref), &WherePredicateTypeTarget::TypeOrConstParam(local_id) => { - let def = self.resolver.generic_def().expect("generics in scope"); let param_id = hir_def::TypeOrConstParamId { parent: def, local_id }; match self.type_param_mode { ParamLoweringMode::Placeholder => { @@ -1056,23 +1052,7 @@ impl<'a> TyLoweringContext<'a> { let clause = match bound.as_ref() { TypeBound::Path(path, TraitBoundModifier::None) => { trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty)); - trait_ref - .clone() - .filter(|tr| { - // ignore `T: Drop` or `T: Destruct` bounds. - // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement. - // (So ideally, we'd only ignore `~const Drop` here) - // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until - // the builtin impls are supported by Chalk, we ignore them here. - if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) { - if matches!(lang, LangItem::Drop | LangItem::Destruct) { - return false; - } - } - true - }) - .map(WhereClause::Implemented) - .map(crate::wrap_empty_binders) + trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self @@ -1166,84 +1146,77 @@ impl<'a> TyLoweringContext<'a> { binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = &binding.type_ref { - if let ( - TypeRef::ImplTrait(bounds), - ImplTraitLoweringState::Param(_) - | ImplTraitLoweringState::Variable(_) - | ImplTraitLoweringState::Disallowed, - ) = (type_ref, &self.impl_trait_mode) - { - for bound in bounds { - predicates.extend( - self.lower_type_bound( - bound, - TyKind::Alias(AliasTy::Projection(projection_ty.clone())) - .intern(Interner), - false, - ), - ); + match (type_ref, &self.impl_trait_mode) { + (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (), + ( + _, + ImplTraitLoweringState::Disallowed | ImplTraitLoweringState::Opaque(_), + ) => { + let ty = self.lower_ty(type_ref); + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates + .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); } - } else { - let ty = 'ty: { - if matches!( - self.impl_trait_mode, - ImplTraitLoweringState::Param(_) - | ImplTraitLoweringState::Variable(_) - ) { - // Find the generic index for the target of our `bound` - let target_param_idx = self - .resolver - .where_predicates_in_scope() - .find_map(|p| match p { - WherePredicate::TypeBound { - target: WherePredicateTypeTarget::TypeOrConstParam(idx), - bound: b, - } if b == bound => Some(idx), - _ => None, - }); - if let Some(target_param_idx) = target_param_idx { - let mut counter = 0; - let generics = self.generics().expect("generics in scope"); - for (idx, data) in generics.params.type_or_consts.iter() { - // Count the number of `impl Trait` things that appear before - // the target of our `bound`. - // Our counter within `impl_trait_mode` should be that number - // to properly lower each types within `type_ref` - if data.type_param().is_some_and(|p| { - p.provenance == TypeParamProvenance::ArgumentImplTrait - }) { - counter += 1; - } - if idx == *target_param_idx { - break; - } + ( + _, + ImplTraitLoweringState::Param(_) | ImplTraitLoweringState::Variable(_), + ) => { + // Find the generic index for the target of our `bound` + let target_param_idx = self + .resolver + .where_predicates_in_scope() + .find_map(|(p, _)| match p { + WherePredicate::TypeBound { + target: WherePredicateTypeTarget::TypeOrConstParam(idx), + bound: b, + } if b == bound => Some(idx), + _ => None, + }); + let ty = if let Some(target_param_idx) = target_param_idx { + let mut counter = 0; + let generics = self.generics().expect("generics in scope"); + for (idx, data) in generics.params.type_or_consts.iter() { + // Count the number of `impl Trait` things that appear before + // the target of our `bound`. + // Our counter within `impl_trait_mode` should be that number + // to properly lower each types within `type_ref` + if data.type_param().is_some_and(|p| { + p.provenance == TypeParamProvenance::ArgumentImplTrait + }) { + counter += 1; } - let mut ext = TyLoweringContext::new_maybe_unowned( - self.db, - self.resolver, - self.owner, - ) - .with_type_param_mode(self.type_param_mode); - match &self.impl_trait_mode { - ImplTraitLoweringState::Param(_) => { - ext.impl_trait_mode = - ImplTraitLoweringState::Param(Cell::new(counter)); - } - ImplTraitLoweringState::Variable(_) => { - ext.impl_trait_mode = ImplTraitLoweringState::Variable( - Cell::new(counter), - ); - } - _ => unreachable!(), + if idx == *target_param_idx { + break; } - break 'ty ext.lower_ty(type_ref); } - } - self.lower_ty(type_ref) - }; - let alias_eq = - AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + let mut ext = TyLoweringContext::new_maybe_unowned( + self.db, + self.resolver, + self.owner, + ) + .with_type_param_mode(self.type_param_mode); + match &self.impl_trait_mode { + ImplTraitLoweringState::Param(_) => { + ext.impl_trait_mode = + ImplTraitLoweringState::Param(Cell::new(counter)); + } + ImplTraitLoweringState::Variable(_) => { + ext.impl_trait_mode = + ImplTraitLoweringState::Variable(Cell::new(counter)); + } + _ => unreachable!(), + } + ext.lower_ty(type_ref) + } else { + self.lower_ty(type_ref) + }; + + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates + .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + } } } for bound in binding.bounds.iter() { @@ -1338,11 +1311,10 @@ impl<'a> TyLoweringContext<'a> { bounds, lifetime: match lifetime { Some(it) => match it.bound_var(Interner) { - Some(bound_var) => LifetimeData::BoundVar(BoundVar::new( - DebruijnIndex::INNERMOST, - bound_var.index, - )) - .intern(Interner), + Some(bound_var) => bound_var + .shifted_out_to(DebruijnIndex::new(2)) + .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner)) + .unwrap_or(it), None => it, }, None => static_lifetime(), @@ -1410,16 +1382,6 @@ impl<'a> TyLoweringContext<'a> { } } -fn count_impl_traits(type_ref: &TypeRef) -> usize { - let mut count = 0; - type_ref.walk(&mut |type_ref| { - if matches!(type_ref, TypeRef::ImplTrait(_)) { - count += 1; - } - }); - count -} - /// Build the signature of a callable item (function, struct or enum variant). pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig { match def { @@ -1438,6 +1400,17 @@ pub fn associated_type_shorthand_candidates( named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id)) } +// FIXME: This does not handle macros! +fn count_impl_traits(type_ref: &TypeRef) -> usize { + let mut count = 0; + type_ref.walk(&mut |type_ref| { + if matches!(type_ref, TypeRef::ImplTrait(_)) { + count += 1; + } + }); + count +} + fn named_associated_type_shorthand_candidates( db: &dyn HirDatabase, // If the type parameter is defined in an impl and we're in a method, there @@ -1575,7 +1548,7 @@ pub(crate) fn generic_predicates_for_param_query( let generics = generics(db.upcast(), def); // we have to filter out all other predicates *first*, before attempting to lower them - let predicate = |pred: &&_| match pred { + let predicate = |(pred, &def): &(&_, _)| match pred { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound, .. } => { let invalid_target = match target { @@ -1617,8 +1590,8 @@ pub(crate) fn generic_predicates_for_param_query( let mut predicates: Vec<_> = resolver .where_predicates_in_scope() .filter(predicate) - .flat_map(|pred| { - ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p)) + .flat_map(|(pred, def)| { + ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p)) }) .collect(); @@ -1671,8 +1644,8 @@ pub(crate) fn trait_environment_query( }; let mut traits_in_scope = Vec::new(); let mut clauses = Vec::new(); - for pred in resolver.where_predicates_in_scope() { - for pred in ctx.lower_where_predicate(pred, false) { + for (pred, def) in resolver.where_predicates_in_scope() { + for pred in ctx.lower_where_predicate(pred, def, false) { if let WhereClause::Implemented(tr) = &pred.skip_binders() { traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id())); } @@ -1726,8 +1699,8 @@ pub(crate) fn generic_predicates_query( let mut predicates = resolver .where_predicates_in_scope() - .flat_map(|pred| { - ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p)) + .flat_map(|(pred, def)| { + ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p)) }) .collect::>(); diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index cd72349471..cb56a6f0bf 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -368,7 +368,7 @@ pub(crate) fn incoherent_inherent_impl_crates( krate: CrateId, fp: TyFingerprint, ) -> SmallVec<[CrateId; 2]> { - let _p = tracing::span!(tracing::Level::INFO, "inherent_impl_crates_query").entered(); + let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered(); let mut res = SmallVec::new(); let crate_graph = db.crate_graph(); diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 045ffb418c..2de1aa30c9 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -428,6 +428,17 @@ impl MirEvalError { } Ok(()) } + + pub fn is_panic(&self) -> Option<&str> { + let mut err = self; + while let MirEvalError::InFunction(e, _) = err { + err = e; + } + match err { + MirEvalError::Panic(msg) => Some(msg), + _ => None, + } + } } impl std::fmt::Debug for MirEvalError { @@ -1138,7 +1149,7 @@ impl Evaluator<'_> { let mut ty = self.operand_ty(lhs, locals)?; while let TyKind::Ref(_, _, z) = ty.kind(Interner) { ty = z.clone(); - let size = if ty.kind(Interner) == &TyKind::Str { + let size = if ty.is_str() { if *op != BinOp::Eq { never!("Only eq is builtin for `str`"); } diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index fee3dd3ada..3438712049 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -49,6 +49,7 @@ impl Evaluator<'_> { if self.not_special_fn_cache.borrow().contains(&def) { return Ok(false); } + let function_data = self.db.function_data(def); let is_intrinsic = match &function_data.abi { Some(abi) => *abi == Interned::new_str("rust-intrinsic"), @@ -131,9 +132,7 @@ impl Evaluator<'_> { return Ok(true); } if let Some(it) = self.detect_lang_function(def) { - let arg_bytes = - args.iter().map(|it| Ok(it.get(self)?.to_owned())).collect::>>()?; - let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?; + let result = self.exec_lang_item(it, generic_args, args, locals, span)?; destination.write_from_bytes(self, &result)?; return Ok(true); } @@ -311,16 +310,20 @@ impl Evaluator<'_> { fn detect_lang_function(&self, def: FunctionId) -> Option { use LangItem::*; - let candidate = self.db.lang_attr(def.into())?; + let attrs = self.db.attrs(def.into()); + + if attrs.by_key("rustc_const_panic_str").exists() { + // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE. + return Some(LangItem::BeginPanic); + } + + let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?; // We want to execute these functions with special logic // `PanicFmt` is not detected here as it's redirected later. if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) { return Some(candidate); } - if self.db.attrs(def.into()).by_key("rustc_const_panic_str").exists() { - // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE. - return Some(LangItem::BeginPanic); - } + None } @@ -328,18 +331,52 @@ impl Evaluator<'_> { &mut self, it: LangItem, generic_args: &Substitution, - args: &[Vec], + args: &[IntervalAndTy], locals: &Locals, span: MirSpan, ) -> Result> { use LangItem::*; let mut args = args.iter(); match it { - BeginPanic => Err(MirEvalError::Panic("".to_owned())), + BeginPanic => { + let mut arg = args + .next() + .ok_or(MirEvalError::InternalError( + "argument of BeginPanic is not provided".into(), + ))? + .clone(); + while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) { + if ty.is_str() { + let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size()); + let len = from_bytes!(usize, metadata); + + return { + Err(MirEvalError::Panic( + std::str::from_utf8( + self.read_memory(Address::from_bytes(pointee)?, len)?, + ) + .unwrap() + .to_owned(), + )) + }; + } + let size = self.size_of_sized(ty, locals, "begin panic arg")?; + let pointee = arg.interval.get(self)?; + arg = IntervalAndTy { + interval: Interval::new(Address::from_bytes(pointee)?, size), + ty: ty.clone(), + }; + } + Err(MirEvalError::Panic(format!( + "unknown-panic-payload: {:?}", + arg.ty.kind(Interner) + ))) + } SliceLen => { let arg = args.next().ok_or(MirEvalError::InternalError( "argument of <[T]>::len() is not provided".into(), ))?; + let arg = arg.get(self)?; let ptr_size = arg.len() / 2; Ok(arg[ptr_size..].into()) } @@ -353,6 +390,7 @@ impl Evaluator<'_> { let arg = args.next().ok_or(MirEvalError::InternalError( "argument of drop_in_place is not provided".into(), ))?; + let arg = arg.interval.get(self)?.to_owned(); self.run_drop_glue_deep( ty.clone(), locals, diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index 381522c9ab..4abbda56cb 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -31,6 +31,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr db.trait_environment(func_id.into()), ) .map_err(|e| MirEvalError::MirLowerError(func_id, e))?; + let (result, output) = interpret_mir(db, body, false, None); result?; Ok((output.stdout().into_owned(), output.stderr().into_owned())) @@ -72,6 +73,13 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr } } +fn check_panic(ra_fixture: &str, expected_panic: &str) { + let (db, file_ids) = TestDB::with_many_files(ra_fixture); + let file_id = *file_ids.last().unwrap(); + let e = eval_main(&db, file_id).unwrap_err(); + assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic); +} + #[test] fn function_with_extern_c_abi() { check_pass( @@ -87,6 +95,43 @@ fn main() { ); } +#[test] +fn panic_fmt() { + // panic! + // -> panic_2021 (builtin macro redirection) + // -> #[lang = "panic_fmt"] core::panicking::panic_fmt (hooked by CTFE for redirection) + // -> core::panicking::const_panic_fmt + // -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic) + // -> Err(ConstEvalError::Panic) + check_panic( + r#" +//- minicore: fmt, panic +fn main() { + panic!("hello, world!"); +} + "#, + "hello, world!", + ); +} + +#[test] +fn panic_display() { + // panic! + // -> panic_2021 (builtin macro redirection) + // -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic) + // -> Err(ConstEvalError::Panic) + check_panic( + r#" +//- minicore: fmt, panic + +fn main() { + panic!("{}", "hello, world!"); +} + "#, + "hello, world!", + ); +} + #[test] fn drop_basic() { check_pass( diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index d56b15b9b7..526db2af6d 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -186,7 +186,7 @@ fn test() { let x = match 1 { 1 => t as *mut i32, 2 => t as &i32, - //^^^^^^^^^ expected *mut i32, got &i32 + //^^^^^^^^^ expected *mut i32, got &'? i32 _ => t as *const i32, // ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer) @@ -307,7 +307,7 @@ fn test() { let foo = Foo; //^^^ type: Foo<{unknown}> let _: &u32 = &Foo; - //^^^^ expected &u32, got &Foo<{unknown}> + //^^^^ expected &'? u32, got &'? Foo<{unknown}> }", ); } @@ -544,9 +544,9 @@ struct Bar(Foo); fn test() { let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; - //^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]> + //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]> let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); - //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]> + //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]> } "#, ); @@ -562,7 +562,7 @@ trait Foo {} fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { let _: &dyn Foo = &f; let _: &dyn Foo = g; - //^ expected &dyn Foo, got &impl Foo + ?Sized + //^ expected &'? dyn Foo, got &'? impl Foo + ?Sized } "#, ); @@ -828,11 +828,11 @@ struct V { t: T } fn main() { let a: V<&dyn Tr>; (a,) = V { t: &S }; - //^^^^expected V<&S>, got (V<&dyn Tr>,) + //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,) let mut a: V<&dyn Tr> = V { t: &S }; (a,) = V { t: &S }; - //^^^^expected V<&S>, got (V<&dyn Tr>,) + //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,) } "#, ); diff --git a/crates/hir-ty/src/tests/diagnostics.rs b/crates/hir-ty/src/tests/diagnostics.rs index 119de7f050..def06f2d59 100644 --- a/crates/hir-ty/src/tests/diagnostics.rs +++ b/crates/hir-ty/src/tests/diagnostics.rs @@ -8,7 +8,7 @@ fn function_return_type_mismatch_1() { r#" fn test() -> &'static str { 5 - //^ expected &str, got i32 + //^ expected &'static str, got i32 } "#, ); @@ -21,7 +21,7 @@ fn function_return_type_mismatch_2() { fn test(x: bool) -> &'static str { if x { return 1; - //^ expected &str, got i32 + //^ expected &'static str, got i32 } "ok" } @@ -38,7 +38,7 @@ fn test(x: bool) -> &'static str { return "ok"; } 1 - //^ expected &str, got i32 + //^ expected &'static str, got i32 } "#, ); @@ -53,7 +53,7 @@ fn test(x: bool) -> &'static str { "ok" } else { 1 - //^ expected &str, got i32 + //^ expected &'static str, got i32 } } "#, @@ -67,7 +67,7 @@ fn function_return_type_mismatch_5() { fn test(x: bool) -> &'static str { if x { 1 - //^ expected &str, got i32 + //^ expected &'static str, got i32 } else { "ok" } @@ -83,10 +83,10 @@ fn non_unit_block_expr_stmt_no_semi() { fn test(x: bool) { if x { "notok" - //^^^^^^^ expected (), got &str + //^^^^^^^ expected (), got &'static str } else { "ok" - //^^^^ expected (), got &str + //^^^^ expected (), got &'static str } match x { true => true, false => 0 } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), got bool diff --git a/crates/hir-ty/src/tests/display_source_code.rs b/crates/hir-ty/src/tests/display_source_code.rs index e8369caa77..60c03b5224 100644 --- a/crates/hir-ty/src/tests/display_source_code.rs +++ b/crates/hir-ty/src/tests/display_source_code.rs @@ -67,11 +67,11 @@ trait B: A {} fn test( _: &(dyn A + Send), - //^ &(dyn A + Send) + //^ &'_ (dyn A + Send) _: &(dyn Send + A), - //^ &(dyn A + Send) + //^ &'_ (dyn A + Send) _: &dyn B, - //^ &(dyn B) + //^ &'_ (dyn B) ) {} "#, ); @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &dyn Foo<'_> + // ^^^ &'_ dyn Foo<'_> "#, ); } @@ -111,11 +111,11 @@ fn test( b; //^ impl Foo c; - //^ &impl Foo + ?Sized + //^ &'_ impl Foo + ?Sized d; //^ S ref_any; - //^^^^^^^ &impl ?Sized + //^^^^^^^ &'_ impl ?Sized empty; } //^^^^^ impl Sized "#, @@ -192,7 +192,7 @@ fn test( b; //^ fn(impl Foo) -> impl Foo c; -} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized +} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized "#, ); } diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index 2f75338f99..a0899cb1d6 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -200,8 +200,8 @@ fn expr_macro_def_expanded_in_various_places() { 100..119 'for _ ...!() {}': IntoIterator::IntoIter 100..119 'for _ ...!() {}': ! 100..119 'for _ ...!() {}': IntoIterator::IntoIter - 100..119 'for _ ...!() {}': &mut IntoIterator::IntoIter - 100..119 'for _ ...!() {}': fn next>(&mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> + 100..119 'for _ ...!() {}': &'? mut IntoIterator::IntoIter + 100..119 'for _ ...!() {}': fn next>(&'? mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> 100..119 'for _ ...!() {}': Option> 100..119 'for _ ...!() {}': () 100..119 'for _ ...!() {}': () @@ -221,7 +221,7 @@ fn expr_macro_def_expanded_in_various_places() { 281..303 'Spam {...m!() }': {unknown} 309..325 'spam!(...am!()]': {unknown} 350..366 'spam!(... usize': usize - 372..380 '&spam!()': &isize + 372..380 '&spam!()': &'? isize 386..394 '-spam!()': isize 400..416 'spam!(...pam!()': {unknown} 422..439 'spam!(...pam!()': isize @@ -293,8 +293,8 @@ fn expr_macro_rules_expanded_in_various_places() { 114..133 'for _ ...!() {}': IntoIterator::IntoIter 114..133 'for _ ...!() {}': ! 114..133 'for _ ...!() {}': IntoIterator::IntoIter - 114..133 'for _ ...!() {}': &mut IntoIterator::IntoIter - 114..133 'for _ ...!() {}': fn next>(&mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> + 114..133 'for _ ...!() {}': &'? mut IntoIterator::IntoIter + 114..133 'for _ ...!() {}': fn next>(&'? mut IntoIterator::IntoIter) -> Option< as Iterator>::Item> 114..133 'for _ ...!() {}': Option> 114..133 'for _ ...!() {}': () 114..133 'for _ ...!() {}': () @@ -314,7 +314,7 @@ fn expr_macro_rules_expanded_in_various_places() { 295..317 'Spam {...m!() }': {unknown} 323..339 'spam!(...am!()]': {unknown} 364..380 'spam!(... usize': usize - 386..394 '&spam!()': &isize + 386..394 '&spam!()': &'? isize 400..408 '-spam!()': isize 414..430 'spam!(...pam!()': {unknown} 436..453 'spam!(...pam!()': isize @@ -539,7 +539,7 @@ fn test() { let msg = foo::Message(foo::MessageRef); let r = msg.deref(); r; - //^ &MessageRef + //^ &'? MessageRef } //- /lib.rs crate:foo @@ -703,9 +703,9 @@ fn infer_builtin_macros_file() { } "#, expect![[r#" - !0..2 '""': &str + !0..2 '""': &'static str 63..87 '{ ...!(); }': () - 73..74 'x': &str + 73..74 'x': &'static str "#]], ); } @@ -741,9 +741,9 @@ fn infer_builtin_macros_concat() { } "#, expect![[r#" - !0..13 '"helloworld!"': &str + !0..13 '"helloworld!"': &'static str 65..121 '{ ...")); }': () - 75..76 'x': &str + 75..76 'x': &'static str "#]], ); } @@ -820,7 +820,7 @@ macro_rules! include_str {() => {}} fn main() { let a = include_str!("foo.rs"); a; -} //^ &str +} //^ &'static str //- /foo.rs hello @@ -847,7 +847,7 @@ macro_rules! m { fn main() { let a = include_str!(m!(".rs")); a; -} //^ &str +} //^ &'static str //- /foo.rs hello @@ -960,9 +960,9 @@ fn infer_builtin_macros_concat_with_lazy() { } "#, expect![[r#" - !0..13 '"helloworld!"': &str + !0..13 '"helloworld!"': &'static str 103..160 '{ ...")); }': () - 113..114 'x': &str + 113..114 'x': &'static str "#]], ); } @@ -977,7 +977,7 @@ fn infer_builtin_macros_env() { fn main() { let x = env!("foo"); - //^ &str + //^ &'static str } "#, ); @@ -991,7 +991,7 @@ fn infer_builtin_macros_option_env() { //- /main.rs env:foo=bar fn main() { let x = option_env!("foo"); - //^ Option<&str> + //^ Option<&'static str> } "#, ); diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index 8609ba4103..63a83d403f 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -658,7 +658,7 @@ fn infer_call_trait_method_on_generic_param_1() { } "#, expect![[r#" - 29..33 'self': &Self + 29..33 'self': &'? Self 63..64 't': T 69..88 '{ ...d(); }': () 75..76 't': T @@ -679,7 +679,7 @@ fn infer_call_trait_method_on_generic_param_2() { } "#, expect![[r#" - 32..36 'self': &Self + 32..36 'self': &'? Self 70..71 't': T 76..95 '{ ...d(); }': () 82..83 't': T @@ -757,7 +757,7 @@ struct S; impl Clone for S {} impl Clone for &S {} fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S) + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &'? S) "#, ); } @@ -1150,12 +1150,12 @@ fn dyn_trait_super_trait_not_in_scope() { } "#, expect![[r#" - 51..55 'self': &Self + 51..55 'self': &'? Self 64..69 '{ 0 }': u32 66..67 '0': u32 - 176..177 'd': &dyn Trait + 176..177 'd': &'? dyn Trait 191..207 '{ ...o(); }': () - 197..198 'd': &dyn Trait + 197..198 'd': &'? dyn Trait 197..204 'd.foo()': u32 "#]], ); @@ -1182,15 +1182,15 @@ fn test() { } "#, expect![[r#" - 75..79 'self': &S + 75..79 'self': &'? S 89..109 '{ ... }': bool 99..103 'true': bool 123..167 '{ ...o(); }': () - 133..134 's': &S - 137..151 'unsafe { f() }': &S - 146..147 'f': fn f() -> &S - 146..149 'f()': &S - 157..158 's': &S + 133..134 's': &'? S + 137..151 'unsafe { f() }': &'static S + 146..147 'f': fn f() -> &'static S + 146..149 'f()': &'static S + 157..158 's': &'? S 157..164 's.foo()': bool "#]], ); @@ -1601,11 +1601,11 @@ use core::IntoIterator; fn f() { let v = [4].into_iter(); v; - //^ &i32 + //^ &'? i32 let a = [0, 1].into_iter(); a; - //^ &i32 + //^ &'? i32 } //- /main2021.rs crate:main2021 deps:core edition:2021 @@ -1618,7 +1618,7 @@ fn f() { let a = [0, 1].into_iter(); a; - //^ &i32 + //^ &'? i32 } //- /core.rs crate:core @@ -1767,7 +1767,7 @@ fn test() { let a2 = A(make(), 1i32); let _: &str = a2.thing(); a2; - //^^ A, i32> + //^^ A, i32> } "#, ); diff --git a/crates/hir-ty/src/tests/never_type.rs b/crates/hir-ty/src/tests/never_type.rs index 5d809b8239..0ccbcf63e2 100644 --- a/crates/hir-ty/src/tests/never_type.rs +++ b/crates/hir-ty/src/tests/never_type.rs @@ -104,7 +104,7 @@ enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; - //^ Option<&str> + //^ Option<&'static str> match 42 { 42 => a, _ => Option::Some("str"), @@ -317,8 +317,8 @@ fn diverging_expression_2() { 63..81 '{ loop...foo" }': u32 65..72 'loop {}': ! 70..72 '{}': () - 74..79 '"foo"': &str - 74..79: expected u32, got &str + 74..79 '"foo"': &'static str + 74..79: expected u32, got &'static str "#]], ); } @@ -365,8 +365,8 @@ fn diverging_expression_3_break() { 151..172 'for a ...eak; }': {unknown} 151..172 'for a ...eak; }': ! 151..172 'for a ...eak; }': {unknown} - 151..172 'for a ...eak; }': &mut {unknown} - 151..172 'for a ...eak; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 151..172 'for a ...eak; }': &'? mut {unknown} + 151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 151..172 'for a ...eak; }': Option<{unknown}> 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () @@ -381,8 +381,8 @@ fn diverging_expression_3_break() { 237..250 'for a in b {}': {unknown} 237..250 'for a in b {}': ! 237..250 'for a in b {}': {unknown} - 237..250 'for a in b {}': &mut {unknown} - 237..250 'for a in b {}': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 237..250 'for a in b {}': &'? mut {unknown} + 237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 237..250 'for a in b {}': Option<{unknown}> 237..250 'for a in b {}': () 237..250 'for a in b {}': () @@ -396,8 +396,8 @@ fn diverging_expression_3_break() { 315..337 'for a ...urn; }': {unknown} 315..337 'for a ...urn; }': ! 315..337 'for a ...urn; }': {unknown} - 315..337 'for a ...urn; }': &mut {unknown} - 315..337 'for a ...urn; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 315..337 'for a ...urn; }': &'? mut {unknown} + 315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 315..337 'for a ...urn; }': Option<{unknown}> 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 4355881d72..5e040a60e2 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -32,27 +32,27 @@ fn infer_pattern() { } "#, expect![[r#" - 8..9 'x': &i32 + 8..9 'x': &'? i32 17..400 '{ ...o_x; }': () - 27..28 'y': &i32 - 31..32 'x': &i32 - 42..44 '&z': &i32 + 27..28 'y': &'? i32 + 31..32 'x': &'? i32 + 42..44 '&z': &'? i32 43..44 'z': i32 - 47..48 'x': &i32 + 47..48 'x': &'? i32 58..59 'a': i32 62..63 'z': i32 - 73..79 '(c, d)': (i32, &str) + 73..79 '(c, d)': (i32, &'static str) 74..75 'c': i32 - 77..78 'd': &str - 82..94 '(1, "hello")': (i32, &str) + 77..78 'd': &'static str + 82..94 '(1, "hello")': (i32, &'static str) 83..84 '1': i32 - 86..93 '"hello"': &str + 86..93 '"hello"': &'static str 101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 101..151 'for (e... }': {unknown} 101..151 'for (e... }': ! 101..151 'for (e... }': {unknown} - 101..151 'for (e... }': &mut {unknown} - 101..151 'for (e... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 101..151 'for (e... }': &'? mut {unknown} + 101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 101..151 'for (e... }': Option<({unknown}, {unknown})> 101..151 'for (e... }': () 101..151 'for (e... }': () @@ -74,10 +74,10 @@ fn infer_pattern() { 194..197 'val': {unknown} 210..236 'if let...rue {}': () 213..233 'let x ... &true': bool - 217..225 'x @ true': &bool + 217..225 'x @ true': &'? bool 221..225 'true': bool 221..225 'true': bool - 228..233 '&true': &bool + 228..233 '&true': &'? bool 229..233 'true': bool 234..236 '{}': () 246..252 'lambda': impl Fn(u64, u64, i32) -> i32 @@ -90,14 +90,14 @@ fn infer_pattern() { 277..282 'a + b': u64 281..282 'b': u64 284..285 'c': i32 - 298..310 'ref ref_to_x': &&i32 - 313..314 'x': &i32 - 324..333 'mut mut_x': &i32 - 336..337 'x': &i32 - 347..367 'ref mu...f_to_x': &mut &i32 - 370..371 'x': &i32 - 381..382 'k': &mut &i32 - 385..397 'mut_ref_to_x': &mut &i32 + 298..310 'ref ref_to_x': &'? &'? i32 + 313..314 'x': &'? i32 + 324..333 'mut mut_x': &'? i32 + 336..337 'x': &'? i32 + 347..367 'ref mu...f_to_x': &'? mut &'? i32 + 370..371 'x': &'? i32 + 381..382 'k': &'? mut &'? i32 + 385..397 'mut_ref_to_x': &'? mut &'? i32 "#]], ); } @@ -120,14 +120,14 @@ fn infer_literal_pattern() { 17..28 '{ loop {} }': T 19..26 'loop {}': ! 24..26 '{}': () - 37..38 'x': &i32 + 37..38 'x': &'? i32 46..208 '{ ...) {} }': () 52..75 'if let...y() {}': () 55..72 'let "f... any()': bool - 59..64 '"foo"': &str - 59..64 '"foo"': &str - 67..70 'any': fn any<&str>() -> &str - 67..72 'any()': &str + 59..64 '"foo"': &'static str + 59..64 '"foo"': &'static str + 67..70 'any': fn any<&'static str>() -> &'static str + 67..72 'any()': &'static str 73..75 '{}': () 80..99 'if let...y() {}': () 83..96 'let 1 = any()': bool @@ -178,7 +178,7 @@ fn infer_range_pattern() { } "#, expect![[r#" - 8..9 'x': &i32 + 8..9 'x': &'? i32 17..75 '{ ...2 {} }': () 23..45 'if let...u32 {}': () 26..42 'let 1....= 2u32': bool @@ -208,14 +208,14 @@ fn infer_pattern_match_ergonomics() { expect![[r#" 27..78 '{ ...(1); }': () 37..41 'A(n)': A - 39..40 'n': &i32 - 44..49 '&A(1)': &A + 39..40 'n': &'? i32 + 44..49 '&A(1)': &'? A 45..46 'A': extern "rust-call" A(i32) -> A 45..49 'A(1)': A 47..48 '1': i32 59..63 'A(n)': A - 61..62 'n': &mut i32 - 66..75 '&mut A(1)': &mut A + 61..62 'n': &'? mut i32 + 66..75 '&mut A(1)': &'? mut A 71..72 'A': extern "rust-call" A(i32) -> A 71..75 'A(1)': A 73..74 '1': i32 @@ -235,17 +235,17 @@ fn infer_pattern_match_ergonomics_ref() { "#, expect![[r#" 10..56 '{ ...= v; }': () - 20..21 'v': &(i32, &i32) - 24..32 '&(1, &2)': &(i32, &i32) - 25..32 '(1, &2)': (i32, &i32) + 20..21 'v': &'? (i32, &'? i32) + 24..32 '&(1, &2)': &'? (i32, &'? i32) + 25..32 '(1, &2)': (i32, &'? i32) 26..27 '1': i32 - 29..31 '&2': &i32 + 29..31 '&2': &'? i32 30..31 '2': i32 - 42..49 '(_, &w)': (i32, &i32) + 42..49 '(_, &w)': (i32, &'? i32) 43..44 '_': i32 - 46..48 '&w': &i32 + 46..48 '&w': &'? i32 47..48 'w': i32 - 52..53 'v': &(i32, &i32) + 52..53 'v': &'? (i32, &'? i32) "#]], ); } @@ -286,28 +286,28 @@ fn infer_pattern_match_slice() { "#, expect![[r#" 10..209 '{ ... } }': () - 20..25 'slice': &[f64] - 36..42 '&[0.0]': &[f64; 1] + 20..25 'slice': &'? [f64] + 36..42 '&[0.0]': &'? [f64; 1] 37..42 '[0.0]': [f64; 1] 38..41 '0.0': f64 48..207 'match ... }': () - 54..59 'slice': &[f64] - 70..73 '&[]': &[f64] + 54..59 'slice': &'? [f64] + 70..73 '&[]': &'? [f64] 71..73 '[]': [f64] 77..79 '{}': () - 89..93 '&[a]': &[f64] + 89..93 '&[a]': &'? [f64] 90..93 '[a]': [f64] 91..92 'a': f64 97..123 '{ ... }': () 111..112 'a': f64 - 133..140 '&[b, c]': &[f64] + 133..140 '&[b, c]': &'? [f64] 134..140 '[b, c]': [f64] 135..136 'b': f64 138..139 'c': f64 144..185 '{ ... }': () 158..159 'b': f64 173..174 'c': f64 - 194..195 '_': &[f64] + 194..195 '_': &'? [f64] 199..201 '{}': () "#]], ); @@ -327,14 +327,14 @@ fn infer_pattern_match_string_literal() { "#, expect![[r#" 10..98 '{ ... } }': () - 20..21 's': &str - 30..37 '"hello"': &str + 20..21 's': &'? str + 30..37 '"hello"': &'static str 43..96 'match ... }': () - 49..50 's': &str - 61..68 '"hello"': &str - 61..68 '"hello"': &str + 49..50 's': &'? str + 61..68 '"hello"': &'static str + 61..68 '"hello"': &'static str 72..74 '{}': () - 83..84 '_': &str + 83..84 '_': &'? str 88..90 '{}': () "#]], ); @@ -358,27 +358,27 @@ fn infer_pattern_match_byte_string_literal() { } "#, expect![[r#" - 105..109 'self': &[T; N] + 105..109 'self': &'? [T; N] 111..116 'index': {unknown} - 157..180 '{ ... }': &[u8] + 157..180 '{ ... }': &'? [u8] 167..174 'loop {}': ! 172..174 '{}': () 191..192 'v': [u8; 3] 203..261 '{ ...v {} }': () 209..233 'if let...[S] {}': () 212..230 'let b"... &v[S]': bool - 216..222 'b"foo"': &[u8] - 216..222 'b"foo"': &[u8] - 225..230 '&v[S]': &[u8] + 216..222 'b"foo"': &'static [u8] + 216..222 'b"foo"': &'static [u8] + 225..230 '&v[S]': &'? [u8] 226..227 'v': [u8; 3] 226..230 'v[S]': [u8] 228..229 'S': S 231..233 '{}': () 238..259 'if let... &v {}': () 241..256 'let b"foo" = &v': bool - 245..251 'b"foo"': &[u8; 3] - 245..251 'b"foo"': &[u8; 3] - 254..256 '&v': &[u8; 3] + 245..251 'b"foo"': &'static [u8; 3] + 245..251 'b"foo"': &'static [u8; 3] + 254..256 '&v': &'? [u8; 3] 255..256 'v': [u8; 3] 257..259 '{}': () "#]], @@ -399,17 +399,17 @@ fn infer_pattern_match_or() { "#, expect![[r#" 10..108 '{ ... } }': () - 20..21 's': &str - 30..37 '"hello"': &str + 20..21 's': &'? str + 30..37 '"hello"': &'static str 43..106 'match ... }': () - 49..50 's': &str - 61..68 '"hello"': &str - 61..68 '"hello"': &str - 61..78 '"hello...world"': &str - 71..78 '"world"': &str - 71..78 '"world"': &str + 49..50 's': &'? str + 61..68 '"hello"': &'static str + 61..68 '"hello"': &'static str + 61..78 '"hello...world"': &'? str + 71..78 '"world"': &'static str + 71..78 '"world"': &'static str 82..84 '{}': () - 93..94 '_': &str + 93..94 '_': &'? str 98..100 '{}': () "#]], ); @@ -505,10 +505,10 @@ fn infer_adt_pattern() { 216..217 '1': usize 227..231 'E::B': E 235..237 '10': usize - 255..274 'ref d ...{ .. }': &E + 255..274 'ref d ...{ .. }': &'? E 263..274 'E::A { .. }': E 277..278 'e': E - 284..285 'd': &E + 284..285 'd': &'? E "#]], ); } @@ -529,14 +529,14 @@ impl Foo { expect![[r#" 42..151 '{ ... }': () 56..64 'Self(s,)': Foo - 61..62 's': &usize - 67..75 '&Foo(0,)': &Foo + 61..62 's': &'? usize + 67..75 '&Foo(0,)': &'? Foo 68..71 'Foo': extern "rust-call" Foo(usize) -> Foo 68..75 'Foo(0,)': Foo 72..73 '0': usize 89..97 'Self(s,)': Foo - 94..95 's': &mut usize - 100..112 '&mut Foo(0,)': &mut Foo + 94..95 's': &'? mut usize + 100..112 '&mut Foo(0,)': &'? mut Foo 105..108 'Foo': extern "rust-call" Foo(usize) -> Foo 105..112 'Foo(0,)': Foo 109..110 '0': usize @@ -669,7 +669,7 @@ fn main() { } "#, expect![[r#" - 27..31 'self': &S + 27..31 'self': &'? S 41..50 '{ false }': bool 43..48 'false': bool 64..115 '{ ... } }': () @@ -679,7 +679,7 @@ fn main() { 93..94 's': S 93..100 's.foo()': bool 104..106 '()': () - "#]], + "#]], ) } @@ -702,29 +702,29 @@ fn test() { 51..58 'loop {}': ! 56..58 '{}': () 72..171 '{ ... x); }': () - 78..81 'foo': fn foo<&(i32, &str), i32, impl FnOnce(&(i32, &str)) -> i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> i32) -> i32 + 78..81 'foo': fn foo<&'? (i32, &'? str), i32, impl FnOnce(&'? (i32, &'? str)) -> i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> i32) -> i32 78..105 'foo(&(...y)| x)': i32 - 82..91 '&(1, "a")': &(i32, &str) - 83..91 '(1, "a")': (i32, &str) + 82..91 '&(1, "a")': &'? (i32, &'static str) + 83..91 '(1, "a")': (i32, &'static str) 84..85 '1': i32 - 87..90 '"a"': &str - 93..104 '|&(x, y)| x': impl FnOnce(&(i32, &str)) -> i32 - 94..101 '&(x, y)': &(i32, &str) - 95..101 '(x, y)': (i32, &str) + 87..90 '"a"': &'static str + 93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> i32 + 94..101 '&(x, y)': &'? (i32, &'? str) + 95..101 '(x, y)': (i32, &'? str) 96..97 'x': i32 - 99..100 'y': &str + 99..100 'y': &'? str 103..104 'x': i32 - 142..145 'foo': fn foo<&(i32, &str), &i32, impl FnOnce(&(i32, &str)) -> &i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> &i32) -> &i32 - 142..168 'foo(&(...y)| x)': &i32 - 146..155 '&(1, "a")': &(i32, &str) - 147..155 '(1, "a")': (i32, &str) + 142..145 'foo': fn foo<&'? (i32, &'? str), &'? i32, impl FnOnce(&'? (i32, &'? str)) -> &'? i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> &'? i32) -> &'? i32 + 142..168 'foo(&(...y)| x)': &'? i32 + 146..155 '&(1, "a")': &'? (i32, &'static str) + 147..155 '(1, "a")': (i32, &'static str) 148..149 '1': i32 - 151..154 '"a"': &str - 157..167 '|(x, y)| x': impl FnOnce(&(i32, &str)) -> &i32 - 158..164 '(x, y)': (i32, &str) - 159..160 'x': &i32 - 162..163 'y': &&str - 166..167 'x': &i32 + 151..154 '"a"': &'static str + 157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> &'? i32 + 158..164 '(x, y)': (i32, &'? str) + 159..160 'x': &'? i32 + 162..163 'y': &'? &'? str + 166..167 'x': &'? i32 "#]], ); } @@ -741,13 +741,13 @@ fn slice_tail_pattern() { } "#, expect![[r#" - 7..13 'params': &[i32] + 7..13 'params': &'? [i32] 23..92 '{ ... } }': () 29..90 'match ... }': () - 35..41 'params': &[i32] + 35..41 'params': &'? [i32] 52..69 '[head,... @ ..]': [i32] - 53..57 'head': &i32 - 59..68 'tail @ ..': &[i32] + 53..57 'head': &'? i32 + 59..68 'tail @ ..': &'? [i32] 66..68 '..': [i32] 73..84 '{ }': () "#]], @@ -1109,7 +1109,7 @@ fn var_args() { #[lang = "va_list"] pub struct VaListImpl<'f>; fn my_fn(foo: ...) {} - //^^^ VaListImpl<'{error}> + //^^^ VaListImpl<'?> "#, ); } @@ -1122,9 +1122,9 @@ fn foo() { let &() = &(); let &mut () = &mut (); let &mut () = &(); - //^^^^^^^ expected &(), got &mut () + //^^^^^^^ expected &'? (), got &'? mut () let &() = &mut (); - //^^^ expected &mut (), got &() + //^^^ expected &'? mut (), got &'? () } "#, ); @@ -1148,7 +1148,7 @@ fn main() { }; if let Wrap::::A { cool, ..} = &wrapped {} - //^^^^ &u32 + //^^^^ &'? u32 } "#, ); @@ -1182,7 +1182,7 @@ fn main() { }; if let Wrap::<::Props>::A { cool, ..} = &wrapped {} - //^^^^ &u32 + //^^^^ &'? u32 } "#, ); @@ -1217,7 +1217,7 @@ fn main() { match &6 { Foo::::TEST_I32_REF => (), Foo::::TEST_I32 => (), - //^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32 + //^^^^^^^^^^^^^^^^^^^^ expected &'? i32, got i32 _ => (), } } diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index c2d2047e6f..3aa94be755 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -99,7 +99,7 @@ fn recursive_vars() { 24..31 'unknown': {unknown} 37..44 '[y, &y]': [{unknown}; 2] 38..39 'y': {unknown} - 41..43 '&y': &{unknown} + 41..43 '&y': &'? {unknown} 42..43 'y': {unknown} "#]], ); @@ -117,19 +117,19 @@ fn recursive_vars_2() { "#, expect![[r#" 10..79 '{ ...x)]; }': () - 20..21 'x': &{unknown} - 24..31 'unknown': &{unknown} + 20..21 'x': &'? {unknown} + 24..31 'unknown': &'? {unknown} 41..42 'y': {unknown} 45..52 'unknown': {unknown} - 58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2] - 59..65 '(x, y)': (&{unknown}, {unknown}) - 60..61 'x': &{unknown} + 58..76 '[(x, y..., &x)]': [(&'? {unknown}, {unknown}); 2] + 59..65 '(x, y)': (&'? {unknown}, {unknown}) + 60..61 'x': &'? {unknown} 63..64 'y': {unknown} - 67..75 '(&y, &x)': (&{unknown}, {unknown}) - 68..70 '&y': &{unknown} + 67..75 '(&y, &x)': (&'? {unknown}, {unknown}) + 68..70 '&y': &'? {unknown} 69..70 'y': {unknown} - 72..74 '&x': &&{unknown} - 73..74 'x': &{unknown} + 72..74 '&x': &'? &'? {unknown} + 73..74 'x': &'? {unknown} "#]], ); } @@ -166,7 +166,7 @@ fn infer_std_crash_1() { 59..136 'match ... }': () 65..82 'someth...nknown': Maybe<{unknown}> 93..123 'Maybe:...thing)': Maybe<{unknown}> - 105..122 'ref mu...ething': &mut {unknown} + 105..122 'ref mu...ething': &'? mut {unknown} 127..129 '()': () "#]], ); @@ -183,7 +183,7 @@ fn infer_std_crash_2() { "#, expect![[r#" 22..52 '{ ...n']; }': () - 28..49 '&[0, b...b'\n']': &[u8; 4] + 28..49 '&[0, b...b'\n']': &'? [u8; 4] 29..49 '[0, b'...b'\n']': [u8; 4] 30..31 '0': u8 33..38 'b'\n'': u8 @@ -269,8 +269,8 @@ fn infer_std_crash_5() { 32..320 'for co... }': {unknown} 32..320 'for co... }': ! 32..320 'for co... }': {unknown} - 32..320 'for co... }': &mut {unknown} - 32..320 'for co... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> + 32..320 'for co... }': &'? mut {unknown} + 32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 32..320 'for co... }': Option<{unknown}> 32..320 'for co... }': () 32..320 'for co... }': () @@ -278,22 +278,22 @@ fn infer_std_crash_5() { 36..43 'content': {unknown} 47..60 'doesnt_matter': {unknown} 61..320 '{ ... }': () - 75..79 'name': &{unknown} - 82..166 'if doe... }': &{unknown} + 75..79 'name': &'? {unknown} + 82..166 'if doe... }': &'? {unknown} 85..98 'doesnt_matter': bool - 99..128 '{ ... }': &{unknown} - 113..118 'first': &{unknown} - 134..166 '{ ... }': &{unknown} - 148..156 '&content': &{unknown} + 99..128 '{ ... }': &'? {unknown} + 113..118 'first': &'? {unknown} + 134..166 '{ ... }': &'? {unknown} + 148..156 '&content': &'? {unknown} 149..156 'content': {unknown} - 181..188 'content': &{unknown} - 191..313 'if ICE... }': &{unknown} + 181..188 'content': &'? {unknown} + 191..313 'if ICE... }': &'? {unknown} 194..231 'ICE_RE..._VALUE': {unknown} 194..247 'ICE_RE...&name)': bool - 241..246 '&name': &&{unknown} - 242..246 'name': &{unknown} - 248..276 '{ ... }': &{unknown} - 262..266 'name': &{unknown} + 241..246 '&name': &'? &'? {unknown} + 242..246 'name': &'? {unknown} + 248..276 '{ ... }': &'? {unknown} + 262..266 'name': &'? {unknown} 282..313 '{ ... }': {unknown} 296..303 'content': {unknown} "#]], @@ -318,7 +318,7 @@ fn infer_nested_generics_crash() { expect![[r#" 91..105 'query_response': Canonical> 136..166 '{ ...lue; }': () - 142..163 '&query....value': &QueryResponse + 142..163 '&query....value': &'? QueryResponse 143..157 'query_response': Canonical> 143..163 'query_....value': QueryResponse "#]], @@ -465,12 +465,12 @@ fn issue_3999_slice() { } "#, expect![[r#" - 7..13 'params': &[usize] + 7..13 'params': &'? [usize] 25..80 '{ ... } }': () 31..78 'match ... }': () - 37..43 'params': &[usize] + 37..43 'params': &'? [usize] 54..66 '[ps @ .., _]': [usize] - 55..62 'ps @ ..': &[usize] + 55..62 'ps @ ..': &'? [usize] 60..62 '..': [usize] 64..65 '_': usize 70..72 '{}': () @@ -523,13 +523,13 @@ fn issue_4235_name_conflicts() { "#, expect![[r#" 31..37 'FOO {}': FOO - 63..67 'self': &FOO + 63..67 'self': &'? FOO 69..71 '{}': () 85..119 '{ ...o(); }': () - 95..96 'a': &FOO - 99..103 '&FOO': &FOO + 95..96 'a': &'? FOO + 99..103 '&FOO': &'? FOO 100..103 'FOO': FOO - 109..110 'a': &FOO + 109..110 'a': &'? FOO 109..116 'a.foo()': () "#]], ); @@ -715,12 +715,12 @@ fn issue_4885() { } "#, expect![[r#" - 70..73 'key': &K + 70..73 'key': &'? K 132..148 '{ ...key) }': impl Future>::Bar> - 138..141 'bar': fn bar(&K) -> impl Future>::Bar> + 138..141 'bar': fn bar(&'? K) -> impl Future>::Bar> 138..146 'bar(key)': impl Future>::Bar> - 142..145 'key': &K - 162..165 'key': &K + 142..145 'key': &'? K + 162..165 'key': &'? K 224..227 '{ }': () "#]], ); @@ -771,11 +771,11 @@ fn issue_4800() { } "#, expect![[r#" - 379..383 'self': &mut PeerSet + 379..383 'self': &'? mut PeerSet 401..424 '{ ... }': dyn Future 411..418 'loop {}': ! 416..418 '{}': () - 575..579 'self': &mut Self + 575..579 'self': &'? mut Self "#]], ); } @@ -815,19 +815,19 @@ fn issue_4966() { 225..229 'iter': T 244..246 '{}': Vec 258..402 '{ ...r(); }': () - 268..273 'inner': Map f64> - 276..300 'Map { ... 0.0 }': Map f64> - 285..298 '|_: &f64| 0.0': impl Fn(&f64) -> f64 - 286..287 '_': &f64 + 268..273 'inner': Map f64> + 276..300 'Map { ... 0.0 }': Map f64> + 285..298 '|_: &f64| 0.0': impl Fn(&'? f64) -> f64 + 286..287 '_': &'? f64 295..298 '0.0': f64 - 311..317 'repeat': Repeat f64>> - 320..345 'Repeat...nner }': Repeat f64>> - 338..343 'inner': Map f64> - 356..359 'vec': Vec f64>>>> - 362..371 'from_iter': fn from_iter f64>>>, Repeat f64>>>(Repeat f64>>) -> Vec f64>>>> - 362..379 'from_i...epeat)': Vec f64>>>> - 372..378 'repeat': Repeat f64>> - 386..389 'vec': Vec f64>>>> + 311..317 'repeat': Repeat f64>> + 320..345 'Repeat...nner }': Repeat f64>> + 338..343 'inner': Map f64> + 356..359 'vec': Vec f64>>>> + 362..371 'from_iter': fn from_iter f64>>>, Repeat f64>>>(Repeat f64>>) -> Vec f64>>>> + 362..379 'from_i...epeat)': Vec f64>>>> + 372..378 'repeat': Repeat f64>> + 386..389 'vec': Vec f64>>>> 386..399 'vec.foo_bar()': {unknown} "#]], ); @@ -850,10 +850,10 @@ fn main() { } "#, expect![[r#" - 40..44 'self': &S + 40..44 'self': &'? S 46..48 '_t': T 53..55 '{}': () - 81..85 'self': &S + 81..85 'self': &'? S 87..89 '_f': F 94..96 '{}': () 109..160 '{ ...10); }': () @@ -862,8 +862,8 @@ fn main() { 123..126 'S()': S 132..133 's': S 132..144 's.g(|_x| {})': () - 136..143 '|_x| {}': impl FnOnce(&i32) - 137..139 '_x': &i32 + 136..143 '|_x| {}': impl FnOnce(&'? i32) + 137..139 '_x': &'? i32 141..143 '{}': () 150..151 's': S 150..157 's.f(10)': () @@ -895,14 +895,14 @@ fn flush(&self) { } "#, expect![[r#" - 123..127 'self': &Mutex - 150..152 '{}': MutexGuard<'{error}, T> - 234..238 'self': &{unknown} + 123..127 'self': &'? Mutex + 150..152 '{}': MutexGuard<'?, T> + 234..238 'self': &'? {unknown} 240..290 '{ ...()); }': () - 250..251 'w': &Mutex + 250..251 'w': &'? Mutex 276..287 '*(w.lock())': BufWriter - 278..279 'w': &Mutex - 278..286 'w.lock()': MutexGuard<'{error}, BufWriter> + 278..279 'w': &'? Mutex + 278..286 'w.lock()': MutexGuard<'?, BufWriter> "#]], ); } @@ -1023,20 +1023,20 @@ fn cfg_tail() { expect![[r#" 14..53 '{ ...)] 9 }': () 20..31 '{ "first" }': () - 22..29 '"first"': &str + 22..29 '"first"': &'static str 72..190 '{ ...] 13 }': () 78..88 '{ "fake" }': () - 80..86 '"fake"': &str + 80..86 '"fake"': &'static str 93..103 '{ "fake" }': () - 95..101 '"fake"': &str + 95..101 '"fake"': &'static str 108..120 '{ "second" }': () - 110..118 '"second"': &str + 110..118 '"second"': &'static str 210..273 '{ ... 15; }': () 216..227 '{ "third" }': () - 218..225 '"third"': &str + 218..225 '"third"': &'static str 293..357 '{ ...] 15 }': () - 299..311 '{ "fourth" }': &str - 301..309 '"fourth"': &str + 299..311 '{ "fourth" }': &'static str + 301..309 '"fourth"': &'static str "#]], ) } @@ -1238,8 +1238,8 @@ fn test() { 16..66 'for _ ... }': IntoIterator::IntoIter<()> 16..66 'for _ ... }': ! 16..66 'for _ ... }': IntoIterator::IntoIter<()> - 16..66 'for _ ... }': &mut IntoIterator::IntoIter<()> - 16..66 'for _ ... }': fn next>(&mut IntoIterator::IntoIter<()>) -> Option< as Iterator>::Item> + 16..66 'for _ ... }': &'? mut IntoIterator::IntoIter<()> + 16..66 'for _ ... }': fn next>(&'? mut IntoIterator::IntoIter<()>) -> Option< as Iterator>::Item> 16..66 'for _ ... }': Option> 16..66 'for _ ... }': () 16..66 'for _ ... }': () @@ -1599,85 +1599,6 @@ fn f(s: S) { ); } -#[test] -fn rust_161_option_clone() { - check_types( - r#" -//- minicore: option, drop - -fn test(o: &Option) { - o.my_clone(); - //^^^^^^^^^^^^ Option -} - -pub trait MyClone: Sized { - fn my_clone(&self) -> Self; -} - -impl const MyClone for Option -where - T: ~const MyClone + ~const Drop + ~const Destruct, -{ - fn my_clone(&self) -> Self { - match self { - Some(x) => Some(x.my_clone()), - None => None, - } - } -} - -impl const MyClone for i32 { - fn my_clone(&self) -> Self { - *self - } -} - -pub trait Destruct {} - -impl const Destruct for T {} -"#, - ); -} - -#[test] -fn rust_162_option_clone() { - check_types( - r#" -//- minicore: option, drop - -fn test(o: &Option) { - o.my_clone(); - //^^^^^^^^^^^^ Option -} - -pub trait MyClone: Sized { - fn my_clone(&self) -> Self; -} - -impl const MyClone for Option -where - T: ~const MyClone + ~const Destruct, -{ - fn my_clone(&self) -> Self { - match self { - Some(x) => Some(x.my_clone()), - None => None, - } - } -} - -impl const MyClone for i32 { - fn my_clone(&self) -> Self { - *self - } -} - -#[lang = "destruct"] -pub trait Destruct {} -"#, - ); -} - #[test] fn tuple_struct_pattern_with_unmatched_args_crash() { check_infer( @@ -1727,7 +1648,7 @@ fn dyn_with_unresolved_trait() { r#" fn foo(a: &dyn DoesNotExist) { a.bar(); - //^&{unknown} + //^&'? {unknown} } "#, ); @@ -1851,9 +1772,9 @@ fn foo() { match &E::A { b @ (x @ E::A | x) => { b; - //^ &E + //^ &'? E x; - //^ &E + //^ &'? E } } }", @@ -2040,3 +1961,41 @@ fn main() { "#, ) } + +#[test] +fn cfg_first_trait_param_16141() { + check_no_mismatches( + r#" +//- minicore: sized, coerce_unsized +trait Bar { + fn bar(&self) {} +} + +impl<#[cfg(feature = "a-feature")] A> Bar for (){} +"#, + ) +} + +#[test] +fn nested_anon_generics_and_where_bounds_17173() { + check_types( + r#" +//- minicore: sized, fn +pub trait Lookup { + type Data; + fn lookup(&self) -> Self::Data; +} +pub trait ItemTreeLoc { + type Id; +} +fn id_to_generics(id: impl Lookup>, + //^^ impl Lookup> + enabled_params: impl Fn(), + //^^^^^^^^^^^^^^ impl Fn() + ) +where + (): Sized, +{} +"#, + ); +} diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index a9d28ebfef..e2cd7fa26b 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -115,15 +115,15 @@ fn test(a: u32, b: isize, c: !, d: &str) { 8..9 'a': u32 16..17 'b': isize 26..27 'c': ! - 32..33 'd': &str + 32..33 'd': &'? str 41..120 '{ ...f32; }': () 47..48 'a': u32 54..55 'b': isize 61..62 'c': ! - 68..69 'd': &str + 68..69 'd': &'? str 75..81 '1usize': usize 87..93 '1isize': isize - 99..105 '"test"': &str + 99..105 '"test"': &'static str 111..117 '1.0f32': f32 "#]], ); @@ -344,23 +344,23 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { } "#, expect![[r#" - 8..9 'a': &u32 - 17..18 'b': &mut u32 + 8..9 'a': &'? u32 + 17..18 'b': &'? mut u32 30..31 'c': *const u32 45..46 'd': *mut u32 58..149 '{ ... *d; }': () - 64..65 'a': &u32 + 64..65 'a': &'? u32 71..73 '*a': u32 - 72..73 'a': &u32 - 79..81 '&a': &&u32 - 80..81 'a': &u32 - 87..93 '&mut a': &mut &u32 - 92..93 'a': &u32 - 99..100 'b': &mut u32 + 72..73 'a': &'? u32 + 79..81 '&a': &'? &'? u32 + 80..81 'a': &'? u32 + 87..93 '&mut a': &'? mut &'? u32 + 92..93 'a': &'? u32 + 99..100 'b': &'? mut u32 106..108 '*b': u32 - 107..108 'b': &mut u32 - 114..116 '&b': &&mut u32 - 115..116 'b': &mut u32 + 107..108 'b': &'? mut u32 + 114..116 '&b': &'? &'? mut u32 + 115..116 'b': &'? mut u32 122..123 'c': *const u32 129..131 '*c': u32 130..131 'c': *const u32 @@ -425,22 +425,22 @@ h"; 32..36 '5i32': i32 50..54 '5f32': f32 68..72 '5f64': f64 - 86..93 '"hello"': &str - 107..115 'b"bytes"': &[u8; 5] + 86..93 '"hello"': &'static str + 107..115 'b"bytes"': &'static [u8; 5] 129..132 ''c'': char 146..150 'b'b'': u8 164..168 '3.14': f64 182..186 '5000': i32 200..205 'false': bool 219..223 'true': bool - 237..333 'r#" ... "#': &str - 347..357 'br#"yolo"#': &[u8; 4] - 375..376 'a': &[u8; 4] - 379..403 'b"a\x2... c"': &[u8; 4] - 421..422 'b': &[u8; 4] - 425..433 'br"g\ h"': &[u8; 4] - 451..452 'c': &[u8; 6] - 455..467 'br#"x"\"yb"#': &[u8; 6] + 237..333 'r#" ... "#': &'static str + 347..357 'br#"yolo"#': &'static [u8; 4] + 375..376 'a': &'static [u8; 4] + 379..403 'b"a\x2... c"': &'static [u8; 4] + 421..422 'b': &'static [u8; 4] + 425..433 'br"g\ h"': &'static [u8; 4] + 451..452 'c': &'static [u8; 6] + 455..467 'br#"x"\"yb"#': &'static [u8; 6] "##]], ); } @@ -508,9 +508,9 @@ fn test(x: SomeType) { 238..240 '!x': {unknown} 239..240 'x': SomeType 246..254 '-"hello"': {unknown} - 247..254 '"hello"': &str + 247..254 '"hello"': &'static str 260..268 '!"hello"': {unknown} - 261..268 '"hello"': &str + 261..268 '"hello"': &'static str "#]], ); } @@ -535,7 +535,7 @@ fn test() -> &mut &f64 { expect![[r#" 13..14 'x': u32 21..23 '{}': () - 77..230 '{ ...t &c }': &mut &f64 + 77..230 '{ ...t &c }': &'? mut &'? f64 87..88 'a': u32 91..107 'unknow...nction': {unknown} 91..109 'unknow...tion()': u32 @@ -550,8 +550,8 @@ fn test() -> &mut &f64 { 193..194 'c': f64 197..213 'unknow...nction': {unknown} 197..215 'unknow...tion()': f64 - 221..228 '&mut &c': &mut &f64 - 226..228 '&c': &f64 + 221..228 '&mut &c': &'? mut &'? f64 + 226..228 '&c': &'? f64 227..228 'c': f64 "#]], ); @@ -579,12 +579,12 @@ impl S { } "#, expect![[r#" - 33..37 'self': &S + 33..37 'self': &'? S 39..60 '{ ... }': () - 49..53 'self': &S - 74..78 'self': &S + 49..53 'self': &'? S + 74..78 'self': &'? S 87..108 '{ ... }': () - 97..101 'self': &S + 97..101 'self': &'? S 132..152 '{ ... }': S 142..146 'S {}': S 176..199 '{ ... }': S @@ -771,35 +771,35 @@ fn test2(a1: *const A, a2: *mut A) { 64..65 'a': A 71..73 'a1': A 71..75 'a1.b': B - 85..87 'a2': &A - 90..92 '&a': &A + 85..87 'a2': &'? A + 90..92 '&a': &'? A 91..92 'a': A - 98..100 'a2': &A + 98..100 'a2': &'? A 98..102 'a2.b': B - 112..114 'a3': &mut A - 117..123 '&mut a': &mut A + 112..114 'a3': &'? mut A + 117..123 '&mut a': &'? mut A 122..123 'a': A - 129..131 'a3': &mut A + 129..131 'a3': &'? mut A 129..133 'a3.b': B - 143..145 'a4': &&&&&&&A - 148..156 '&&&&&&&a': &&&&&&&A - 149..156 '&&&&&&a': &&&&&&A - 150..156 '&&&&&a': &&&&&A - 151..156 '&&&&a': &&&&A - 152..156 '&&&a': &&&A - 153..156 '&&a': &&A - 154..156 '&a': &A + 143..145 'a4': &'? &'? &'? &'? &'? &'? &'? A + 148..156 '&&&&&&&a': &'? &'? &'? &'? &'? &'? &'? A + 149..156 '&&&&&&a': &'? &'? &'? &'? &'? &'? A + 150..156 '&&&&&a': &'? &'? &'? &'? &'? A + 151..156 '&&&&a': &'? &'? &'? &'? A + 152..156 '&&&a': &'? &'? &'? A + 153..156 '&&a': &'? &'? A + 154..156 '&a': &'? A 155..156 'a': A - 162..164 'a4': &&&&&&&A + 162..164 'a4': &'? &'? &'? &'? &'? &'? &'? A 162..166 'a4.b': B - 176..178 'a5': &mut &&mut &&mut A - 181..199 '&mut &...&mut a': &mut &&mut &&mut A - 186..199 '&&mut &&mut a': &&mut &&mut A - 187..199 '&mut &&mut a': &mut &&mut A - 192..199 '&&mut a': &&mut A - 193..199 '&mut a': &mut A + 176..178 'a5': &'? mut &'? &'? mut &'? &'? mut A + 181..199 '&mut &...&mut a': &'? mut &'? &'? mut &'? &'? mut A + 186..199 '&&mut &&mut a': &'? &'? mut &'? &'? mut A + 187..199 '&mut &&mut a': &'? mut &'? &'? mut A + 192..199 '&&mut a': &'? &'? mut A + 193..199 '&mut a': &'? mut A 198..199 'a': A - 205..207 'a5': &mut &&mut &&mut A + 205..207 'a5': &'? mut &'? &'? mut &'? &'? mut A 205..209 'a5.b': B 223..225 'a1': *const A 237..239 'a2': *mut A @@ -840,22 +840,22 @@ fn test() { } "#, expect![[r#" - 66..70 'self': &A - 78..101 '{ ... }': &T - 88..95 '&self.0': &T - 89..93 'self': &A + 66..70 'self': &'? A + 78..101 '{ ... }': &'? T + 88..95 '&self.0': &'? T + 89..93 'self': &'? A 89..95 'self.0': T - 182..186 'self': &B - 205..228 '{ ... }': &T - 215..222 '&self.0': &T - 216..220 'self': &B + 182..186 'self': &'? B + 205..228 '{ ... }': &'? T + 215..222 '&self.0': &'? T + 216..220 'self': &'? B 216..222 'self.0': T 242..280 '{ ...))); }': () - 252..253 't': &i32 - 256..262 'A::foo': fn foo(&A) -> &i32 - 256..277 'A::foo...42))))': &i32 - 263..276 '&&B(B(A(42)))': &&B>> - 264..276 '&B(B(A(42)))': &B>> + 252..253 't': &'? i32 + 256..262 'A::foo': fn foo(&'? A) -> &'? i32 + 256..277 'A::foo...42))))': &'? i32 + 263..276 '&&B(B(A(42)))': &'? &'? B>> + 264..276 '&B(B(A(42)))': &'? B>> 265..266 'B': extern "rust-call" B>>(B>) -> B>> 265..276 'B(B(A(42)))': B>> 267..268 'B': extern "rust-call" B>(A) -> B> @@ -895,28 +895,28 @@ fn test(a: A) { } "#, expect![[r#" - 71..75 'self': &A - 77..78 'x': &A - 93..114 '{ ... }': &T - 103..108 '&*x.0': &T + 71..75 'self': &'? A + 77..78 'x': &'? A + 93..114 '{ ... }': &'? T + 103..108 '&*x.0': &'? T 104..108 '*x.0': T - 105..106 'x': &A + 105..106 'x': &'? A 105..108 'x.0': *mut T - 195..199 'self': &B - 218..241 '{ ... }': &T - 228..235 '&self.0': &T - 229..233 'self': &B + 195..199 'self': &'? B + 218..241 '{ ... }': &'? T + 228..235 '&self.0': &'? T + 229..233 'self': &'? B 229..235 'self.0': T 253..254 'a': A 264..310 '{ ...))); }': () - 274..275 't': &i32 + 274..275 't': &'? i32 278..279 'A': extern "rust-call" A(*mut i32) -> A 278..292 'A(0 as *mut _)': A - 278..307 'A(0 as...B(a)))': &i32 + 278..307 'A(0 as...B(a)))': &'? i32 280..281 '0': i32 280..291 '0 as *mut _': *mut i32 - 297..306 '&&B(B(a))': &&B>> - 298..306 '&B(B(a))': &B>> + 297..306 '&&B(B(a))': &'? &'? B>> + 298..306 '&B(B(a))': &'? B>> 299..300 'B': extern "rust-call" B>>(B>) -> B>> 299..306 'B(B(a))': B>> 301..302 'B': extern "rust-call" B>(A) -> B> @@ -1044,7 +1044,7 @@ fn infer_inherent_method() { 31..35 'self': A 37..38 'x': u32 52..54 '{}': i32 - 106..110 'self': &A + 106..110 'self': &'? A 112..113 'x': u64 127..129 '{}': i64 147..148 'a': A @@ -1053,7 +1053,7 @@ fn infer_inherent_method() { 159..167 'a.foo(1)': i32 165..166 '1': u32 173..184 '(&a).bar(1)': i64 - 174..176 '&a': &A + 174..176 '&a': &'? A 175..176 'a': A 182..183 '1': u64 190..191 'a': A @@ -1078,10 +1078,10 @@ fn test() { } "#, expect![[r#" - 67..71 'self': &str + 67..71 'self': &'? str 80..82 '{}': i32 96..116 '{ ...o(); }': () - 102..107 '"foo"': &str + 102..107 '"foo"': &'static str 102..113 '"foo".foo()': i32 "#]], ); @@ -1101,33 +1101,33 @@ fn infer_tuple() { } "#, expect![[r#" - 8..9 'x': &str + 8..9 'x': &'? str 17..18 'y': isize 27..169 '{ ...d"); }': () - 37..38 'a': (u32, &str) - 54..62 '(1, "a")': (u32, &str) + 37..38 'a': (u32, &'? str) + 54..62 '(1, "a")': (u32, &'? str) 55..56 '1': u32 - 58..61 '"a"': &str - 72..73 'b': ((u32, &str), &str) - 76..82 '(a, x)': ((u32, &str), &str) - 77..78 'a': (u32, &str) - 80..81 'x': &str - 92..93 'c': (isize, &str) - 96..102 '(y, x)': (isize, &str) + 58..61 '"a"': &'static str + 72..73 'b': ((u32, &'? str), &'? str) + 76..82 '(a, x)': ((u32, &'? str), &'? str) + 77..78 'a': (u32, &'? str) + 80..81 'x': &'? str + 92..93 'c': (isize, &'? str) + 96..102 '(y, x)': (isize, &'? str) 97..98 'y': isize - 100..101 'x': &str - 112..113 'd': ((isize, &str), &str) - 116..122 '(c, x)': ((isize, &str), &str) - 117..118 'c': (isize, &str) - 120..121 'x': &str - 132..133 'e': (i32, &str) - 136..144 '(1, "e")': (i32, &str) + 100..101 'x': &'? str + 112..113 'd': ((isize, &'? str), &'? str) + 116..122 '(c, x)': ((isize, &'? str), &'? str) + 117..118 'c': (isize, &'? str) + 120..121 'x': &'? str + 132..133 'e': (i32, &'static str) + 136..144 '(1, "e")': (i32, &'static str) 137..138 '1': i32 - 140..143 '"e"': &str - 154..155 'f': ((i32, &str), &str) - 158..166 '(e, "d")': ((i32, &str), &str) - 159..160 'e': (i32, &str) - 162..165 '"d"': &str + 140..143 '"e"': &'static str + 154..155 'f': ((i32, &'static str), &'static str) + 158..166 '(e, "d")': ((i32, &'static str), &'static str) + 159..160 'e': (i32, &'static str) + 162..165 '"d"': &'static str "#]], ); } @@ -1156,20 +1156,20 @@ fn infer_array() { } "#, expect![[r#" - 8..9 'x': &str + 8..9 'x': &'? str 17..18 'y': isize 27..326 '{ ...,4]; }': () - 37..38 'a': [&str; 1] - 41..44 '[x]': [&str; 1] - 42..43 'x': &str - 54..55 'b': [[&str; 1]; 2] - 58..64 '[a, a]': [[&str; 1]; 2] - 59..60 'a': [&str; 1] - 62..63 'a': [&str; 1] - 74..75 'c': [[[&str; 1]; 2]; 2] - 78..84 '[b, b]': [[[&str; 1]; 2]; 2] - 79..80 'b': [[&str; 1]; 2] - 82..83 'b': [[&str; 1]; 2] + 37..38 'a': [&'? str; 1] + 41..44 '[x]': [&'? str; 1] + 42..43 'x': &'? str + 54..55 'b': [[&'? str; 1]; 2] + 58..64 '[a, a]': [[&'? str; 1]; 2] + 59..60 'a': [&'? str; 1] + 62..63 'a': [&'? str; 1] + 74..75 'c': [[[&'? str; 1]; 2]; 2] + 78..84 '[b, b]': [[[&'? str; 1]; 2]; 2] + 79..80 'b': [[&'? str; 1]; 2] + 82..83 'b': [[&'? str; 1]; 2] 95..96 'd': [isize; 4] 99..111 '[y, 1, 2, 3]': [isize; 4] 100..101 'y': isize @@ -1197,15 +1197,15 @@ fn infer_array() { 209..215 '[1, 2]': [i32; 2] 210..211 '1': i32 213..214 '2': i32 - 225..226 'i': [&str; 2] - 229..239 '["a", "b"]': [&str; 2] - 230..233 '"a"': &str - 235..238 '"b"': &str - 250..251 'b': [[&str; 1]; 2] - 254..264 '[a, ["b"]]': [[&str; 1]; 2] - 255..256 'a': [&str; 1] - 258..263 '["b"]': [&str; 1] - 259..262 '"b"': &str + 225..226 'i': [&'? str; 2] + 229..239 '["a", "b"]': [&'? str; 2] + 230..233 '"a"': &'static str + 235..238 '"b"': &'static str + 250..251 'b': [[&'? str; 1]; 2] + 254..264 '[a, ["b"]]': [[&'? str; 1]; 2] + 255..256 'a': [&'? str; 1] + 258..263 '["b"]': [&'? str; 1] + 259..262 '"b"': &'static str 274..275 'x': [u8; 0] 287..289 '[]': [u8; 0] 299..300 'y': [u8; 4] @@ -1279,12 +1279,12 @@ fn infer_tuple_struct_generics() { 92..93 'A': extern "rust-call" A(u128) -> A 92..101 'A(42u128)': A 94..100 '42u128': u128 - 107..111 'Some': extern "rust-call" Some<&str>(&str) -> Option<&str> - 107..116 'Some("x")': Option<&str> - 112..115 '"x"': &str - 122..134 'Option::Some': extern "rust-call" Some<&str>(&str) -> Option<&str> - 122..139 'Option...e("x")': Option<&str> - 135..138 '"x"': &str + 107..111 'Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str> + 107..116 'Some("x")': Option<&'static str> + 112..115 '"x"': &'static str + 122..134 'Option::Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str> + 122..139 'Option...e("x")': Option<&'static str> + 135..138 '"x"': &'static str 145..149 'None': Option<{unknown}> 159..160 'x': Option 176..180 'None': Option @@ -1405,15 +1405,15 @@ fn infer_impl_generics_with_autoderef() { } "#, expect![[r#" - 77..81 'self': &Option - 97..99 '{}': Option<&T> + 77..81 'self': &'? Option + 97..99 '{}': Option<&'? T> 110..111 'o': Option 126..164 '{ ...f(); }': () - 132..145 '(&o).as_ref()': Option<&u32> - 133..135 '&o': &Option + 132..145 '(&o).as_ref()': Option<&'? u32> + 133..135 '&o': &'? Option 134..135 'o': Option 151..152 'o': Option - 151..161 'o.as_ref()': Option<&u32> + 151..161 'o.as_ref()': Option<&'? u32> "#]], ); } @@ -1551,16 +1551,16 @@ fn infer_type_alias() { "#, expect![[r#" 115..116 'x': A - 123..124 'y': A<&str, u128> + 123..124 'y': A<&'? str, u128> 137..138 'z': A 153..210 '{ ...z.y; }': () 159..160 'x': A 159..162 'x.x': u32 168..169 'x': A 168..171 'x.y': i128 - 177..178 'y': A<&str, u128> - 177..180 'y.x': &str - 186..187 'y': A<&str, u128> + 177..178 'y': A<&'? str, u128> + 177..180 'y.x': &'? str + 186..187 'y': A<&'? str, u128> 186..189 'y.y': u128 195..196 'z': A 195..198 'z.x': u8 @@ -1572,8 +1572,8 @@ fn infer_type_alias() { 312..328 'm::Ali...Foo(0)': Enum 326..327 '0': u8 338..354 'm::Ali...Foo(x)': Enum - 352..353 'x': &u8 - 357..359 '&e': &Enum + 352..353 'x': &'? u8 + 357..359 '&e': &'? Enum 358..359 'e': Enum "#]], ) @@ -1618,10 +1618,10 @@ fn infer_type_param() { 9..10 'x': T 20..29 '{ x }': T 26..27 'x': T - 43..44 'x': &T + 43..44 'x': &'? T 55..65 '{ *x }': T 61..63 '*x': T - 62..63 'x': &T + 62..63 'x': &'? T 77..157 '{ ...(1); }': () 87..88 'y': u32 91..96 '10u32': u32 @@ -1629,9 +1629,9 @@ fn infer_type_param() { 102..107 'id(y)': u32 105..106 'y': u32 117..118 'x': bool - 127..132 'clone': fn clone(&bool) -> bool + 127..132 'clone': fn clone(&'? bool) -> bool 127..135 'clone(z)': bool - 133..134 'z': &bool + 133..134 'z': &'? bool 141..151 'id::': fn id(i128) -> i128 141..154 'id::(1)': i128 152..153 '1': i128 @@ -1842,7 +1842,7 @@ fn foo() -> &'static str { "" } fn main() { foo(); - //^^^^^ &str + //^^^^^ &'static str }"#, ); } @@ -1940,10 +1940,10 @@ fn closure_return_inferred() { "#, expect![[r#" 16..46 '{ ..." }; }': u32 - 26..27 'x': impl Fn() -> &str - 30..43 '|| { "test" }': impl Fn() -> &str - 33..43 '{ "test" }': &str - 35..41 '"test"': &str + 26..27 'x': impl Fn() -> &'static str + 30..43 '|| { "test" }': impl Fn() -> &'static str + 33..43 '{ "test" }': &'static str + 35..41 '"test"': &'static str "#]], ); } @@ -1975,10 +1975,10 @@ fn test() { 70..71 'v': i64 78..80 '{}': () 91..362 '{ ... } }': () - 101..106 'mut g': |usize| yields i64 -> &str - 109..218 '|r| { ... }': |usize| yields i64 -> &str + 101..106 'mut g': |usize| yields i64 -> &'static str + 109..218 '|r| { ... }': |usize| yields i64 -> &'static str 110..111 'r': usize - 113..218 '{ ... }': &str + 113..218 '{ ... }': &'static str 127..128 'a': usize 131..138 'yield 0': usize 137..138 '0': i64 @@ -1988,22 +1988,22 @@ fn test() { 177..178 'a': usize 181..188 'yield 2': usize 187..188 '2': i64 - 198..212 '"return value"': &str + 198..212 '"return value"': &'static str 225..360 'match ... }': () - 231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str> - 231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str> - 231..262 'Pin::n...usize)': CoroutineState - 240..246 '&mut g': &mut |usize| yields i64 -> &str - 245..246 'g': |usize| yields i64 -> &str + 231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str> + 231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str> + 231..262 'Pin::n...usize)': CoroutineState + 240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str + 245..246 'g': |usize| yields i64 -> &'static str 255..261 '0usize': usize - 273..299 'Corout...ded(y)': CoroutineState + 273..299 'Corout...ded(y)': CoroutineState 297..298 'y': i64 303..312 '{ f(y); }': () 305..306 'f': fn f(i64) 305..309 'f(y)': () 307..308 'y': i64 - 321..348 'Corout...ete(r)': CoroutineState - 346..347 'r': &str + 321..348 'Corout...ete(r)': CoroutineState + 346..347 'r': &'static str 352..354 '{}': () "#]], ); @@ -2050,7 +2050,7 @@ fn f(x: (&&&&i32, &&&i32)) { _ => loop {}, }; f; - //^ (&&&&i32, &&&i32) + //^ (&'? &'? &'? &'? i32, &'? &'? &'? i32) } "#, ); @@ -2059,10 +2059,10 @@ fn f(x: (&&&&i32, &&&i32)) { fn f() { let x = &&&(&&&2, &&&&&3); let (y, z) = x; - //^ &&&&i32 + //^ &'? &'? &'? &'? i32 let t @ (y, z) = x; t; - //^ &&&(&&&i32, &&&&&i32) + //^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32) } "#, ); @@ -2071,10 +2071,10 @@ fn f() { fn f() { let x = &&&(&&&2, &&&&&3); let (y, z) = x; - //^ &&&&i32 + //^ &'? &'? &'? &'? i32 let t @ (y, z) = x; t; - //^ &&&(&&&i32, &&&&&i32) + //^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32) } "#, ); @@ -2761,23 +2761,23 @@ impl S { fn f() { let x = S; let c1 = || x.read(); - //^^ impl Fn() -> &S + //^^ impl Fn() -> &'? S let c2 = || x.write(); - //^^ impl FnMut() -> &mut S + //^^ impl FnMut() -> &'? mut S let c3 = || x.consume(); //^^ impl FnOnce() -> S let c3 = || x.consume().consume().consume(); //^^ impl FnOnce() -> S let c3 = || x.consume().write().read(); - //^^ impl FnOnce() -> &S + //^^ impl FnOnce() -> &'? S let x = &mut x; let c1 = || x.write(); - //^^ impl FnMut() -> &mut S + //^^ impl FnMut() -> &'? mut S let x = S; let c1 = || { let ref t = x; t }; - //^^ impl Fn() -> &S + //^^ impl Fn() -> &'? S let c2 = || { let ref mut t = x; t }; - //^^ impl FnMut() -> &mut S + //^^ impl FnMut() -> &'? mut S let c3 = || { let t = x; t }; //^^ impl FnOnce() -> S } @@ -3074,11 +3074,11 @@ fn main() { } "#, expect![[r#" - 104..108 'self': &Box - 188..192 'self': &Box> - 218..220 '{}': &T - 242..246 'self': &Box> - 275..277 '{}': &Foo + 104..108 'self': &'? Box + 188..192 'self': &'a Box> + 218..220 '{}': &'a T + 242..246 'self': &'a Box> + 275..277 '{}': &'a Foo 297..301 'self': Box> 322..324 '{}': Foo 338..559 '{ ...r(); }': () @@ -3088,21 +3088,21 @@ fn main() { 360..363 'Foo': extern "rust-call" Foo(i32) -> Foo 360..370 'Foo(0_i32)': Foo 364..369 '0_i32': i32 - 382..386 'bad1': &i32 + 382..386 'bad1': &'? i32 389..394 'boxed': Box> - 389..406 'boxed....nner()': &i32 - 416..421 'good1': &i32 - 424..438 'Foo::get_inner': fn get_inner(&Box>) -> &i32 - 424..446 'Foo::g...boxed)': &i32 - 439..445 '&boxed': &Box> + 389..406 'boxed....nner()': &'? i32 + 416..421 'good1': &'? i32 + 424..438 'Foo::get_inner': fn get_inner(&'? Box>) -> &'? i32 + 424..446 'Foo::g...boxed)': &'? i32 + 439..445 '&boxed': &'? Box> 440..445 'boxed': Box> - 457..461 'bad2': &Foo + 457..461 'bad2': &'? Foo 464..469 'boxed': Box> - 464..480 'boxed....self()': &Foo - 490..495 'good2': &Foo - 498..511 'Foo::get_self': fn get_self(&Box>) -> &Foo - 498..519 'Foo::g...boxed)': &Foo - 512..518 '&boxed': &Box> + 464..480 'boxed....self()': &'? Foo + 490..495 'good2': &'? Foo + 498..511 'Foo::get_self': fn get_self(&'? Box>) -> &'? Foo + 498..519 'Foo::g...boxed)': &'? Foo + 512..518 '&boxed': &'? Box> 513..518 'boxed': Box> 530..535 'inner': Foo 538..543 'boxed': Box> @@ -3414,31 +3414,31 @@ struct TS(usize); fn main() { let x; [x,] = &[1,]; - //^^^^expected &[i32; 1], got [{unknown}; _] + //^^^^expected &'? [i32; 1], got [{unknown}; _] let x; [(x,),] = &[(1,),]; - //^^^^^^^expected &[(i32,); 1], got [{unknown}; _] + //^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _] let x; ((x,),) = &((1,),); - //^^^^^^^expected &((i32,),), got (({unknown},),) + //^^^^^^^expected &'? ((i32,),), got (({unknown},),) let x; (x,) = &(1,); - //^^^^expected &(i32,), got ({unknown},) + //^^^^expected &'? (i32,), got ({unknown},) let x; (S { a: x },) = &(S { a: 42 },); - //^^^^^^^^^^^^^expected &(S,), got (S,) + //^^^^^^^^^^^^^expected &'? (S,), got (S,) let x; S { a: x } = &S { a: 42 }; - //^^^^^^^^^^expected &S, got S + //^^^^^^^^^^expected &'? S, got S let x; TS(x) = &TS(42); - //^^^^^expected &TS, got TS + //^^^^^expected &'? TS, got TS } "#, ); @@ -3548,17 +3548,17 @@ fn f(t: Ark) { } "#, expect![[r#" - 47..51 'self': &Ark + 47..51 'self': &'? Ark 65..88 '{ ... }': *const T - 75..82 '&self.0': &T - 76..80 'self': &Ark + 75..82 '&self.0': &'? T + 76..80 'self': &'? Ark 76..82 'self.0': T 99..100 't': Ark 110..144 '{ ... (); }': () - 116..124 'Ark::foo': fn foo(&Ark) -> *const T + 116..124 'Ark::foo': fn foo(&'? Ark) -> *const T 116..128 'Ark::foo(&t)': *const T 116..141 'Ark::f...nst ()': *const () - 125..127 '&t': &Ark + 125..127 '&t': &'? Ark 126..127 't': Ark "#]], ); @@ -3632,7 +3632,7 @@ pub struct CStr; fn main() { c"ello"; - //^^^^^^^ &CStr + //^^^^^^^ &'static CStr } "#, ); @@ -3659,7 +3659,25 @@ fn main() { let are = "are"; let count = 10; builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!"); - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'{error}> + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'?> +} +"#, + ); +} + +#[test] +fn inline_const_expression() { + check( + r#" +fn main() { + let foo = 0; + const { + let bar = 1; + let unresolved = foo; + // ^^^^^^^^^^ type: {unknown} + let resolved = bar; + // ^^^^^^^^ type: i32 + } } "#, ); diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index dfcd322a39..18fc8afd18 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -238,6 +238,7 @@ fn infer_for_loop() { //- minicore: iterator //- /main.rs crate:main deps:alloc #![no_std] +extern crate alloc; use alloc::collections::Vec; fn test() { @@ -245,7 +246,7 @@ fn test() { v.push("foo"); for x in v { x; - } //^ &str + } //^ &'static str } //- /alloc.rs crate:alloc @@ -575,7 +576,7 @@ fn indexing_arrays() { "fn main() { &mut [9][2]; }", expect![[r#" 10..26 '{ &mut...[2]; }': () - 12..23 '&mut [9][2]': &mut {unknown} + 12..23 '&mut [9][2]': &'? mut {unknown} 17..20 '[9]': [i32; 1] 17..23 '[9][2]': {unknown} 18..19 '9': i32 @@ -873,7 +874,7 @@ impl> O { fn test(o: O) { o.foo(); -} //^^^^^^^ &str +} //^^^^^^^ &'? str "#, ); } @@ -1016,15 +1017,15 @@ fn test(x: impl Trait, y: &impl Trait) { z.foo2(); }"#, expect![[r#" - 29..33 'self': &Self - 54..58 'self': &Self + 29..33 'self': &'? Self + 54..58 'self': &'? Self 77..78 'x': impl Trait 97..99 '{}': () 154..155 'x': impl Trait - 174..175 'y': &impl Trait + 174..175 'y': &'? impl Trait 195..323 '{ ...2(); }': () 201..202 'x': impl Trait - 208..209 'y': &impl Trait + 208..209 'y': &'? impl Trait 219..220 'z': S 223..224 'S': extern "rust-call" S(u16) -> S 223..227 'S(1)': S @@ -1034,13 +1035,13 @@ fn test(x: impl Trait, y: &impl Trait) { 237..238 'z': S 245..246 'x': impl Trait 245..252 'x.foo()': u64 - 258..259 'y': &impl Trait + 258..259 'y': &'? impl Trait 258..265 'y.foo()': u32 271..272 'z': S 271..278 'z.foo()': u16 284..285 'x': impl Trait 284..292 'x.foo2()': i64 - 298..299 'y': &impl Trait + 298..299 'y': &'? impl Trait 298..306 'y.foo2()': i64 312..313 'z': S 312..320 'z.foo2()': i64 @@ -1204,26 +1205,26 @@ fn test(x: impl Trait, y: &impl Trait) { z.foo2(); }"#, expect![[r#" - 29..33 'self': &Self - 54..58 'self': &Self + 29..33 'self': &'? Self + 54..58 'self': &'? Self 98..100 '{}': () 110..111 'x': impl Trait - 130..131 'y': &impl Trait + 130..131 'y': &'? impl Trait 151..268 '{ ...2(); }': () 157..158 'x': impl Trait - 164..165 'y': &impl Trait + 164..165 'y': &'? impl Trait 175..176 'z': impl Trait 179..182 'bar': fn bar() -> impl Trait 179..184 'bar()': impl Trait 190..191 'x': impl Trait 190..197 'x.foo()': u64 - 203..204 'y': &impl Trait + 203..204 'y': &'? impl Trait 203..210 'y.foo()': u64 216..217 'z': impl Trait 216..223 'z.foo()': u64 229..230 'x': impl Trait 229..237 'x.foo2()': i64 - 243..244 'y': &impl Trait + 243..244 'y': &'? impl Trait 243..251 'y.foo2()': i64 257..258 'z': impl Trait 257..265 'z.foo2()': i64 @@ -1328,7 +1329,7 @@ fn test() { a.foo(); }"#, expect![[r#" - 29..33 'self': &Self + 29..33 'self': &'? Self 71..82 '{ loop {} }': ! 73..80 'loop {}': ! 78..80 '{}': () @@ -1366,8 +1367,8 @@ fn test() { d.foo(); }"#, expect![[r#" - 49..53 'self': &mut Self - 101..105 'self': &Self + 49..53 'self': &'? mut Self + 101..105 'self': &'? Self 184..195 '{ loop {} }': ({unknown}, {unknown}) 186..193 'loop {}': ! 191..193 '{}': () @@ -1414,10 +1415,10 @@ fn foo() -> (impl FnOnce(&str, T), impl Trait) { } "#, expect![[r#" - 134..165 '{ ...(C)) }': (impl FnOnce(&str, T), Bar) - 140..163 '(|inpu...ar(C))': (impl FnOnce(&str, T), Bar) - 141..154 '|input, t| {}': impl FnOnce(&str, T) - 142..147 'input': &str + 134..165 '{ ...(C)) }': (impl FnOnce(&'? str, T), Bar) + 140..163 '(|inpu...ar(C))': (impl FnOnce(&'? str, T), Bar) + 141..154 '|input, t| {}': impl FnOnce(&'? str, T) + 142..147 'input': &'? str 149..150 't': T 152..154 '{}': () 156..159 'Bar': extern "rust-call" Bar(u8) -> Bar @@ -1466,26 +1467,26 @@ fn test(x: dyn Trait, y: &dyn Trait) { z.foo2(); }"#, expect![[r#" - 29..33 'self': &Self - 54..58 'self': &Self + 29..33 'self': &'? Self + 54..58 'self': &'? Self 97..99 '{}': dyn Trait 109..110 'x': dyn Trait - 128..129 'y': &dyn Trait + 128..129 'y': &'? dyn Trait 148..265 '{ ...2(); }': () 154..155 'x': dyn Trait - 161..162 'y': &dyn Trait + 161..162 'y': &'? dyn Trait 172..173 'z': dyn Trait 176..179 'bar': fn bar() -> dyn Trait 176..181 'bar()': dyn Trait 187..188 'x': dyn Trait 187..194 'x.foo()': u64 - 200..201 'y': &dyn Trait + 200..201 'y': &'? dyn Trait 200..207 'y.foo()': u64 213..214 'z': dyn Trait 213..220 'z.foo()': u64 226..227 'x': dyn Trait 226..234 'x.foo2()': i64 - 240..241 'y': &dyn Trait + 240..241 'y': &'? dyn Trait 240..248 'y.foo2()': i64 254..255 'z': dyn Trait 254..262 'z.foo2()': i64 @@ -1514,16 +1515,16 @@ fn test(s: S) { s.bar().baz(); }"#, expect![[r#" - 32..36 'self': &Self - 102..106 'self': &S - 128..139 '{ loop {} }': &dyn Trait + 32..36 'self': &'? Self + 102..106 'self': &'? S + 128..139 '{ loop {} }': &'? dyn Trait 130..137 'loop {}': ! 135..137 '{}': () - 175..179 'self': &Self + 175..179 'self': &'? Self 251..252 's': S 267..289 '{ ...z(); }': () 273..274 's': S - 273..280 's.bar()': &dyn Trait + 273..280 's.bar()': &'? dyn Trait 273..286 's.bar().baz()': (u32, i32) "#]], ); @@ -1548,19 +1549,19 @@ fn test(x: Trait, y: &Trait) -> u64 { z.foo(); }"#, expect![[r#" - 26..30 'self': &Self + 26..30 'self': &'? Self 60..62 '{}': dyn Trait 72..73 'x': dyn Trait - 82..83 'y': &dyn Trait + 82..83 'y': &'? dyn Trait 100..175 '{ ...o(); }': u64 106..107 'x': dyn Trait - 113..114 'y': &dyn Trait + 113..114 'y': &'? dyn Trait 124..125 'z': dyn Trait 128..131 'bar': fn bar() -> dyn Trait 128..133 'bar()': dyn Trait 139..140 'x': dyn Trait 139..146 'x.foo()': u64 - 152..153 'y': &dyn Trait + 152..153 'y': &'? dyn Trait 152..159 'y.foo()': u64 165..166 'z': dyn Trait 165..172 'z.foo()': u64 @@ -1580,14 +1581,14 @@ fn main() { } "#, expect![[r#" - 31..35 'self': &S + 31..35 'self': &'? S 37..39 '{}': () - 47..48 '_': &dyn Fn(S) + 47..48 '_': &'? dyn Fn(S) 58..60 '{}': () 71..105 '{ ...()); }': () - 77..78 'f': fn f(&dyn Fn(S)) + 77..78 'f': fn f(&'? dyn Fn(S)) 77..102 'f(&|nu...foo())': () - 79..101 '&|numb....foo()': &impl Fn(S) + 79..101 '&|numb....foo()': &'? impl Fn(S) 80..101 '|numbe....foo()': impl Fn(S) 81..87 'number': S 89..95 'number': S @@ -1790,7 +1791,7 @@ fn test(x: T, y: U) { y.foo(); }"#, expect![[r#" - 53..57 'self': &Self + 53..57 'self': &'? Self 66..68 '{}': u32 185..186 'x': T 191..192 'y': U @@ -1819,11 +1820,11 @@ fn test(x: &impl Trait1) { x.foo(); }"#, expect![[r#" - 53..57 'self': &Self + 53..57 'self': &'? Self 66..68 '{}': u32 - 119..120 'x': &impl Trait1 + 119..120 'x': &'? impl Trait1 136..152 '{ ...o(); }': () - 142..143 'x': &impl Trait1 + 142..143 'x': &'? impl Trait1 142..149 'x.foo()': u32 "#]], ); @@ -1934,8 +1935,8 @@ fn test() { opt.map(f); }"#, expect![[r#" - 28..32 'self': &Self - 132..136 'self': &Bar + 28..32 'self': &'? Self + 132..136 'self': &'? Bar 149..160 '{ loop {} }': (A1, R) 151..158 'loop {}': ! 156..158 '{}': () @@ -1988,7 +1989,7 @@ fn test() { let r2 = lazy2.foo(); }"#, expect![[r#" - 36..40 'self': &Foo + 36..40 'self': &'? Foo 51..53 '{}': usize 131..132 'f': F 151..153 '{}': Lazy @@ -2262,14 +2263,14 @@ impl Trait for S2 { fn f(&self, x: ::Item) { let y = x; } }"#, expect![[r#" - 40..44 'self': &Self + 40..44 'self': &'? Self 46..47 'x': Trait::Item - 126..130 'self': &S + 126..130 'self': &'? S 132..133 'x': u32 147..161 '{ let y = x; }': () 153..154 'y': u32 157..158 'x': u32 - 228..232 'self': &S2 + 228..232 'self': &'? S2 234..235 'x': i32 251..265 '{ let y = x; }': () 257..258 'y': i32 @@ -2643,12 +2644,12 @@ fn main() { 72..74 '_v': F 117..120 '{ }': () 132..163 '{ ... }); }': () - 138..148 'f::<(), _>': fn f<(), impl FnOnce(&())>(impl FnOnce(&())) + 138..148 'f::<(), _>': fn f<(), impl FnOnce(&'? ())>(impl FnOnce(&'? ())) 138..160 'f::<()... z; })': () - 149..159 '|z| { z; }': impl FnOnce(&()) - 150..151 'z': &() + 149..159 '|z| { z; }': impl FnOnce(&'? ()) + 150..151 'z': &'? () 153..159 '{ z; }': () - 155..156 'z': &() + 155..156 'z': &'? () "#]], ); } @@ -2897,13 +2898,13 @@ fn test(x: &dyn Foo) { foo(x); }"#, expect![[r#" - 21..22 'x': &dyn Foo + 21..22 'x': &'? dyn Foo 34..36 '{}': () - 46..47 'x': &dyn Foo + 46..47 'x': &'? dyn Foo 59..74 '{ foo(x); }': () - 65..68 'foo': fn foo(&dyn Foo) + 65..68 'foo': fn foo(&'? dyn Foo) 65..71 'foo(x)': () - 69..70 'x': &dyn Foo + 69..70 'x': &'? dyn Foo "#]], ); } @@ -2927,7 +2928,7 @@ fn test() { (IsCopy, NotCopy).test(); }"#, expect![[r#" - 78..82 'self': &Self + 78..82 'self': &'? Self 134..235 '{ ...t(); }': () 140..146 'IsCopy': IsCopy 140..153 'IsCopy.test()': bool @@ -2969,7 +2970,7 @@ fn test() { 28..29 'T': {unknown} 36..38 '{}': T 36..38: expected T, got () - 113..117 'self': &Self + 113..117 'self': &'? Self 169..249 '{ ...t(); }': () 175..178 'foo': fn foo() 175..185 'foo.test()': bool @@ -2997,16 +2998,16 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { f3.test(); }"#, expect![[r#" - 22..26 'self': &Self + 22..26 'self': &'? Self 76..78 'f1': fn() 86..88 'f2': fn(usize) -> u8 - 107..109 'f3': fn(u8, u8) -> &u8 + 107..109 'f3': fn(u8, u8) -> &'? u8 130..178 '{ ...t(); }': () 136..138 'f1': fn() 136..145 'f1.test()': bool 151..153 'f2': fn(usize) -> u8 151..160 'f2.test()': bool - 166..168 'f3': fn(u8, u8) -> &u8 + 166..168 'f3': fn(u8, u8) -> &'? u8 166..175 'f3.test()': bool "#]], ); @@ -3027,13 +3028,13 @@ fn test() { (1u8, *"foo").test(); // not Sized }"#, expect![[r#" - 22..26 'self': &Self + 22..26 'self': &'? Self 79..194 '{ ...ized }': () 85..88 '1u8': u8 85..95 '1u8.test()': bool 101..116 '(*"foo").test()': {unknown} 102..108 '*"foo"': str - 103..108 '"foo"': &str + 103..108 '"foo"': &'static str 135..145 '(1u8, 1u8)': (u8, u8) 135..152 '(1u8, ...test()': bool 136..139 '1u8': u8 @@ -3042,7 +3043,7 @@ fn test() { 158..178 '(1u8, ...test()': {unknown} 159..162 '1u8': u8 164..170 '*"foo"': str - 165..170 '"foo"': &str + 165..170 '"foo"': &'static str "#]], ); } @@ -3093,7 +3094,7 @@ fn foo() { 93..94 'x': Option 109..111 '{}': () 117..124 '(&f)(s)': () - 118..120 '&f': &impl Fn(Option) + 118..120 '&f': &'? impl Fn(Option) 119..120 'f': impl Fn(Option) 122..123 's': Option "#]], @@ -3170,25 +3171,25 @@ fn foo() { f(&s); }"#, expect![[r#" - 154..158 'self': &Box - 166..205 '{ ... }': &T - 176..199 'unsafe...nner }': &T - 185..197 '&*self.inner': &T + 154..158 'self': &'? Box + 166..205 '{ ... }': &'? T + 176..199 'unsafe...nner }': &'? T + 185..197 '&*self.inner': &'? T 186..197 '*self.inner': T - 187..191 'self': &Box + 187..191 'self': &'? Box 187..197 'self.inner': *mut T 218..324 '{ ...&s); }': () 228..229 's': Option 232..236 'None': Option - 246..247 'f': Box)> - 281..310 'Box { ... {}) }': Box)> - 294..308 '&mut (|ps| {})': &mut impl FnOnce(&Option) - 300..307 '|ps| {}': impl FnOnce(&Option) - 301..303 'ps': &Option + 246..247 'f': Box)> + 281..310 'Box { ... {}) }': Box)> + 294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option) + 300..307 '|ps| {}': impl FnOnce(&'? Option) + 301..303 'ps': &'? Option 305..307 '{}': () - 316..317 'f': Box)> + 316..317 'f': Box)> 316..321 'f(&s)': () - 318..320 '&s': &Option + 318..320 '&s': &'? Option 319..320 's': Option "#]], ); @@ -3320,7 +3321,7 @@ fn f() { } }"#, expect![[r#" - 46..50 'self': &Self + 46..50 'self': &'? Self 58..63 '{ 0 }': u8 60..61 '0': u8 115..185 '{ ... } }': () @@ -3595,7 +3596,7 @@ fn take_u32(_: u32) {} fn minimized() { let v = V::default(); let p = v.get(&0); - //^ &u32 + //^ &'? u32 take_u32(42 + p); } "#, @@ -3625,7 +3626,7 @@ fn take_u32(_: u32) {} fn minimized() { let v = V::default(); let p = v.get(); - //^ &{unknown} + //^ &'? {unknown} take_u32(42 + p); } "#, @@ -3684,11 +3685,11 @@ fn main() { } "#, expect![[r#" - 44..48 'self': &Self - 133..137 'self': &[u8; 4] + 44..48 'self': &'? Self + 133..137 'self': &'? [u8; 4] 155..172 '{ ... }': usize 165..166 '2': usize - 236..240 'self': &[u8; 2] + 236..240 'self': &'? [u8; 2] 258..275 '{ ... }': u8 268..269 '2': u8 289..392 '{ ...g(); }': () @@ -3732,11 +3733,11 @@ fn main() { } "#, expect![[r#" - 44..48 'self': &Self - 151..155 'self': &[u8; L] + 44..48 'self': &'? Self + 151..155 'self': &'? [u8; L] 173..194 '{ ... }': [u8; L] 183..188 '*self': [u8; L] - 184..188 'self': &[u8; L] + 184..188 'self': &'? [u8; L] 208..260 '{ ...g(); }': () 218..219 'v': [u8; 2] 222..230 '[0u8; 2]': [u8; 2] @@ -4056,13 +4057,13 @@ fn g(t: &(dyn Sync + T2 + T1 + Send)) { } "#, expect![[r#" - 68..69 't': &{unknown} + 68..69 't': &'? {unknown} 101..103 '{}': () - 109..110 't': &{unknown} + 109..110 't': &'? {unknown} 142..155 '{ f(t); }': () - 148..149 'f': fn f(&{unknown}) + 148..149 'f': fn f(&'? {unknown}) 148..152 'f(t)': () - 150..151 't': &{unknown} + 150..151 't': &'? {unknown} "#]], ); @@ -4105,7 +4106,7 @@ trait Trait { } fn f(t: &dyn Trait) {} - //^&{unknown} + //^&'? {unknown} "#, ); } @@ -4175,27 +4176,27 @@ trait Trait { fn f(v: impl Trait) { let a = v.get::().deref(); - //^ &i32 + //^ &'? i32 let a = v.get::().deref(); - //^ &T + //^ &'? T } fn g<'a, T: 'a>(v: impl Trait = &'a T>) { let a = v.get::(); - //^ &T + //^ &'a T let a = v.get::<()>(); - //^ Trait::Assoc<(), impl Trait = &T>> + //^ Trait::Assoc<(), impl Trait = &'a T>> } fn h<'a>(v: impl Trait = &'a i32> + Trait = &'a i64>) { let a = v.get::(); - //^ &i32 + //^ &'a i32 let a = v.get::(); - //^ &i64 + //^ &'a i64 } fn i<'a>(v: impl Trait = &'a i32, Assoc = &'a i64>) { let a = v.get::(); - //^ &i32 + //^ &'a i32 let a = v.get::(); - //^ &i64 + //^ &'a i64 } "#, ); @@ -4221,12 +4222,12 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { } "#, expect![[r#" - 90..94 'self': &Self - 127..128 'v': &(dyn Trait = &i32>) + 90..94 'self': &'? Self + 127..128 'v': &'? (dyn Trait = &'a i32>) 164..195 '{ ...f(); }': () - 170..171 'v': &(dyn Trait = &i32>) - 170..184 'v.get::()': &i32 - 170..192 'v.get:...eref()': &i32 + 170..171 'v': &'? (dyn Trait = &'a i32>) + 170..184 'v.get::()': &'? i32 + 170..192 'v.get:...eref()': &'? i32 "#]], ); } @@ -4487,19 +4488,19 @@ fn derive_macro_bounds() { let x = (&Copy).clone(); //^ Copy let x = (&NotCopy).clone(); - //^ &NotCopy + //^ &'? NotCopy let x = (&Generic(Copy)).clone(); //^ Generic let x = (&Generic(NotCopy)).clone(); - //^ &Generic + //^ &'? Generic let x: &AssocGeneric = &AssocGeneric(NotCopy); let x = x.clone(); - //^ &AssocGeneric + //^ &'? AssocGeneric // let x: &AssocGeneric2 = &AssocGeneric2(NotCopy); // let x = x.clone(); let x: &AssocGeneric3 = &AssocGeneric3(Generic(NotCopy)); let x = x.clone(); - //^ &AssocGeneric3 + //^ &'? AssocGeneric3 let x = (&R1(Vec())).clone(); //^ R1 let x = (&R2(R1(Vec()))).clone(); @@ -4582,7 +4583,7 @@ impl B for u16 { fn ttt() { let inp = Y; x::(&inp); - //^^^^ expected &X, got &Y + //^^^^ expected &'? X, got &'? Y } "#, ); @@ -4629,7 +4630,7 @@ fn foo() { let mut map = SomeMap; map["a"] = (); map; - //^^^ SomeMap<&str> + //^^^ SomeMap<&'static str> } "#, ); @@ -4764,3 +4765,62 @@ fn test() { "#, ); } + +#[test] +fn associated_type_with_impl_trait_in_tuple() { + check_no_mismatches( + r#" +pub trait Iterator { + type Item; +} + +pub trait Value {} + +fn bar>() {} + +fn foo() { + bar(); +} +"#, + ); +} + +#[test] +fn associated_type_with_impl_trait_in_nested_tuple() { + check_no_mismatches( + r#" +pub trait Iterator { + type Item; +} + +pub trait Value {} + +fn bar>() {} + +fn foo() { + bar(); +} +"#, + ); +} + +#[test] +fn dyn_trait_with_lifetime_in_rpit() { + check_types( + r#" +//- minicore: future +pub struct Box {} + +trait Trait {} + +pub async fn foo_async<'a>() -> Box { + Box {} +} + +fn foo() { + foo_async(); + //^^^^^^^^^^^impl Future> + ?Sized +} +"#, + ) +} diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 4518422d27..72272934ab 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -9,9 +9,11 @@ use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDi use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use either::Either; +pub use hir_def::VariantId; use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId}; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; +use triomphe::Arc; use crate::{AssocItem, Field, Local, MacroKind, Trait, Type}; @@ -171,7 +173,7 @@ pub struct MacroError { pub struct MacroExpansionParseError { pub node: InFile, pub precise_location: Option, - pub errors: Box<[SyntaxError]>, + pub errors: Arc<[SyntaxError]>, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -200,6 +202,7 @@ pub struct MalformedDerive { pub struct NoSuchField { pub field: InFile>>, pub private: bool, + pub variant: VariantId, } #[derive(Debug)] @@ -525,7 +528,7 @@ impl AnyDiagnostic { source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok() }; Some(match d { - &InferenceDiagnostic::NoSuchField { field: expr, private } => { + &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => { let expr_or_pat = match expr { ExprOrPatId::ExprId(expr) => { source_map.field_syntax(expr).map(AstPtr::wrap_left) @@ -534,7 +537,7 @@ impl AnyDiagnostic { source_map.pat_field_syntax(pat).map(AstPtr::wrap_right) } }; - NoSuchField { field: expr_or_pat, private }.into() + NoSuchField { field: expr_or_pat, private, variant }.into() } &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { MismatchedArgCount { call_expr: expr_syntax(call_expr)?, expected, found }.into() diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 84f03d111f..c276e87786 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -188,28 +188,7 @@ impl HirDisplay for Struct { StructKind::Record => { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - let fields = self.fields(f.db); - let count = fields.len().min(limit); - f.write_char(if !has_where_clause { ' ' } else { '\n' })?; - if count == 0 { - if fields.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } - } else { - f.write_str(" {\n")?; - for field in &fields[..count] { - f.write_str(" ")?; - field.hir_fmt(f)?; - f.write_str(",\n")?; - } - - if fields.len() > count { - f.write_str(" /* … */\n")?; - } - f.write_str("}")?; - } + display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } } StructKind::Unit => _ = write_where_clause(def_id, f)?, @@ -226,18 +205,10 @@ impl HirDisplay for Enum { write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); write_generic_params(def_id, f)?; - let has_where_clause = write_where_clause(def_id, f)?; - let variants = self.variants(f.db); - if !variants.is_empty() { - f.write_char(if !has_where_clause { ' ' } else { '\n' })?; - f.write_str("{\n")?; - for variant in variants { - f.write_str(" ")?; - variant.hir_fmt(f)?; - f.write_str(",\n")?; - } - f.write_str("}")?; + let has_where_clause = write_where_clause(def_id, f)?; + if let Some(limit) = f.entity_limit { + display_variants(&self.variants(f.db), has_where_clause, limit, f)?; } Ok(()) @@ -251,24 +222,104 @@ impl HirDisplay for Union { write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); write_generic_params(def_id, f)?; + let has_where_clause = write_where_clause(def_id, f)?; - - let fields = self.fields(f.db); - if !fields.is_empty() { - f.write_char(if !has_where_clause { ' ' } else { '\n' })?; - f.write_str("{\n")?; - for field in self.fields(f.db) { - f.write_str(" ")?; - field.hir_fmt(f)?; - f.write_str(",\n")?; - } - f.write_str("}")?; + if let Some(limit) = f.entity_limit { + display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } - Ok(()) } } +fn display_fields( + fields: &[Field], + has_where_clause: bool, + limit: usize, + in_line: bool, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + let count = fields.len().min(limit); + let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; + f.write_char(if !has_where_clause { ' ' } else { separator })?; + if count == 0 { + if fields.is_empty() { + f.write_str("{}")?; + } else { + f.write_str("{ /* … */ }")?; + } + } else { + f.write_char('{')?; + + if !fields.is_empty() { + f.write_char(separator)?; + for field in &fields[..count] { + f.write_str(indent)?; + field.hir_fmt(f)?; + f.write_char(',')?; + f.write_char(separator)?; + } + + if fields.len() > count { + f.write_str(indent)?; + f.write_str("/* … */")?; + f.write_char(separator)?; + } + } + + f.write_str("}")?; + } + + Ok(()) +} + +fn display_variants( + variants: &[Variant], + has_where_clause: bool, + limit: usize, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + let count = variants.len().min(limit); + f.write_char(if !has_where_clause { ' ' } else { '\n' })?; + if count == 0 { + if variants.is_empty() { + f.write_str("{}")?; + } else { + f.write_str("{ /* … */ }")?; + } + } else { + f.write_str("{\n")?; + for variant in &variants[..count] { + f.write_str(" ")?; + write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?; + match variant.kind(f.db) { + StructKind::Tuple => { + if variant.fields(f.db).is_empty() { + f.write_str("()")?; + } else { + f.write_str("( /* … */ )")?; + } + } + StructKind::Record => { + if variant.fields(f.db).is_empty() { + f.write_str(" {}")?; + } else { + f.write_str(" { /* … */ }")?; + } + } + StructKind::Unit => {} + } + f.write_str(",\n")?; + } + + if variants.len() > count { + f.write_str(" /* … */\n")?; + } + f.write_str("}")?; + } + + Ok(()) +} + impl HirDisplay for Field { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; @@ -304,21 +355,10 @@ impl HirDisplay for Variant { } f.write_char(')')?; } - VariantData::Record(fields) => { - f.write_str(" {")?; - let mut first = true; - for (_, field) in fields.iter() { - if first { - first = false; - f.write_char(' ')?; - } else { - f.write_str(", ")?; - } - // Enum variant fields must be pub. - write!(f, "{}: ", field.name.display(f.db.upcast()))?; - field.type_ref.hir_fmt(f)?; + VariantData::Record(_) => { + if let Some(limit) = f.entity_limit { + display_fields(&self.fields(f.db), false, limit, true, f)?; } - f.write_str(" }")?; } } Ok(()) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index bcd94a611a..85f33a10fc 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -59,7 +59,9 @@ use hir_def::{ ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; -use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind}; +use hir_expand::{ + attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, +}; use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, @@ -79,7 +81,7 @@ use hir_ty::{ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; -use span::Edition; +use span::{Edition, MacroCallId}; use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasName}, @@ -559,6 +561,12 @@ impl Module { emit_def_diagnostic(db, acc, diag); } + if !self.id.is_block_module() { + // These are reported by the body of block modules + let scope = &def_map[self.id.local_id].scope; + scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc)); + } + for def in self.declarations(db) { match def { ModuleDef::Module(m) => { @@ -577,6 +585,10 @@ impl Module { item.diagnostics(db, acc, style_lints); } + t.all_macro_calls(db) + .iter() + .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc)); + acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Adt(adt) => { @@ -621,6 +633,11 @@ impl Module { // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow continue; } + impl_def + .all_macro_calls(db) + .iter() + .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc)); + let ast_id_map = db.ast_id_map(file_id); for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { @@ -809,6 +826,37 @@ impl Module { } } +fn macro_call_diagnostics( + db: &dyn HirDatabase, + macro_call_id: MacroCallId, + acc: &mut Vec, +) { + let Some(e) = db.parse_macro_expansion_error(macro_call_id) else { + return; + }; + let ValueResult { value: parse_errors, err } = &*e; + if let Some(err) = err { + let loc = db.lookup_intern_macro_call(macro_call_id); + let (node, precise_location, macro_name, kind) = precise_macro_call_location(&loc.kind, db); + let diag = match err { + &hir_expand::ExpandError::UnresolvedProcMacro(krate) => { + UnresolvedProcMacro { node, precise_location, macro_name, kind, krate }.into() + } + err => MacroError { node, precise_location, message: err.to_string() }.into(), + }; + acc.push(diag); + } + + if !parse_errors.is_empty() { + let loc = db.lookup_intern_macro_call(macro_call_id); + let (node, precise_location, _, _) = precise_macro_call_location(&loc.kind, db); + acc.push( + MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() } + .into(), + ) + } +} + fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec, m: Macro) { let id = db.macro_def(m.id); if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) { @@ -888,16 +936,6 @@ fn emit_def_diagnostic_( .into(), ); } - DefDiagnosticKind::MacroError { ast, message } => { - let (node, precise_location, _, _) = precise_macro_call_location(ast, db); - acc.push(MacroError { node, precise_location, message: message.clone() }.into()); - } - DefDiagnosticKind::MacroExpansionParseError { ast, errors } => { - let (node, precise_location, _, _) = precise_macro_call_location(ast, db); - acc.push( - MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(), - ); - } DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { let node = ast.to_node(db.upcast()); // Must have a name, otherwise we wouldn't emit it. @@ -1489,6 +1527,14 @@ impl Adt { .map(|arena| arena.1.clone()) } + pub fn as_struct(&self) -> Option { + if let Self::Struct(v) = self { + Some(*v) + } else { + None + } + } + pub fn as_enum(&self) -> Option { if let Self::Enum(v) = self { Some(*v) @@ -1636,6 +1682,10 @@ impl DefWithBody { Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); } + source_map + .macro_calls() + .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id.macro_call_id, acc)); + for diag in source_map.diagnostics() { acc.push(match diag { BodyDiagnostic::InactiveCode { node, cfg, opts } => { @@ -2437,6 +2487,14 @@ impl Trait { .filter(|(_, ty)| !count_required_only || !ty.has_default()) .count() } + + fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { + db.trait_data(self.id) + .macro_calls + .as_ref() + .map(|it| it.as_ref().clone().into_boxed_slice()) + .unwrap_or_default() + } } impl HasVisibility for Trait { @@ -2505,6 +2563,15 @@ impl HasVisibility for TypeAlias { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct StaticLifetime; + +impl StaticLifetime { + pub fn name(self) -> Name { + known::STATIC_LIFETIME + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct BuiltinType { pub(crate) inner: hir_def::builtin_type::BuiltinType, @@ -2535,6 +2602,20 @@ impl BuiltinType { matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_)) } + pub fn is_f32(&self) -> bool { + matches!( + self.inner, + hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F32) + ) + } + + pub fn is_f64(&self) -> bool { + matches!( + self.inner, + hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F64) + ) + } + pub fn is_char(&self) -> bool { matches!(self.inner, hir_def::builtin_type::BuiltinType::Char) } @@ -3743,6 +3824,14 @@ impl Impl { pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool { check_orphan_rules(db, self.id) } + + fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { + db.impl_data(self.id) + .macro_calls + .as_ref() + .map(|it| it.as_ref().clone().into_boxed_slice()) + .unwrap_or_default() + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] @@ -4495,7 +4584,8 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(Function) -> Option, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "iterate_method_candidates").entered(); + let _p = + tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered(); let mut slot = None; self.iterate_method_candidates_dyn( diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index e792e159ac..6c70cc4baf 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -131,7 +131,7 @@ pub struct SemanticsImpl<'db> { pub db: &'db dyn HirDatabase, s2d_cache: RefCell, /// Rootnode to HirFileId cache - cache: RefCell>, + root_to_file_cache: RefCell>, // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens // So we might wanna move them out into something specific for semantic highlighting expansion_info_cache: RefCell>, @@ -294,7 +294,7 @@ impl<'db> SemanticsImpl<'db> { SemanticsImpl { db, s2d_cache: Default::default(), - cache: Default::default(), + root_to_file_cache: Default::default(), expansion_info_cache: Default::default(), macro_call_cache: Default::default(), } @@ -690,6 +690,7 @@ impl<'db> SemanticsImpl<'db> { exp_info }); + // FIXME: uncached parse // Create the source analyzer for the macro call scope let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file())) else { @@ -722,7 +723,7 @@ impl<'db> SemanticsImpl<'db> { mut token: SyntaxToken, f: &mut dyn FnMut(InFile) -> ControlFlow<()>, ) { - let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros").entered(); + let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered(); let (sa, span, file_id) = match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) { Some(sa) => match sa.file_id.file_id() { @@ -1025,6 +1026,7 @@ impl<'db> SemanticsImpl<'db> { None => { let call_node = file_id.macro_file()?.call_node(db); // cache the node + // FIXME: uncached parse self.parse_or_expand(call_node.file_id); Some(call_node) } @@ -1370,7 +1372,7 @@ impl<'db> SemanticsImpl<'db> { offset: Option, infer_body: bool, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "Semantics::analyze_impl").entered(); + let _p = tracing::span!(tracing::Level::INFO, "SemanticsImpl::analyze_impl").entered(); let node = self.find_file(node); let container = self.with_ctx(|ctx| ctx.find_container(node))?; @@ -1397,7 +1399,7 @@ impl<'db> SemanticsImpl<'db> { fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { assert!(root_node.parent().is_none()); - let mut cache = self.cache.borrow_mut(); + let mut cache = self.root_to_file_cache.borrow_mut(); let prev = cache.insert(root_node, file_id); assert!(prev.is_none() || prev == Some(file_id)) } @@ -1407,7 +1409,7 @@ impl<'db> SemanticsImpl<'db> { } fn lookup(&self, root_node: &SyntaxNode) -> Option { - let cache = self.cache.borrow(); + let cache = self.root_to_file_cache.borrow(); cache.get(root_node).copied() } @@ -1427,7 +1429,7 @@ impl<'db> SemanticsImpl<'db> { known nodes: {}\n\n", node, root_node, - self.cache + self.root_to_file_cache .borrow() .keys() .map(|it| format!("{it:?}")) diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 434e4b5a0c..d2bd8b0e79 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -118,10 +118,10 @@ pub(super) struct SourceToDefCtx<'a, 'b> { impl SourceToDefCtx<'_, '_> { pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> { - let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def").entered(); + let _p = tracing::span!(tracing::Level::INFO, "SourceToDefCtx::file_to_def").entered(); let mut mods = SmallVec::new(); for &crate_id in self.db.relevant_crates(file).iter() { - // FIXME: inner items + // Note: `mod` declarations in block modules cannot be supported here let crate_def_map = self.db.crate_def_map(crate_id); mods.extend( crate_def_map @@ -129,6 +129,9 @@ impl SourceToDefCtx<'_, '_> { .map(|local_id| crate_def_map.module_id(local_id)), ) } + if mods.is_empty() { + // FIXME: detached file + } mods } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index dc96a1b03d..057b03baef 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -28,7 +28,7 @@ use hir_expand::{ mod_path::path, name, name::{AsName, Name}, - HirFileId, InFile, MacroFileId, MacroFileIdExt, + HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt, }; use hir_ty::{ diagnostics::{ @@ -118,7 +118,7 @@ impl SourceAnalyzer { fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option { let src = match expr { ast::Expr::MacroExpr(expr) => { - self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))? + self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into() } _ => InFile::new(self.file_id, expr.clone()), }; @@ -145,20 +145,20 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, expr: InFile, - ) -> Option> { + ) -> Option> { let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; - let expanded = db.parse_or_expand(macro_file); + let expanded = db.parse_macro_expansion(macro_file).value.0.syntax_node(); let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { match stmts.expr()? { ast::Expr::MacroExpr(mac) => { - self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))? + self.expand_expr(db, InFile::new(macro_file.into(), mac.macro_call()?))? } - expr => InFile::new(macro_file, expr), + expr => InMacroFile::new(macro_file, expr), } } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) { - self.expand_expr(db, InFile::new(macro_file, call))? + self.expand_expr(db, InFile::new(macro_file.into(), call))? } else { - InFile::new(macro_file, ast::Expr::cast(expanded)?) + InMacroFile::new(macro_file, ast::Expr::cast(expanded)?) }; Some(res) diff --git a/crates/hir/src/term_search.rs b/crates/hir/src/term_search.rs index 93e7300491..5c5ddae19e 100644 --- a/crates/hir/src/term_search.rs +++ b/crates/hir/src/term_search.rs @@ -127,6 +127,13 @@ impl LookupTable { self.types_wishlist.insert(ty.clone()); } + // Collapse suggestions if there are many + if let Some(res) = &res { + if res.len() > self.many_threshold { + return Some(vec![Expr::Many(ty.clone())]); + } + } + res } @@ -158,6 +165,13 @@ impl LookupTable { self.types_wishlist.insert(ty.clone()); } + // Collapse suggestions if there are many + if let Some(res) = &res { + if res.len() > self.many_threshold { + return Some(vec![Expr::Many(ty.clone())]); + } + } + res } @@ -255,13 +269,13 @@ pub struct TermSearchConfig { pub enable_borrowcheck: bool, /// Indicate when to squash multiple trees to `Many` as there are too many to keep track pub many_alternatives_threshold: usize, - /// Depth of the search eg. number of cycles to run - pub depth: usize, + /// Fuel for term search in "units of work" + pub fuel: u64, } impl Default for TermSearchConfig { fn default() -> Self { - Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 } + Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 } } } @@ -280,8 +294,7 @@ impl Default for TermSearchConfig { /// transformation tactics. For example functions take as from set of types (arguments) to some /// type (return type). Other transformations include methods on type, type constructors and /// projections to struct fields (field access). -/// 3. Once we manage to find path to type we are interested in we continue for single round to see -/// if we can find more paths that take us to the `goal` type. +/// 3. If we run out of fuel (term search takes too long) we stop iterating. /// 4. Return all the paths (type trees) that take us to the `goal` type. /// /// Note that there are usually more ways we can get to the `goal` type but some are discarded to @@ -297,21 +310,31 @@ pub fn term_search(ctx: &TermSearchCtx<'_, DB>) -> Vec { }); let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone()); + let fuel = std::cell::Cell::new(ctx.config.fuel); + + let should_continue = &|| { + let remaining = fuel.get(); + fuel.set(remaining.saturating_sub(1)); + if remaining == 0 { + tracing::debug!("fuel exhausted"); + } + remaining > 0 + }; // Try trivial tactic first, also populates lookup table let mut solutions: Vec = tactics::trivial(ctx, &defs, &mut lookup).collect(); // Use well known types tactic before iterations as it does not depend on other tactics solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup)); - for _ in 0..ctx.config.depth { + while should_continue() { lookup.new_round(); - solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup)); - solutions.extend(tactics::free_function(ctx, &defs, &mut lookup)); - solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup)); - solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup)); - solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup)); - solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup)); + solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup, should_continue)); + solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue)); + solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue)); + solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue)); + solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue)); + solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue)); // Discard not interesting `ScopeDef`s for speedup for def in lookup.exhausted_scopedefs() { diff --git a/crates/hir/src/term_search/expr.rs b/crates/hir/src/term_search/expr.rs index 2d0c5630e1..9f56a1ee55 100644 --- a/crates/hir/src/term_search/expr.rs +++ b/crates/hir/src/term_search/expr.rs @@ -211,13 +211,13 @@ impl Expr { } } Expr::Method { func, target, params, .. } => { - if target.contains_many_in_illegal_pos() { + if self.contains_many_in_illegal_pos(db) { return Ok(many_formatter(&target.ty(db))); } let func_name = func.name(db).display(db.upcast()).to_string(); let self_param = func.self_param(db).unwrap(); - let target = target.gen_source_code( + let target_str = target.gen_source_code( sema_scope, many_formatter, prefer_no_std, @@ -236,9 +236,12 @@ impl Expr { Some(trait_) => { let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?; let target = match self_param.access(db) { - crate::Access::Shared => format!("&{target}"), - crate::Access::Exclusive => format!("&mut {target}"), - crate::Access::Owned => target, + crate::Access::Shared if !target.is_many() => format!("&{target_str}"), + crate::Access::Exclusive if !target.is_many() => { + format!("&mut {target_str}") + } + crate::Access::Owned => target_str, + _ => many_formatter(&target.ty(db)), }; let res = match args.is_empty() { true => format!("{trait_name}::{func_name}({target})",), @@ -246,7 +249,7 @@ impl Expr { }; Ok(res) } - None => Ok(format!("{target}.{func_name}({args})")), + None => Ok(format!("{target_str}.{func_name}({args})")), } } Expr::Variant { variant, generics, params } => { @@ -381,7 +384,7 @@ impl Expr { Ok(res) } Expr::Field { expr, field } => { - if expr.contains_many_in_illegal_pos() { + if expr.contains_many_in_illegal_pos(db) { return Ok(many_formatter(&expr.ty(db))); } @@ -395,7 +398,7 @@ impl Expr { Ok(format!("{strukt}.{field}")) } Expr::Reference(expr) => { - if expr.contains_many_in_illegal_pos() { + if expr.contains_many_in_illegal_pos(db) { return Ok(many_formatter(&expr.ty(db))); } @@ -466,10 +469,15 @@ impl Expr { /// macro!().bar() /// ¯o!() /// ``` - fn contains_many_in_illegal_pos(&self) -> bool { + fn contains_many_in_illegal_pos(&self, db: &dyn HirDatabase) -> bool { match self { - Expr::Method { target, .. } => target.contains_many_in_illegal_pos(), - Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(), + Expr::Method { target, func, .. } => { + match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) { + Some(_) => false, + None => target.is_many(), + } + } + Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(db), Expr::Reference(target) => target.is_many(), Expr::Many(_) => true, _ => false, diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs index 63b2a2506f..a26728272d 100644 --- a/crates/hir/src/term_search/tactics.rs +++ b/crates/hir/src/term_search/tactics.rs @@ -4,6 +4,7 @@ //! * `ctx` - Context for the term search //! * `defs` - Set of items in scope at term search target location //! * `lookup` - Lookup table for types +//! * `should_continue` - Function that indicates when to stop iterating //! And they return iterator that yields type trees that unify with the `goal` type. use std::iter; @@ -97,16 +98,19 @@ pub(super) fn trivial<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types +/// * `should_continue` - Function that indicates when to stop iterating pub(super) fn type_constructor<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, defs: &'a FxHashSet, lookup: &'a mut LookupTable, + should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); fn variant_helper( db: &dyn HirDatabase, lookup: &mut LookupTable, + should_continue: &dyn std::ops::Fn() -> bool, parent_enum: Enum, variant: Variant, config: &TermSearchConfig, @@ -152,6 +156,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>( .chain((non_default_type_params_len == 0).then_some(Vec::new())); generic_params + .filter(|_| should_continue()) .filter_map(move |generics| { // Insert default type params let mut g = generics.into_iter(); @@ -194,8 +199,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>( defs.iter() .filter_map(move |def| match def { ScopeDef::ModuleDef(ModuleDef::Variant(it)) => { - let variant_exprs = - variant_helper(db, lookup, it.parent_enum(db), *it, &ctx.config); + let variant_exprs = variant_helper( + db, + lookup, + should_continue, + it.parent_enum(db), + *it, + &ctx.config, + ); if variant_exprs.is_empty() { return None; } @@ -213,7 +224,9 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>( let exprs: Vec<(Type, Vec)> = enum_ .variants(db) .into_iter() - .flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.config)) + .flat_map(|it| { + variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config) + }) .collect(); if exprs.is_empty() { @@ -271,6 +284,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>( .chain((non_default_type_params_len == 0).then_some(Vec::new())); let exprs = generic_params + .filter(|_| should_continue()) .filter_map(|generics| { // Insert default type params let mut g = generics.into_iter(); @@ -345,10 +359,12 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types +/// * `should_continue` - Function that indicates when to stop iterating pub(super) fn free_function<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, defs: &'a FxHashSet, lookup: &'a mut LookupTable, + should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -390,6 +406,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>( .permutations(non_default_type_params_len); let exprs: Vec<_> = generic_params + .filter(|_| should_continue()) .filter_map(|generics| { // Insert default type params let mut g = generics.into_iter(); @@ -474,10 +491,12 @@ pub(super) fn free_function<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types +/// * `should_continue` - Function that indicates when to stop iterating pub(super) fn impl_method<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, _defs: &'a FxHashSet, lookup: &'a mut LookupTable, + should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -554,6 +573,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( .permutations(non_default_fn_type_params_len); let exprs: Vec<_> = generic_params + .filter(|_| should_continue()) .filter_map(|generics| { // Insert default type params let mut g = generics.into_iter(); @@ -645,10 +665,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types +/// * `should_continue` - Function that indicates when to stop iterating pub(super) fn struct_projection<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, _defs: &'a FxHashSet, lookup: &'a mut LookupTable, + should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -656,6 +678,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>( .new_types(NewTypesKey::StructProjection) .into_iter() .map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup"))) + .filter(|_| should_continue()) .flat_map(move |(ty, targets)| { ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| { if !field.is_visible_from(db, module) { @@ -716,10 +739,12 @@ pub(super) fn famous_types<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types +/// * `should_continue` - Function that indicates when to stop iterating pub(super) fn impl_static_method<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, _defs: &'a FxHashSet, lookup: &'a mut LookupTable, + should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -728,6 +753,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( .clone() .into_iter() .chain(iter::once(ctx.goal.clone())) + .filter(|_| should_continue()) .flat_map(|ty| { Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp)) }) @@ -801,6 +827,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( .permutations(non_default_fn_type_params_len); let exprs: Vec<_> = generic_params + .filter(|_| should_continue()) .filter_map(|generics| { // Insert default type params let mut g = generics.into_iter(); @@ -884,10 +911,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( /// * `ctx` - Context for the term search /// * `defs` - Set of items in scope at term search target location /// * `lookup` - Lookup table for types +/// * `should_continue` - Function that indicates when to stop iterating pub(super) fn make_tuple<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, _defs: &'a FxHashSet, lookup: &'a mut LookupTable, + should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); @@ -896,6 +925,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>( .types_wishlist() .clone() .into_iter() + .filter(|_| should_continue()) .filter(|ty| ty.is_tuple()) .filter_map(move |ty| { // Double check to not contain unknown @@ -915,6 +945,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>( let exprs: Vec = param_exprs .into_iter() .multi_cartesian_product() + .filter(|_| should_continue()) .map(|params| { let tys: Vec = params.iter().map(|it| it.ty(db)).collect(); let tuple_ty = Type::new_tuple(module.krate().into(), &tys); diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs index fbe17dbfd7..5d76cb0432 100644 --- a/crates/ide-assists/src/assist_config.rs +++ b/crates/ide-assists/src/assist_config.rs @@ -16,4 +16,5 @@ pub struct AssistConfig { pub prefer_no_std: bool, pub prefer_prelude: bool, pub assist_emit_must_use: bool, + pub term_search_fuel: u64, } diff --git a/crates/ide-assists/src/handlers/apply_demorgan.rs b/crates/ide-assists/src/handlers/apply_demorgan.rs index 55e0d7f3b2..f178a7e0ce 100644 --- a/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -8,8 +8,7 @@ use ide_db::{ }; use syntax::{ ast::{self, make, AstNode, Expr::BinExpr, HasArgList}, - ted::{self, Position}, - SyntaxKind, + ted, SyntaxKind, T, }; use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; @@ -62,7 +61,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti let demorganed = bin_expr.clone_subtree().clone_for_update(); ted::replace(demorganed.op_token()?, ast::make::token(inv_token)); - let mut exprs = VecDeque::from(vec![ + let mut exprs = VecDeque::from([ (bin_expr.lhs()?, demorganed.lhs()?), (bin_expr.rhs()?, demorganed.rhs()?), ]); @@ -93,58 +92,38 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti } } - let dm_lhs = demorganed.lhs()?; - acc.add_group( &GroupLabel("Apply De Morgan's law".to_owned()), AssistId("apply_demorgan", AssistKind::RefactorRewrite), "Apply De Morgan's law", op_range, |edit| { + let demorganed = ast::Expr::BinExpr(demorganed); let paren_expr = bin_expr.syntax().parent().and_then(ast::ParenExpr::cast); let neg_expr = paren_expr .clone() .and_then(|paren_expr| paren_expr.syntax().parent()) .and_then(ast::PrefixExpr::cast) - .and_then(|prefix_expr| { - if prefix_expr.op_kind()? == ast::UnaryOp::Not { - Some(prefix_expr) - } else { - None - } - }); + .filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not))) + .map(ast::Expr::PrefixExpr); if let Some(paren_expr) = paren_expr { if let Some(neg_expr) = neg_expr { cov_mark::hit!(demorgan_double_negation); - edit.replace_ast(ast::Expr::PrefixExpr(neg_expr), demorganed.into()); + let parent = neg_expr.syntax().parent(); + + if parent.is_some_and(|parent| demorganed.needs_parens_in(parent)) { + cov_mark::hit!(demorgan_keep_parens_for_op_precedence2); + edit.replace_ast(neg_expr, make::expr_paren(demorganed)); + } else { + edit.replace_ast(neg_expr, demorganed); + }; } else { cov_mark::hit!(demorgan_double_parens); - ted::insert_all_raw( - Position::before(dm_lhs.syntax()), - vec![ - syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)), - syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)), - ], - ); - - ted::append_child_raw( - demorganed.syntax(), - syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::R_PAREN)), - ); - - edit.replace_ast(ast::Expr::ParenExpr(paren_expr), demorganed.into()); + edit.replace_ast(paren_expr.into(), add_bang_paren(demorganed)); } } else { - ted::insert_all_raw( - Position::before(dm_lhs.syntax()), - vec![ - syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)), - syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)), - ], - ); - ted::append_child_raw(demorganed.syntax(), ast::make::token(SyntaxKind::R_PAREN)); - edit.replace_ast(bin_expr, demorganed); + edit.replace_ast(bin_expr.into(), add_bang_paren(demorganed)); } }, ) @@ -271,6 +250,11 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) { } } +/// Add bang and parentheses to the expression. +fn add_bang_paren(expr: ast::Expr) -> ast::Expr { + make::expr_prefix(T![!], make::expr_paren(expr)) +} + #[cfg(test)] mod tests { use super::*; @@ -349,16 +333,14 @@ fn f() { !(S <= S || S < S) } check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }") } - // FIXME : This needs to go. - // // https://github.com/rust-lang/rust-analyzer/issues/10963 - // #[test] - // fn demorgan_doesnt_hang() { - // check_assist( - // apply_demorgan, - // "fn f() { 1 || 3 &&$0 4 || 5 }", - // "fn f() { !(!1 || !3 || !4) || 5 }", - // ) - // } + #[test] + fn demorgan_doesnt_hang() { + check_assist( + apply_demorgan, + "fn f() { 1 || 3 &&$0 4 || 5 }", + "fn f() { 1 || !(!3 || !4) || 5 }", + ) + } #[test] fn demorgan_keep_pars_for_op_precedence() { @@ -375,6 +357,21 @@ fn f() { !(S <= S || S < S) } ); } + #[test] + fn demorgan_keep_pars_for_op_precedence2() { + cov_mark::check!(demorgan_keep_parens_for_op_precedence2); + check_assist( + apply_demorgan, + "fn f() { (a && !(b &&$0 c); }", + "fn f() { (a && (!b || !c); }", + ); + } + + #[test] + fn demorgan_keep_pars_for_op_precedence3() { + check_assist(apply_demorgan, "fn f() { (a || !(b &&$0 c); }", "fn f() { (a || !b || !c; }"); + } + #[test] fn demorgan_removes_pars_in_eq_precedence() { check_assist( @@ -384,6 +381,11 @@ fn f() { !(S <= S || S < S) } ) } + #[test] + fn demorgan_removes_pars_for_op_precedence2() { + check_assist(apply_demorgan, "fn f() { (a || !(b ||$0 c); }", "fn f() { (a || !b && !c; }"); + } + #[test] fn demorgan_iterator_any_all_reverse() { check_assist( diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 76f021ed91..43ff115886 100644 --- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -85,7 +85,7 @@ fn edit_struct_def( strukt: &Either, record_fields: ast::RecordFieldList, ) { - // Note that we don't need to consider macro files in this function because this this is + // Note that we don't need to consider macro files in this function because this is // currently not triggered for struct definitions inside macro calls. let tuple_fields = record_fields .fields() diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 34326294d2..2b8de3443b 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -5623,7 +5623,7 @@ fn func(i: Struct<'_, T>) { fun_name(i); } -fn $0fun_name(i: Struct<'_, T>) { +fn $0fun_name(i: Struct) { foo(i); } "#, diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index db94a21a6d..0fc122d623 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -1,6 +1,6 @@ use hir::{ - Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics, Type, - TypeInfo, + Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics, + StructKind, Type, TypeInfo, }; use ide_db::{ base_db::FileId, @@ -15,8 +15,8 @@ use itertools::Itertools; use stdx::to_lower_snake_case; use syntax::{ ast::{ - self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, CallExpr, HasArgList, - HasGenericParams, HasModuleItem, HasTypeBounds, + self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr, + HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds, }, ted, SyntaxKind, SyntaxNode, TextRange, T, }; @@ -66,7 +66,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } let fn_name = &*name_ref.text(); - let TargetInfo { target_module, adt_name, target, file } = + let TargetInfo { target_module, adt_info, target, file } = fn_target_info(ctx, path, &call, fn_name)?; if let Some(m) = target_module { @@ -75,15 +75,16 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { } } - let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?; + let function_builder = + FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target, &adt_info)?; let text_range = call.syntax().text_range(); let label = format!("Generate {} function", function_builder.fn_name); - add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label) + add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_info, label) } struct TargetInfo { target_module: Option, - adt_name: Option, + adt_info: Option, target: GeneratedFunctionTarget, file: FileId, } @@ -91,11 +92,11 @@ struct TargetInfo { impl TargetInfo { fn new( target_module: Option, - adt_name: Option, + adt_info: Option, target: GeneratedFunctionTarget, file: FileId, ) -> Self { - Self { target_module, adt_name, target, file } + Self { target_module, adt_info, target, file } } } @@ -157,9 +158,9 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { target, )?; let text_range = call.syntax().text_range(); - let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; + let adt_info = AdtInfo::new(adt, impl_.is_some()); let label = format!("Generate {} method", function_builder.fn_name); - add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label) + add_func_to_accumulator(acc, ctx, text_range, function_builder, file, Some(adt_info), label) } fn add_func_to_accumulator( @@ -168,7 +169,7 @@ fn add_func_to_accumulator( text_range: TextRange, function_builder: FunctionBuilder, file: FileId, - adt_name: Option, + adt_info: Option, label: String, ) -> Option<()> { acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |edit| { @@ -177,8 +178,14 @@ fn add_func_to_accumulator( let target = function_builder.target.clone(); let func = function_builder.render(ctx.config.snippet_cap, edit); - if let Some(name) = adt_name { - let name = make::ty_path(make::ext::ident_path(&format!("{}", name.display(ctx.db())))); + if let Some(adt) = + adt_info + .and_then(|adt_info| if adt_info.impl_exists { None } else { Some(adt_info.adt) }) + { + let name = make::ty_path(make::ext::ident_path(&format!( + "{}", + adt.name(ctx.db()).display(ctx.db()) + ))); // FIXME: adt may have generic params. let impl_ = make::impl_(None, None, name, None, None).clone_for_update(); @@ -210,6 +217,7 @@ struct FunctionBuilder { generic_param_list: Option, where_clause: Option, params: ast::ParamList, + fn_body: BlockExpr, ret_type: Option, should_focus_return_type: bool, visibility: Visibility, @@ -225,6 +233,7 @@ impl FunctionBuilder { fn_name: &str, target_module: Option, target: GeneratedFunctionTarget, + adt_info: &Option, ) -> Option { let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?; @@ -243,9 +252,27 @@ impl FunctionBuilder { let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast); let is_async = await_expr.is_some(); - let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into()); - let (ret_type, should_focus_return_type) = - make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params); + let ret_type; + let should_focus_return_type; + let fn_body; + + // If generated function has the name "new" and is an associated function, we generate fn body + // as a constructor and assume a "Self" return type. + if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) { + ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self")))); + should_focus_return_type = false; + fn_body = body; + } else { + let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into()); + (ret_type, should_focus_return_type) = make_return_type( + ctx, + &expr_for_ret_ty, + target_module, + &mut necessary_generic_params, + ); + let placeholder_expr = make::ext::expr_todo(); + fn_body = make::block_expr(vec![], Some(placeholder_expr)); + }; let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; @@ -256,6 +283,7 @@ impl FunctionBuilder { generic_param_list, where_clause, params, + fn_body, ret_type, should_focus_return_type, visibility, @@ -294,12 +322,16 @@ impl FunctionBuilder { let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; + let placeholder_expr = make::ext::expr_todo(); + let fn_body = make::block_expr(vec![], Some(placeholder_expr)); + Some(Self { target, fn_name, generic_param_list, where_clause, params, + fn_body, ret_type, should_focus_return_type, visibility, @@ -308,8 +340,6 @@ impl FunctionBuilder { } fn render(self, cap: Option, edit: &mut SourceChangeBuilder) -> ast::Fn { - let placeholder_expr = make::ext::expr_todo(); - let fn_body = make::block_expr(vec![], Some(placeholder_expr)); let visibility = match self.visibility { Visibility::None => None, Visibility::Crate => Some(make::visibility_pub_crate()), @@ -321,7 +351,7 @@ impl FunctionBuilder { self.generic_param_list, self.where_clause, self.params, - fn_body, + self.fn_body, self.ret_type, self.is_async, false, // FIXME : const and unsafe are not handled yet. @@ -391,6 +421,53 @@ fn make_return_type( (ret_type, should_focus_return_type) } +fn make_fn_body_as_new_function( + ctx: &AssistContext<'_>, + fn_name: &str, + adt_info: &Option, +) -> Option { + if fn_name != "new" { + return None; + }; + let adt_info = adt_info.as_ref()?; + + let path_self = make::ext::ident_path("Self"); + let placeholder_expr = make::ext::expr_todo(); + let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() { + match strukt.kind(ctx.db()) { + StructKind::Record => { + let fields = strukt + .fields(ctx.db()) + .iter() + .map(|field| { + make::record_expr_field( + make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))), + Some(placeholder_expr.clone()), + ) + }) + .collect::>(); + + make::record_expr(path_self, make::record_expr_field_list(fields)).into() + } + StructKind::Tuple => { + let args = strukt + .fields(ctx.db()) + .iter() + .map(|_| placeholder_expr.clone()) + .collect::>(); + + make::expr_call(make::expr_path(path_self), make::arg_list(args)) + } + StructKind::Unit => make::expr_path(path_self), + } + } else { + placeholder_expr + }; + + let fn_body = make::block_expr(vec![], Some(tail_expr)); + Some(fn_body) +} + fn get_fn_target_info( ctx: &AssistContext<'_>, target_module: Option, @@ -443,8 +520,8 @@ fn assoc_fn_target_info( } let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?; let target = get_method_target(ctx, &impl_, &adt)?; - let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None }; - Some(TargetInfo::new(target_module, adt_name, target, file)) + let adt_info = AdtInfo::new(adt, impl_.is_some()); + Some(TargetInfo::new(target_module, Some(adt_info), target, file)) } #[derive(Clone)] @@ -560,6 +637,17 @@ impl GeneratedFunctionTarget { } } +struct AdtInfo { + adt: hir::Adt, + impl_exists: bool, +} + +impl AdtInfo { + fn new(adt: Adt, impl_exists: bool) -> Self { + Self { adt, impl_exists } + } +} + /// Computes parameter list for the generated function. fn fn_args( ctx: &AssistContext<'_>, @@ -2758,18 +2846,18 @@ fn main() { r" enum Foo {} fn main() { - Foo::new$0(); + Foo::bar$0(); } ", r" enum Foo {} impl Foo { - fn new() ${0:-> _} { + fn bar() ${0:-> _} { todo!() } } fn main() { - Foo::new(); + Foo::bar(); } ", ) @@ -2849,4 +2937,152 @@ fn main() { ", ); } + + #[test] + fn new_function_assume_self_type() { + check_assist( + generate_function, + r" +pub struct Foo { + field_1: usize, + field_2: String, +} + +fn main() { + let foo = Foo::new$0(); +} + ", + r" +pub struct Foo { + field_1: usize, + field_2: String, +} +impl Foo { + fn new() -> Self { + ${0:Self { field_1: todo!(), field_2: todo!() }} + } +} + +fn main() { + let foo = Foo::new(); +} + ", + ) + } + + #[test] + fn new_function_assume_self_type_for_tuple_struct() { + check_assist( + generate_function, + r" +pub struct Foo (usize, String); + +fn main() { + let foo = Foo::new$0(); +} + ", + r" +pub struct Foo (usize, String); +impl Foo { + fn new() -> Self { + ${0:Self(todo!(), todo!())} + } +} + +fn main() { + let foo = Foo::new(); +} + ", + ) + } + + #[test] + fn new_function_assume_self_type_for_unit_struct() { + check_assist( + generate_function, + r" +pub struct Foo; + +fn main() { + let foo = Foo::new$0(); +} + ", + r" +pub struct Foo; +impl Foo { + fn new() -> Self { + ${0:Self} + } +} + +fn main() { + let foo = Foo::new(); +} + ", + ) + } + + #[test] + fn new_function_assume_self_type_for_enum() { + check_assist( + generate_function, + r" +pub enum Foo {} + +fn main() { + let foo = Foo::new$0(); +} + ", + r" +pub enum Foo {} +impl Foo { + fn new() -> Self { + ${0:todo!()} + } +} + +fn main() { + let foo = Foo::new(); +} + ", + ) + } + + #[test] + fn new_function_assume_self_type_with_args() { + check_assist( + generate_function, + r#" +pub struct Foo { + field_1: usize, + field_2: String, +} + +struct Baz; +fn baz() -> Baz { Baz } + +fn main() { + let foo = Foo::new$0(baz(), baz(), "foo", "bar"); +} + "#, + r#" +pub struct Foo { + field_1: usize, + field_2: String, +} +impl Foo { + fn new(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) -> Self { + ${0:Self { field_1: todo!(), field_2: todo!() }} + } +} + +struct Baz; +fn baz() -> Baz { Baz } + +fn main() { + let foo = Foo::new(baz(), baz(), "foo", "bar"); +} + "#, + ) + } } diff --git a/crates/ide-assists/src/handlers/move_module_to_file.rs b/crates/ide-assists/src/handlers/move_module_to_file.rs index 048906d9d9..9af8411f4c 100644 --- a/crates/ide-assists/src/handlers/move_module_to_file.rs +++ b/crates/ide-assists/src/handlers/move_module_to_file.rs @@ -1,6 +1,7 @@ use std::iter; use ast::edit::IndentLevel; +use hir::HasAttrs; use ide_db::base_db::AnchoredPathBuf; use itertools::Itertools; use stdx::format_to; @@ -50,9 +51,17 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) -> |builder| { let path = { let mut buf = String::from("./"); - match parent_module.name(ctx.db()) { - Some(name) if !parent_module.is_mod_rs(ctx.db()) => { - format_to!(buf, "{}/", name.display(ctx.db())) + let db = ctx.db(); + match parent_module.name(db) { + Some(name) + if !parent_module.is_mod_rs(db) + && parent_module + .attrs(db) + .by_key("path") + .string_value_unescape() + .is_none() => + { + format_to!(buf, "{}/", name.display(db)) } _ => (), } @@ -107,6 +116,72 @@ mod tests { use super::*; + #[test] + fn extract_with_specified_path_attr() { + check_assist( + move_module_to_file, + r#" +//- /main.rs +#[path="parser/__mod.rs"] +mod parser; +//- /parser/__mod.rs +fn test() {} +mod $0expr { + struct A {} +} +"#, + r#" +//- /parser/__mod.rs +fn test() {} +mod expr; +//- /parser/expr.rs +struct A {} +"#, + ); + + check_assist( + move_module_to_file, + r#" +//- /main.rs +#[path="parser/a/__mod.rs"] +mod parser; +//- /parser/a/__mod.rs +fn test() {} +mod $0expr { + struct A {} +} +"#, + r#" +//- /parser/a/__mod.rs +fn test() {} +mod expr; +//- /parser/a/expr.rs +struct A {} +"#, + ); + + check_assist( + move_module_to_file, + r#" +//- /main.rs +#[path="a.rs"] +mod parser; +//- /a.rs +fn test() {} +mod $0expr { + struct A {} +} +"#, + r#" +//- /a.rs +fn test() {} +mod expr; +//- /expr.rs +struct A {} +"#, + ); + } + #[test] fn extract_from_root() { check_assist( diff --git a/crates/ide-assists/src/handlers/raw_string.rs b/crates/ide-assists/src/handlers/raw_string.rs index 63db606336..5a197f23d0 100644 --- a/crates/ide-assists/src/handlers/raw_string.rs +++ b/crates/ide-assists/src/handlers/raw_string.rs @@ -25,7 +25,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt if token.is_raw() { return None; } - let value = token.value()?; + let value = token.value().ok()?; let target = token.syntax().text_range(); acc.add( AssistId("make_raw_string", AssistKind::RefactorRewrite), @@ -64,7 +64,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O if !token.is_raw() { return None; } - let value = token.value()?; + let value = token.value().ok()?; let target = token.syntax().text_range(); acc.add( AssistId("make_usual_string", AssistKind::RefactorRewrite), @@ -398,12 +398,12 @@ string"###; } #[test] - fn remove_hash_doesnt_work() { + fn remove_hash_does_not_work() { check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#); } #[test] - fn remove_hash_no_hash_doesnt_work() { + fn remove_hash_no_hash_does_not_work() { check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#); } diff --git a/crates/ide-assists/src/handlers/reorder_impl_items.rs b/crates/ide-assists/src/handlers/reorder_impl_items.rs index 6666966231..cf135f83e7 100644 --- a/crates/ide-assists/src/handlers/reorder_impl_items.rs +++ b/crates/ide-assists/src/handlers/reorder_impl_items.rs @@ -77,7 +77,7 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> ast::AssocItem::MacroCall(_) => None, }; - name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value()) + name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX) }) .collect(); diff --git a/crates/ide-assists/src/handlers/replace_string_with_char.rs b/crates/ide-assists/src/handlers/replace_string_with_char.rs index 6310981ccc..a48b20acbc 100644 --- a/crates/ide-assists/src/handlers/replace_string_with_char.rs +++ b/crates/ide-assists/src/handlers/replace_string_with_char.rs @@ -25,7 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?; - let value = token.value()?; + let value = token.value().ok()?; let target = token.syntax().text_range(); if value.chars().take(2).count() != 1 { diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs index 0f4a8e3aec..d0c6ae2198 100644 --- a/crates/ide-assists/src/handlers/term_search.rs +++ b/crates/ide-assists/src/handlers/term_search.rs @@ -1,5 +1,5 @@ //! Term search assist -use hir::term_search::TermSearchCtx; +use hir::term_search::{TermSearchConfig, TermSearchCtx}; use ide_db::{ assists::{AssistId, AssistKind, GroupLabel}, famous_defs::FamousDefs, @@ -34,7 +34,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< sema: &ctx.sema, scope: &scope, goal: target_ty, - config: Default::default(), + config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() }, }; let paths = hir::term_search::term_search(&term_search_ctx); diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs index 32d6984102..3b6c951251 100644 --- a/crates/ide-assists/src/tests.rs +++ b/crates/ide-assists/src/tests.rs @@ -31,6 +31,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { prefer_no_std: false, prefer_prelude: true, assist_emit_must_use: false, + term_search_fuel: 400, }; pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { @@ -46,6 +47,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { prefer_no_std: false, prefer_prelude: true, assist_emit_must_use: false, + term_search_fuel: 400, }; pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { @@ -61,6 +63,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { prefer_no_std: false, prefer_prelude: true, assist_emit_must_use: false, + term_search_fuel: 400, }; pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 802e9bc3a8..1e31d65fdd 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -353,7 +353,7 @@ pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>) config: hir::term_search::TermSearchConfig { enable_borrowcheck: false, many_alternatives_threshold: 1, - depth: 6, + fuel: 200, }, }; let exprs = hir::term_search::term_search(&term_search_ctx); diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 3bc329ecd7..bf6747d71b 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -296,7 +296,7 @@ fn import_on_the_fly_pat_( position: SyntaxNode, potential_import_name: String, ) -> Option<()> { - let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat", ?potential_import_name) + let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat_", ?potential_import_name) .entered(); ImportScope::find_insert_use_container(&position, &ctx.sema)?; diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs index 04563fb0f4..809c305ed8 100644 --- a/crates/ide-completion/src/config.rs +++ b/crates/ide-completion/src/config.rs @@ -15,6 +15,7 @@ pub struct CompletionConfig { pub enable_self_on_the_fly: bool, pub enable_private_editable: bool, pub enable_term_search: bool, + pub term_search_fuel: u64, pub full_function_signatures: bool, pub callable: Option, pub snippet_cap: Option, diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 8b435f419c..db34beadc0 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -466,7 +466,7 @@ impl CompletionContext<'_> { cov_mark::hit!(completes_if_lifetime_without_idents); TextRange::at(self.original_token.text_range().start(), TextSize::from(1)) } - IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(), + IDENT | LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(), _ if kind.is_keyword() => self.original_token.text_range(), _ => TextRange::empty(self.position.offset), } diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index ca0424809e..7fa31e2757 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -368,7 +368,7 @@ fn render_resolution_pat( import_to_add: Option, resolution: ScopeDef, ) -> Builder { - let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered(); + let _p = tracing::span!(tracing::Level::INFO, "render_resolution_pat").entered(); use hir::ModuleDef::*; if let ScopeDef::ModuleDef(Macro(mac)) = resolution { @@ -386,7 +386,7 @@ fn render_resolution_path( import_to_add: Option, resolution: ScopeDef, ) -> Builder { - let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered(); + let _p = tracing::span!(tracing::Level::INFO, "render_resolution_path").entered(); use hir::ModuleDef::*; match resolution { @@ -494,7 +494,7 @@ fn render_resolution_simple_( import_to_add: Option, resolution: ScopeDef, ) -> Builder { - let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered(); + let _p = tracing::span!(tracing::Level::INFO, "render_resolution_simple_").entered(); let db = ctx.db(); let ctx = ctx.import_to_add(import_to_add); @@ -1730,6 +1730,51 @@ fn foo(a: A) { B { bar: a.$0 }; } ) } + #[test] + fn tuple_field_detail() { + check( + r#" +struct S(i32); + +fn f() -> i32 { + let s = S(0); + s.0$0 +} +"#, + SymbolKind::Field, + expect![[r#" + [ + CompletionItem { + label: "0", + source_range: 56..57, + delete: 56..57, + insert: "0", + kind: SymbolKind( + Field, + ), + detail: "i32", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: Some( + Exact, + ), + is_local: false, + is_item_from_trait: false, + is_item_from_notable_trait: false, + is_name_already_imported: false, + requires_import: false, + is_op_method: false, + is_private_editable: false, + postfix_match: None, + is_definite: false, + function: None, + }, + }, + ] + "#]], + ); + } + #[test] fn record_field_and_call_relevances() { check_relevance( @@ -1808,8 +1853,7 @@ fn f() { A { bar: b$0 }; } fn baz() [type] ex baz() [type] ex bar() [type] - ex A { bar: baz() }.bar [type] - ex A { bar: bar() }.bar [type] + ex A { bar: ... }.bar [type] st A [] fn f() [] "#]], @@ -1947,8 +1991,8 @@ fn main() { } "#, expect![[r#" - ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify] ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify] + ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify] lc m [local] lc t [local] lc &t [type+local] @@ -1997,8 +2041,8 @@ fn main() { } "#, expect![[r#" - ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify] ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify] + ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify] lc m [local] lc t [local] lc &mut t [type+local] diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs index f52a5f7625..9c5cb1e37d 100644 --- a/crates/ide-completion/src/render/literal.rs +++ b/crates/ide-completion/src/render/literal.rs @@ -27,7 +27,7 @@ pub(crate) fn render_variant_lit( variant: hir::Variant, path: Option, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "render_enum_variant").entered(); + let _p = tracing::span!(tracing::Level::INFO, "render_variant_lit").entered(); let db = ctx.db(); let name = local_name.unwrap_or_else(|| variant.name(db)); diff --git a/crates/ide-completion/src/render/macro_.rs b/crates/ide-completion/src/render/macro_.rs index 540cfd03d6..8b81a95abb 100644 --- a/crates/ide-completion/src/render/macro_.rs +++ b/crates/ide-completion/src/render/macro_.rs @@ -27,7 +27,7 @@ pub(crate) fn render_macro_pat( name: hir::Name, macro_: hir::Macro, ) -> Builder { - let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered(); + let _p = tracing::span!(tracing::Level::INFO, "render_macro_pat").entered(); render(ctx, false, false, false, name, macro_) } diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index 1f032c7df4..70e0aa4e9a 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -80,6 +80,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { }, snippets: Vec::new(), limit: None, + term_search_fuel: 200, }; pub(crate) fn completion_list(ra_fixture: &str) -> String { diff --git a/crates/ide-completion/src/tests/predicate.rs b/crates/ide-completion/src/tests/predicate.rs index 64a32dee3d..62eb642b3b 100644 --- a/crates/ide-completion/src/tests/predicate.rs +++ b/crates/ide-completion/src/tests/predicate.rs @@ -19,7 +19,7 @@ struct Foo<'lt, T, const C: usize> where $0 {} en Enum Enum ma makro!(…) macro_rules! makro md module - st Foo<…> Foo<'{error}, {unknown}, _> + st Foo<…> Foo<{unknown}, _> st Record Record st Tuple Tuple st Unit Unit @@ -92,7 +92,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {} en Enum Enum ma makro!(…) macro_rules! makro md module - st Foo<…> Foo<'{error}, {unknown}, _> + st Foo<…> Foo<{unknown}, _> st Record Record st Tuple Tuple st Unit Unit diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs index 66f1bff7c1..ff38c16108 100644 --- a/crates/ide-completion/src/tests/type_pos.rs +++ b/crates/ide-completion/src/tests/type_pos.rs @@ -20,8 +20,8 @@ struct Foo<'lt, T, const C: usize> { en Enum Enum ma makro!(…) macro_rules! makro md module - sp Self Foo<'{error}, {unknown}, _> - st Foo<…> Foo<'{error}, {unknown}, _> + sp Self Foo<{unknown}, _> + st Foo<…> Foo<{unknown}, _> st Record Record st Tuple Tuple st Unit Unit @@ -45,8 +45,8 @@ struct Foo<'lt, T, const C: usize>(f$0); en Enum Enum ma makro!(…) macro_rules! makro md module - sp Self Foo<'{error}, {unknown}, _> - st Foo<…> Foo<'{error}, {unknown}, _> + sp Self Foo<{unknown}, _> + st Foo<…> Foo<{unknown}, _> st Record Record st Tuple Tuple st Unit Unit diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index c0f0faba35..634277e869 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -11,8 +11,8 @@ use hir::{ Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType, Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field, Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module, - ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField, - TypeAlias, Variant, VariantDef, Visibility, + ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, + TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, }; use stdx::{format_to, impl_from}; use syntax::{ @@ -39,12 +39,13 @@ pub enum Definition { Trait(Trait), TraitAlias(TraitAlias), TypeAlias(TypeAlias), - BuiltinType(BuiltinType), SelfType(Impl), GenericParam(GenericParam), Local(Local), Label(Label), DeriveHelper(DeriveHelper), + BuiltinType(BuiltinType), + BuiltinLifetime(StaticLifetime), BuiltinAttr(BuiltinAttr), ToolModule(ToolModule), ExternCrateDecl(ExternCrateDecl), @@ -83,6 +84,7 @@ impl Definition { Definition::DeriveHelper(it) => it.derive().module(db), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) + | Definition::BuiltinLifetime(_) | Definition::TupleField(_) | Definition::ToolModule(_) => return None, }; @@ -112,6 +114,7 @@ impl Definition { Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public, Definition::Macro(_) => return None, Definition::BuiltinAttr(_) + | Definition::BuiltinLifetime(_) | Definition::ToolModule(_) | Definition::SelfType(_) | Definition::Local(_) @@ -141,6 +144,7 @@ impl Definition { Definition::Local(it) => it.name(db), Definition::GenericParam(it) => it.name(db), Definition::Label(it) => it.name(db), + Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME, Definition::BuiltinAttr(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME Definition::DeriveHelper(it) => it.name(db), @@ -174,6 +178,7 @@ impl Definition { doc_owner.docs(fd.0.db) }) } + Definition::BuiltinLifetime(StaticLifetime) => None, Definition::Local(_) => None, Definition::SelfType(impl_def) => { impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))? @@ -228,6 +233,7 @@ impl Definition { Definition::TraitAlias(it) => it.display(db).to_string(), Definition::TypeAlias(it) => it.display(db).to_string(), Definition::BuiltinType(it) => it.name().display(db).to_string(), + Definition::BuiltinLifetime(it) => it.name().display(db).to_string(), Definition::Local(it) => { let ty = it.ty(db); let ty_display = ty.display_truncated(db, None); @@ -693,6 +699,9 @@ impl NameRefClass { ) -> Option { let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime) .entered(); + if lifetime.text() == "'static" { + return Some(NameRefClass::Definition(Definition::BuiltinLifetime(StaticLifetime))); + } let parent = lifetime.syntax().parent()?; match parent.kind() { SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => { diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index c597555a3b..766bfcf4d0 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -209,8 +209,7 @@ impl ImportAssets { prefer_no_std: bool, prefer_prelude: bool, ) -> impl Iterator { - let _p = - tracing::span!(tracing::Level::INFO, "import_assets::search_for_imports").entered(); + let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_imports").entered(); self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude) } @@ -221,7 +220,7 @@ impl ImportAssets { prefer_no_std: bool, prefer_prelude: bool, ) -> impl Iterator { - let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for_relative_paths") + let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_relative_paths") .entered(); self.search_for(sema, None, prefer_no_std, prefer_prelude) } @@ -263,7 +262,7 @@ impl ImportAssets { prefer_no_std: bool, prefer_prelude: bool, ) -> impl Iterator { - let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for").entered(); + let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for").entered(); let scope = match sema.scope(&self.candidate_node) { Some(it) => it, @@ -308,7 +307,7 @@ impl ImportAssets { } fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet { - let _p = tracing::span!(tracing::Level::INFO, "import_assets::scope_definitions").entered(); + let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::scope_definitions").entered(); let mut scope_definitions = FxHashSet::default(); if let Some(scope) = sema.scope(&self.candidate_node) { scope.process_all_names(&mut |_, scope_def| { @@ -327,7 +326,7 @@ fn path_applicable_imports( scope_filter: impl Fn(ItemInNs) -> bool + Copy, ) -> FxHashSet { let _p = - tracing::span!(tracing::Level::INFO, "import_assets::path_applicable_imports").entered(); + tracing::span!(tracing::Level::INFO, "ImportAssets::path_applicable_imports").entered(); match &path_candidate.qualifier { None => { @@ -374,7 +373,7 @@ fn import_for_item( original_item: ItemInNs, scope_filter: impl Fn(ItemInNs) -> bool, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "import_assets::import_for_item").entered(); + let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::import_for_item").entered(); let [first_segment, ..] = unresolved_qualifier else { return None }; let item_as_assoc = item_as_assoc(db, original_item); @@ -508,8 +507,7 @@ fn trait_applicable_items( mod_path: impl Fn(ItemInNs) -> Option, scope_filter: impl Fn(hir::Trait) -> bool, ) -> FxHashSet { - let _p = - tracing::span!(tracing::Level::INFO, "import_assets::trait_applicable_items").entered(); + let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::trait_applicable_items").entered(); let db = sema.db; diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs index e97f1b8614..026d4e36f9 100644 --- a/crates/ide-db/src/imports/insert_use.rs +++ b/crates/ide-db/src/imports/insert_use.rs @@ -194,7 +194,7 @@ fn insert_use_with_alias_option( cfg: &InsertUseConfig, alias: Option, ) { - let _p = tracing::span!(tracing::Level::INFO, "insert_use").entered(); + let _p = tracing::span!(tracing::Level::INFO, "insert_use_with_alias_option").entered(); let mut mb = match cfg.granularity { ImportGranularity::Crate => Some(MergeBehavior::Crate), ImportGranularity::Module => Some(MergeBehavior::Module), diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs index 024e8f6ae3..58077f636b 100644 --- a/crates/ide-db/src/prime_caches.rs +++ b/crates/ide-db/src/prime_caches.rs @@ -1,6 +1,6 @@ //! rust-analyzer is lazy and doesn't compute anything unless asked. This //! sometimes is counter productive when, for example, the first goto definition -//! request takes longer to compute. This modules implemented prepopulation of +//! request takes longer to compute. This module implements prepopulation of //! various caches, it's not really advanced at the moment. mod topologic_sort; @@ -32,7 +32,7 @@ pub fn parallel_prime_caches( num_worker_threads: u8, cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync), ) { - let _p = tracing::span!(tracing::Level::INFO, "prime_caches").entered(); + let _p = tracing::span!(tracing::Level::INFO, "parallel_prime_caches").entered(); let graph = db.crate_graph(); let mut crates_to_prime = { diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 6a7042988a..288d56b534 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -196,11 +196,12 @@ impl Definition { .and_then(syn_ctx_is_root) } } - Definition::BuiltinType(_) => return None, - Definition::SelfType(_) => return None, - Definition::BuiltinAttr(_) => return None, - Definition::ToolModule(_) => return None, - Definition::TupleField(_) => return None, + Definition::BuiltinType(_) + | Definition::BuiltinLifetime(_) + | Definition::BuiltinAttr(_) + | Definition::SelfType(_) + | Definition::ToolModule(_) + | Definition::TupleField(_) => return None, // FIXME: This should be doable in theory Definition::DeriveHelper(_) => return None, }; diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index cb103313c9..8f633065f3 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -1,7 +1,7 @@ //! Implementation of find-usages functionality. //! //! It is based on the standard ide trick: first, we run a fast text search to -//! get a super-set of matches. Then, we we confirm each match using precise +//! get a super-set of matches. Then, we confirm each match using precise //! name resolution. use std::mem; diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs index c65467a432..12085f9ebd 100644 --- a/crates/ide-db/src/symbol_index.rs +++ b/crates/ide-db/src/symbol_index.rs @@ -301,8 +301,8 @@ impl SymbolIndex { } fn range_to_map_value(start: usize, end: usize) -> u64 { - debug_assert![start <= (std::u32::MAX as usize)]; - debug_assert![end <= (std::u32::MAX as usize)]; + debug_assert![start <= (u32::MAX as usize)]; + debug_assert![end <= (u32::MAX as usize)]; ((start as u64) << 32) | end as u64 } diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 241fddbb90..b3dde977b1 100644 --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -7,7 +7,7 @@ use ide_db::{ helpers::mod_path_to_ast, imports::insert_use::{insert_use, ImportScope}, source_change::SourceChangeBuilder, - RootDatabase, + FxHashMap, RootDatabase, }; use itertools::Itertools; use stdx::{format_to, never}; @@ -22,15 +22,22 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity}; #[derive(Default)] struct State { result: String, - struct_counts: usize, has_serialize: bool, has_deserialize: bool, + names: FxHashMap, } impl State { - fn generate_new_name(&mut self) -> ast::Name { - self.struct_counts += 1; - make::name(&format!("Struct{}", self.struct_counts)) + fn generate_new_name(&mut self, name: &str) -> ast::Name { + let name = stdx::to_camel_case(name); + let count = if let Some(count) = self.names.get_mut(&name) { + *count += 1; + *count + } else { + self.names.insert(name.clone(), 1); + 1 + }; + make::name(&format!("{}{}", name, count)) } fn serde_derive(&self) -> String { @@ -52,15 +59,21 @@ impl State { } } - fn build_struct(&mut self, value: &serde_json::Map) -> ast::Type { - let name = self.generate_new_name(); + fn build_struct( + &mut self, + name: &str, + value: &serde_json::Map, + ) -> ast::Type { + let name = self.generate_new_name(name); let ty = make::ty(&name.to_string()); let strukt = make::struct_( None, name, None, make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map( - |(name, value)| make::record_field(None, make::name(name), self.type_of(value)), + |(name, value)| { + make::record_field(None, make::name(name), self.type_of(name, value)) + }, )) .into(), ); @@ -68,7 +81,7 @@ impl State { ty } - fn type_of(&mut self, value: &serde_json::Value) -> ast::Type { + fn type_of(&mut self, name: &str, value: &serde_json::Value) -> ast::Type { match value { serde_json::Value::Null => make::ty_unit(), serde_json::Value::Bool(_) => make::ty("bool"), @@ -76,12 +89,12 @@ impl State { serde_json::Value::String(_) => make::ty("String"), serde_json::Value::Array(it) => { let ty = match it.iter().next() { - Some(x) => self.type_of(x), + Some(x) => self.type_of(name, x), None => make::ty_placeholder(), }; make::ty(&format!("Vec<{ty}>")) } - serde_json::Value::Object(x) => self.build_struct(x), + serde_json::Value::Object(x) => self.build_struct(name, x), } } } @@ -113,7 +126,7 @@ pub(crate) fn json_in_items( let serialize_resolved = scope_resolve("::serde::Serialize"); state.has_deserialize = deserialize_resolved.is_some(); state.has_serialize = serialize_resolved.is_some(); - state.build_struct(&it); + state.build_struct("Root", &it); edit.insert(range.start(), state.result); acc.push( Diagnostic::new( @@ -218,7 +231,7 @@ mod tests { } #[derive(Serialize)] - struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String } + struct Root1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String } "#, ); @@ -237,9 +250,44 @@ mod tests { } "#, r#" - struct Struct3{ } - struct Struct2{ kind: String, value: Struct3 } - struct Struct1{ bar: Struct2, foo: String } + struct Value1{ } + struct Bar1{ kind: String, value: Value1 } + struct Root1{ bar: Bar1, foo: String } + + "#, + ); + } + + #[test] + fn naming() { + check_fix( + r#" + {$0 + "user": { + "address": { + "street": "Main St", + "house": 3 + }, + "email": "example@example.com" + }, + "another_user": { + "user": { + "address": { + "street": "Main St", + "house": 3 + }, + "email": "example@example.com" + } + } + } + "#, + r#" + struct Address1{ house: i64, street: String } + struct User1{ address: Address1, email: String } + struct AnotherUser1{ user: User1 } + struct Address2{ house: i64, street: String } + struct User2{ address: Address2, email: String } + struct Root1{ another_user: AnotherUser1, user: User2 } "#, ); @@ -276,9 +324,9 @@ mod tests { use serde::Deserialize; #[derive(Serialize, Deserialize)] - struct Struct2{ x: i64, y: i64 } + struct OfObject1{ x: i64, y: i64 } #[derive(Serialize, Deserialize)] - struct Struct1{ empty: Vec<_>, nested: Vec>>, of_object: Vec, of_string: Vec } + struct Root1{ empty: Vec<_>, nested: Vec>>, of_object: Vec, of_string: Vec } "#, ); diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index 8d77e566ed..5a3206445c 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics}; +use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId}; use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase}; use syntax::{ ast::{self, edit::IndentLevel, make}, @@ -25,7 +25,10 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) } else { Diagnostic::new_with_syntax_node_ptr( ctx, - DiagnosticCode::RustcHardError("E0559"), + match d.variant { + VariantId::EnumVariantId(_) => DiagnosticCode::RustcHardError("E0559"), + _ => DiagnosticCode::RustcHardError("E0560"), + }, "no such field", node, ) diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs index 56c8181e84..656d79dc73 100644 --- a/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -1,6 +1,6 @@ use hir::{ db::ExpandDatabase, - term_search::{term_search, TermSearchCtx}, + term_search::{term_search, TermSearchConfig, TermSearchCtx}, ClosureStyle, HirDisplay, }; use ide_db::{ @@ -47,7 +47,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option sema: &ctx.sema, scope: &scope, goal: d.expected.clone(), - config: Default::default(), + config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() }, }; let paths = term_search(&term_search_ctx); @@ -274,7 +274,7 @@ impl Foo for Baz { } fn asd() -> Bar { let a = Baz; - Foo::foo(a) + Foo::foo(_) } ", ); @@ -363,7 +363,7 @@ impl Foo for A { } fn main() { let a = A; - let c: Bar = Foo::foo(&a); + let c: Bar = Foo::foo(_); }"#, ); } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index c3ced36a69..15543a5d65 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -232,6 +232,7 @@ pub struct DiagnosticsConfig { pub insert_use: InsertUseConfig, pub prefer_no_std: bool, pub prefer_prelude: bool, + pub term_search_fuel: u64, } impl DiagnosticsConfig { @@ -256,6 +257,7 @@ impl DiagnosticsConfig { }, prefer_no_std: false, prefer_prelude: true, + term_search_fuel: 400, } } } @@ -297,11 +299,10 @@ pub fn diagnostics( ) -> Vec { let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered(); let sema = Semantics::new(db); - let parse = db.parse(file_id); let mut res = Vec::new(); // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. - res.extend(parse.errors().into_iter().take(128).map(|err| { + res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| { Diagnostic::new( DiagnosticCode::RustcHardError("syntax-error"), format!("Syntax Error: {err}"), @@ -340,7 +341,8 @@ pub fn diagnostics( AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d), AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), AnyDiagnostic::MacroExpansionParseError(d) => { - res.extend(d.errors.iter().take(32).map(|err| { + // FIXME: Point to the correct error span here, not just the macro-call name + res.extend(d.errors.iter().take(16).map(|err| { { Diagnostic::new( DiagnosticCode::RustcHardError("syntax-error"), diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index bb5c2b7913..cd5e95cc1e 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -293,6 +293,7 @@ fn minicore_smoke_test() { // This should be ignored since we conditionally remove code which creates single item use with braces config.disabled.insert("unused_braces".to_owned()); config.disabled.insert("unused_variables".to_owned()); + config.disabled.insert("remove-unnecessary-else".to_owned()); check_diagnostics_with_config(config, &source); } diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 64b4ccc5bd..8d765dfc91 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -214,8 +214,9 @@ pub(crate) fn resolve_doc_path_for_def( Definition::SelfType(it) => it.resolve_doc_path(db, link, ns), Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns), Definition::BuiltinAttr(_) - | Definition::ToolModule(_) | Definition::BuiltinType(_) + | Definition::BuiltinLifetime(_) + | Definition::ToolModule(_) | Definition::TupleField(_) | Definition::Local(_) | Definition::GenericParam(_) @@ -648,6 +649,7 @@ fn filename_and_frag_for_def( | Definition::TupleField(_) | Definition::Label(_) | Definition::BuiltinAttr(_) + | Definition::BuiltinLifetime(_) | Definition::ToolModule(_) | Definition::DeriveHelper(_) => return None, }; diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index e2d629a02f..1ead045788 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -76,8 +76,6 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< return derive; } - // FIXME: Intermix attribute and bang! expansions - // currently we only recursively expand one of the two types let mut anc = tok.parent_ancestors(); let (name, expanded, kind) = loop { let node = anc.next()?; @@ -86,7 +84,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< if let Some(def) = sema.resolve_attr_macro_call(&item) { break ( def.name(db).display(db).to_string(), - expand_attr_macro_recur(&sema, &item)?, + expand_macro_recur(&sema, &item)?, SyntaxKind::MACRO_ITEMS, ); } @@ -94,11 +92,9 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< if let Some(mac) = ast::MacroCall::cast(node) { let mut name = mac.path()?.segment()?.name_ref()?.to_string(); name.push('!'); - break ( - name, - expand_macro_recur(&sema, &mac)?, - mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS), - ); + let syntax_kind = + mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS); + break (name, expand_macro_recur(&sema, &ast::Item::MacroCall(mac))?, syntax_kind); } }; @@ -112,31 +108,23 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< fn expand_macro_recur( sema: &Semantics<'_, RootDatabase>, - macro_call: &ast::MacroCall, + macro_call: &ast::Item, ) -> Option { - let expanded = sema.expand(macro_call)?.clone_for_update(); - expand(sema, expanded, ast::MacroCall::cast, expand_macro_recur) + let expanded = match macro_call { + item @ ast::Item::MacroCall(macro_call) => { + sema.expand_attr_macro(item).or_else(|| sema.expand(macro_call))?.clone_for_update() + } + item => sema.expand_attr_macro(item)?.clone_for_update(), + }; + expand(sema, expanded) } -fn expand_attr_macro_recur( - sema: &Semantics<'_, RootDatabase>, - item: &ast::Item, -) -> Option { - let expanded = sema.expand_attr_macro(item)?.clone_for_update(); - expand(sema, expanded, ast::Item::cast, expand_attr_macro_recur) -} - -fn expand( - sema: &Semantics<'_, RootDatabase>, - expanded: SyntaxNode, - f: impl FnMut(SyntaxNode) -> Option, - exp: impl Fn(&Semantics<'_, RootDatabase>, &T) -> Option, -) -> Option { - let children = expanded.descendants().filter_map(f); +fn expand(sema: &Semantics<'_, RootDatabase>, expanded: SyntaxNode) -> Option { + let children = expanded.descendants().filter_map(ast::Item::cast); let mut replacements = Vec::new(); for child in children { - if let Some(new_node) = exp(sema, &child) { + if let Some(new_node) = expand_macro_recur(sema, &child) { // check if the whole original syntax is replaced if expanded == *child.syntax() { return Some(new_node); diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index ddeeca5f7b..76b80fcefa 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -123,7 +123,7 @@ fn try_lookup_include_path( { return None; } - let path = token.value()?; + let path = token.value().ok()?; let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?; let size = sema.db.file_text(file_id).len().try_into().ok()?; @@ -179,11 +179,11 @@ fn try_filter_trait_item_definition( AssocItem::Const(..) | AssocItem::TypeAlias(..) => { let trait_ = assoc.implemented_trait(db)?; let name = def.name(db)?; - let discri_value = discriminant(&assoc); + let discriminant_value = discriminant(&assoc); trait_ .items(db) .iter() - .filter(|itm| discriminant(*itm) == discri_value) + .filter(|itm| discriminant(*itm) == discriminant_value) .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) .map(|it| it.collect()) } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 95de3c88c8..bdb56081c3 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -15,7 +15,7 @@ use ide_db::{ FxIndexSet, RootDatabase, }; use itertools::{multizip, Itertools}; -use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T}; +use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T}; use crate::{ doc_links::token_as_doc_comment, @@ -33,7 +33,8 @@ pub struct HoverConfig { pub keywords: bool, pub format: HoverDocFormat, pub max_trait_assoc_items_count: Option, - pub max_struct_field_count: Option, + pub max_fields_count: Option, + pub max_enum_variants_count: Option, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -297,61 +298,8 @@ fn hover_simple( }) // tokens .or_else(|| { - let mut res = HoverResult::default(); - match_ast! { - match original_token { - ast::String(string) => { - res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?)); - }, - ast::ByteString(string) => { - res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?)); - }, - ast::CString(string) => { - let val = string.value()?; - res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?)); - }, - ast::Char(char) => { - let mut res = HoverResult::default(); - res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?)); - }, - ast::Byte(byte) => { - res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?)); - }, - ast::FloatNumber(num) => { - res.markup = if num.suffix() == Some("f32") { - match num.value_f32() { - Ok(num) => { - Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits())) - }, - Err(e) => { - Markup::fenced_block_text(format_args!("{e}")) - }, - } - } else { - match num.value() { - Ok(num) => { - Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits())) - }, - Err(e) => { - Markup::fenced_block_text(format_args!("{e}")) - }, - } - }; - }, - ast::IntNumber(num) => { - res.markup = match num.value() { - Ok(num) => { - Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0b{num:b})")) - }, - Err(e) => { - Markup::fenced_block_text(format_args!("{e}")) - }, - }; - }, - _ => return None - } - } - Some(res) + render::literal(sema, original_token.clone()) + .map(|markup| HoverResult { markup, actions: vec![] }) }); result.map(|mut res: HoverResult| { diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 3f0fc85134..3bc17f95e7 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -17,11 +17,7 @@ use ide_db::{ }; use itertools::Itertools; use stdx::format_to; -use syntax::{ - algo, - ast::{self, RecordPat}, - match_ast, AstNode, Direction, SyntaxToken, T, -}; +use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T}; use crate::{ doc_links::{remove_links, rewrite_links}, @@ -276,7 +272,7 @@ pub(super) fn keyword( pub(super) fn struct_rest_pat( sema: &Semantics<'_, RootDatabase>, _config: &HoverConfig, - pattern: &RecordPat, + pattern: &ast::RecordPat, ) -> HoverResult { let missing_fields = sema.record_pattern_missing_fields(pattern); @@ -411,8 +407,21 @@ pub(super) fn definition( Definition::Trait(trait_) => { trait_.display_limited(db, config.max_trait_assoc_items_count).to_string() } - Definition::Adt(Adt::Struct(struct_)) => { - struct_.display_limited(db, config.max_struct_field_count).to_string() + Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => { + adt.display_limited(db, config.max_fields_count).to_string() + } + Definition::Variant(variant) => { + variant.display_limited(db, config.max_fields_count).to_string() + } + Definition::Adt(adt @ Adt::Enum(_)) => { + adt.display_limited(db, config.max_enum_variants_count).to_string() + } + Definition::SelfType(impl_def) => { + let self_ty = &impl_def.self_ty(db); + match self_ty.as_adt() { + Some(adt) => adt.display_limited(db, config.max_fields_count).to_string(), + None => self_ty.display(db).to_string(), + } } Definition::Macro(it) => { let mut label = it.display(db).to_string(); @@ -513,6 +522,60 @@ pub(super) fn definition( markup(docs.map(Into::into), desc, mod_path) } +pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { + let lit = token.parent().and_then(ast::Literal::cast)?; + let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) { + sema.type_of_pat(&p)? + } else { + sema.type_of_expr(&ast::Expr::Literal(lit))? + } + .original; + + let value = match_ast! { + match token { + ast::String(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string), + ast::ByteString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("{it:?}")), + ast::CString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| std::str::from_utf8(it).map_or_else(|e| format!("{e:?}"), ToOwned::to_owned)), + ast::Char(char) => char .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string), + ast::Byte(byte) => byte .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")), + ast::FloatNumber(num) => { + let (text, _) = num.split_into_parts(); + let text = text.replace('_', ""); + if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) { + match text.parse::() { + Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), + Err(e) => Err(e.to_string()), + } + } else { + match text.parse::() { + Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), + Err(e) => Err(e.to_string()), + } + } + }, + ast::IntNumber(num) => match num.value() { + Ok(num) => Ok(format!("{num} (0x{num:X}|0b{num:b})")), + Err(e) => Err(e.to_string()), + }, + _ => return None + } + }; + let ty = ty.display(sema.db); + + let mut s = format!("```rust\n{ty}\n```\n___\n\n"); + match value { + Ok(value) => { + if let Some(newline) = value.find('\n') { + format_to!(s, "value of literal (truncated up to newline): {}", &value[..newline]) + } else { + format_to!(s, "value of literal: {value}") + } + } + Err(error) => format_to!(s, "invalid literal: {error}"), + } + Some(s.into()) +} + fn render_notable_trait_comment( db: &RootDatabase, notable_traits: &[(Trait, Vec<(Option, Name)>)], @@ -693,15 +756,7 @@ fn closure_ty( } fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { - if matches!( - def, - Definition::GenericParam(_) - | Definition::BuiltinType(_) - | Definition::Local(_) - | Definition::Label(_) - | Definition::BuiltinAttr(_) - | Definition::ToolModule(_) - ) { + if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) { return None; } def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 6bbc8b380d..20d07bf991 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -18,7 +18,8 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { format: HoverDocFormat::Markdown, keywords: true, max_trait_assoc_items_count: None, - max_struct_field_count: None, + max_fields_count: Some(5), + max_enum_variants_count: Some(5), }; fn check_hover_no_result(ra_fixture: &str) { @@ -51,13 +52,43 @@ fn check(ra_fixture: &str, expect: Expect) { } #[track_caller] -fn check_hover_struct_limit(count: usize, ra_fixture: &str, expect: Expect) { +fn check_hover_fields_limit( + fields_count: impl Into>, + ra_fixture: &str, + expect: Expect, +) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( &HoverConfig { links_in_hover: true, - max_struct_field_count: Some(count), + max_fields_count: fields_count.into(), + ..HOVER_BASE_CONFIG + }, + FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + ) + .unwrap() + .unwrap(); + + let content = analysis.db.file_text(position.file_id); + let hovered_element = &content[hover.range]; + + let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); + expect.assert_eq(&actual) +} + +#[track_caller] +fn check_hover_enum_variants_limit( + variants_count: impl Into>, + ra_fixture: &str, + expect: Expect, +) { + let (analysis, position) = fixture::position(ra_fixture); + let hover = analysis + .hover( + &HoverConfig { + links_in_hover: true, + max_enum_variants_count: variants_count.into(), ..HOVER_BASE_CONFIG }, FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, @@ -876,7 +907,9 @@ struct Foo$0 { field: u32 } ```rust // size = 4, align = 4 - struct Foo + struct Foo { + field: u32, + } ``` "#]], ); @@ -896,6 +929,9 @@ struct Foo$0 where u32: Copy { field: u32 } struct Foo where u32: Copy, + { + field: u32, + } ``` "#]], ); @@ -903,7 +939,7 @@ struct Foo$0 where u32: Copy { field: u32 } #[test] fn hover_record_struct_limit() { - check_hover_struct_limit( + check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32, b: i32, c: i32 } @@ -917,7 +953,7 @@ fn hover_record_struct_limit() { ```rust // size = 12 (0xC), align = 4 - struct Foo { + struct Foo { a: u32, b: i32, c: i32, @@ -925,7 +961,7 @@ fn hover_record_struct_limit() { ``` "#]], ); - check_hover_struct_limit( + check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32 } @@ -939,13 +975,13 @@ fn hover_record_struct_limit() { ```rust // size = 4, align = 4 - struct Foo { + struct Foo { a: u32, } ``` "#]], ); - check_hover_struct_limit( + check_hover_fields_limit( 3, r#" struct Foo$0 { a: u32, b: i32, c: i32, d: u32 } @@ -959,7 +995,7 @@ fn hover_record_struct_limit() { ```rust // size = 16 (0x10), align = 4 - struct Foo { + struct Foo { a: u32, b: i32, c: i32, @@ -968,6 +1004,338 @@ fn hover_record_struct_limit() { ``` "#]], ); + check_hover_fields_limit( + None, + r#" + struct Foo$0 { a: u32, b: i32, c: i32 } + "#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 12 (0xC), align = 4 + struct Foo + ``` + "#]], + ); + check_hover_fields_limit( + 0, + r#" + struct Foo$0 { a: u32, b: i32, c: i32 } + "#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 12 (0xC), align = 4 + struct Foo { /* … */ } + ``` + "#]], + ); + + // No extra spaces within `{}` when there are no fields + check_hover_fields_limit( + 5, + r#" + struct Foo$0 {} + "#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 0, align = 1 + struct Foo {} + ``` + "#]], + ); +} + +#[test] +fn hover_record_variant_limit() { + check_hover_fields_limit( + 3, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 12 (0xC), align = 4 + A { a: u32, b: i32, c: i32, } + ``` + "#]], + ); + check_hover_fields_limit( + 3, + r#" + enum Foo { A$0 { a: u32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 4, align = 4 + A { a: u32, } + ``` + "#]], + ); + check_hover_fields_limit( + 3, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32, d: u32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 16 (0x10), align = 4 + A { a: u32, b: i32, c: i32, /* … */ } + ``` + "#]], + ); + check_hover_fields_limit( + None, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 12 (0xC), align = 4 + A + ``` + "#]], + ); + check_hover_fields_limit( + 0, + r#" + enum Foo { A$0 { a: u32, b: i32, c: i32 } } + "#, + expect![[r#" + *A* + + ```rust + test::Foo + ``` + + ```rust + // size = 12 (0xC), align = 4 + A { /* … */ } + ``` + "#]], + ); +} + +#[test] +fn hover_enum_limit() { + check_hover_enum_variants_limit( + 5, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo { + A, + B, + } + ``` + "#]], + ); + check_hover_enum_variants_limit( + 1, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo { + A, + /* … */ + } + ``` + "#]], + ); + check_hover_enum_variants_limit( + 0, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo { /* … */ } + ``` + "#]], + ); + check_hover_enum_variants_limit( + None, + r#"enum Foo$0 { A, B }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 1, align = 1, niches = 254 + enum Foo + ``` + "#]], + ); + check_hover_enum_variants_limit( + 7, + r#"enum Enum$0 { + Variant {}, + Variant2 { field: i32 }, + Variant3 { field: i32, field2: i32 }, + Variant4(), + Variant5(i32), + Variant6(i32, i32), + Variant7, + Variant8, + }"#, + expect![[r#" + *Enum* + + ```rust + test + ``` + + ```rust + // size = 12 (0xC), align = 4, niches = 4294967288 + enum Enum { + Variant {}, + Variant2 { /* … */ }, + Variant3 { /* … */ }, + Variant4(), + Variant5( /* … */ ), + Variant6( /* … */ ), + Variant7, + /* … */ + } + ``` + "#]], + ); +} + +#[test] +fn hover_union_limit() { + check_hover_fields_limit( + 5, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo { + a: u32, + b: i32, + } + ``` + "#]], + ); + check_hover_fields_limit( + 1, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo { + a: u32, + /* … */ + } + ``` + "#]], + ); + check_hover_fields_limit( + 0, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo { /* … */ } + ``` + "#]], + ); + check_hover_fields_limit( + None, + r#"union Foo$0 { a: u32, b: i32 }"#, + expect![[r#" + *Foo* + + ```rust + test + ``` + + ```rust + // size = 4, align = 4 + union Foo + ``` + "#]], + ); } #[test] @@ -1431,11 +1799,14 @@ impl Thing { ``` ```rust - struct Thing + struct Thing { + x: u32, + } ``` "#]], ); - check( + check_hover_fields_limit( + None, r#" struct Thing { x: u32 } impl Thing { @@ -1456,9 +1827,9 @@ impl Thing { ); check( r#" -enum Thing { A } +struct Thing { x: u32 } impl Thing { - pub fn new() -> Self$0 { Thing::A } + fn new() -> Self$0 { Self { x: 0 } } } "#, expect![[r#" @@ -1469,8 +1840,8 @@ impl Thing { ``` ```rust - enum Thing { - A, + struct Thing { + x: u32, } ``` "#]], @@ -1478,23 +1849,44 @@ impl Thing { check( r#" enum Thing { A } +impl Thing { + pub fn new() -> Self$0 { Thing::A } +} +"#, + expect![[r#" + *Self* + + ```rust + test + ``` + + ```rust + enum Thing { + A, + } + ``` + "#]], + ); + check( + r#" +enum Thing { A } impl Thing { pub fn thing(a: Self$0) {} } "#, expect![[r#" - *Self* + *Self* - ```rust - test - ``` + ```rust + test + ``` - ```rust - enum Thing { - A, - } - ``` - "#]], + ```rust + enum Thing { + A, + } + ``` + "#]], ); check( r#" @@ -2382,8 +2774,8 @@ fn test_hover_layout_of_enum() { ```rust // size = 16 (0x10), align = 8, niches = 254 enum Foo { - Variant1(u8, u16), - Variant2(i32, u8, i64), + Variant1( /* … */ ), + Variant2( /* … */ ), } ``` "#]], @@ -4049,7 +4441,7 @@ fn foo() { ```rust 'label ``` - "#]], + "#]], ); } @@ -4063,7 +4455,17 @@ fn hover_lifetime() { ```rust 'lifetime ``` - "#]], + "#]], + ); + check( + r#"fn foo(_: &'static$0 ()) {}"#, + expect![[r#" + *'static* + + ```rust + 'static + ``` + "#]], ); } @@ -6554,7 +6956,7 @@ enum Enum { ```rust // size = 4, align = 4 - RecordV { field: u32 } + RecordV { field: u32, } ``` "#]], ); @@ -7398,9 +7800,12 @@ fn main() { "#, expect![[r#" *"🦀\u{1f980}\\\x41"* - ```text - 🦀🦀\A + ```rust + &str ``` + ___ + + value of literal: 🦀🦀\A "#]], ); check( @@ -7411,9 +7816,34 @@ fn main() { "#, expect![[r#" *r"🦀\u{1f980}\\\x41"* - ```text - 🦀\u{1f980}\\\x41 + ```rust + &str ``` + ___ + + value of literal: 🦀\u{1f980}\\\x41 + "#]], + ); + check( + r#" +fn main() { + $0r"🦀\u{1f980}\\\x41 + + +fsdghs"; +} +"#, + expect![[r#" + *r"🦀\u{1f980}\\\x41 + + + fsdghs"* + ```rust + &str + ``` + ___ + + value of literal (truncated up to newline): 🦀\u{1f980}\\\x41 "#]], ); } @@ -7428,9 +7858,12 @@ fn main() { "#, expect![[r#" *c"🦀\u{1f980}\\\x41"* - ```text - 🦀🦀\A + ```rust + &{unknown} ``` + ___ + + value of literal: 🦀🦀\A "#]], ); } @@ -7445,9 +7878,12 @@ fn main() { "#, expect![[r#" *b"\xF0\x9F\xA6\x80\\"* - ```text - [240, 159, 166, 128, 92] + ```rust + &[u8; 5] ``` + ___ + + value of literal: [240, 159, 166, 128, 92] "#]], ); check( @@ -7458,9 +7894,12 @@ fn main() { "#, expect![[r#" *br"\xF0\x9F\xA6\x80\\"* - ```text - [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] + ```rust + &[u8; 18] ``` + ___ + + value of literal: [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] "#]], ); } @@ -7475,9 +7914,12 @@ fn main() { "#, expect![[r#" *b'\xF0'* - ```text - 0xF0 + ```rust + u8 ``` + ___ + + value of literal: 0xF0 "#]], ); check( @@ -7488,9 +7930,12 @@ fn main() { "#, expect![[r#" *b'\\'* - ```text - 0x5C + ```rust + u8 ``` + ___ + + value of literal: 0x5C "#]], ); } @@ -7505,7 +7950,12 @@ fn main() { "#, expect![[r#" *'\x41'* + ```rust + char + ``` + ___ + value of literal: A "#]], ); check( @@ -7516,7 +7966,12 @@ fn main() { "#, expect![[r#" *'\\'* + ```rust + char + ``` + ___ + value of literal: \ "#]], ); check( @@ -7527,7 +7982,12 @@ fn main() { "#, expect![[r#" *'\u{1f980}'* + ```rust + char + ``` + ___ + value of literal: 🦀 "#]], ); } @@ -7542,9 +8002,12 @@ fn main() { "#, expect![[r#" *1.0* - ```text - 1 (bits: 0x3FF0000000000000) + ```rust + f64 ``` + ___ + + value of literal: 1 (bits: 0x3FF0000000000000) "#]], ); check( @@ -7555,9 +8018,12 @@ fn main() { "#, expect![[r#" *1.0f32* - ```text - 1 (bits: 0x3F800000) + ```rust + f32 ``` + ___ + + value of literal: 1 (bits: 0x3F800000) "#]], ); check( @@ -7568,9 +8034,12 @@ fn main() { "#, expect![[r#" *134e12* - ```text - 134000000000000 (bits: 0x42DE77D399980000) + ```rust + f64 ``` + ___ + + value of literal: 134000000000000 (bits: 0x42DE77D399980000) "#]], ); check( @@ -7581,9 +8050,12 @@ fn main() { "#, expect![[r#" *1523527134274733643531312.0* - ```text - 1523527134274733600000000 (bits: 0x44F429E9249F629B) + ```rust + f64 ``` + ___ + + value of literal: 1523527134274733600000000 (bits: 0x44F429E9249F629B) "#]], ); check( @@ -7594,9 +8066,12 @@ fn main() { "#, expect![[r#" *0.1ea123* - ```text - invalid float literal + ```rust + f64 ``` + ___ + + invalid literal: invalid float literal "#]], ); } @@ -7611,9 +8086,12 @@ fn main() { "#, expect![[r#" *34325236457856836345234* - ```text - 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) + ```rust + i32 ``` + ___ + + value of literal: 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) "#]], ); check( @@ -7624,9 +8102,12 @@ fn main() { "#, expect![[r#" *134_123424_21* - ```text - 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) + ```rust + i32 ``` + ___ + + value of literal: 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) "#]], ); check( @@ -7637,9 +8118,12 @@ fn main() { "#, expect![[r#" *0x12423423* - ```text - 306328611 (0x12423423|0b10010010000100011010000100011) + ```rust + i32 ``` + ___ + + value of literal: 306328611 (0x12423423|0b10010010000100011010000100011) "#]], ); check( @@ -7650,9 +8134,12 @@ fn main() { "#, expect![[r#" *0b1111_1111* - ```text - 255 (0xFF|0b11111111) + ```rust + i32 ``` + ___ + + value of literal: 255 (0xFF|0b11111111) "#]], ); check( @@ -7663,9 +8150,12 @@ fn main() { "#, expect![[r#" *0o12345* - ```text - 5349 (0x14E5|0b1010011100101) + ```rust + i32 ``` + ___ + + value of literal: 5349 (0x14E5|0b1010011100101) "#]], ); check( @@ -7676,9 +8166,12 @@ fn main() { "#, expect![[r#" *0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F* - ```text - number too large to fit in target type + ```rust + i32 ``` + ___ + + invalid literal: number too large to fit in target type "#]], ); } @@ -7864,8 +8357,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 6290..6498, - focus_range: 6355..6361, + full_range: 7791..7999, + focus_range: 7856..7862, name: "Future", kind: Trait, container_name: "future", @@ -7878,8 +8371,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 7128..7594, - focus_range: 7172..7180, + full_range: 8629..9095, + focus_range: 8673..8681, name: "Iterator", kind: Trait, container_name: "iterator", @@ -7936,7 +8429,9 @@ struct Pedro$0<'a> { ```rust // size = 16 (0x10), align = 8, niches = 1 - struct Pedro<'a> + struct Pedro<'a> { + hola: &str, + } ``` "#]], ) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 15eecd1b54..dda5a005a7 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -496,7 +496,7 @@ pub(crate) fn inlay_hints_resolve( config: &InlayHintsConfig, hasher: impl Fn(&InlayHint) -> u64, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered(); + let _p = tracing::span!(tracing::Level::INFO, "inlay_hints_resolve").entered(); let sema = Semantics::new(db); let file = sema.parse(file_id); let file = file.syntax(); diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 07b9f9cc1f..0cb8c485b2 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -331,6 +331,25 @@ fn main(a: SliceIter<'_, Container>) { ); } + #[test] + fn lt_hints() { + check_types( + r#" +struct S<'lt>; + +fn f<'a>() { + let x = S::<'static>; + //^ S<'static> + let y = S::<'_>; + //^ S + let z = S::<'a>; + //^ S<'a> + +} +"#, + ); + } + #[test] fn fn_hints() { check_types( @@ -341,7 +360,7 @@ fn foo1() -> impl Fn(f64) { loop {} } fn foo2() -> impl Fn(f64, f64) { loop {} } fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } -fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } +fn foo5() -> &'static for<'a> dyn Fn(&'a dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 08760c0d88..68854c33ce 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -211,6 +211,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati } } Definition::BuiltinType(..) => Type, + Definition::BuiltinLifetime(_) => TypeParameter, Definition::SelfType(..) => TypeAlias, Definition::GenericParam(..) => TypeParameter, Definition::Local(it) => { @@ -316,6 +317,7 @@ pub(crate) fn def_to_moniker( Definition::GenericParam(_) | Definition::Label(_) | Definition::DeriveHelper(_) + | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_) | Definition::ToolModule(_) => return None, diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 2123c98605..fc836d5540 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -235,9 +235,11 @@ impl TryToNav for Definition { Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?), - Definition::BuiltinType(_) | Definition::TupleField(_) => None, - Definition::ToolModule(_) => None, - Definition::BuiltinAttr(_) => None, + Definition::BuiltinLifetime(_) + | Definition::BuiltinType(_) + | Definition::TupleField(_) + | Definition::ToolModule(_) + | Definition::BuiltinAttr(_) => None, // FIXME: The focus range should be set to the helper declaration Definition::DeriveHelper(it) => it.derive().try_to_nav(db), } diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index b6c6753755..64ffa59101 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -15,6 +15,7 @@ use ide_db::{ FxHashMap, FxHashSet, RootDatabase, SymbolKind, }; use itertools::Itertools; +use span::TextSize; use stdx::{always, format_to}; use syntax::{ ast::{self, AstNode}, @@ -48,16 +49,15 @@ impl fmt::Display for TestId { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum RunnableKind { - Test { test_id: TestId, attr: TestAttr }, TestMod { path: String }, + Test { test_id: TestId, attr: TestAttr }, Bench { test_id: TestId }, DocTest { test_id: TestId }, Bin, } -#[cfg(test)] -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -enum RunnableTestKind { +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +enum RunnableDiscKind { Test, TestMod, DocTest, @@ -65,6 +65,18 @@ enum RunnableTestKind { Bin, } +impl RunnableKind { + fn disc(&self) -> RunnableDiscKind { + match self { + RunnableKind::TestMod { .. } => RunnableDiscKind::TestMod, + RunnableKind::Test { .. } => RunnableDiscKind::Test, + RunnableKind::DocTest { .. } => RunnableDiscKind::DocTest, + RunnableKind::Bench { .. } => RunnableDiscKind::Bench, + RunnableKind::Bin => RunnableDiscKind::Bin, + } + } +} + impl Runnable { // test package::module::testname pub fn label(&self, target: Option) -> String { @@ -97,17 +109,6 @@ impl Runnable { s.push_str(suffix); s } - - #[cfg(test)] - fn test_kind(&self) -> RunnableTestKind { - match &self.kind { - RunnableKind::TestMod { .. } => RunnableTestKind::TestMod, - RunnableKind::Test { .. } => RunnableTestKind::Test, - RunnableKind::DocTest { .. } => RunnableTestKind::DocTest, - RunnableKind::Bench { .. } => RunnableTestKind::Bench, - RunnableKind::Bin => RunnableTestKind::Bin, - } - } } // Feature: Run @@ -193,6 +194,20 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { r }) })); + res.sort_by(|Runnable { nav, kind, .. }, Runnable { nav: nav_b, kind: kind_b, .. }| { + // full_range.start < focus_range.start < name, should give us a decent unique ordering + nav.full_range + .start() + .cmp(&nav_b.full_range.start()) + .then_with(|| { + let t_0 = || TextSize::from(0); + nav.focus_range + .map_or_else(t_0, |it| it.start()) + .cmp(&nav_b.focus_range.map_or_else(t_0, |it| it.start())) + }) + .then_with(|| kind.disc().cmp(&kind_b.disc())) + .then_with(|| nav.name.cmp(&nav_b.name)) + }); res } @@ -571,13 +586,12 @@ mod tests { fn check(ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let mut runnables = analysis.runnables(position.file_id).unwrap(); - runnables.sort_by_key(|it| (it.nav.full_range.start(), it.nav.name.clone())); - - let result = runnables + let result = analysis + .runnables(position.file_id) + .unwrap() .into_iter() .map(|runnable| { - let mut a = format!("({:?}, {:?}", runnable.test_kind(), runnable.nav); + let mut a = format!("({:?}, {:?}", runnable.kind.disc(), runnable.nav); if runnable.use_name_in_title { a.push_str(", true"); } @@ -609,6 +623,9 @@ fn main() {} #[export_name = "main"] fn __cortex_m_rt_main_trampoline() {} +#[unsafe(export_name = "main")] +fn __cortex_m_rt_main_trampoline_unsafe() {} + #[test] fn test_foo() {} @@ -628,13 +645,14 @@ mod not_a_root { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..253, name: \"\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"\", kind: Module })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 78..102, focus_range: 89..97, name: \"test_foo\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 104..155, focus_range: 136..150, name: \"test_full_path\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 157..191, focus_range: 178..186, name: \"test_foo\", kind: Function })", - "(Bench, NavigationTarget { file_id: FileId(0), full_range: 193..215, focus_range: 205..210, name: \"bench\", kind: Function })", + "(Bin, NavigationTarget { file_id: FileId(0), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 156..180, focus_range: 167..175, name: \"test_foo\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 182..233, focus_range: 214..228, name: \"test_full_path\", kind: Function })", + "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..269, focus_range: 256..264, name: \"test_foo\", kind: Function })", + "(Bench, NavigationTarget { file_id: FileId(0), full_range: 271..293, focus_range: 283..288, name: \"bench\", kind: Function })", ] "#]], ); diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index ca013da709..0d2311b6e9 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -167,7 +167,8 @@ impl StaticIndex<'_> { keywords: true, format: crate::HoverDocFormat::Markdown, max_trait_assoc_items_count: None, - max_struct_field_count: None, + max_fields_count: Some(5), + max_enum_variants_count: Some(5), }; let tokens = tokens.filter(|token| { matches!( diff --git a/crates/ide/src/syntax_highlighting/escape.rs b/crates/ide/src/syntax_highlighting/escape.rs index 5913ca5e45..0439e509d2 100644 --- a/crates/ide/src/syntax_highlighting/escape.rs +++ b/crates/ide/src/syntax_highlighting/escape.rs @@ -25,7 +25,7 @@ pub(super) fn highlight_escape_string( } pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) { - if char.value().is_none() { + if char.value().is_err() { // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad // state and this token contains junks, since `'` is not a reliable delimiter (consider // lifetimes). Nonetheless, parser errors should already be emitted. @@ -48,7 +48,7 @@ pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: } pub(super) fn highlight_escape_byte(stack: &mut Highlights, byte: &Byte, start: TextSize) { - if byte.value().is_none() { + if byte.value().is_err() { // See `highlight_escape_char` for why no error highlighting here. return; } diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index a72f505eb8..3b784ebec3 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs @@ -484,6 +484,7 @@ pub(super) fn highlight_def( h } Definition::BuiltinType(_) => Highlight::new(HlTag::BuiltinType), + Definition::BuiltinLifetime(_) => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)), Definition::Static(s) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); @@ -542,13 +543,14 @@ pub(super) fn highlight_def( let def_crate = def.krate(db); let is_from_other_crate = def_crate != Some(krate); let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db)); - let is_builtin_type = matches!(def, Definition::BuiltinType(_)); - let is_public = def.visibility(db) == Some(hir::Visibility::Public); - - match (is_from_other_crate, is_builtin_type, is_public) { - (true, false, _) => h |= HlMod::Library, - (false, _, true) => h |= HlMod::Public, - _ => {} + let is_builtin = matches!( + def, + Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_) + ); + match is_from_other_crate { + true if !is_builtin => h |= HlMod::Library, + false if def.visibility(db) == Some(hir::Visibility::Public) => h |= HlMod::Public, + _ => (), } if is_from_builtin_crate { diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 6bf13ffd06..f9b8a22a3c 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -30,7 +30,7 @@ pub(super) fn ra_fixture( if !active_parameter.ident().map_or(false, |name| name.text().starts_with("ra_fixture")) { return None; } - let value = literal.value()?; + let value = literal.value().ok()?; if let Some(range) = literal.open_quote_text_range() { hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None }) @@ -299,6 +299,7 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag { Definition::Trait(_) => SymbolKind::Trait, Definition::TraitAlias(_) => SymbolKind::TraitAlias, Definition::TypeAlias(_) => SymbolKind::TypeAlias, + Definition::BuiltinLifetime(_) => SymbolKind::LifetimeParam, Definition::BuiltinType(_) => return HlTag::BuiltinType, Definition::Macro(_) => SymbolKind::Macro, Definition::Field(_) | Definition::TupleField(_) => SymbolKind::Field, diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html index de902b5137..cad5a8b593 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html @@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -
#[allow(dead_code)]
+
#[allow(dead_code)]
 #[rustfmt::skip]
 #[proc_macros::identity]
 #[derive(Default)]
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index 366895ce7e..893e3c0675 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -49,5 +49,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 fn main() {
     let foo = Some(92);
-    let nums = iter::repeat(foo.unwrap());
+    let nums = iter::repeat(foo.unwrap());
 }
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index b2ca6e1ca4..35650bbe87 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -79,7 +79,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd /// # Examples /// /// ``` - /// # #![allow(unused_mut)] + /// # #![allow(unused_mut)] /// let mut foo: Foo = Foo::new(); /// ``` pub const fn new() -> Foo { @@ -162,12 +162,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd /// /// ``` /// loop {} -#[cfg_attr(not(feature = "false"), doc = "loop {}")] -#[doc = "loop {}"] +#[cfg_attr(not(feature = "false"), doc = "loop {}")] +#[doc = "loop {}"] /// ``` /// -#[cfg_attr(feature = "alloc", doc = "```rust")] -#[cfg_attr(not(feature = "alloc"), doc = "```ignore")] +#[cfg_attr(feature = "alloc", doc = "```rust")] +#[cfg_attr(not(feature = "alloc"), doc = "```ignore")] /// let _ = example(&alloc::vec![1, 2, 3]); /// ``` pub fn mix_and_match() {} diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index 5234d362c2..413edb6d65 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -49,13 +49,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd mod inner {} pub mod ops { - #[lang = "fn_once"] + #[lang = "fn_once"] pub trait FnOnce<Args> {} - #[lang = "fn_mut"] + #[lang = "fn_mut"] pub trait FnMut<Args>: FnOnce<Args> {} - #[lang = "fn"] + #[lang = "fn"] pub trait Fn<Args>: FnMut<Args> {} } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 7a07d17b27..22706dea1f 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -158,9 +158,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd println!("{ничоси}", ничоси = 92); println!("{:x?} {} ", thingy, n2); - panic!("{}", 0); + panic!("{}", 0); panic!("more {}", 1); - assert!(true, "{}", 1); + assert!(true, "{}", 1); assert!(true, "{} asdasd", 1); toho!("{}fmt", 0); let i: u64 = 3; diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 15d6be6334..be6176894b 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html @@ -69,7 +69,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd unsafe fn unsafe_method(&self) {} } -#[repr(packed)] +#[repr(packed)] struct Packed { a: u16, } diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index 31b0c8cdec..76940ab57a 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -17,6 +17,7 @@ use itertools::Itertools; use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; use span::Span; +use tracing::{instrument, Level}; use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath}; pub struct LoadCargoConfig { @@ -50,6 +51,7 @@ pub fn load_workspace_at( load_workspace(workspace, &cargo_config.extra_env, load_config) } +#[instrument(skip_all)] pub fn load_workspace( ws: ProjectWorkspace, extra_env: &FxHashMap, @@ -66,9 +68,9 @@ pub fn load_workspace( let proc_macro_server = match &load_config.with_proc_macro_server { ProcMacroServerChoice::Sysroot => ws .find_sysroot_proc_macro_srv() - .and_then(|it| ProcMacroServer::spawn(it, extra_env).map_err(Into::into)), + .and_then(|it| ProcMacroServer::spawn(&it, extra_env).map_err(Into::into)), ProcMacroServerChoice::Explicit(path) => { - ProcMacroServer::spawn(path.clone(), extra_env).map_err(Into::into) + ProcMacroServer::spawn(path, extra_env).map_err(Into::into) } ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")), }; @@ -333,9 +335,7 @@ fn load_crate_graph( vfs: &mut vfs::Vfs, receiver: &Receiver, ) -> RootDatabase { - let (ProjectWorkspace::Cargo { toolchain, target_layout, .. } - | ProjectWorkspace::Json { toolchain, target_layout, .. } - | ProjectWorkspace::DetachedFile { toolchain, target_layout, .. }) = ws; + let ProjectWorkspace { toolchain, target_layout, .. } = ws; let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); let mut db = RootDatabase::new(lru_cap); @@ -352,6 +352,8 @@ fn load_crate_graph( } } vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => { + let _p = tracing::span!(Level::INFO, "load_cargo::load_crate_craph/LoadedChanged") + .entered(); for (path, contents) in files { vfs.set_file_contents(path.into(), contents); } @@ -359,8 +361,8 @@ fn load_crate_graph( } } let changes = vfs.take_changes(); - for file in changes { - if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change { + for (_, file) in changes { + if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change { if let Ok(text) = String::from_utf8(v) { analysis_change.change_file(file.file_id, Some(text)) } diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index f4bbaef7af..f73e188c79 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -10,7 +10,7 @@ use test_utils::{bench, bench_fixture, skip_slow_tests}; use crate::{ parser::{MetaVarKind, Op, RepeatKind, Separator}, - syntax_node_to_token_tree, DeclarativeMacro, DummyTestSpanMap, DUMMY, + syntax_node_to_token_tree, DeclarativeMacro, DocCommentDesugarMode, DummyTestSpanMap, DUMMY, }; #[test] @@ -78,6 +78,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap> { rule.token_tree().unwrap().syntax(), DummyTestSpanMap, DUMMY, + DocCommentDesugarMode::Mbe, ); (id, def_tt) }) diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index d5de56312a..6920832dd2 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -34,7 +34,7 @@ pub use tt::{Delimiter, DelimiterKind, Punct}; pub use crate::syntax_bridge::{ parse_exprs_with_sep, parse_to_token_tree, parse_to_token_tree_static_span, syntax_node_to_token_tree, syntax_node_to_token_tree_modified, token_tree_to_syntax_node, - SpanMapper, + DocCommentDesugarMode, SpanMapper, }; pub use crate::syntax_bridge::dummy_test_span_utils::*; diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 3230eeb5bd..412e492176 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -69,18 +69,28 @@ pub(crate) mod dummy_test_span_utils { } } +/// Doc comment desugaring differs between mbe and proc-macros. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum DocCommentDesugarMode { + /// Desugars doc comments as quoted raw strings + Mbe, + /// Desugars doc comments as quoted strings + ProcMacro, +} + /// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the /// subtree's spans. pub fn syntax_node_to_token_tree( node: &SyntaxNode, map: SpanMap, span: SpanData, + mode: DocCommentDesugarMode, ) -> tt::Subtree> where SpanData: Copy + fmt::Debug, SpanMap: SpanMapper>, { - let mut c = Converter::new(node, map, Default::default(), Default::default(), span); + let mut c = Converter::new(node, map, Default::default(), Default::default(), span, mode); convert_tokens(&mut c) } @@ -93,12 +103,13 @@ pub fn syntax_node_to_token_tree_modified( append: FxHashMap>>>, remove: FxHashSet, call_site: SpanData, + mode: DocCommentDesugarMode, ) -> tt::Subtree> where SpanMap: SpanMapper>, SpanData: Copy + fmt::Debug, { - let mut c = Converter::new(node, map, append, remove, call_site); + let mut c = Converter::new(node, map, append, remove, call_site, mode); convert_tokens(&mut c) } @@ -165,7 +176,8 @@ where if lexed.errors().next().is_some() { return None; } - let mut conv = RawConverter { lexed, anchor, pos: 0, ctx }; + let mut conv = + RawConverter { lexed, anchor, pos: 0, ctx, mode: DocCommentDesugarMode::ProcMacro }; Some(convert_tokens(&mut conv)) } @@ -178,7 +190,8 @@ where if lexed.errors().next().is_some() { return None; } - let mut conv = StaticRawConverter { lexed, pos: 0, span }; + let mut conv = + StaticRawConverter { lexed, pos: 0, span, mode: DocCommentDesugarMode::ProcMacro }; Some(convert_tokens(&mut conv)) } @@ -405,7 +418,7 @@ fn is_single_token_op(kind: SyntaxKind) -> bool { /// That is, strips leading `///` (or `/**`, etc) /// and strips the ending `*/` /// And then quote the string, which is needed to convert to `tt::Literal` -fn doc_comment_text(comment: &ast::Comment) -> SmolStr { +fn doc_comment_text(comment: &ast::Comment, mode: DocCommentDesugarMode) -> SmolStr { let prefix_len = comment.prefix().len(); let mut text = &comment.text()[prefix_len..]; @@ -414,26 +427,34 @@ fn doc_comment_text(comment: &ast::Comment) -> SmolStr { text = &text[0..text.len() - 2]; } - let mut num_of_hashes = 0; - let mut count = 0; - for ch in text.chars() { - count = match ch { - '"' => 1, - '#' if count > 0 => count + 1, - _ => 0, - }; - num_of_hashes = num_of_hashes.max(count); - } + let text = match mode { + DocCommentDesugarMode::Mbe => { + let mut num_of_hashes = 0; + let mut count = 0; + for ch in text.chars() { + count = match ch { + '"' => 1, + '#' if count > 0 => count + 1, + _ => 0, + }; + num_of_hashes = num_of_hashes.max(count); + } - // Quote raw string with delimiters - // Note that `tt::Literal` expect an escaped string - let text = format!("r{delim}\"{text}\"{delim}", delim = "#".repeat(num_of_hashes)); + // Quote raw string with delimiters + // Note that `tt::Literal` expect an escaped string + format!(r#"r{delim}"{text}"{delim}"#, delim = "#".repeat(num_of_hashes)) + } + // Quote string with delimiters + // Note that `tt::Literal` expect an escaped string + DocCommentDesugarMode::ProcMacro => format!(r#""{}""#, text.escape_debug()), + }; text.into() } fn convert_doc_comment( token: &syntax::SyntaxToken, span: S, + mode: DocCommentDesugarMode, ) -> Option>> { cov_mark::hit!(test_meta_doc_comments); let comment = ast::Comment::cast(token.clone())?; @@ -451,7 +472,7 @@ fn convert_doc_comment( }; let mk_doc_literal = |comment: &ast::Comment| { - let lit = tt::Literal { text: doc_comment_text(comment), span }; + let lit = tt::Literal { text: doc_comment_text(comment, mode), span }; tt::TokenTree::from(tt::Leaf::from(lit)) }; @@ -479,12 +500,14 @@ struct RawConverter<'a, Ctx> { pos: usize, anchor: SpanAnchor, ctx: Ctx, + mode: DocCommentDesugarMode, } /// A raw token (straight from lexer) converter that gives every token the same span. struct StaticRawConverter<'a, S> { lexed: parser::LexedStr<'a>, pos: usize, span: S, + mode: DocCommentDesugarMode, } trait SrcToken { @@ -553,7 +576,7 @@ where span: SpanData, ) -> Option>>> { let text = self.lexed.text(token); - convert_doc_comment(&doc_comment(text), span) + convert_doc_comment(&doc_comment(text), span, self.mode) } fn bump(&mut self) -> Option<(Self::Token, TextRange)> { @@ -592,7 +615,7 @@ where fn convert_doc_comment(&self, &token: &usize, span: S) -> Option>> { let text = self.lexed.text(token); - convert_doc_comment(&doc_comment(text), span) + convert_doc_comment(&doc_comment(text), span, self.mode) } fn bump(&mut self) -> Option<(Self::Token, TextRange)> { @@ -634,6 +657,7 @@ struct Converter { append: FxHashMap>>, remove: FxHashSet, call_site: S, + mode: DocCommentDesugarMode, } impl Converter { @@ -643,6 +667,7 @@ impl Converter { append: FxHashMap>>, remove: FxHashSet, call_site: S, + mode: DocCommentDesugarMode, ) -> Self { let mut this = Converter { current: None, @@ -654,6 +679,7 @@ impl Converter { remove, call_site, current_leaves: vec![], + mode, }; let first = this.next_token(); this.current = first; @@ -755,7 +781,7 @@ where { type Token = SynToken; fn convert_doc_comment(&self, token: &Self::Token, span: S) -> Option>> { - convert_doc_comment(token.token(), span) + convert_doc_comment(token.token(), span, self.mode) } fn bump(&mut self) -> Option<(Self::Token, TextRange)> { diff --git a/crates/mbe/src/syntax_bridge/tests.rs b/crates/mbe/src/syntax_bridge/tests.rs index bbfe378200..2988fb3cf1 100644 --- a/crates/mbe/src/syntax_bridge/tests.rs +++ b/crates/mbe/src/syntax_bridge/tests.rs @@ -7,11 +7,16 @@ use tt::{ Leaf, Punct, Spacing, }; -use crate::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY}; +use crate::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY}; fn check_punct_spacing(fixture: &str) { let source_file = ast::SourceFile::parse(fixture, span::Edition::CURRENT).ok().unwrap(); - let subtree = syntax_node_to_token_tree(source_file.syntax(), DummyTestSpanMap, DUMMY); + let subtree = syntax_node_to_token_tree( + source_file.syntax(), + DummyTestSpanMap, + DUMMY, + DocCommentDesugarMode::Mbe, + ); let mut annotations: FxHashMap<_, _> = extract_annotations(fixture) .into_iter() .map(|(range, annotation)| { diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs index c13a194379..82e4d66148 100644 --- a/crates/parser/src/grammar/attributes.rs +++ b/crates/parser/src/grammar/attributes.rs @@ -36,8 +36,33 @@ fn attr(p: &mut Parser<'_>, inner: bool) { attr.complete(p, ATTR); } +// test metas +// #![simple_ident] +// #![simple::path] +// #![simple_ident_expr = ""] +// #![simple::path::Expr = ""] +// #![simple_ident_tt(a b c)] +// #![simple_ident_tt[a b c]] +// #![simple_ident_tt{a b c}] +// #![simple::path::tt(a b c)] +// #![simple::path::tt[a b c]] +// #![simple::path::tt{a b c}] +// #![unsafe(simple_ident)] +// #![unsafe(simple::path)] +// #![unsafe(simple_ident_expr = "")] +// #![unsafe(simple::path::Expr = "")] +// #![unsafe(simple_ident_tt(a b c))] +// #![unsafe(simple_ident_tt[a b c])] +// #![unsafe(simple_ident_tt{a b c})] +// #![unsafe(simple::path::tt(a b c))] +// #![unsafe(simple::path::tt[a b c])] +// #![unsafe(simple::path::tt{a b c})] pub(super) fn meta(p: &mut Parser<'_>) { let meta = p.start(); + let is_unsafe = p.eat(T![unsafe]); + if is_unsafe { + p.expect(T!['(']); + } paths::use_path(p); match p.current() { @@ -50,6 +75,9 @@ pub(super) fn meta(p: &mut Parser<'_>) { T!['('] | T!['['] | T!['{'] => items::token_tree(p), _ => {} } + if is_unsafe { + p.expect(T![')']); + } meta.complete(p, META); } diff --git a/crates/parser/test_data/parser/inline/ok/0213_metas.rast b/crates/parser/test_data/parser/inline/ok/0213_metas.rast new file mode 100644 index 0000000000..b1ac60b530 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0213_metas.rast @@ -0,0 +1,457 @@ +SOURCE_FILE + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Expr" + WHITESPACE " " + EQ "=" + WHITESPACE " " + LITERAL + STRING "\"\"" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple_ident_tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_PAREN "(" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_PAREN ")" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_BRACK "[" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_BRACK "]" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + L_PAREN "(" + PATH + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "simple" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "path" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "tt" + TOKEN_TREE + L_CURLY "{" + IDENT "a" + WHITESPACE " " + IDENT "b" + WHITESPACE " " + IDENT "c" + R_CURLY "}" + R_PAREN ")" + R_BRACK "]" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0213_metas.rs b/crates/parser/test_data/parser/inline/ok/0213_metas.rs new file mode 100644 index 0000000000..57b7bb7170 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0213_metas.rs @@ -0,0 +1,20 @@ +#![simple_ident] +#![simple::path] +#![simple_ident_expr = ""] +#![simple::path::Expr = ""] +#![simple_ident_tt(a b c)] +#![simple_ident_tt[a b c]] +#![simple_ident_tt{a b c}] +#![simple::path::tt(a b c)] +#![simple::path::tt[a b c]] +#![simple::path::tt{a b c}] +#![unsafe(simple_ident)] +#![unsafe(simple::path)] +#![unsafe(simple_ident_expr = "")] +#![unsafe(simple::path::Expr = "")] +#![unsafe(simple_ident_tt(a b c))] +#![unsafe(simple_ident_tt[a b c])] +#![unsafe(simple_ident_tt{a b c})] +#![unsafe(simple::path::tt(a b c))] +#![unsafe(simple::path::tt[a b c])] +#![unsafe(simple::path::tt{a b c})] diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index 0ab16c38c8..8749417290 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -13,7 +13,7 @@ mod version; use base_db::Env; use indexmap::IndexSet; -use paths::AbsPathBuf; +use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; use span::Span; use std::{ @@ -54,6 +54,7 @@ pub struct ProcMacroServer { /// /// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here. process: Arc>, + path: AbsPathBuf, } pub struct MacroDylib { @@ -113,15 +114,22 @@ pub struct MacroPanic { impl ProcMacroServer { /// Spawns an external process as the proc macro server and returns a client connected to it. pub fn spawn( - process_path: AbsPathBuf, + process_path: &AbsPath, env: &FxHashMap, ) -> io::Result { let process = ProcMacroProcessSrv::run(process_path, env)?; - Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) }) + Ok(ProcMacroServer { + process: Arc::new(Mutex::new(process)), + path: process_path.to_owned(), + }) + } + + pub fn path(&self) -> &AbsPath { + &self.path } pub fn load_dylib(&self, dylib: MacroDylib) -> Result, ServerError> { - let _p = tracing::span!(tracing::Level::INFO, "ProcMacroClient::load_dylib").entered(); + let _p = tracing::span!(tracing::Level::INFO, "ProcMacroServer::load_dylib").entered(); let macros = self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?; diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 35d48a1554..dce086d429 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -6,7 +6,7 @@ use std::{ sync::Arc, }; -use paths::{AbsPath, AbsPathBuf}; +use paths::AbsPath; use rustc_hash::FxHashMap; use stdx::JodChild; @@ -28,11 +28,11 @@ pub(crate) struct ProcMacroProcessSrv { impl ProcMacroProcessSrv { pub(crate) fn run( - process_path: AbsPathBuf, + process_path: &AbsPath, env: &FxHashMap, ) -> io::Result { let create_srv = |null_stderr| { - let mut process = Process::run(process_path.clone(), env, null_stderr)?; + let mut process = Process::run(process_path, env, null_stderr)?; let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { @@ -153,11 +153,11 @@ struct Process { impl Process { fn run( - path: AbsPathBuf, + path: &AbsPath, env: &FxHashMap, null_stderr: bool, ) -> io::Result { - let child = JodChild(mk_child(&path, env, null_stderr)?); + let child = JodChild(mk_child(path, env, null_stderr)?); Ok(Process { child }) } diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index a87b67f5c6..11a8e7af56 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -24,7 +24,7 @@ jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = tr perf-event = "=0.4.7" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] } +windows-sys = { version = "0.52", features = ["Win32_System_Threading", "Win32_System_ProcessStatus"] } [features] cpu_profiler = [] diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs index a3fdb72a6d..2ccb1cd06a 100644 --- a/crates/profile/src/lib.rs +++ b/crates/profile/src/lib.rs @@ -26,7 +26,7 @@ thread_local!(static IN_SCOPE: RefCell = const { RefCell::new(false) }); /// A wrapper around google_cpu_profiler. /// /// Usage: -/// 1. Install gpref_tools (), probably packaged with your Linux distro. +/// 1. Install gperf_tools (), probably packaged with your Linux distro. /// 2. Build with `cpu_profiler` feature. /// 3. Run the code, the *raw* output would be in the `./out.profile` file. /// 4. Install pprof for visualization (). diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs index f089c78e0c..660afff3dc 100644 --- a/crates/profile/src/memory_usage.rs +++ b/crates/profile/src/memory_usage.rs @@ -37,8 +37,7 @@ impl MemoryUsage { // There doesn't seem to be an API for determining heap usage, so we try to // approximate that by using the Commit Charge value. - use winapi::um::processthreadsapi::*; - use winapi::um::psapi::*; + use windows_sys::Win32::System::{Threading::*, ProcessStatus::*}; use std::mem::{MaybeUninit, size_of}; let proc = unsafe { GetCurrentProcess() }; diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index fbd423c9ea..8e1f7fdcde 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -24,7 +24,7 @@ use toolchain::Tool; use crate::{ cfg::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation, - InvocationStrategy, Package, Sysroot, TargetKind, + InvocationStrategy, ManifestPath, Package, Sysroot, TargetKind, }; /// Output of the build script and proc-macro building steps for a workspace. @@ -63,9 +63,11 @@ impl WorkspaceBuildScripts { fn build_command( config: &CargoConfig, allowed_features: &FxHashSet, - workspace_root: &AbsPathBuf, + manifest_path: &ManifestPath, + toolchain: Option<&Version>, sysroot: Option<&Sysroot>, ) -> io::Result { + const RUST_1_75: Version = Version::new(1, 75, 0); let mut cmd = match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { let mut cmd = Command::new(program); @@ -79,7 +81,7 @@ impl WorkspaceBuildScripts { cmd.args(&config.extra_args); cmd.arg("--manifest-path"); - cmd.arg(workspace_root.join("Cargo.toml")); + cmd.arg(manifest_path.as_ref()); if let Some(target_dir) = &config.target_dir { cmd.arg("--target-dir").arg(target_dir); @@ -116,6 +118,14 @@ impl WorkspaceBuildScripts { } } + if manifest_path.is_rust_manifest() { + cmd.arg("-Zscript"); + } + + if toolchain.map_or(false, |it| *it >= RUST_1_75) { + cmd.arg("--keep-going"); + } + cmd } }; @@ -138,11 +148,9 @@ impl WorkspaceBuildScripts { config: &CargoConfig, workspace: &CargoWorkspace, progress: &dyn Fn(String), - toolchain: &Option, + toolchain: Option<&Version>, sysroot: Option<&Sysroot>, ) -> io::Result { - const RUST_1_75: Version = Version::new(1, 75, 0); - let current_dir = match &config.invocation_location { InvocationLocation::Root(root) if config.run_build_script_command.is_some() => { root.as_path() @@ -152,37 +160,14 @@ impl WorkspaceBuildScripts { .as_ref(); let allowed_features = workspace.workspace_features(); - - match Self::run_per_ws( - Self::build_command( - config, - &allowed_features, - &workspace.workspace_root().to_path_buf(), - sysroot, - )?, - workspace, - current_dir, - progress, - ) { - Ok(WorkspaceBuildScripts { error: Some(error), .. }) - if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_75) => - { - // building build scripts failed, attempt to build with --keep-going so - // that we potentially get more build data - let mut cmd = Self::build_command( - config, - &allowed_features, - &workspace.workspace_root().to_path_buf(), - sysroot, - )?; - - cmd.args(["--keep-going"]); - let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?; - res.error = Some(error); - Ok(res) - } - res => res, - } + let cmd = Self::build_command( + config, + &allowed_features, + workspace.manifest_path(), + toolchain, + sysroot, + )?; + Self::run_per_ws(cmd, workspace, current_dir, progress) } /// Runs the build scripts by invoking the configured command *once*. @@ -204,7 +189,14 @@ impl WorkspaceBuildScripts { )) } }; - let cmd = Self::build_command(config, &Default::default(), workspace_root, None)?; + let cmd = Self::build_command( + config, + &Default::default(), + // This is not gonna be used anyways, so just construct a dummy here + &ManifestPath::try_from(workspace_root.clone()).unwrap(), + None, + None, + )?; // NB: Cargo.toml could have been modified between `cargo metadata` and // `cargo check`. We shouldn't assume that package ids we see here are // exactly those from `config`. diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index ff7cf144aa..9955f2687c 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -32,6 +32,7 @@ pub struct CargoWorkspace { targets: Arena, workspace_root: AbsPathBuf, target_directory: AbsPathBuf, + manifest_path: ManifestPath, } impl ops::Index for CargoWorkspace { @@ -306,7 +307,7 @@ impl CargoWorkspace { ); } // The manifest is a rust file, so this means its a script manifest - if cargo_toml.extension().is_some_and(|ext| ext == "rs") { + if cargo_toml.is_rust_manifest() { // Deliberately don't set up RUSTC_BOOTSTRAP or a nightly override here, the user should // opt into it themselves. other_options.push("-Zscript".to_owned()); @@ -334,7 +335,7 @@ impl CargoWorkspace { .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())) } - pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace { + pub fn new(mut meta: cargo_metadata::Metadata, manifest_path: ManifestPath) -> CargoWorkspace { let mut pkg_by_id = FxHashMap::default(); let mut packages = Arena::default(); let mut targets = Arena::default(); @@ -448,7 +449,7 @@ impl CargoWorkspace { let target_directory = AbsPathBuf::assert(meta.target_directory); - CargoWorkspace { packages, targets, workspace_root, target_directory } + CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path } } pub fn packages(&self) -> impl ExactSizeIterator + '_ { @@ -466,6 +467,10 @@ impl CargoWorkspace { &self.workspace_root } + pub fn manifest_path(&self) -> &ManifestPath { + &self.manifest_path + } + pub fn target_directory(&self) -> &AbsPath { &self.target_directory } diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs index 762e01c917..5520cdaff6 100644 --- a/crates/project-model/src/env.rs +++ b/crates/project-model/src/env.rs @@ -60,16 +60,19 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe } pub(crate) fn cargo_config_env( - cargo_toml: &ManifestPath, + manifest: &ManifestPath, extra_env: &FxHashMap, sysroot: Option<&Sysroot>, ) -> FxHashMap { let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo); cargo_config.envs(extra_env); cargo_config - .current_dir(cargo_toml.parent()) + .current_dir(manifest.parent()) .args(["-Z", "unstable-options", "config", "get", "env"]) .env("RUSTC_BOOTSTRAP", "1"); + if manifest.is_rust_manifest() { + cargo_config.arg("-Zscript"); + } // if successful we receive `env.key.value = "value" per entry tracing::debug!("Discovering cargo config env by {:?}", cargo_config); utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default() diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index 7f3e35ca5d..181c07f46b 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -52,13 +52,15 @@ pub use crate::{ manifest_path::ManifestPath, project_json::{ProjectJson, ProjectJsonData}, sysroot::Sysroot, - workspace::{FileLoader, PackageRoot, ProjectWorkspace}, + workspace::{FileLoader, PackageRoot, ProjectWorkspace, ProjectWorkspaceKind}, }; +pub use cargo_metadata::Metadata; #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ProjectManifest { ProjectJson(ManifestPath), CargoToml(ManifestPath), + CargoScript(ManifestPath), } impl ProjectManifest { @@ -71,7 +73,10 @@ impl ProjectManifest { if path.file_name().unwrap_or_default() == "Cargo.toml" { return Ok(ProjectManifest::CargoToml(path)); } - bail!("project root must point to Cargo.toml or rust-project.json: {path}"); + if path.extension().unwrap_or_default() == "rs" { + return Ok(ProjectManifest::CargoScript(path)); + } + bail!("project root must point to a Cargo.toml, rust-project.json or