mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-11 04:38:49 +00:00
merge rustc history
This commit is contained in:
commit
7d2cf69fb4
187 changed files with 6034 additions and 2746 deletions
27
.github/workflows/ci.yaml
vendored
27
.github/workflows/ci.yaml
vendored
|
@ -43,14 +43,31 @@ jobs:
|
||||||
rustup component add rustfmt rust-src
|
rustup component add rustfmt rust-src
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
|
uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
|
||||||
|
|
||||||
- name: Compile
|
- name: Bump opt-level
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: sed -i '/\[profile.dev]/a opt-level=1' Cargo.toml
|
||||||
|
|
||||||
|
- name: Compile (tests)
|
||||||
run: cargo test --no-run --locked
|
run: cargo test --no-run --locked
|
||||||
|
|
||||||
|
# It's faster to `test` before `build` ¯\_(ツ)_/¯
|
||||||
|
- name: Compile (rust-analyzer)
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: cargo build --quiet
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: cargo test -- --nocapture --quiet
|
run: cargo test -- --nocapture --quiet
|
||||||
|
|
||||||
|
- name: Run analysis-stats on rust-analyzer
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats .
|
||||||
|
|
||||||
|
- name: Run analysis-stats on rust std library
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
|
||||||
|
|
||||||
# Weird targets to catch non-portable code
|
# Weird targets to catch non-portable code
|
||||||
rust-cross:
|
rust-cross:
|
||||||
if: github.repository == 'rust-lang/rust-analyzer'
|
if: github.repository == 'rust-lang/rust-analyzer'
|
||||||
|
@ -73,7 +90,7 @@ jobs:
|
||||||
rustup target add ${{ env.targets }} ${{ env.targets_ide }}
|
rustup target add ${{ env.targets }} ${{ env.targets_ide }}
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Cache Dependencies
|
||||||
uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
|
uses: Swatinem/rust-cache@76686c56f2b581d1bb5bda44b51f7e24bd9b8b8e
|
||||||
|
|
||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
|
@ -99,9 +116,9 @@ jobs:
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install Nodejs
|
- name: Install Nodejs
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 16
|
||||||
|
|
||||||
- name: Install xvfb
|
- name: Install xvfb
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|
10
.github/workflows/release.yaml
vendored
10
.github/workflows/release.yaml
vendored
|
@ -76,9 +76,9 @@ jobs:
|
||||||
rustup component add rust-src
|
rustup component add rust-src
|
||||||
|
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 16
|
||||||
|
|
||||||
- name: Update apt repositories
|
- name: Update apt repositories
|
||||||
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
|
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
|
||||||
|
@ -184,9 +184,9 @@ jobs:
|
||||||
needs: ["dist", "dist-x86_64-unknown-linux-musl"]
|
needs: ["dist", "dist-x86_64-unknown-linux-musl"]
|
||||||
steps:
|
steps:
|
||||||
- name: Install Nodejs
|
- name: Install Nodejs
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 16
|
||||||
|
|
||||||
- run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
|
- run: echo "TAG=$(date --iso -u)" >> $GITHUB_ENV
|
||||||
if: github.ref == 'refs/heads/release'
|
if: github.ref == 'refs/heads/release'
|
||||||
|
@ -259,6 +259,7 @@ jobs:
|
||||||
working-directory: ./editors/code
|
working-directory: ./editors/code
|
||||||
# token from https://dev.azure.com/rust-analyzer/
|
# token from https://dev.azure.com/rust-analyzer/
|
||||||
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
|
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
|
||||||
|
timeout-minutes: 2
|
||||||
|
|
||||||
- name: Publish Extension (Code Marketplace, nightly)
|
- name: Publish Extension (Code Marketplace, nightly)
|
||||||
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
|
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
|
||||||
|
@ -269,3 +270,4 @@ jobs:
|
||||||
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
|
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
|
||||||
working-directory: ./editors/code
|
working-directory: ./editors/code
|
||||||
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
|
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
|
||||||
|
timeout-minutes: 2
|
||||||
|
|
203
Cargo.lock
generated
203
Cargo.lock
generated
|
@ -37,9 +37,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.62"
|
version = "1.0.65"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
|
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anymap"
|
name = "anymap"
|
||||||
|
@ -49,9 +49,9 @@ checksum = "8f1f8f5a6f3d50d89e3797d7593a50f96bb2aaa20ca0cc7be1fb673232c91d72"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
version = "1.1.3"
|
version = "1.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a7924531f38b1970ff630f03eb20a2fde69db5c590c93b0f3482e95dcc5fd60"
|
checksum = "d86fd10d912cab78764cc44307d9cd5f164e09abbeb87fb19fb6d95937e8da5f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
|
@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chalk-derive"
|
name = "chalk-derive"
|
||||||
version = "0.84.0"
|
version = "0.86.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf29c109d57f8d57b0e7675391be37a9285d86dd93278bd5f14a0ad3c447a6c2"
|
checksum = "5499d415d855b5094366a824815341893ad3de0ecb6048c430118bdae6d27402"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -183,9 +183,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chalk-ir"
|
name = "chalk-ir"
|
||||||
version = "0.84.0"
|
version = "0.86.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d391763027b5e50a5e15caf6d2857ec585fd68160367bbeac9e1804209620918"
|
checksum = "3800118c76a48507b0eece3a01f3a429b5c478d203c493096e6040c67ab960e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"chalk-derive",
|
"chalk-derive",
|
||||||
|
@ -194,9 +194,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chalk-recursive"
|
name = "chalk-recursive"
|
||||||
version = "0.84.0"
|
version = "0.86.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afafd92dcdc7fe0ea940ee94bdd8cc5bd18f4a4a84c593d6d7025fe16c150478"
|
checksum = "1baf60628fd73104d1f8562586a52d48f37f1e84435aab2e62674b1fd935b8c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chalk-derive",
|
"chalk-derive",
|
||||||
"chalk-ir",
|
"chalk-ir",
|
||||||
|
@ -207,9 +207,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chalk-solve"
|
name = "chalk-solve"
|
||||||
version = "0.84.0"
|
version = "0.86.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3af1d111f11c91c48ace02e93e470c5bae6d2631bd112e4545317da53660d7fc"
|
checksum = "0e9c3c068f9358786348e58a1b94ef0a5cf90a9810fc1f10fda896f0b5d80185"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chalk-derive",
|
"chalk-derive",
|
||||||
"chalk-ir",
|
"chalk-ir",
|
||||||
|
@ -270,45 +270,44 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "crossbeam-epoch"
|
||||||
version = "0.9.10"
|
version = "0.9.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
|
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
"once_cell",
|
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.11"
|
version = "0.8.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
|
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dashmap"
|
name = "dashmap"
|
||||||
version = "5.3.4"
|
version = "5.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f"
|
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
|
"once_cell",
|
||||||
"parking_lot_core 0.9.3",
|
"parking_lot_core 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_arbitrary"
|
name = "derive_arbitrary"
|
||||||
version = "1.1.3"
|
version = "1.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9a577516173adb681466d517d39bd468293bc2c2a16439375ef0f35bba45f3d"
|
checksum = "226ad66541d865d7a7173ad6a9e691c33fdb910ac723f4bc734b3e5294a1f931"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -404,11 +403,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
|
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matches",
|
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -546,6 +544,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"base-db",
|
"base-db",
|
||||||
|
"chalk-derive",
|
||||||
"chalk-ir",
|
"chalk-ir",
|
||||||
"chalk-recursive",
|
"chalk-recursive",
|
||||||
"chalk-solve",
|
"chalk-solve",
|
||||||
|
@ -573,9 +572,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.3"
|
version = "0.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -714,11 +713,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.3"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matches",
|
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
@ -764,18 +762,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.3"
|
version = "0.10.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.3"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jod-thread"
|
name = "jod-thread"
|
||||||
|
@ -815,9 +813,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.132"
|
version = "0.2.135"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
|
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
|
@ -831,9 +829,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libmimalloc-sys"
|
name = "libmimalloc-sys"
|
||||||
version = "0.1.25"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11ca136052550448f55df7898c6dbe651c6b574fe38a0d9ea687a9f8088a2e2c"
|
checksum = "8fc093ab289b0bfda3aa1bdfab9c9542be29c7ef385cfcbe77f8c9813588eb48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
@ -844,9 +842,9 @@ version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.7"
|
version = "0.4.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
|
@ -863,7 +861,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsp-server"
|
name = "lsp-server"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"log",
|
"log",
|
||||||
|
@ -894,12 +892,6 @@ dependencies = [
|
||||||
"regex-automata",
|
"regex-automata",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matches"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mbe"
|
name = "mbe"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -941,18 +933,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mimalloc"
|
name = "mimalloc"
|
||||||
version = "0.1.29"
|
version = "0.1.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2f64ad83c969af2e732e907564deb0d0ed393cec4af80776f77dd77a1a427698"
|
checksum = "76ce6a4b40d3bff9eb3ce9881ca0737a85072f9f975886082640cd46a75cdb35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libmimalloc-sys",
|
"libmimalloc-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.5.3"
|
version = "0.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
|
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
]
|
]
|
||||||
|
@ -980,9 +972,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "5.0.0-pre.16"
|
version = "5.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "530f6314d6904508082f4ea424a0275cf62d341e118b313663f266429cb19693"
|
checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
@ -1017,9 +1009,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.13.1"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
|
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
|
@ -1088,9 +1080,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.8"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
|
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paths"
|
name = "paths"
|
||||||
|
@ -1098,9 +1090,9 @@ version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "perf-event"
|
name = "perf-event"
|
||||||
|
@ -1190,9 +1182,9 @@ version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.43"
|
version = "1.0.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
@ -1265,9 +1257,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pulldown-cmark-to-cmark"
|
name = "pulldown-cmark-to-cmark"
|
||||||
version = "10.0.2"
|
version = "10.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1353ac408192fa925228d3e60ff746167d03f4f7e54835d78ef79e08225d913"
|
checksum = "0194e6e1966c23cc5fd988714f85b18d548d773e81965413555d96569931833d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
]
|
]
|
||||||
|
@ -1340,9 +1332,9 @@ checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rowan"
|
name = "rowan"
|
||||||
version = "0.15.8"
|
version = "0.15.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e88acf7b001007e9e8c989fe7449f6601d909e5dd2c56399fc158977ad6c56e8"
|
checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"countme",
|
"countme",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
@ -1493,27 +1485,27 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.13"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "93f6841e709003d68bb2deee8c343572bf446003ec20a583e76f7b15cebf3711"
|
checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.143"
|
version = "1.0.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
|
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.143"
|
version = "1.0.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
|
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1522,9 +1514,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.83"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
|
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
@ -1554,9 +1546,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smol_str"
|
name = "smol_str"
|
||||||
|
@ -1593,9 +1585,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.99"
|
version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1666,18 +1658,18 @@ checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.31"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.31"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1715,9 +1707,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tikv-jemalloc-sys"
|
name = "tikv-jemalloc-sys"
|
||||||
version = "0.5.1+5.3.0-patched"
|
version = "0.5.2+5.3.0-patched"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "931e876f91fed0827f863a2d153897790da0b24d882c721a79cb3beb0b903261"
|
checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
|
@ -1758,9 +1750,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.36"
|
version = "0.1.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
|
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
@ -1770,9 +1762,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.22"
|
version = "0.1.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
|
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1781,9 +1773,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.29"
|
version = "0.1.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
|
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"valuable",
|
"valuable",
|
||||||
|
@ -1802,9 +1794,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.15"
|
version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
|
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matchers",
|
"matchers",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -1866,40 +1858,39 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.1"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.21"
|
version = "0.1.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
|
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.2.2"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
"matches",
|
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -2082,18 +2073,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xflags"
|
name = "xflags"
|
||||||
version = "0.2.4"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
|
checksum = "cbf19f5031a1a812e96fede16f8161218883079946cea87619d3613db1efd268"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"xflags-macros",
|
"xflags-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xflags-macros"
|
name = "xflags-macros"
|
||||||
version = "0.2.4"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
|
checksum = "2afbd7f2039bb6cad2dd45f0c5dff49c0d4e26118398768b7a605524d4251809"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xshell"
|
name = "xshell"
|
||||||
|
|
|
@ -27,6 +27,7 @@ debug = 0
|
||||||
# chalk-solve = { path = "../chalk/chalk-solve" }
|
# chalk-solve = { path = "../chalk/chalk-solve" }
|
||||||
# chalk-ir = { path = "../chalk/chalk-ir" }
|
# chalk-ir = { path = "../chalk/chalk-ir" }
|
||||||
# chalk-recursive = { path = "../chalk/chalk-recursive" }
|
# chalk-recursive = { path = "../chalk/chalk-recursive" }
|
||||||
|
# chalk-derive = { path = "../chalk/chalk-derive" }
|
||||||
|
|
||||||
# ungrammar = { path = "../ungrammar" }
|
# ungrammar = { path = "../ungrammar" }
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ impl ChangeFixture {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
for (from, to, prelude) in crate_deps {
|
for (from, to, prelude) in crate_deps {
|
||||||
|
@ -270,7 +270,7 @@ impl ChangeFixture {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(proc_macro),
|
Ok(proc_macro),
|
||||||
true,
|
true,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
|
|
||||||
for krate in all_crates {
|
for krate in all_crates {
|
||||||
|
@ -398,7 +398,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
|
||||||
let (version, origin) = match b.split_once(':') {
|
let (version, origin) = match b.split_once(':') {
|
||||||
Some(("CratesIo", data)) => match data.split_once(',') {
|
Some(("CratesIo", data)) => match data.split_once(',') {
|
||||||
Some((version, url)) => {
|
Some((version, url)) => {
|
||||||
(version, CrateOrigin::CratesIo { repo: Some(url.to_owned()) })
|
(version, CrateOrigin::CratesIo { repo: Some(url.to_owned()), name: None })
|
||||||
}
|
}
|
||||||
_ => panic!("Bad crates.io parameter: {}", data),
|
_ => panic!("Bad crates.io parameter: {}", data),
|
||||||
},
|
},
|
||||||
|
@ -409,7 +409,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
|
||||||
let crate_origin = match &*crate_str {
|
let crate_origin = match &*crate_str {
|
||||||
"std" => CrateOrigin::Lang(LangCrateOrigin::Std),
|
"std" => CrateOrigin::Lang(LangCrateOrigin::Std),
|
||||||
"core" => CrateOrigin::Lang(LangCrateOrigin::Core),
|
"core" => CrateOrigin::Lang(LangCrateOrigin::Core),
|
||||||
_ => CrateOrigin::CratesIo { repo: None },
|
_ => CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
};
|
};
|
||||||
(crate_str, crate_origin, None)
|
(crate_str, crate_origin, None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl ops::Deref for CrateName {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum CrateOrigin {
|
pub enum CrateOrigin {
|
||||||
/// Crates that are from crates.io official registry,
|
/// Crates that are from crates.io official registry,
|
||||||
CratesIo { repo: Option<String> },
|
CratesIo { repo: Option<String>, name: Option<String> },
|
||||||
/// Crates that are provided by the language, like std, core, proc-macro, ...
|
/// Crates that are provided by the language, like std, core, proc-macro, ...
|
||||||
Lang(LangCrateOrigin),
|
Lang(LangCrateOrigin),
|
||||||
}
|
}
|
||||||
|
@ -648,7 +648,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
FileId(2u32),
|
FileId(2u32),
|
||||||
|
@ -660,7 +660,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
let crate3 = graph.add_crate_root(
|
let crate3 = graph.add_crate_root(
|
||||||
FileId(3u32),
|
FileId(3u32),
|
||||||
|
@ -672,7 +672,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||||
|
@ -698,7 +698,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
FileId(2u32),
|
FileId(2u32),
|
||||||
|
@ -710,7 +710,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||||
|
@ -733,7 +733,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
FileId(2u32),
|
FileId(2u32),
|
||||||
|
@ -745,7 +745,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
let crate3 = graph.add_crate_root(
|
let crate3 = graph.add_crate_root(
|
||||||
FileId(3u32),
|
FileId(3u32),
|
||||||
|
@ -757,7 +757,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||||
|
@ -780,7 +780,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
let crate2 = graph.add_crate_root(
|
let crate2 = graph.add_crate_root(
|
||||||
FileId(2u32),
|
FileId(2u32),
|
||||||
|
@ -792,7 +792,7 @@ mod tests {
|
||||||
Env::default(),
|
Env::default(),
|
||||||
Ok(Vec::new()),
|
Ok(Vec::new()),
|
||||||
false,
|
false,
|
||||||
CrateOrigin::CratesIo { repo: None },
|
CrateOrigin::CratesIo { repo: None, name: None },
|
||||||
);
|
);
|
||||||
assert!(graph
|
assert!(graph
|
||||||
.add_dep(
|
.add_dep(
|
||||||
|
|
|
@ -22,5 +22,5 @@ oorandom = "11.1.3"
|
||||||
# We depend on both individually instead of using `features = ["derive"]` to microoptimize the
|
# We depend on both individually instead of using `features = ["derive"]` to microoptimize the
|
||||||
# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
|
# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
|
||||||
# supports `arbitrary`. This way, we avoid feature unification.
|
# supports `arbitrary`. This way, we avoid feature unification.
|
||||||
arbitrary = "1.1.0"
|
arbitrary = "1.1.7"
|
||||||
derive_arbitrary = "1.1.0"
|
derive_arbitrary = "1.1.6"
|
||||||
|
|
|
@ -11,11 +11,11 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossbeam-channel = "0.5.5"
|
crossbeam-channel = "0.5.5"
|
||||||
tracing = "0.1.35"
|
tracing = "0.1.37"
|
||||||
cargo_metadata = "0.15.0"
|
cargo_metadata = "0.15.0"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
serde = { version = "1.0.137", features = ["derive"] }
|
serde = { version = "1.0.137", features = ["derive"] }
|
||||||
serde_json = "1.0.81"
|
serde_json = "1.0.86"
|
||||||
jod-thread = "0.1.2"
|
jod-thread = "0.1.2"
|
||||||
|
|
||||||
toolchain = { path = "../toolchain", version = "0.0.0" }
|
toolchain = { path = "../toolchain", version = "0.0.0" }
|
||||||
|
|
|
@ -169,13 +169,17 @@ impl FlycheckActor {
|
||||||
}
|
}
|
||||||
fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
|
fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
|
||||||
let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
|
let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
|
||||||
|
if let Ok(msg) = inbox.try_recv() {
|
||||||
|
// give restarts a preference so check outputs don't block a restart or stop
|
||||||
|
return Some(Event::Restart(msg));
|
||||||
|
}
|
||||||
select! {
|
select! {
|
||||||
recv(inbox) -> msg => msg.ok().map(Event::Restart),
|
recv(inbox) -> msg => msg.ok().map(Event::Restart),
|
||||||
recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
|
recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn run(mut self, inbox: Receiver<Restart>) {
|
fn run(mut self, inbox: Receiver<Restart>) {
|
||||||
while let Some(event) = self.next_event(&inbox) {
|
'event: while let Some(event) = self.next_event(&inbox) {
|
||||||
match event {
|
match event {
|
||||||
Event::Restart(Restart::No) => {
|
Event::Restart(Restart::No) => {
|
||||||
self.cancel_check_process();
|
self.cancel_check_process();
|
||||||
|
@ -183,7 +187,12 @@ impl FlycheckActor {
|
||||||
Event::Restart(Restart::Yes) => {
|
Event::Restart(Restart::Yes) => {
|
||||||
// Cancel the previously spawned process
|
// Cancel the previously spawned process
|
||||||
self.cancel_check_process();
|
self.cancel_check_process();
|
||||||
while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
|
while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
|
||||||
|
// restart chained with a stop, so just cancel
|
||||||
|
if let Restart::No = restart {
|
||||||
|
continue 'event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let command = self.check_command();
|
let command = self.check_command();
|
||||||
tracing::debug!(?command, "will restart flycheck");
|
tracing::debug!(?command, "will restart flycheck");
|
||||||
|
|
|
@ -15,17 +15,17 @@ arrayvec = "0.7.2"
|
||||||
bitflags = "1.3.2"
|
bitflags = "1.3.2"
|
||||||
cov-mark = "2.0.0-pre.1"
|
cov-mark = "2.0.0-pre.1"
|
||||||
# We need to freeze the version of the crate, as the raw-api feature is considered unstable
|
# We need to freeze the version of the crate, as the raw-api feature is considered unstable
|
||||||
dashmap = { version = "=5.3.4", features = ["raw-api"] }
|
dashmap = { version = "=5.4.0", features = ["raw-api"] }
|
||||||
drop_bomb = "0.1.5"
|
drop_bomb = "0.1.5"
|
||||||
either = "1.7.0"
|
either = "1.7.0"
|
||||||
fst = { version = "0.4.7", default-features = false }
|
fst = { version = "0.4.7", default-features = false }
|
||||||
hashbrown = { version = "0.12.1", default-features = false }
|
hashbrown = { version = "0.12.1", default-features = false }
|
||||||
indexmap = "1.9.1"
|
indexmap = "1.9.1"
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
|
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.15.0"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
smallvec = "1.9.0"
|
smallvec = "1.10.0"
|
||||||
tracing = "0.1.35"
|
tracing = "0.1.35"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! Defines hir-level representation of structs, enums and unions
|
//! Defines hir-level representation of structs, enums and unions
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{num::NonZeroU32, sync::Arc};
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
name::{AsName, Name},
|
name::{AsName, Name},
|
||||||
InFile,
|
HirFileId, InFile,
|
||||||
};
|
};
|
||||||
use la_arena::{Arena, ArenaMap};
|
use la_arena::{Arena, ArenaMap};
|
||||||
use syntax::ast::{self, HasName, HasVisibility};
|
use syntax::ast::{self, HasName, HasVisibility};
|
||||||
|
@ -14,15 +14,18 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{CfgExpander, LowerCtx},
|
body::{CfgExpander, LowerCtx},
|
||||||
|
builtin_type::{BuiltinInt, BuiltinUint},
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
|
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
|
||||||
|
nameres::diagnostics::DefDiagnostic,
|
||||||
src::HasChildSource,
|
src::HasChildSource,
|
||||||
src::HasSource,
|
src::HasSource,
|
||||||
trace::Trace,
|
trace::Trace,
|
||||||
type_ref::TypeRef,
|
type_ref::TypeRef,
|
||||||
visibility::RawVisibility,
|
visibility::RawVisibility,
|
||||||
EnumId, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
|
EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId,
|
||||||
|
VariantId,
|
||||||
};
|
};
|
||||||
use cfg::CfgOptions;
|
use cfg::CfgOptions;
|
||||||
|
|
||||||
|
@ -31,7 +34,7 @@ use cfg::CfgOptions;
|
||||||
pub struct StructData {
|
pub struct StructData {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub variant_data: Arc<VariantData>,
|
pub variant_data: Arc<VariantData>,
|
||||||
pub repr: Option<ReprKind>,
|
pub repr: Option<ReprData>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +42,7 @@ pub struct StructData {
|
||||||
pub struct EnumData {
|
pub struct EnumData {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub variants: Arena<EnumVariantData>,
|
pub variants: Arena<EnumVariantData>,
|
||||||
|
pub repr: Option<ReprData>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +67,19 @@ pub struct FieldData {
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ReprKind {
|
pub enum ReprKind {
|
||||||
Packed,
|
C,
|
||||||
Other,
|
BuiltinInt { builtin: Either<BuiltinInt, BuiltinUint>, is_c: bool },
|
||||||
|
Transparent,
|
||||||
|
Default,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ReprData {
|
||||||
|
pub kind: ReprKind,
|
||||||
|
pub packed: bool,
|
||||||
|
pub align: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repr_from_value(
|
fn repr_from_value(
|
||||||
|
@ -74,25 +87,71 @@ fn repr_from_value(
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
item_tree: &ItemTree,
|
item_tree: &ItemTree,
|
||||||
of: AttrOwner,
|
of: AttrOwner,
|
||||||
) -> Option<ReprKind> {
|
) -> Option<ReprData> {
|
||||||
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
|
item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
|
fn parse_repr_tt(tt: &Subtree) -> Option<ReprData> {
|
||||||
match tt.delimiter {
|
match tt.delimiter {
|
||||||
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
|
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut it = tt.token_trees.iter();
|
let mut data = ReprData { kind: ReprKind::Default, packed: false, align: None };
|
||||||
match it.next()? {
|
|
||||||
TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed),
|
let mut tts = tt.token_trees.iter().peekable();
|
||||||
_ => Some(ReprKind::Other),
|
while let Some(tt) = tts.next() {
|
||||||
|
if let TokenTree::Leaf(Leaf::Ident(ident)) = tt {
|
||||||
|
match &*ident.text {
|
||||||
|
"packed" => {
|
||||||
|
data.packed = true;
|
||||||
|
if let Some(TokenTree::Subtree(_)) = tts.peek() {
|
||||||
|
tts.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"align" => {
|
||||||
|
if let Some(TokenTree::Subtree(tt)) = tts.peek() {
|
||||||
|
tts.next();
|
||||||
|
if let Some(TokenTree::Leaf(Leaf::Literal(lit))) = tt.token_trees.first() {
|
||||||
|
if let Ok(align) = lit.text.parse() {
|
||||||
|
data.align = Some(align);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"C" => {
|
||||||
|
if let ReprKind::BuiltinInt { is_c, .. } = &mut data.kind {
|
||||||
|
*is_c = true;
|
||||||
|
} else {
|
||||||
|
data.kind = ReprKind::C;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"transparent" => data.kind = ReprKind::Transparent,
|
||||||
|
repr => {
|
||||||
|
let is_c = matches!(data.kind, ReprKind::C);
|
||||||
|
if let Some(builtin) = BuiltinInt::from_suffix(repr)
|
||||||
|
.map(Either::Left)
|
||||||
|
.or_else(|| BuiltinUint::from_suffix(repr).map(Either::Right))
|
||||||
|
{
|
||||||
|
data.kind = ReprKind::BuiltinInt { builtin, is_c };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StructData {
|
impl StructData {
|
||||||
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
|
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
|
||||||
|
db.struct_data_with_diagnostics(id).0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn struct_data_with_diagnostics_query(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
id: StructId,
|
||||||
|
) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
|
||||||
let loc = id.lookup(db);
|
let loc = id.lookup(db);
|
||||||
let krate = loc.container.krate;
|
let krate = loc.container.krate;
|
||||||
let item_tree = loc.id.item_tree(db);
|
let item_tree = loc.id.item_tree(db);
|
||||||
|
@ -100,15 +159,35 @@ impl StructData {
|
||||||
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
|
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
|
||||||
|
|
||||||
let strukt = &item_tree[loc.id.value];
|
let strukt = &item_tree[loc.id.value];
|
||||||
let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
|
let (variant_data, diagnostics) = lower_fields(
|
||||||
Arc::new(StructData {
|
db,
|
||||||
name: strukt.name.clone(),
|
krate,
|
||||||
variant_data: Arc::new(variant_data),
|
loc.id.file_id(),
|
||||||
repr,
|
loc.container.local_id,
|
||||||
visibility: item_tree[strukt.visibility].clone(),
|
&item_tree,
|
||||||
})
|
&cfg_options,
|
||||||
|
&strukt.fields,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
(
|
||||||
|
Arc::new(StructData {
|
||||||
|
name: strukt.name.clone(),
|
||||||
|
variant_data: Arc::new(variant_data),
|
||||||
|
repr,
|
||||||
|
visibility: item_tree[strukt.visibility].clone(),
|
||||||
|
}),
|
||||||
|
diagnostics.into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
|
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
|
||||||
|
db.union_data_with_diagnostics(id).0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn union_data_with_diagnostics_query(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
id: UnionId,
|
||||||
|
) -> (Arc<StructData>, Arc<[DefDiagnostic]>) {
|
||||||
let loc = id.lookup(db);
|
let loc = id.lookup(db);
|
||||||
let krate = loc.container.krate;
|
let krate = loc.container.krate;
|
||||||
let item_tree = loc.id.item_tree(db);
|
let item_tree = loc.id.item_tree(db);
|
||||||
|
@ -116,56 +195,98 @@ impl StructData {
|
||||||
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
|
let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
|
||||||
|
|
||||||
let union = &item_tree[loc.id.value];
|
let union = &item_tree[loc.id.value];
|
||||||
let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
|
let (variant_data, diagnostics) = lower_fields(
|
||||||
|
db,
|
||||||
Arc::new(StructData {
|
krate,
|
||||||
name: union.name.clone(),
|
loc.id.file_id(),
|
||||||
variant_data: Arc::new(variant_data),
|
loc.container.local_id,
|
||||||
repr,
|
&item_tree,
|
||||||
visibility: item_tree[union.visibility].clone(),
|
&cfg_options,
|
||||||
})
|
&union.fields,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
(
|
||||||
|
Arc::new(StructData {
|
||||||
|
name: union.name.clone(),
|
||||||
|
variant_data: Arc::new(variant_data),
|
||||||
|
repr,
|
||||||
|
visibility: item_tree[union.visibility].clone(),
|
||||||
|
}),
|
||||||
|
diagnostics.into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumData {
|
impl EnumData {
|
||||||
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
||||||
|
db.enum_data_with_diagnostics(e).0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enum_data_with_diagnostics_query(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
e: EnumId,
|
||||||
|
) -> (Arc<EnumData>, Arc<[DefDiagnostic]>) {
|
||||||
let loc = e.lookup(db);
|
let loc = e.lookup(db);
|
||||||
let krate = loc.container.krate;
|
let krate = loc.container.krate;
|
||||||
let item_tree = loc.id.item_tree(db);
|
let item_tree = loc.id.item_tree(db);
|
||||||
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
||||||
|
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||||
|
|
||||||
let enum_ = &item_tree[loc.id.value];
|
let enum_ = &item_tree[loc.id.value];
|
||||||
let mut variants = Arena::new();
|
let mut variants = Arena::new();
|
||||||
|
let mut diagnostics = Vec::new();
|
||||||
for tree_id in enum_.variants.clone() {
|
for tree_id in enum_.variants.clone() {
|
||||||
if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) {
|
let attrs = item_tree.attrs(db, krate, tree_id.into());
|
||||||
let var = &item_tree[tree_id];
|
let var = &item_tree[tree_id];
|
||||||
let var_data = lower_fields(
|
if attrs.is_cfg_enabled(&cfg_options) {
|
||||||
|
let (var_data, field_diagnostics) = lower_fields(
|
||||||
db,
|
db,
|
||||||
krate,
|
krate,
|
||||||
|
loc.id.file_id(),
|
||||||
|
loc.container.local_id,
|
||||||
&item_tree,
|
&item_tree,
|
||||||
&cfg_options,
|
&cfg_options,
|
||||||
&var.fields,
|
&var.fields,
|
||||||
Some(enum_.visibility),
|
Some(enum_.visibility),
|
||||||
);
|
);
|
||||||
|
diagnostics.extend(field_diagnostics);
|
||||||
|
|
||||||
variants.alloc(EnumVariantData {
|
variants.alloc(EnumVariantData {
|
||||||
name: var.name.clone(),
|
name: var.name.clone(),
|
||||||
variant_data: Arc::new(var_data),
|
variant_data: Arc::new(var_data),
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||||
|
loc.container.local_id,
|
||||||
|
InFile::new(loc.id.file_id(), var.ast_id.upcast()),
|
||||||
|
attrs.cfg().unwrap(),
|
||||||
|
cfg_options.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Arc::new(EnumData {
|
(
|
||||||
name: enum_.name.clone(),
|
Arc::new(EnumData {
|
||||||
variants,
|
name: enum_.name.clone(),
|
||||||
visibility: item_tree[enum_.visibility].clone(),
|
variants,
|
||||||
})
|
repr,
|
||||||
|
visibility: item_tree[enum_.visibility].clone(),
|
||||||
|
}),
|
||||||
|
diagnostics.into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
|
pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
|
||||||
let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
|
let (id, _) = self.variants.iter().find(|(_id, data)| &data.name == name)?;
|
||||||
Some(id)
|
Some(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn variant_body_type(&self) -> Either<BuiltinInt, BuiltinUint> {
|
||||||
|
match self.repr {
|
||||||
|
Some(ReprData { kind: ReprKind::BuiltinInt { builtin, .. }, .. }) => builtin,
|
||||||
|
_ => Either::Left(BuiltinInt::Isize),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasChildSource<LocalEnumVariantId> for EnumId {
|
impl HasChildSource<LocalEnumVariantId> for EnumId {
|
||||||
|
@ -324,31 +445,64 @@ fn lower_struct(
|
||||||
fn lower_fields(
|
fn lower_fields(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
|
current_file_id: HirFileId,
|
||||||
|
container: LocalModuleId,
|
||||||
item_tree: &ItemTree,
|
item_tree: &ItemTree,
|
||||||
cfg_options: &CfgOptions,
|
cfg_options: &CfgOptions,
|
||||||
fields: &Fields,
|
fields: &Fields,
|
||||||
override_visibility: Option<RawVisibilityId>,
|
override_visibility: Option<RawVisibilityId>,
|
||||||
) -> VariantData {
|
) -> (VariantData, Vec<DefDiagnostic>) {
|
||||||
|
let mut diagnostics = Vec::new();
|
||||||
match fields {
|
match fields {
|
||||||
Fields::Record(flds) => {
|
Fields::Record(flds) => {
|
||||||
let mut arena = Arena::new();
|
let mut arena = Arena::new();
|
||||||
for field_id in flds.clone() {
|
for field_id in flds.clone() {
|
||||||
if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
|
let attrs = item_tree.attrs(db, krate, field_id.into());
|
||||||
arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
|
let field = &item_tree[field_id];
|
||||||
|
if attrs.is_cfg_enabled(cfg_options) {
|
||||||
|
arena.alloc(lower_field(item_tree, field, override_visibility));
|
||||||
|
} else {
|
||||||
|
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||||
|
container,
|
||||||
|
InFile::new(
|
||||||
|
current_file_id,
|
||||||
|
match field.ast_id {
|
||||||
|
FieldAstId::Record(it) => it.upcast(),
|
||||||
|
FieldAstId::Tuple(it) => it.upcast(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
attrs.cfg().unwrap(),
|
||||||
|
cfg_options.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariantData::Record(arena)
|
(VariantData::Record(arena), diagnostics)
|
||||||
}
|
}
|
||||||
Fields::Tuple(flds) => {
|
Fields::Tuple(flds) => {
|
||||||
let mut arena = Arena::new();
|
let mut arena = Arena::new();
|
||||||
for field_id in flds.clone() {
|
for field_id in flds.clone() {
|
||||||
if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
|
let attrs = item_tree.attrs(db, krate, field_id.into());
|
||||||
arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
|
let field = &item_tree[field_id];
|
||||||
|
if attrs.is_cfg_enabled(cfg_options) {
|
||||||
|
arena.alloc(lower_field(item_tree, field, override_visibility));
|
||||||
|
} else {
|
||||||
|
diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||||
|
container,
|
||||||
|
InFile::new(
|
||||||
|
current_file_id,
|
||||||
|
match field.ast_id {
|
||||||
|
FieldAstId::Record(it) => it.upcast(),
|
||||||
|
FieldAstId::Tuple(it) => it.upcast(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
attrs.cfg().unwrap(),
|
||||||
|
cfg_options.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariantData::Tuple(arena)
|
(VariantData::Tuple(arena), diagnostics)
|
||||||
}
|
}
|
||||||
Fields::Unit => VariantData::Unit,
|
Fields::Unit => (VariantData::Unit, diagnostics),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use crate::{
|
||||||
macro_id_to_def_id,
|
macro_id_to_def_id,
|
||||||
nameres::DefMap,
|
nameres::DefMap,
|
||||||
path::{ModPath, Path},
|
path::{ModPath, Path},
|
||||||
src::HasSource,
|
src::{HasChildSource, HasSource},
|
||||||
AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
|
AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
|
||||||
UnresolvedMacro,
|
UnresolvedMacro,
|
||||||
};
|
};
|
||||||
|
@ -311,7 +311,20 @@ impl Body {
|
||||||
DefWithBodyId::FunctionId(f) => {
|
DefWithBodyId::FunctionId(f) => {
|
||||||
let f = f.lookup(db);
|
let f = f.lookup(db);
|
||||||
let src = f.source(db);
|
let src = f.source(db);
|
||||||
params = src.value.param_list();
|
params = src.value.param_list().map(|param_list| {
|
||||||
|
let item_tree = f.id.item_tree(db);
|
||||||
|
let func = &item_tree[f.id.value];
|
||||||
|
let krate = f.container.module(db).krate;
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
(
|
||||||
|
param_list,
|
||||||
|
func.params.clone().map(move |param| {
|
||||||
|
item_tree
|
||||||
|
.attrs(db, krate, param.into())
|
||||||
|
.is_cfg_enabled(&crate_graph[krate].cfg_options)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
});
|
||||||
(src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
|
(src.file_id, f.module(db), src.value.body().map(ast::Expr::from))
|
||||||
}
|
}
|
||||||
DefWithBodyId::ConstId(c) => {
|
DefWithBodyId::ConstId(c) => {
|
||||||
|
@ -324,10 +337,17 @@ impl Body {
|
||||||
let src = s.source(db);
|
let src = s.source(db);
|
||||||
(src.file_id, s.module(db), src.value.body())
|
(src.file_id, s.module(db), src.value.body())
|
||||||
}
|
}
|
||||||
|
DefWithBodyId::VariantId(v) => {
|
||||||
|
let e = v.parent.lookup(db);
|
||||||
|
let src = v.parent.child_source(db);
|
||||||
|
let variant = &src.value[v.local_id];
|
||||||
|
(src.file_id, e.container, variant.expr())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let expander = Expander::new(db, file_id, module);
|
let expander = Expander::new(db, file_id, module);
|
||||||
let (mut body, source_map) = Body::new(db, expander, params, body);
|
let (mut body, source_map) = Body::new(db, expander, params, body);
|
||||||
body.shrink_to_fit();
|
body.shrink_to_fit();
|
||||||
|
|
||||||
(Arc::new(body), Arc::new(source_map))
|
(Arc::new(body), Arc::new(source_map))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +384,7 @@ impl Body {
|
||||||
fn new(
|
fn new(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
expander: Expander,
|
expander: Expander,
|
||||||
params: Option<ast::ParamList>,
|
params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
|
||||||
body: Option<ast::Expr>,
|
body: Option<ast::Expr>,
|
||||||
) -> (Body, BodySourceMap) {
|
) -> (Body, BodySourceMap) {
|
||||||
lower::lower(db, expander, params, body)
|
lower::lower(db, expander, params, body)
|
||||||
|
|
|
@ -29,8 +29,9 @@ use crate::{
|
||||||
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
|
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expr::{
|
expr::{
|
||||||
dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
|
dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper,
|
||||||
Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField,
|
||||||
|
Statement,
|
||||||
},
|
},
|
||||||
intern::Interned,
|
intern::Interned,
|
||||||
item_scope::BuiltinShadowMode,
|
item_scope::BuiltinShadowMode,
|
||||||
|
@ -76,7 +77,7 @@ impl<'a> LowerCtx<'a> {
|
||||||
pub(super) fn lower(
|
pub(super) fn lower(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
expander: Expander,
|
expander: Expander,
|
||||||
params: Option<ast::ParamList>,
|
params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
|
||||||
body: Option<ast::Expr>,
|
body: Option<ast::Expr>,
|
||||||
) -> (Body, BodySourceMap) {
|
) -> (Body, BodySourceMap) {
|
||||||
ExprCollector {
|
ExprCollector {
|
||||||
|
@ -97,6 +98,7 @@ pub(super) fn lower(
|
||||||
name_to_pat_grouping: Default::default(),
|
name_to_pat_grouping: Default::default(),
|
||||||
is_lowering_inside_or_pat: false,
|
is_lowering_inside_or_pat: false,
|
||||||
is_lowering_assignee_expr: false,
|
is_lowering_assignee_expr: false,
|
||||||
|
is_lowering_generator: false,
|
||||||
}
|
}
|
||||||
.collect(params, body)
|
.collect(params, body)
|
||||||
}
|
}
|
||||||
|
@ -111,16 +113,19 @@ struct ExprCollector<'a> {
|
||||||
name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
|
name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
|
||||||
is_lowering_inside_or_pat: bool,
|
is_lowering_inside_or_pat: bool,
|
||||||
is_lowering_assignee_expr: bool,
|
is_lowering_assignee_expr: bool,
|
||||||
|
is_lowering_generator: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprCollector<'_> {
|
impl ExprCollector<'_> {
|
||||||
fn collect(
|
fn collect(
|
||||||
mut self,
|
mut self,
|
||||||
param_list: Option<ast::ParamList>,
|
param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
|
||||||
body: Option<ast::Expr>,
|
body: Option<ast::Expr>,
|
||||||
) -> (Body, BodySourceMap) {
|
) -> (Body, BodySourceMap) {
|
||||||
if let Some(param_list) = param_list {
|
if let Some((param_list, mut attr_enabled)) = param_list {
|
||||||
if let Some(self_param) = param_list.self_param() {
|
if let Some(self_param) =
|
||||||
|
param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
|
||||||
|
{
|
||||||
let ptr = AstPtr::new(&self_param);
|
let ptr = AstPtr::new(&self_param);
|
||||||
let param_pat = self.alloc_pat(
|
let param_pat = self.alloc_pat(
|
||||||
Pat::Bind {
|
Pat::Bind {
|
||||||
|
@ -136,7 +141,11 @@ impl ExprCollector<'_> {
|
||||||
self.body.params.push(param_pat);
|
self.body.params.push(param_pat);
|
||||||
}
|
}
|
||||||
|
|
||||||
for pat in param_list.params().filter_map(|param| param.pat()) {
|
for pat in param_list
|
||||||
|
.params()
|
||||||
|
.zip(attr_enabled)
|
||||||
|
.filter_map(|(param, enabled)| param.pat().filter(|_| enabled))
|
||||||
|
{
|
||||||
let param_pat = self.collect_pat(pat);
|
let param_pat = self.collect_pat(pat);
|
||||||
self.body.params.push(param_pat);
|
self.body.params.push(param_pat);
|
||||||
}
|
}
|
||||||
|
@ -358,6 +367,7 @@ impl ExprCollector<'_> {
|
||||||
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
|
self.alloc_expr(Expr::Return { expr }, syntax_ptr)
|
||||||
}
|
}
|
||||||
ast::Expr::YieldExpr(e) => {
|
ast::Expr::YieldExpr(e) => {
|
||||||
|
self.is_lowering_generator = true;
|
||||||
let expr = e.expr().map(|e| self.collect_expr(e));
|
let expr = e.expr().map(|e| self.collect_expr(e));
|
||||||
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
|
self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
|
||||||
}
|
}
|
||||||
|
@ -459,13 +469,31 @@ impl ExprCollector<'_> {
|
||||||
.ret_type()
|
.ret_type()
|
||||||
.and_then(|r| r.ty())
|
.and_then(|r| r.ty())
|
||||||
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
.map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
|
||||||
|
|
||||||
|
let prev_is_lowering_generator = self.is_lowering_generator;
|
||||||
|
self.is_lowering_generator = false;
|
||||||
|
|
||||||
let body = self.collect_expr_opt(e.body());
|
let body = self.collect_expr_opt(e.body());
|
||||||
|
|
||||||
|
let closure_kind = if self.is_lowering_generator {
|
||||||
|
let movability = if e.static_token().is_some() {
|
||||||
|
Movability::Static
|
||||||
|
} else {
|
||||||
|
Movability::Movable
|
||||||
|
};
|
||||||
|
ClosureKind::Generator(movability)
|
||||||
|
} else {
|
||||||
|
ClosureKind::Closure
|
||||||
|
};
|
||||||
|
self.is_lowering_generator = prev_is_lowering_generator;
|
||||||
|
|
||||||
self.alloc_expr(
|
self.alloc_expr(
|
||||||
Expr::Closure {
|
Expr::Closure {
|
||||||
args: args.into(),
|
args: args.into(),
|
||||||
arg_types: arg_types.into(),
|
arg_types: arg_types.into(),
|
||||||
ret_type,
|
ret_type,
|
||||||
body,
|
body,
|
||||||
|
closure_kind,
|
||||||
},
|
},
|
||||||
syntax_ptr,
|
syntax_ptr,
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
|
use syntax::ast::HasName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
expr::{Array, BindingAnnotation, Literal, Statement},
|
expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
|
||||||
pretty::{print_generic_args, print_path, print_type_ref},
|
pretty::{print_generic_args, print_path, print_type_ref},
|
||||||
type_ref::TypeRef,
|
type_ref::TypeRef,
|
||||||
};
|
};
|
||||||
|
@ -32,6 +34,16 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
|
||||||
};
|
};
|
||||||
format!("const {} = ", name)
|
format!("const {} = ", name)
|
||||||
}
|
}
|
||||||
|
DefWithBodyId::VariantId(it) => {
|
||||||
|
needs_semi = false;
|
||||||
|
let src = it.parent.child_source(db);
|
||||||
|
let variant = &src.value[it.local_id];
|
||||||
|
let name = match &variant.name() {
|
||||||
|
Some(name) => name.to_string(),
|
||||||
|
None => "_".to_string(),
|
||||||
|
};
|
||||||
|
format!("{}", name)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
|
let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
|
||||||
|
@ -350,7 +362,10 @@ impl<'a> Printer<'a> {
|
||||||
self.print_expr(*index);
|
self.print_expr(*index);
|
||||||
w!(self, "]");
|
w!(self, "]");
|
||||||
}
|
}
|
||||||
Expr::Closure { args, arg_types, ret_type, body } => {
|
Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
|
||||||
|
if let ClosureKind::Generator(Movability::Static) = closure_kind {
|
||||||
|
w!(self, "static ");
|
||||||
|
}
|
||||||
w!(self, "|");
|
w!(self, "|");
|
||||||
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
|
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
|
|
|
@ -379,7 +379,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
||||||
rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
||||||
gated!(
|
gated!(
|
||||||
alloc_error_handler, Normal, template!(Word), WarnFollowing,
|
alloc_error_handler, Normal, template!(Word), WarnFollowing,
|
||||||
experimental!(alloc_error_handler)
|
experimental!(alloc_error_handler)
|
||||||
|
|
|
@ -198,6 +198,10 @@ impl ChildBySource for EnumId {
|
||||||
impl ChildBySource for DefWithBodyId {
|
impl ChildBySource for DefWithBodyId {
|
||||||
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
|
fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
|
||||||
let body = db.body(*self);
|
let body = db.body(*self);
|
||||||
|
if let &DefWithBodyId::VariantId(v) = self {
|
||||||
|
VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id)
|
||||||
|
}
|
||||||
|
|
||||||
for (_, def_map) in body.blocks(db) {
|
for (_, def_map) in body.blocks(db) {
|
||||||
// All block expressions are merged into the same map, because they logically all add
|
// All block expressions are merged into the same map, because they logically all add
|
||||||
// inner items to the containing `DefWithBodyId`.
|
// inner items to the containing `DefWithBodyId`.
|
||||||
|
|
|
@ -219,7 +219,7 @@ impl TraitData {
|
||||||
pub(crate) fn trait_data_with_diagnostics_query(
|
pub(crate) fn trait_data_with_diagnostics_query(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
tr: TraitId,
|
tr: TraitId,
|
||||||
) -> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>) {
|
) -> (Arc<TraitData>, Arc<[DefDiagnostic]>) {
|
||||||
let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
|
let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
|
||||||
let item_tree = tree_id.item_tree(db);
|
let item_tree = tree_id.item_tree(db);
|
||||||
let tr_def = &item_tree[tree_id.value];
|
let tr_def = &item_tree[tree_id.value];
|
||||||
|
@ -251,7 +251,7 @@ impl TraitData {
|
||||||
visibility,
|
visibility,
|
||||||
skip_array_during_method_dispatch,
|
skip_array_during_method_dispatch,
|
||||||
}),
|
}),
|
||||||
Arc::new(diagnostics),
|
diagnostics.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ impl ImplData {
|
||||||
pub(crate) fn impl_data_with_diagnostics_query(
|
pub(crate) fn impl_data_with_diagnostics_query(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
id: ImplId,
|
id: ImplId,
|
||||||
) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>) {
|
) -> (Arc<ImplData>, Arc<[DefDiagnostic]>) {
|
||||||
let _p = profile::span("impl_data_with_diagnostics_query");
|
let _p = profile::span("impl_data_with_diagnostics_query");
|
||||||
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
|
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ impl ImplData {
|
||||||
|
|
||||||
(
|
(
|
||||||
Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
|
Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls }),
|
||||||
Arc::new(diagnostics),
|
diagnostics.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,24 +97,33 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
|
||||||
#[salsa::invoke(StructData::struct_data_query)]
|
#[salsa::invoke(StructData::struct_data_query)]
|
||||||
fn struct_data(&self, id: StructId) -> Arc<StructData>;
|
fn struct_data(&self, id: StructId) -> Arc<StructData>;
|
||||||
|
|
||||||
|
#[salsa::invoke(StructData::struct_data_with_diagnostics_query)]
|
||||||
|
fn struct_data_with_diagnostics(&self, id: StructId)
|
||||||
|
-> (Arc<StructData>, Arc<[DefDiagnostic]>);
|
||||||
|
|
||||||
#[salsa::invoke(StructData::union_data_query)]
|
#[salsa::invoke(StructData::union_data_query)]
|
||||||
fn union_data(&self, id: UnionId) -> Arc<StructData>;
|
fn union_data(&self, id: UnionId) -> Arc<StructData>;
|
||||||
|
|
||||||
|
#[salsa::invoke(StructData::union_data_with_diagnostics_query)]
|
||||||
|
fn union_data_with_diagnostics(&self, id: UnionId) -> (Arc<StructData>, Arc<[DefDiagnostic]>);
|
||||||
|
|
||||||
#[salsa::invoke(EnumData::enum_data_query)]
|
#[salsa::invoke(EnumData::enum_data_query)]
|
||||||
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
|
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
|
||||||
|
|
||||||
|
#[salsa::invoke(EnumData::enum_data_with_diagnostics_query)]
|
||||||
|
fn enum_data_with_diagnostics(&self, e: EnumId) -> (Arc<EnumData>, Arc<[DefDiagnostic]>);
|
||||||
|
|
||||||
#[salsa::invoke(ImplData::impl_data_query)]
|
#[salsa::invoke(ImplData::impl_data_query)]
|
||||||
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
|
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
|
||||||
|
|
||||||
#[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
|
#[salsa::invoke(ImplData::impl_data_with_diagnostics_query)]
|
||||||
fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<Vec<DefDiagnostic>>);
|
fn impl_data_with_diagnostics(&self, e: ImplId) -> (Arc<ImplData>, Arc<[DefDiagnostic]>);
|
||||||
|
|
||||||
#[salsa::invoke(TraitData::trait_data_query)]
|
#[salsa::invoke(TraitData::trait_data_query)]
|
||||||
fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
|
fn trait_data(&self, e: TraitId) -> Arc<TraitData>;
|
||||||
|
|
||||||
#[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
|
#[salsa::invoke(TraitData::trait_data_with_diagnostics_query)]
|
||||||
fn trait_data_with_diagnostics(&self, tr: TraitId)
|
fn trait_data_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitData>, Arc<[DefDiagnostic]>);
|
||||||
-> (Arc<TraitData>, Arc<Vec<DefDiagnostic>>);
|
|
||||||
|
|
||||||
#[salsa::invoke(TypeAliasData::type_alias_data_query)]
|
#[salsa::invoke(TypeAliasData::type_alias_data_query)]
|
||||||
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
|
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
|
||||||
|
|
|
@ -198,6 +198,7 @@ pub enum Expr {
|
||||||
arg_types: Box<[Option<Interned<TypeRef>>]>,
|
arg_types: Box<[Option<Interned<TypeRef>>]>,
|
||||||
ret_type: Option<Interned<TypeRef>>,
|
ret_type: Option<Interned<TypeRef>>,
|
||||||
body: ExprId,
|
body: ExprId,
|
||||||
|
closure_kind: ClosureKind,
|
||||||
},
|
},
|
||||||
Tuple {
|
Tuple {
|
||||||
exprs: Box<[ExprId]>,
|
exprs: Box<[ExprId]>,
|
||||||
|
@ -211,6 +212,18 @@ pub enum Expr {
|
||||||
Underscore,
|
Underscore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum ClosureKind {
|
||||||
|
Closure,
|
||||||
|
Generator(Movability),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Movability {
|
||||||
|
Static,
|
||||||
|
Movable,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum Array {
|
pub enum Array {
|
||||||
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
|
ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
|
||||||
|
|
|
@ -333,8 +333,8 @@ fn calculate_best_path(
|
||||||
db,
|
db,
|
||||||
def_map,
|
def_map,
|
||||||
visited_modules,
|
visited_modules,
|
||||||
from,
|
|
||||||
crate_root,
|
crate_root,
|
||||||
|
from,
|
||||||
info.container,
|
info.container,
|
||||||
max_len - 1,
|
max_len - 1,
|
||||||
prefixed,
|
prefixed,
|
||||||
|
|
|
@ -943,6 +943,7 @@ impl AssocItem {
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub fields: Fields,
|
pub fields: Fields,
|
||||||
|
pub ast_id: FileAstId<ast::Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -952,10 +953,17 @@ pub enum Fields {
|
||||||
Unit,
|
Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum FieldAstId {
|
||||||
|
Record(FileAstId<ast::RecordField>),
|
||||||
|
Tuple(FileAstId<ast::TupleField>),
|
||||||
|
}
|
||||||
|
|
||||||
/// A single field of an enum variant or struct
|
/// A single field of an enum variant or struct
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub type_ref: Interned<TypeRef>,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub visibility: RawVisibilityId,
|
pub visibility: RawVisibilityId,
|
||||||
|
pub ast_id: FieldAstId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,8 @@ impl<'a> Ctx<'a> {
|
||||||
let name = field.name()?.as_name();
|
let name = field.name()?.as_name();
|
||||||
let visibility = self.lower_visibility(field);
|
let visibility = self.lower_visibility(field);
|
||||||
let type_ref = self.lower_type_ref_opt(field.ty());
|
let type_ref = self.lower_type_ref_opt(field.ty());
|
||||||
let res = Field { name, type_ref, visibility };
|
let ast_id = FieldAstId::Record(self.source_ast_id_map.ast_id(field));
|
||||||
|
let res = Field { name, type_ref, visibility, ast_id };
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +204,8 @@ impl<'a> Ctx<'a> {
|
||||||
let name = Name::new_tuple_field(idx);
|
let name = Name::new_tuple_field(idx);
|
||||||
let visibility = self.lower_visibility(field);
|
let visibility = self.lower_visibility(field);
|
||||||
let type_ref = self.lower_type_ref_opt(field.ty());
|
let type_ref = self.lower_type_ref_opt(field.ty());
|
||||||
Field { name, type_ref, visibility }
|
let ast_id = FieldAstId::Tuple(self.source_ast_id_map.ast_id(field));
|
||||||
|
Field { name, type_ref, visibility, ast_id }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
|
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
|
||||||
|
@ -247,7 +249,8 @@ impl<'a> Ctx<'a> {
|
||||||
fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
|
fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
|
||||||
let name = variant.name()?.as_name();
|
let name = variant.name()?.as_name();
|
||||||
let fields = self.lower_fields(&variant.kind());
|
let fields = self.lower_fields(&variant.kind());
|
||||||
let res = Variant { name, fields };
|
let ast_id = self.source_ast_id_map.ast_id(variant);
|
||||||
|
let res = Variant { name, fields, ast_id };
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ impl<'a> Printer<'a> {
|
||||||
w!(self, "{{");
|
w!(self, "{{");
|
||||||
self.indented(|this| {
|
self.indented(|this| {
|
||||||
for field in fields.clone() {
|
for field in fields.clone() {
|
||||||
let Field { visibility, name, type_ref } = &this.tree[field];
|
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||||
this.print_attrs_of(field);
|
this.print_attrs_of(field);
|
||||||
this.print_visibility(*visibility);
|
this.print_visibility(*visibility);
|
||||||
w!(this, "{}: ", name);
|
w!(this, "{}: ", name);
|
||||||
|
@ -129,7 +129,7 @@ impl<'a> Printer<'a> {
|
||||||
w!(self, "(");
|
w!(self, "(");
|
||||||
self.indented(|this| {
|
self.indented(|this| {
|
||||||
for field in fields.clone() {
|
for field in fields.clone() {
|
||||||
let Field { visibility, name, type_ref } = &this.tree[field];
|
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||||
this.print_attrs_of(field);
|
this.print_attrs_of(field);
|
||||||
this.print_visibility(*visibility);
|
this.print_visibility(*visibility);
|
||||||
w!(this, "{}: ", name);
|
w!(this, "{}: ", name);
|
||||||
|
@ -323,7 +323,7 @@ impl<'a> Printer<'a> {
|
||||||
self.print_where_clause_and_opening_brace(generic_params);
|
self.print_where_clause_and_opening_brace(generic_params);
|
||||||
self.indented(|this| {
|
self.indented(|this| {
|
||||||
for variant in variants.clone() {
|
for variant in variants.clone() {
|
||||||
let Variant { name, fields } = &this.tree[variant];
|
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
|
||||||
this.print_attrs_of(variant);
|
this.print_attrs_of(variant);
|
||||||
w!(this, "{}", name);
|
w!(this, "{}", name);
|
||||||
this.print_fields(fields);
|
this.print_fields(fields);
|
||||||
|
|
|
@ -474,16 +474,24 @@ pub enum DefWithBodyId {
|
||||||
FunctionId(FunctionId),
|
FunctionId(FunctionId),
|
||||||
StaticId(StaticId),
|
StaticId(StaticId),
|
||||||
ConstId(ConstId),
|
ConstId(ConstId),
|
||||||
|
VariantId(EnumVariantId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
|
impl_from!(FunctionId, ConstId, StaticId for DefWithBodyId);
|
||||||
|
|
||||||
|
impl From<EnumVariantId> for DefWithBodyId {
|
||||||
|
fn from(id: EnumVariantId) -> Self {
|
||||||
|
DefWithBodyId::VariantId(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DefWithBodyId {
|
impl DefWithBodyId {
|
||||||
pub fn as_generic_def_id(self) -> Option<GenericDefId> {
|
pub fn as_generic_def_id(self) -> Option<GenericDefId> {
|
||||||
match self {
|
match self {
|
||||||
DefWithBodyId::FunctionId(f) => Some(f.into()),
|
DefWithBodyId::FunctionId(f) => Some(f.into()),
|
||||||
DefWithBodyId::StaticId(_) => None,
|
DefWithBodyId::StaticId(_) => None,
|
||||||
DefWithBodyId::ConstId(c) => Some(c.into()),
|
DefWithBodyId::ConstId(c) => Some(c.into()),
|
||||||
|
DefWithBodyId::VariantId(c) => Some(c.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,6 +689,7 @@ impl HasModule for DefWithBodyId {
|
||||||
DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
|
DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
|
||||||
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
|
DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
|
||||||
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
|
DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
|
||||||
|
DefWithBodyId::VariantId(it) => it.parent.lookup(db).container,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -691,6 +700,7 @@ impl DefWithBodyId {
|
||||||
DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
|
DefWithBodyId::FunctionId(it) => it.lookup(db).id.value.into(),
|
||||||
DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
|
DefWithBodyId::StaticId(it) => it.lookup(db).id.value.into(),
|
||||||
DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
|
DefWithBodyId::ConstId(it) => it.lookup(db).id.value.into(),
|
||||||
|
DefWithBodyId::VariantId(it) => it.parent.lookup(db).id.value.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,12 +93,12 @@ macro_rules! option_env {() => {}}
|
||||||
|
|
||||||
fn main() { option_env!("TEST_ENV_VAR"); }
|
fn main() { option_env!("TEST_ENV_VAR"); }
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! option_env {() => {}}
|
macro_rules! option_env {() => {}}
|
||||||
|
|
||||||
fn main() { std::option::Option::None:: < &str>; }
|
fn main() { $crate::option::Option::None:: < &str>; }
|
||||||
"##]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ fn main() {
|
||||||
format_args!("{} {:?}", arg1(a, b, c), arg2);
|
format_args!("{} {:?}", arg1(a, b, c), arg2);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! format_args {
|
macro_rules! format_args {
|
||||||
($fmt:expr) => ({ /* compiler built-in */ });
|
($fmt:expr) => ({ /* compiler built-in */ });
|
||||||
|
@ -199,9 +199,9 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a, b, c)), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(arg2), std::fmt::Display::fmt), ]);
|
$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]);
|
||||||
}
|
}
|
||||||
"##]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ fn main() {
|
||||||
format_args!("{} {:?}", a::<A,B>(), b);
|
format_args!("{} {:?}", a::<A,B>(), b);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! format_args {
|
macro_rules! format_args {
|
||||||
($fmt:expr) => ({ /* compiler built-in */ });
|
($fmt:expr) => ({ /* compiler built-in */ });
|
||||||
|
@ -227,9 +227,9 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A, B>()), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(b), std::fmt::Display::fmt), ]);
|
$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]);
|
||||||
}
|
}
|
||||||
"##]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ fn main() {
|
||||||
format_args!/*+errors*/("{} {:?}", a.);
|
format_args!/*+errors*/("{} {:?}", a.);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r##"
|
expect![[r#"
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! format_args {
|
macro_rules! format_args {
|
||||||
($fmt:expr) => ({ /* compiler built-in */ });
|
($fmt:expr) => ({ /* compiler built-in */ });
|
||||||
|
@ -258,9 +258,9 @@ macro_rules! format_args {
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ =
|
let _ =
|
||||||
/* parse error: expected field name or number */
|
/* parse error: expected field name or number */
|
||||||
std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a.), std::fmt::Display::fmt), ]);
|
$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]);
|
||||||
}
|
}
|
||||||
"##]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2122,7 +2122,7 @@ impl ModCollector<'_, '_> {
|
||||||
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
|
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
|
||||||
let ast_id = item.ast_id(self.item_tree);
|
let ast_id = item.ast_id(self.item_tree);
|
||||||
|
|
||||||
let ast_id = InFile::new(self.file_id(), ast_id);
|
let ast_id = InFile::new(self.file_id(), ast_id.upcast());
|
||||||
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
|
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
|
||||||
self.module_id,
|
self.module_id,
|
||||||
ast_id,
|
ast_id,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use base_db::CrateId;
|
||||||
use cfg::{CfgExpr, CfgOptions};
|
use cfg::{CfgExpr, CfgOptions};
|
||||||
use hir_expand::MacroCallKind;
|
use hir_expand::MacroCallKind;
|
||||||
use la_arena::Idx;
|
use la_arena::Idx;
|
||||||
use syntax::ast;
|
use syntax::ast::{self, AnyHasAttrs};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::AttrId,
|
attr::AttrId,
|
||||||
|
@ -22,7 +22,7 @@ pub enum DefDiagnosticKind {
|
||||||
|
|
||||||
UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
|
UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
|
||||||
|
|
||||||
UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
|
UnconfiguredCode { ast: AstId<AnyHasAttrs>, cfg: CfgExpr, opts: CfgOptions },
|
||||||
|
|
||||||
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
|
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ impl DefDiagnostic {
|
||||||
|
|
||||||
pub fn unconfigured_code(
|
pub fn unconfigured_code(
|
||||||
container: LocalModuleId,
|
container: LocalModuleId,
|
||||||
ast: AstId<ast::Item>,
|
ast: AstId<ast::AnyHasAttrs>,
|
||||||
cfg: CfgExpr,
|
cfg: CfgExpr,
|
||||||
opts: CfgOptions,
|
opts: CfgOptions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
|
@ -839,6 +839,7 @@ impl HasResolver for DefWithBodyId {
|
||||||
DefWithBodyId::ConstId(c) => c.resolver(db),
|
DefWithBodyId::ConstId(c) => c.resolver(db),
|
||||||
DefWithBodyId::FunctionId(f) => f.resolver(db),
|
DefWithBodyId::FunctionId(f) => f.resolver(db),
|
||||||
DefWithBodyId::StaticId(s) => s.resolver(db),
|
DefWithBodyId::StaticId(s) => s.resolver(db),
|
||||||
|
DefWithBodyId::VariantId(v) => v.parent.resolver(db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ tracing = "0.1.35"
|
||||||
either = "1.7.0"
|
either = "1.7.0"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
|
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
hashbrown = { version = "0.12.1", features = [
|
hashbrown = { version = "0.12.1", features = [
|
||||||
"inline-more",
|
"inline-more",
|
||||||
], default-features = false }
|
], default-features = false }
|
||||||
smallvec = { version = "1.9.0", features = ["const_new"] }
|
smallvec = { version = "1.10.0", features = ["const_new"] }
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
base-db = { path = "../base-db", version = "0.0.0" }
|
base-db = { path = "../base-db", version = "0.0.0" }
|
||||||
|
|
|
@ -93,7 +93,12 @@ impl AstIdMap {
|
||||||
// trait does not change ids of top-level items, which helps caching.
|
// trait does not change ids of top-level items, which helps caching.
|
||||||
bdfs(node, |it| {
|
bdfs(node, |it| {
|
||||||
let kind = it.kind();
|
let kind = it.kind();
|
||||||
if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
|
if ast::Item::can_cast(kind)
|
||||||
|
|| ast::BlockExpr::can_cast(kind)
|
||||||
|
|| ast::Variant::can_cast(kind)
|
||||||
|
|| ast::RecordField::can_cast(kind)
|
||||||
|
|| ast::TupleField::can_cast(kind)
|
||||||
|
{
|
||||||
res.alloc(&it);
|
res.alloc(&it);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -238,9 +238,9 @@ fn format_args_expand(
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
// We expand `format_args!("", a1, a2)` to
|
// We expand `format_args!("", a1, a2)` to
|
||||||
// ```
|
// ```
|
||||||
// std::fmt::Arguments::new_v1(&[], &[
|
// $crate::fmt::Arguments::new_v1(&[], &[
|
||||||
// std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
|
// $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt),
|
||||||
// std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
|
// $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt),
|
||||||
// ])
|
// ])
|
||||||
// ```,
|
// ```,
|
||||||
// which is still not really correct, but close enough for now
|
// which is still not really correct, but close enough for now
|
||||||
|
@ -262,10 +262,10 @@ fn format_args_expand(
|
||||||
}
|
}
|
||||||
let _format_string = args.remove(0);
|
let _format_string = args.remove(0);
|
||||||
let arg_tts = args.into_iter().flat_map(|arg| {
|
let arg_tts = args.into_iter().flat_map(|arg| {
|
||||||
quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
|
quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), }
|
||||||
}.token_trees);
|
}.token_trees);
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
std::fmt::Arguments::new_v1(&[], &[##arg_tts])
|
#DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts])
|
||||||
};
|
};
|
||||||
ExpandResult::ok(expanded)
|
ExpandResult::ok(expanded)
|
||||||
}
|
}
|
||||||
|
@ -675,8 +675,8 @@ fn option_env_expand(
|
||||||
};
|
};
|
||||||
|
|
||||||
let expanded = match get_env_inner(db, arg_id, &key) {
|
let expanded = match get_env_inner(db, arg_id, &key) {
|
||||||
None => quote! { std::option::Option::None::<&str> },
|
None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> },
|
||||||
Some(s) => quote! { std::option::Some(#s) },
|
Some(s) => quote! { #DOLLAR_CRATE::option::Some(#s) },
|
||||||
};
|
};
|
||||||
|
|
||||||
ExpandResult::ok(ExpandedEager::new(expanded))
|
ExpandResult::ok(ExpandedEager::new(expanded))
|
||||||
|
|
|
@ -221,8 +221,16 @@ pub fn expand_speculative(
|
||||||
fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
|
fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
|
||||||
let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
|
let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
|
||||||
|
|
||||||
let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
|
let syntax_node = node.syntax_node();
|
||||||
let token = node.syntax_node().covering_element(range).into_token()?;
|
let token = rev_tmap
|
||||||
|
.ranges_by_token(token_id, token_to_map.kind())
|
||||||
|
.filter_map(|range| syntax_node.covering_element(range).into_token())
|
||||||
|
.min_by_key(|t| {
|
||||||
|
// prefer tokens of the same kind and text
|
||||||
|
// Note the inversion of the score here, as we want to prefer the first token in case
|
||||||
|
// of all tokens having the same score
|
||||||
|
(t.kind() != token_to_map.kind()) as u8 + (t.text() != token_to_map.text()) as u8
|
||||||
|
})?;
|
||||||
Some((node.syntax_node(), token))
|
Some((node.syntax_node(), token))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -811,6 +811,31 @@ impl<'a> InFile<&'a SyntaxNode> {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
|
||||||
|
// This kind of upmapping can only be achieved in attribute expanded files,
|
||||||
|
// as we don't have node inputs otherwise and therefor can't find an `N` node in the input
|
||||||
|
if !self.file_id.is_macro() {
|
||||||
|
return Some(self.map(Clone::clone));
|
||||||
|
} else if !self.file_id.is_attr_macro(db) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(InFile { file_id, value: (first, last) }) = ascend_node_border_tokens(db, self)
|
||||||
|
{
|
||||||
|
if file_id.is_macro() {
|
||||||
|
let range = first.text_range().cover(last.text_range());
|
||||||
|
tracing::error!("Failed mapping out of macro file for {:?}", range);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// FIXME: This heuristic is brittle and with the right macro may select completely unrelated nodes
|
||||||
|
let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
|
||||||
|
let kind = self.value.kind();
|
||||||
|
let value = anc.ancestors().find(|it| it.kind() == kind)?;
|
||||||
|
return Some(InFile::new(file_id, value));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InFile<SyntaxToken> {
|
impl InFile<SyntaxToken> {
|
||||||
|
|
|
@ -259,6 +259,7 @@ macro_rules! __known_path {
|
||||||
(core::future::Future) => {};
|
(core::future::Future) => {};
|
||||||
(core::future::IntoFuture) => {};
|
(core::future::IntoFuture) => {};
|
||||||
(core::ops::Try) => {};
|
(core::ops::Try) => {};
|
||||||
|
(core::ops::FromResidual) => {};
|
||||||
($path:path) => {
|
($path:path) => {
|
||||||
compile_error!("Please register your known path in the path module")
|
compile_error!("Please register your known path in the path module")
|
||||||
};
|
};
|
||||||
|
|
|
@ -263,6 +263,7 @@ pub mod known {
|
||||||
Iterator,
|
Iterator,
|
||||||
IntoIterator,
|
IntoIterator,
|
||||||
Item,
|
Item,
|
||||||
|
IntoIter,
|
||||||
Try,
|
Try,
|
||||||
Ok,
|
Ok,
|
||||||
Future,
|
Future,
|
||||||
|
@ -278,6 +279,8 @@ pub mod known {
|
||||||
RangeToInclusive,
|
RangeToInclusive,
|
||||||
RangeTo,
|
RangeTo,
|
||||||
Range,
|
Range,
|
||||||
|
Residual,
|
||||||
|
FromResidual,
|
||||||
Neg,
|
Neg,
|
||||||
Not,
|
Not,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -11,18 +11,19 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cov-mark = "2.0.0-pre.1"
|
cov-mark = "2.0.0-pre.1"
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
arrayvec = "0.7.2"
|
arrayvec = "0.7.2"
|
||||||
smallvec = "1.9.0"
|
smallvec = "1.10.0"
|
||||||
ena = "0.14.0"
|
ena = "0.14.0"
|
||||||
tracing = "0.1.35"
|
tracing = "0.1.35"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
scoped-tls = "1.0.0"
|
scoped-tls = "1.0.0"
|
||||||
chalk-solve = { version = "0.84.0", default-features = false }
|
chalk-solve = { version = "0.86.0", default-features = false }
|
||||||
chalk-ir = "0.84.0"
|
chalk-ir = "0.86.0"
|
||||||
chalk-recursive = { version = "0.84.0", default-features = false }
|
chalk-recursive = { version = "0.86.0", default-features = false }
|
||||||
|
chalk-derive = "0.86.0"
|
||||||
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
|
la-arena = { version = "0.3.0", path = "../../lib/la-arena" }
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.15.0"
|
||||||
typed-arena = "2.0.1"
|
typed-arena = "2.0.1"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
|
@ -37,7 +38,7 @@ limit = { path = "../limit", version = "0.0.0" }
|
||||||
test-utils = { path = "../test-utils" }
|
test-utils = { path = "../test-utils" }
|
||||||
expect-test = "1.4.0"
|
expect-test = "1.4.0"
|
||||||
tracing = "0.1.35"
|
tracing = "0.1.35"
|
||||||
tracing-subscriber = { version = "0.3.14", default-features = false, features = [
|
tracing-subscriber = { version = "0.3.16", default-features = false, features = [
|
||||||
"env-filter",
|
"env-filter",
|
||||||
"registry",
|
"registry",
|
||||||
] }
|
] }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! In certain situations, rust automatically inserts derefs as necessary: for
|
//! In certain situations, rust automatically inserts derefs as necessary: for
|
||||||
//! example, field accesses `foo.bar` still work when `foo` is actually a
|
//! example, field accesses `foo.bar` still work when `foo` is actually a
|
||||||
//! reference to a type with the field `bar`. This is an approximation of the
|
//! reference to a type with the field `bar`. This is an approximation of the
|
||||||
//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
|
//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
|
||||||
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
|
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
|
||||||
|
|
||||||
let projection = {
|
let projection = {
|
||||||
let b = TyBuilder::assoc_type_projection(db, target);
|
let b = TyBuilder::subst_for_def(db, deref_trait, None);
|
||||||
if b.remaining() != 1 {
|
if b.remaining() != 1 {
|
||||||
// the Target type + Deref trait should only have one generic parameter,
|
// the Target type + Deref trait should only have one generic parameter,
|
||||||
// namely Deref's Self type
|
// namely Deref's Self type
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
b.push(ty).build()
|
let deref_subst = b.push(ty).build();
|
||||||
|
TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that the type implements Deref at all
|
// Check that the type implements Deref at all
|
||||||
|
|
|
@ -6,19 +6,19 @@ use chalk_ir::{
|
||||||
cast::{Cast, CastTo, Caster},
|
cast::{Cast, CastTo, Caster},
|
||||||
fold::TypeFoldable,
|
fold::TypeFoldable,
|
||||||
interner::HasInterner,
|
interner::HasInterner,
|
||||||
AdtId, BoundVar, DebruijnIndex, Scalar,
|
AdtId, DebruijnIndex, Scalar,
|
||||||
};
|
};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
|
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
|
||||||
TypeAliasId,
|
GenericDefId, TraitId, TypeAliasId,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
|
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
|
||||||
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
|
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
|
||||||
ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
|
GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
|
||||||
TyDefId, TyExt, TyKind, ValueTyDefId,
|
ValueTyDefId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -34,17 +34,32 @@ pub struct TyBuilder<D> {
|
||||||
data: D,
|
data: D,
|
||||||
vec: SmallVec<[GenericArg; 2]>,
|
vec: SmallVec<[GenericArg; 2]>,
|
||||||
param_kinds: SmallVec<[ParamKind; 2]>,
|
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||||
|
parent_subst: Substitution,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> TyBuilder<A> {
|
impl<A> TyBuilder<A> {
|
||||||
fn with_data<B>(self, data: B) -> TyBuilder<B> {
|
fn with_data<B>(self, data: B) -> TyBuilder<B> {
|
||||||
TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
|
TyBuilder {
|
||||||
|
data,
|
||||||
|
vec: self.vec,
|
||||||
|
param_kinds: self.param_kinds,
|
||||||
|
parent_subst: self.parent_subst,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> TyBuilder<D> {
|
impl<D> TyBuilder<D> {
|
||||||
fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
|
fn new(
|
||||||
TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
|
data: D,
|
||||||
|
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||||
|
parent_subst: Option<Substitution>,
|
||||||
|
) -> Self {
|
||||||
|
let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||||
|
Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_empty(data: D) -> Self {
|
||||||
|
TyBuilder::new(data, SmallVec::new(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_internal(self) -> (D, Substitution) {
|
fn build_internal(self) -> (D, Substitution) {
|
||||||
|
@ -52,13 +67,18 @@ impl<D> TyBuilder<D> {
|
||||||
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
|
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
|
||||||
self.assert_match_kind(a, e);
|
self.assert_match_kind(a, e);
|
||||||
}
|
}
|
||||||
let subst = Substitution::from_iter(Interner, self.vec);
|
let subst = Substitution::from_iter(
|
||||||
|
Interner,
|
||||||
|
self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
|
||||||
|
);
|
||||||
(self.data, subst)
|
(self.data, subst)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
|
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
|
||||||
|
assert!(self.remaining() > 0);
|
||||||
let arg = arg.cast(Interner);
|
let arg = arg.cast(Interner);
|
||||||
let expected_kind = &self.param_kinds[self.vec.len()];
|
let expected_kind = &self.param_kinds[self.vec.len()];
|
||||||
|
|
||||||
let arg_kind = match arg.data(Interner) {
|
let arg_kind = match arg.data(Interner) {
|
||||||
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
|
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
|
||||||
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
|
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
|
||||||
|
@ -68,7 +88,9 @@ impl<D> TyBuilder<D> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert_eq!(*expected_kind, arg_kind);
|
assert_eq!(*expected_kind, arg_kind);
|
||||||
|
|
||||||
self.vec.push(arg);
|
self.vec.push(arg);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,20 +101,12 @@ impl<D> TyBuilder<D> {
|
||||||
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
|
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
|
||||||
// self.fill is inlined to make borrow checker happy
|
// self.fill is inlined to make borrow checker happy
|
||||||
let mut this = self;
|
let mut this = self;
|
||||||
let other = this.param_kinds.iter().skip(this.vec.len());
|
let other = &this.param_kinds[this.vec.len()..];
|
||||||
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
|
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
|
||||||
ParamKind::Type => {
|
ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
|
||||||
GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
|
ParamKind::Const(ty) => {
|
||||||
.intern(Interner)
|
BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
|
||||||
}
|
}
|
||||||
ParamKind::Const(ty) => GenericArgData::Const(
|
|
||||||
ConstData {
|
|
||||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
|
||||||
ty: ty.clone(),
|
|
||||||
}
|
|
||||||
.intern(Interner),
|
|
||||||
)
|
|
||||||
.intern(Interner),
|
|
||||||
});
|
});
|
||||||
this.vec.extend(filler.take(this.remaining()).casted(Interner));
|
this.vec.extend(filler.take(this.remaining()).casted(Interner));
|
||||||
assert_eq!(this.remaining(), 0);
|
assert_eq!(this.remaining(), 0);
|
||||||
|
@ -102,8 +116,8 @@ impl<D> TyBuilder<D> {
|
||||||
pub fn fill_with_unknown(self) -> Self {
|
pub fn fill_with_unknown(self) -> Self {
|
||||||
// self.fill is inlined to make borrow checker happy
|
// self.fill is inlined to make borrow checker happy
|
||||||
let mut this = self;
|
let mut this = self;
|
||||||
let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
|
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
|
||||||
ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
|
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||||
});
|
});
|
||||||
this.vec.extend(filler.casted(Interner));
|
this.vec.extend(filler.casted(Interner));
|
||||||
|
@ -113,33 +127,17 @@ impl<D> TyBuilder<D> {
|
||||||
|
|
||||||
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
|
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
|
||||||
self.fill(|x| match x {
|
self.fill(|x| match x {
|
||||||
ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
|
ParamKind::Type => table.new_type_var().cast(Interner),
|
||||||
ParamKind::Const(ty) => {
|
ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
|
||||||
GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
|
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
|
||||||
self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
|
self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
|
||||||
assert_eq!(self.remaining(), 0);
|
assert_eq!(self.remaining(), 0);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
|
|
||||||
assert!(self.vec.is_empty());
|
|
||||||
assert!(parent_substs.len(Interner) <= self.param_kinds.len());
|
|
||||||
self.extend(parent_substs.iter(Interner).cloned());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
|
|
||||||
for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
|
|
||||||
self.assert_match_kind(&x.0, &x.1);
|
|
||||||
}
|
|
||||||
self.vec.extend(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
|
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
|
||||||
match (a.data(Interner), e) {
|
match (a.data(Interner), e) {
|
||||||
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
|
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
|
||||||
|
@ -188,21 +186,42 @@ impl TyBuilder<()> {
|
||||||
params.placeholder_subst(db)
|
params.placeholder_subst(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
|
pub fn subst_for_def(
|
||||||
let def = def.into();
|
db: &dyn HirDatabase,
|
||||||
let params = generics(db.upcast(), def);
|
def: impl Into<GenericDefId>,
|
||||||
TyBuilder::new(
|
parent_subst: Option<Substitution>,
|
||||||
(),
|
) -> TyBuilder<()> {
|
||||||
params
|
let generics = generics(db.upcast(), def.into());
|
||||||
.iter()
|
assert!(generics.parent_generics().is_some() == parent_subst.is_some());
|
||||||
.map(|(id, data)| match data {
|
let params = generics
|
||||||
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
.iter_self()
|
||||||
TypeOrConstParamData::ConstParamData(_) => {
|
.map(|(id, data)| match data {
|
||||||
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
||||||
}
|
TypeOrConstParamData::ConstParamData(_) => {
|
||||||
})
|
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
||||||
.collect(),
|
}
|
||||||
)
|
})
|
||||||
|
.collect();
|
||||||
|
TyBuilder::new((), params, parent_subst)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
|
||||||
|
///
|
||||||
|
/// A generator's substitution consists of:
|
||||||
|
/// - resume type of generator
|
||||||
|
/// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
|
||||||
|
/// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
|
||||||
|
/// - generic parameters in scope on `parent`
|
||||||
|
/// in this order.
|
||||||
|
///
|
||||||
|
/// This method prepopulates the builder with placeholder substitution of `parent`, so you
|
||||||
|
/// should only push exactly 3 `GenericArg`s before building.
|
||||||
|
pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
|
||||||
|
let parent_subst =
|
||||||
|
parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
|
||||||
|
// These represent resume type, yield type, and return type of generator.
|
||||||
|
let params = std::iter::repeat(ParamKind::Type).take(3).collect();
|
||||||
|
TyBuilder::new((), params, parent_subst)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Substitution {
|
pub fn build(self) -> Substitution {
|
||||||
|
@ -213,7 +232,7 @@ impl TyBuilder<()> {
|
||||||
|
|
||||||
impl TyBuilder<hir_def::AdtId> {
|
impl TyBuilder<hir_def::AdtId> {
|
||||||
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
|
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
|
||||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
TyBuilder::subst_for_def(db, def, None).with_data(def)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_with_defaults(
|
pub fn fill_with_defaults(
|
||||||
|
@ -221,16 +240,27 @@ impl TyBuilder<hir_def::AdtId> {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
mut fallback: impl FnMut() -> Ty,
|
mut fallback: impl FnMut() -> Ty,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
// Note that we're building ADT, so we never have parent generic parameters.
|
||||||
let defaults = db.generic_defaults(self.data.into());
|
let defaults = db.generic_defaults(self.data.into());
|
||||||
|
let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
|
||||||
for default_ty in defaults.iter().skip(self.vec.len()) {
|
for default_ty in defaults.iter().skip(self.vec.len()) {
|
||||||
if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
|
// NOTE(skip_binders): we only check if the arg type is error type.
|
||||||
|
if let Some(x) = default_ty.skip_binders().ty(Interner) {
|
||||||
if x.is_unknown() {
|
if x.is_unknown() {
|
||||||
self.vec.push(fallback().cast(Interner));
|
self.vec.push(fallback().cast(Interner));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
// each default can depend on the previous parameters
|
// Each default can only depend on the previous parameters.
|
||||||
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
|
// FIXME: we don't handle const generics here.
|
||||||
|
let subst_so_far = Substitution::from_iter(
|
||||||
|
Interner,
|
||||||
|
self.vec
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.chain(iter::repeat(dummy_ty.clone()))
|
||||||
|
.take(self.param_kinds.len()),
|
||||||
|
);
|
||||||
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
|
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -245,7 +275,7 @@ impl TyBuilder<hir_def::AdtId> {
|
||||||
pub struct Tuple(usize);
|
pub struct Tuple(usize);
|
||||||
impl TyBuilder<Tuple> {
|
impl TyBuilder<Tuple> {
|
||||||
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
|
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
|
||||||
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
|
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Ty {
|
pub fn build(self) -> Ty {
|
||||||
|
@ -256,7 +286,7 @@ impl TyBuilder<Tuple> {
|
||||||
|
|
||||||
impl TyBuilder<TraitId> {
|
impl TyBuilder<TraitId> {
|
||||||
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
|
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
|
||||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
TyBuilder::subst_for_def(db, def, None).with_data(def)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> TraitRef {
|
pub fn build(self) -> TraitRef {
|
||||||
|
@ -266,8 +296,12 @@ impl TyBuilder<TraitId> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TyBuilder<TypeAliasId> {
|
impl TyBuilder<TypeAliasId> {
|
||||||
pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
|
pub fn assoc_type_projection(
|
||||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
db: &dyn HirDatabase,
|
||||||
|
def: TypeAliasId,
|
||||||
|
parent_subst: Option<Substitution>,
|
||||||
|
) -> TyBuilder<TypeAliasId> {
|
||||||
|
TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> ProjectionTy {
|
pub fn build(self) -> ProjectionTy {
|
||||||
|
@ -277,19 +311,6 @@ impl TyBuilder<TypeAliasId> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
|
impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
|
||||||
fn subst_binders(b: Binders<T>) -> Self {
|
|
||||||
let param_kinds = b
|
|
||||||
.binders
|
|
||||||
.iter(Interner)
|
|
||||||
.map(|x| match x {
|
|
||||||
chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
|
|
||||||
chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
|
|
||||||
chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
TyBuilder::new(b, param_kinds)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> T {
|
pub fn build(self) -> T {
|
||||||
let (b, subst) = self.build_internal();
|
let (b, subst) = self.build_internal();
|
||||||
b.substitute(Interner, &subst)
|
b.substitute(Interner, &subst)
|
||||||
|
@ -297,15 +318,41 @@ impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Bin
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TyBuilder<Binders<Ty>> {
|
impl TyBuilder<Binders<Ty>> {
|
||||||
pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
|
pub fn def_ty(
|
||||||
TyBuilder::subst_binders(db.ty(def))
|
db: &dyn HirDatabase,
|
||||||
|
def: TyDefId,
|
||||||
|
parent_subst: Option<Substitution>,
|
||||||
|
) -> TyBuilder<Binders<Ty>> {
|
||||||
|
let poly_ty = db.ty(def);
|
||||||
|
let id: GenericDefId = match def {
|
||||||
|
TyDefId::BuiltinType(_) => {
|
||||||
|
assert!(parent_subst.is_none());
|
||||||
|
return TyBuilder::new_empty(poly_ty);
|
||||||
|
}
|
||||||
|
TyDefId::AdtId(id) => id.into(),
|
||||||
|
TyDefId::TypeAliasId(id) => id.into(),
|
||||||
|
};
|
||||||
|
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
|
pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
|
||||||
TyBuilder::subst_binders(db.impl_self_ty(def))
|
TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
|
pub fn value_ty(
|
||||||
TyBuilder::subst_binders(db.value_ty(def))
|
db: &dyn HirDatabase,
|
||||||
|
def: ValueTyDefId,
|
||||||
|
parent_subst: Option<Substitution>,
|
||||||
|
) -> TyBuilder<Binders<Ty>> {
|
||||||
|
let poly_value_ty = db.value_ty(def);
|
||||||
|
let id = match def.to_generic_def_id() {
|
||||||
|
Some(id) => id,
|
||||||
|
None => {
|
||||||
|
// static items
|
||||||
|
assert!(parent_subst.is_none());
|
||||||
|
return TyBuilder::new_empty(poly_value_ty);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
expr::Movability,
|
||||||
lang_item::{lang_attr, LangItemTarget},
|
lang_item::{lang_attr, LangItemTarget},
|
||||||
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
|
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
|
||||||
};
|
};
|
||||||
|
@ -26,9 +27,9 @@ use crate::{
|
||||||
to_assoc_type_id, to_chalk_trait_id,
|
to_assoc_type_id, to_chalk_trait_id,
|
||||||
traits::ChalkContext,
|
traits::ChalkContext,
|
||||||
utils::generics,
|
utils::generics,
|
||||||
AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
|
wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
|
||||||
ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
|
Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
|
||||||
TyExt, TyKind, WhereClause,
|
TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
|
pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
|
||||||
|
@ -372,17 +373,62 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
||||||
}
|
}
|
||||||
fn generator_datum(
|
fn generator_datum(
|
||||||
&self,
|
&self,
|
||||||
_: chalk_ir::GeneratorId<Interner>,
|
id: chalk_ir::GeneratorId<Interner>,
|
||||||
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
|
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
|
||||||
// FIXME
|
let (parent, expr) = self.db.lookup_intern_generator(id.into());
|
||||||
unimplemented!()
|
|
||||||
|
// We fill substitution with unknown type, because we only need to know whether the generic
|
||||||
|
// params are types or consts to build `Binders` and those being filled up are for
|
||||||
|
// `resume_type`, `yield_type`, and `return_type` of the generator in question.
|
||||||
|
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||||
|
|
||||||
|
let input_output = rust_ir::GeneratorInputOutputDatum {
|
||||||
|
resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
|
||||||
|
.intern(Interner),
|
||||||
|
yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
|
||||||
|
.intern(Interner),
|
||||||
|
return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
|
||||||
|
.intern(Interner),
|
||||||
|
// FIXME: calculate upvars
|
||||||
|
upvars: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let it = subst
|
||||||
|
.iter(Interner)
|
||||||
|
.map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
|
||||||
|
let input_output = crate::make_type_and_const_binders(it, input_output);
|
||||||
|
|
||||||
|
let movability = match self.db.body(parent)[expr] {
|
||||||
|
hir_def::expr::Expr::Closure {
|
||||||
|
closure_kind: hir_def::expr::ClosureKind::Generator(movability),
|
||||||
|
..
|
||||||
|
} => movability,
|
||||||
|
_ => unreachable!("non generator expression interned as generator"),
|
||||||
|
};
|
||||||
|
let movability = match movability {
|
||||||
|
Movability::Static => rust_ir::Movability::Static,
|
||||||
|
Movability::Movable => rust_ir::Movability::Movable,
|
||||||
|
};
|
||||||
|
|
||||||
|
Arc::new(rust_ir::GeneratorDatum { movability, input_output })
|
||||||
}
|
}
|
||||||
fn generator_witness_datum(
|
fn generator_witness_datum(
|
||||||
&self,
|
&self,
|
||||||
_: chalk_ir::GeneratorId<Interner>,
|
id: chalk_ir::GeneratorId<Interner>,
|
||||||
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
|
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
|
||||||
// FIXME
|
// FIXME: calculate inner types
|
||||||
unimplemented!()
|
let inner_types =
|
||||||
|
rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) };
|
||||||
|
|
||||||
|
let (parent, _) = self.db.lookup_intern_generator(id.into());
|
||||||
|
// See the comment in `generator_datum()` for unknown types.
|
||||||
|
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||||
|
let it = subst
|
||||||
|
.iter(Interner)
|
||||||
|
.map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
|
||||||
|
let inner_types = crate::make_type_and_const_binders(it, inner_types);
|
||||||
|
|
||||||
|
Arc::new(rust_ir::GeneratorWitnessDatum { inner_types })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
|
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
|
||||||
|
@ -429,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
|
||||||
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
||||||
let ctx = crate::TyLoweringContext::new(db, &resolver)
|
let ctx = crate::TyLoweringContext::new(db, &resolver)
|
||||||
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
||||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
|
|
||||||
|
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
|
||||||
|
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
|
||||||
|
.build();
|
||||||
|
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
|
||||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
|
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
|
||||||
.build();
|
.build();
|
||||||
let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
|
let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
|
||||||
|
|
||||||
let mut bounds: Vec<_> = type_alias_data
|
let mut bounds: Vec<_> = type_alias_data
|
||||||
.bounds
|
.bounds
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -772,10 +823,10 @@ pub(super) fn generic_predicate_to_inline_bound(
|
||||||
Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
|
Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
|
||||||
}
|
}
|
||||||
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
|
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
|
||||||
if projection_ty.self_type_parameter(Interner) != self_ty_shifted_in {
|
let trait_ = projection_ty.trait_(db);
|
||||||
|
if projection_ty.self_type_parameter(db) != self_ty_shifted_in {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let trait_ = projection_ty.trait_(db);
|
|
||||||
let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
|
let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|ty| ty.clone().cast(Interner))
|
.map(|ty| ty.clone().cast(Interner))
|
||||||
|
|
|
@ -152,7 +152,7 @@ impl TyExt for Ty {
|
||||||
TyKind::FnDef(def, parameters) => {
|
TyKind::FnDef(def, parameters) => {
|
||||||
let callable_def = db.lookup_intern_callable_def((*def).into());
|
let callable_def = db.lookup_intern_callable_def((*def).into());
|
||||||
let sig = db.callable_item_signature(callable_def);
|
let sig = db.callable_item_signature(callable_def);
|
||||||
Some(sig.substitute(Interner, ¶meters))
|
Some(sig.substitute(Interner, parameters))
|
||||||
}
|
}
|
||||||
TyKind::Closure(.., substs) => {
|
TyKind::Closure(.., substs) => {
|
||||||
let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
|
let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
|
||||||
|
@ -166,6 +166,8 @@ impl TyExt for Ty {
|
||||||
let trait_ref = match self.kind(Interner) {
|
let trait_ref = match self.kind(Interner) {
|
||||||
// The principal trait bound should be the first element of the bounds. This is an
|
// The principal trait bound should be the first element of the bounds. This is an
|
||||||
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
|
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
|
||||||
|
// FIXME: dyn types may not have principal trait and we don't want to return auto trait
|
||||||
|
// here.
|
||||||
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
|
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
|
||||||
match b.skip_binders() {
|
match b.skip_binders() {
|
||||||
WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
||||||
|
@ -260,7 +262,7 @@ impl TyExt for Ty {
|
||||||
WhereClause::AliasEq(AliasEq {
|
WhereClause::AliasEq(AliasEq {
|
||||||
alias: AliasTy::Projection(proj),
|
alias: AliasTy::Projection(proj),
|
||||||
ty: _,
|
ty: _,
|
||||||
}) => &proj.self_type_parameter(Interner) == self,
|
}) => &proj.self_type_parameter(db) == self,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -331,6 +333,7 @@ impl TyExt for Ty {
|
||||||
pub trait ProjectionTyExt {
|
pub trait ProjectionTyExt {
|
||||||
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
|
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
|
||||||
fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
|
fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
|
||||||
|
fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectionTyExt for ProjectionTy {
|
impl ProjectionTyExt for ProjectionTy {
|
||||||
|
@ -347,6 +350,10 @@ impl ProjectionTyExt for ProjectionTy {
|
||||||
_ => panic!("projection ty without parent trait"),
|
_ => panic!("projection ty without parent trait"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {
|
||||||
|
self.trait_ref(db).self_type_parameter(Interner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TraitRefExt {
|
pub trait TraitRefExt {
|
||||||
|
|
|
@ -7,14 +7,17 @@ use std::{
|
||||||
|
|
||||||
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
|
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
builtin_type::BuiltinInt,
|
||||||
expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId},
|
expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId},
|
||||||
path::ModPath,
|
path::ModPath,
|
||||||
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
|
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
|
||||||
|
src::HasChildSource,
|
||||||
type_ref::ConstScalar,
|
type_ref::ConstScalar,
|
||||||
ConstId, DefWithBodyId,
|
ConstId, DefWithBodyId, EnumVariantId, Lookup,
|
||||||
};
|
};
|
||||||
use la_arena::{Arena, Idx};
|
use la_arena::{Arena, Idx, RawIdx};
|
||||||
use stdx::never;
|
use stdx::never;
|
||||||
|
use syntax::ast::HasName;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
|
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
|
||||||
|
@ -77,6 +80,7 @@ pub enum ConstEvalError {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ComputedExpr {
|
pub enum ComputedExpr {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
|
Enum(String, EnumVariantId, Literal),
|
||||||
Tuple(Box<[ComputedExpr]>),
|
Tuple(Box<[ComputedExpr]>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +108,7 @@ impl Display for ComputedExpr {
|
||||||
Literal::String(x) => std::fmt::Debug::fmt(x, f),
|
Literal::String(x) => std::fmt::Debug::fmt(x, f),
|
||||||
Literal::ByteString(x) => std::fmt::Debug::fmt(x, f),
|
Literal::ByteString(x) => std::fmt::Debug::fmt(x, f),
|
||||||
},
|
},
|
||||||
|
ComputedExpr::Enum(name, _, _) => name.fmt(f),
|
||||||
ComputedExpr::Tuple(t) => {
|
ComputedExpr::Tuple(t) => {
|
||||||
f.write_char('(')?;
|
f.write_char('(')?;
|
||||||
for x in &**t {
|
for x in &**t {
|
||||||
|
@ -148,13 +153,51 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_name(ctx: &mut ConstEvalCtx<'_>, variant: EnumVariantId) -> String {
|
||||||
|
let loc = variant.parent.lookup(ctx.db.upcast());
|
||||||
|
let children = variant.parent.child_source(ctx.db.upcast());
|
||||||
|
let item_tree = loc.id.item_tree(ctx.db.upcast());
|
||||||
|
|
||||||
|
let variant_name = children.value[variant.local_id].name();
|
||||||
|
let enum_name = item_tree[loc.id.value].name.to_string();
|
||||||
|
enum_name + "::" + &variant_name.unwrap().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eval_const(
|
pub fn eval_const(
|
||||||
expr_id: ExprId,
|
expr_id: ExprId,
|
||||||
ctx: &mut ConstEvalCtx<'_>,
|
ctx: &mut ConstEvalCtx<'_>,
|
||||||
) -> Result<ComputedExpr, ConstEvalError> {
|
) -> Result<ComputedExpr, ConstEvalError> {
|
||||||
|
let u128_to_i128 = |it: u128| -> Result<i128, ConstEvalError> {
|
||||||
|
it.try_into().map_err(|_| ConstEvalError::NotSupported("u128 is too big"))
|
||||||
|
};
|
||||||
|
|
||||||
let expr = &ctx.exprs[expr_id];
|
let expr = &ctx.exprs[expr_id];
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Missing => Err(ConstEvalError::IncompleteExpr),
|
Expr::Missing => match ctx.owner {
|
||||||
|
// evaluate the implicit variant index of an enum variant without expression
|
||||||
|
// FIXME: This should return the type of the enum representation
|
||||||
|
DefWithBodyId::VariantId(variant) => {
|
||||||
|
let prev_idx: u32 = variant.local_id.into_raw().into();
|
||||||
|
let prev_idx = prev_idx.checked_sub(1).map(RawIdx::from).map(Idx::from_raw);
|
||||||
|
let value = match prev_idx {
|
||||||
|
Some(local_id) => {
|
||||||
|
let prev_variant = EnumVariantId { local_id, parent: variant.parent };
|
||||||
|
1 + match ctx.db.const_eval_variant(prev_variant)? {
|
||||||
|
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||||
|
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||||
|
_ => {
|
||||||
|
return Err(ConstEvalError::NotSupported(
|
||||||
|
"Enum can't contain this kind of value",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
Ok(ComputedExpr::Literal(Literal::Int(value, Some(BuiltinInt::I128))))
|
||||||
|
}
|
||||||
|
_ => Err(ConstEvalError::IncompleteExpr),
|
||||||
|
},
|
||||||
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
||||||
&Expr::UnaryOp { expr, op } => {
|
&Expr::UnaryOp { expr, op } => {
|
||||||
let ty = &ctx.expr_ty(expr);
|
let ty = &ctx.expr_ty(expr);
|
||||||
|
@ -167,9 +210,7 @@ pub fn eval_const(
|
||||||
return Ok(ComputedExpr::Literal(Literal::Bool(!b)))
|
return Ok(ComputedExpr::Literal(Literal::Bool(!b)))
|
||||||
}
|
}
|
||||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||||
ComputedExpr::Literal(Literal::Uint(v, _)) => v
|
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||||
.try_into()
|
|
||||||
.map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
|
|
||||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||||
};
|
};
|
||||||
let r = match ty.kind(Interner) {
|
let r = match ty.kind(Interner) {
|
||||||
|
@ -198,9 +239,7 @@ pub fn eval_const(
|
||||||
hir_def::expr::UnaryOp::Neg => {
|
hir_def::expr::UnaryOp::Neg => {
|
||||||
let v = match ev {
|
let v = match ev {
|
||||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||||
ComputedExpr::Literal(Literal::Uint(v, _)) => v
|
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||||
.try_into()
|
|
||||||
.map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
|
|
||||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||||
};
|
};
|
||||||
Ok(ComputedExpr::Literal(Literal::Int(
|
Ok(ComputedExpr::Literal(Literal::Int(
|
||||||
|
@ -219,16 +258,12 @@ pub fn eval_const(
|
||||||
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
|
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
|
||||||
let v1 = match lhs {
|
let v1 = match lhs {
|
||||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||||
ComputedExpr::Literal(Literal::Uint(v, _)) => {
|
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||||
v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
|
|
||||||
}
|
|
||||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||||
};
|
};
|
||||||
let v2 = match rhs {
|
let v2 = match rhs {
|
||||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||||
ComputedExpr::Literal(Literal::Uint(v, _)) => {
|
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||||
v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
|
|
||||||
}
|
|
||||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||||
};
|
};
|
||||||
match op {
|
match op {
|
||||||
|
@ -339,9 +374,22 @@ pub fn eval_const(
|
||||||
ValueNs::GenericParam(_) => {
|
ValueNs::GenericParam(_) => {
|
||||||
Err(ConstEvalError::NotSupported("const generic without substitution"))
|
Err(ConstEvalError::NotSupported("const generic without substitution"))
|
||||||
}
|
}
|
||||||
|
ValueNs::EnumVariantId(id) => match ctx.db.const_eval_variant(id)? {
|
||||||
|
ComputedExpr::Literal(lit) => {
|
||||||
|
Ok(ComputedExpr::Enum(get_name(ctx, id), id, lit))
|
||||||
|
}
|
||||||
|
_ => Err(ConstEvalError::NotSupported(
|
||||||
|
"Enums can't evalute to anything but numbers",
|
||||||
|
)),
|
||||||
|
},
|
||||||
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
|
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME: Handle the cast target
|
||||||
|
&Expr::Cast { expr, .. } => match eval_const(expr, ctx)? {
|
||||||
|
ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)),
|
||||||
|
_ => Err(ConstEvalError::NotSupported("Can't cast these types")),
|
||||||
|
},
|
||||||
_ => Err(ConstEvalError::NotSupported("This kind of expression")),
|
_ => Err(ConstEvalError::NotSupported("This kind of expression")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,7 +460,15 @@ pub(crate) fn const_eval_recover(
|
||||||
Err(ConstEvalError::Loop)
|
Err(ConstEvalError::Loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn const_eval_query(
|
pub(crate) fn const_eval_variant_recover(
|
||||||
|
_: &dyn HirDatabase,
|
||||||
|
_: &[String],
|
||||||
|
_: &EnumVariantId,
|
||||||
|
) -> Result<ComputedExpr, ConstEvalError> {
|
||||||
|
Err(ConstEvalError::Loop)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn const_eval_variant_query(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
const_id: ConstId,
|
const_id: ConstId,
|
||||||
) -> Result<ComputedExpr, ConstEvalError> {
|
) -> Result<ComputedExpr, ConstEvalError> {
|
||||||
|
@ -433,6 +489,26 @@ pub(crate) fn const_eval_query(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn const_eval_query_variant(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
variant_id: EnumVariantId,
|
||||||
|
) -> Result<ComputedExpr, ConstEvalError> {
|
||||||
|
let def = variant_id.into();
|
||||||
|
let body = db.body(def);
|
||||||
|
let infer = &db.infer(def);
|
||||||
|
eval_const(
|
||||||
|
body.body_expr,
|
||||||
|
&mut ConstEvalCtx {
|
||||||
|
db,
|
||||||
|
owner: def,
|
||||||
|
exprs: &body.exprs,
|
||||||
|
pats: &body.pats,
|
||||||
|
local_data: HashMap::default(),
|
||||||
|
infer,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn eval_to_const<'a>(
|
pub(crate) fn eval_to_const<'a>(
|
||||||
expr: Idx<Expr>,
|
expr: Idx<Expr>,
|
||||||
mode: ParamLoweringMode,
|
mode: ParamLoweringMode,
|
||||||
|
|
|
@ -87,6 +87,49 @@ fn consts() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enums() {
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
enum E {
|
||||||
|
F1 = 1,
|
||||||
|
F2 = 2 * E::F1 as u8,
|
||||||
|
F3 = 3 * E::F2 as u8,
|
||||||
|
}
|
||||||
|
const GOAL: i32 = E::F3 as u8;
|
||||||
|
"#,
|
||||||
|
6,
|
||||||
|
);
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
enum E { F1 = 1, F2, }
|
||||||
|
const GOAL: i32 = E::F2 as u8;
|
||||||
|
"#,
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
enum E { F1, }
|
||||||
|
const GOAL: i32 = E::F1 as u8;
|
||||||
|
"#,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let r = eval_goal(
|
||||||
|
r#"
|
||||||
|
enum E { A = 1, }
|
||||||
|
const GOAL: E = E::A;
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
match r {
|
||||||
|
ComputedExpr::Enum(name, _, Literal::Uint(val, _)) => {
|
||||||
|
assert_eq!(name, "E::A");
|
||||||
|
assert_eq!(val, 1);
|
||||||
|
}
|
||||||
|
x => panic!("Expected enum but found {:?}", x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn const_loop() {
|
fn const_loop() {
|
||||||
check_fail(
|
check_fail(
|
||||||
|
|
|
@ -6,8 +6,8 @@ use std::sync::Arc;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
|
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
|
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
|
||||||
GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
||||||
};
|
};
|
||||||
use la_arena::ArenaMap;
|
use la_arena::ArenaMap;
|
||||||
|
|
||||||
|
@ -43,10 +43,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
||||||
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
||||||
|
|
||||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
#[salsa::invoke(crate::consteval::const_eval_variant_query)]
|
||||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||||
fn const_eval(&self, def: ConstId) -> Result<ComputedExpr, ConstEvalError>;
|
fn const_eval(&self, def: ConstId) -> Result<ComputedExpr, ConstEvalError>;
|
||||||
|
|
||||||
|
#[salsa::invoke(crate::consteval::const_eval_query_variant)]
|
||||||
|
#[salsa::cycle(crate::consteval::const_eval_variant_recover)]
|
||||||
|
fn const_eval_variant(&self, def: EnumVariantId) -> Result<ComputedExpr, ConstEvalError>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::lower::impl_trait_query)]
|
#[salsa::invoke(crate::lower::impl_trait_query)]
|
||||||
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
||||||
|
|
||||||
|
@ -116,6 +120,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
||||||
fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
|
fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
|
||||||
#[salsa::interned]
|
#[salsa::interned]
|
||||||
fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
|
fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
|
||||||
|
#[salsa::interned]
|
||||||
|
fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId;
|
||||||
|
|
||||||
#[salsa::invoke(chalk_db::associated_ty_data_query)]
|
#[salsa::invoke(chalk_db::associated_ty_data_query)]
|
||||||
fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
|
fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
|
||||||
|
@ -188,6 +194,9 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
|
||||||
DefWithBodyId::ConstId(it) => {
|
DefWithBodyId::ConstId(it) => {
|
||||||
db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
|
db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
|
||||||
}
|
}
|
||||||
|
DefWithBodyId::VariantId(it) => {
|
||||||
|
db.enum_data(it.parent).variants[it.local_id].name.to_string()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
db.infer_query(def)
|
db.infer_query(def)
|
||||||
}
|
}
|
||||||
|
@ -226,6 +235,10 @@ impl_intern_key!(InternedOpaqueTyId);
|
||||||
pub struct InternedClosureId(salsa::InternId);
|
pub struct InternedClosureId(salsa::InternId);
|
||||||
impl_intern_key!(InternedClosureId);
|
impl_intern_key!(InternedClosureId);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct InternedGeneratorId(salsa::InternId);
|
||||||
|
impl_intern_key!(InternedGeneratorId);
|
||||||
|
|
||||||
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
|
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
|
||||||
/// we have different IDs for struct and enum variant constructors.
|
/// we have different IDs for struct and enum variant constructors.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
|
|
|
@ -18,7 +18,9 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
||||||
|
|
||||||
let is_unsafe = match def {
|
let is_unsafe = match def {
|
||||||
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
||||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if is_unsafe {
|
if is_unsafe {
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -20,13 +20,14 @@ use hir_def::{
|
||||||
};
|
};
|
||||||
use hir_expand::{hygiene::Hygiene, name::Name};
|
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
|
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
|
||||||
mapping::from_chalk,
|
mapping::from_chalk,
|
||||||
primitive, subst_prefix, to_assoc_type_id,
|
primitive, to_assoc_type_id,
|
||||||
utils::{self, generics},
|
utils::{self, generics},
|
||||||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
|
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
|
||||||
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
|
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
|
||||||
|
@ -221,6 +222,7 @@ pub enum DisplaySourceCodeError {
|
||||||
PathNotFound,
|
PathNotFound,
|
||||||
UnknownType,
|
UnknownType,
|
||||||
Closure,
|
Closure,
|
||||||
|
Generator,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum HirDisplayError {
|
pub enum HirDisplayError {
|
||||||
|
@ -289,7 +291,7 @@ impl HirDisplay for ProjectionTy {
|
||||||
|
|
||||||
let trait_ = f.db.trait_data(self.trait_(f.db));
|
let trait_ = f.db.trait_data(self.trait_(f.db));
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
self.self_type_parameter(Interner).hir_fmt(f)?;
|
self.self_type_parameter(f.db).hir_fmt(f)?;
|
||||||
write!(f, " as {}", trait_.name)?;
|
write!(f, " as {}", trait_.name)?;
|
||||||
if self.substitution.len(Interner) > 1 {
|
if self.substitution.len(Interner) > 1 {
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
|
@ -504,8 +506,15 @@ impl HirDisplay for Ty {
|
||||||
let total_len = parent_params + self_param + type_params + const_params;
|
let total_len = parent_params + self_param + type_params + const_params;
|
||||||
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
|
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
|
||||||
if total_len > 0 {
|
if total_len > 0 {
|
||||||
|
// `parameters` are in the order of fn's params (including impl traits),
|
||||||
|
// parent's params (those from enclosing impl or trait, if any).
|
||||||
|
let parameters = parameters.as_slice(Interner);
|
||||||
|
let fn_params_len = self_param + type_params + const_params;
|
||||||
|
let fn_params = parameters.get(..fn_params_len);
|
||||||
|
let parent_params = parameters.get(parameters.len() - parent_params..);
|
||||||
|
let params = parent_params.into_iter().chain(fn_params).flatten();
|
||||||
write!(f, "<")?;
|
write!(f, "<")?;
|
||||||
f.write_joined(¶meters.as_slice(Interner)[..total_len], ", ")?;
|
f.write_joined(params, ", ")?;
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,9 +586,8 @@ impl HirDisplay for Ty {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => return true,
|
None => return true,
|
||||||
};
|
};
|
||||||
let actual_default = default_parameter
|
let actual_default =
|
||||||
.clone()
|
default_parameter.clone().substitute(Interner, ¶meters);
|
||||||
.substitute(Interner, &subst_prefix(parameters, i));
|
|
||||||
parameter != &actual_default
|
parameter != &actual_default
|
||||||
}
|
}
|
||||||
let mut default_from = 0;
|
let mut default_from = 0;
|
||||||
|
@ -723,7 +731,7 @@ impl HirDisplay for Ty {
|
||||||
WhereClause::AliasEq(AliasEq {
|
WhereClause::AliasEq(AliasEq {
|
||||||
alias: AliasTy::Projection(proj),
|
alias: AliasTy::Projection(proj),
|
||||||
ty: _,
|
ty: _,
|
||||||
}) => &proj.self_type_parameter(Interner) == self,
|
}) => &proj.self_type_parameter(f.db) == self,
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
@ -743,9 +751,19 @@ impl HirDisplay for Ty {
|
||||||
}
|
}
|
||||||
TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
|
TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
|
||||||
TyKind::Dyn(dyn_ty) => {
|
TyKind::Dyn(dyn_ty) => {
|
||||||
|
// Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
|
||||||
|
// FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
|
||||||
|
// more efficient when either of them hits stable.
|
||||||
|
let mut bounds: SmallVec<[_; 4]> =
|
||||||
|
dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect();
|
||||||
|
let (auto_traits, others): (SmallVec<[_; 4]>, _) =
|
||||||
|
bounds.drain(1..).partition(|b| b.skip_binders().trait_id().is_some());
|
||||||
|
bounds.extend(others);
|
||||||
|
bounds.extend(auto_traits);
|
||||||
|
|
||||||
write_bounds_like_dyn_trait_with_prefix(
|
write_bounds_like_dyn_trait_with_prefix(
|
||||||
"dyn",
|
"dyn",
|
||||||
dyn_ty.bounds.skip_binders().interned(),
|
&bounds,
|
||||||
SizedByDefault::NotSized,
|
SizedByDefault::NotSized,
|
||||||
f,
|
f,
|
||||||
)?;
|
)?;
|
||||||
|
@ -783,7 +801,34 @@ impl HirDisplay for Ty {
|
||||||
write!(f, "{{unknown}}")?;
|
write!(f, "{{unknown}}")?;
|
||||||
}
|
}
|
||||||
TyKind::InferenceVar(..) => write!(f, "_")?,
|
TyKind::InferenceVar(..) => write!(f, "_")?,
|
||||||
TyKind::Generator(..) => write!(f, "{{generator}}")?,
|
TyKind::Generator(_, subst) => {
|
||||||
|
if f.display_target.is_source_code() {
|
||||||
|
return Err(HirDisplayError::DisplaySourceCodeError(
|
||||||
|
DisplaySourceCodeError::Generator,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let subst = subst.as_slice(Interner);
|
||||||
|
let a: Option<SmallVec<[&Ty; 3]>> = subst
|
||||||
|
.get(subst.len() - 3..)
|
||||||
|
.map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
|
||||||
|
write!(f, "|")?;
|
||||||
|
resume_ty.hir_fmt(f)?;
|
||||||
|
write!(f, "|")?;
|
||||||
|
|
||||||
|
write!(f, " yields ")?;
|
||||||
|
yield_ty.hir_fmt(f)?;
|
||||||
|
|
||||||
|
write!(f, " -> ")?;
|
||||||
|
ret_ty.hir_fmt(f)?;
|
||||||
|
} else {
|
||||||
|
// This *should* be unreachable, but fallback just in case.
|
||||||
|
write!(f, "{{generator}}")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
|
TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! the type of each expression and pattern.
|
//! the type of each expression and pattern.
|
||||||
//!
|
//!
|
||||||
//! For type inference, compare the implementations in rustc (the various
|
//! For type inference, compare the implementations in rustc (the various
|
||||||
//! check_* methods in librustc_typeck/check/mod.rs are a good entry point) and
|
//! check_* methods in rustc_hir_analysis/check/mod.rs are a good entry point) and
|
||||||
//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
|
//! IntelliJ-Rust (org.rust.lang.core.types.infer). Our entry point for
|
||||||
//! inference here is the `infer` function, which infers the types of all
|
//! inference here is the `infer` function, which infers the types of all
|
||||||
//! expressions in a given function.
|
//! expressions in a given function.
|
||||||
|
@ -19,14 +19,15 @@ use std::sync::Arc;
|
||||||
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body::Body,
|
body::Body,
|
||||||
|
builtin_type::BuiltinType,
|
||||||
data::{ConstData, StaticData},
|
data::{ConstData, StaticData},
|
||||||
expr::{BindingAnnotation, ExprId, PatId},
|
expr::{BindingAnnotation, ExprId, PatId},
|
||||||
lang_item::LangItemTarget,
|
lang_item::LangItemTarget,
|
||||||
path::{path, Path},
|
path::{path, Path},
|
||||||
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||||
type_ref::TypeRef,
|
type_ref::TypeRef,
|
||||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
|
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
|
||||||
TraitId, TypeAliasId, VariantId,
|
ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::{name, Name};
|
use hir_expand::name::{name, Name};
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
|
@ -67,6 +68,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
||||||
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
||||||
DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
|
DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
|
||||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
||||||
|
DefWithBodyId::VariantId(v) => {
|
||||||
|
ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
|
||||||
|
Either::Left(builtin) => BuiltinType::Int(builtin),
|
||||||
|
Either::Right(builtin) => BuiltinType::Uint(builtin),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.infer_body();
|
ctx.infer_body();
|
||||||
|
@ -183,7 +190,9 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
|
||||||
pub enum InferenceDiagnostic {
|
pub enum InferenceDiagnostic {
|
||||||
NoSuchField { expr: ExprId },
|
NoSuchField { expr: ExprId },
|
||||||
BreakOutsideOfLoop { expr: ExprId, is_break: bool },
|
BreakOutsideOfLoop { expr: ExprId, is_break: bool },
|
||||||
|
IncorrectTryTarget { expr: ExprId },
|
||||||
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
|
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
|
||||||
|
DoesNotImplement { expr: ExprId, trait_: TraitId, ty: Ty },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mismatch between an expected and an inferred type.
|
/// A mismatch between an expected and an inferred type.
|
||||||
|
@ -332,7 +341,7 @@ pub struct InferenceResult {
|
||||||
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
||||||
pub type_of_pat: ArenaMap<PatId, Ty>,
|
pub type_of_pat: ArenaMap<PatId, Ty>,
|
||||||
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||||
/// Interned Unknown to return references to.
|
/// Interned common types to return references to.
|
||||||
standard_types: InternedStandardTypes,
|
standard_types: InternedStandardTypes,
|
||||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
||||||
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
||||||
|
@ -412,6 +421,8 @@ pub(crate) struct InferenceContext<'a> {
|
||||||
/// closures, but currently this is the only field that will change there,
|
/// closures, but currently this is the only field that will change there,
|
||||||
/// so it doesn't make sense.
|
/// so it doesn't make sense.
|
||||||
return_ty: Ty,
|
return_ty: Ty,
|
||||||
|
/// The resume type and the yield type, respectively, of the generator being inferred.
|
||||||
|
resume_yield_tys: Option<(Ty, Ty)>,
|
||||||
diverges: Diverges,
|
diverges: Diverges,
|
||||||
breakables: Vec<BreakableContext>,
|
breakables: Vec<BreakableContext>,
|
||||||
}
|
}
|
||||||
|
@ -476,6 +487,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
table: unify::InferenceTable::new(db, trait_env.clone()),
|
table: unify::InferenceTable::new(db, trait_env.clone()),
|
||||||
trait_env,
|
trait_env,
|
||||||
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
|
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
|
||||||
|
resume_yield_tys: None,
|
||||||
db,
|
db,
|
||||||
owner,
|
owner,
|
||||||
body,
|
body,
|
||||||
|
@ -703,6 +715,8 @@ impl<'a> InferenceContext<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
inner_ty: Ty,
|
inner_ty: Ty,
|
||||||
assoc_ty: Option<TypeAliasId>,
|
assoc_ty: Option<TypeAliasId>,
|
||||||
|
// FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
|
||||||
|
// handled when we support them.
|
||||||
params: &[GenericArg],
|
params: &[GenericArg],
|
||||||
) -> Ty {
|
) -> Ty {
|
||||||
match assoc_ty {
|
match assoc_ty {
|
||||||
|
@ -794,7 +808,18 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||||
}
|
}
|
||||||
TypeNs::TypeAliasId(it) => {
|
TypeNs::TypeAliasId(it) => {
|
||||||
let ty = TyBuilder::def_ty(self.db, it.into())
|
let container = it.lookup(self.db.upcast()).container;
|
||||||
|
let parent_subst = match container {
|
||||||
|
ItemContainerId::TraitId(id) => {
|
||||||
|
let subst = TyBuilder::subst_for_def(self.db, id, None)
|
||||||
|
.fill_with_inference_vars(&mut self.table)
|
||||||
|
.build();
|
||||||
|
Some(subst)
|
||||||
|
}
|
||||||
|
// Type aliases do not exist in impls.
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
|
||||||
.fill_with_inference_vars(&mut self.table)
|
.fill_with_inference_vars(&mut self.table)
|
||||||
.build();
|
.build();
|
||||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||||
|
@ -873,18 +898,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
||||||
let path = path![core::iter::IntoIterator];
|
let path = path![core::iter::IntoIterator];
|
||||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||||
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
|
fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
|
||||||
// FIXME resolve via lang_item once try v2 is stable
|
let path = path![core::iter::Iterator];
|
||||||
let path = path![core::ops::Try];
|
|
||||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||||
let trait_data = self.db.trait_data(trait_);
|
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
||||||
trait_data
|
|
||||||
// FIXME remove once try v2 is stable
|
|
||||||
.associated_type_by_name(&name![Ok])
|
|
||||||
.or_else(|| trait_data.associated_type_by_name(&name![Output]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
|
fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
||||||
use super::{Expectation, InferenceContext};
|
use super::{Expectation, InferenceContext};
|
||||||
|
|
||||||
impl InferenceContext<'_> {
|
impl InferenceContext<'_> {
|
||||||
|
// This function handles both closures and generators.
|
||||||
pub(super) fn deduce_closure_type_from_expectations(
|
pub(super) fn deduce_closure_type_from_expectations(
|
||||||
&mut self,
|
&mut self,
|
||||||
closure_expr: ExprId,
|
closure_expr: ExprId,
|
||||||
|
@ -27,6 +28,11 @@ impl InferenceContext<'_> {
|
||||||
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
||||||
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
|
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
|
||||||
|
|
||||||
|
// Generators are not Fn* so return early.
|
||||||
|
if matches!(closure_ty.kind(Interner), TyKind::Generator(..)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Deduction based on the expected `dyn Fn` is done separately.
|
// Deduction based on the expected `dyn Fn` is done separately.
|
||||||
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
|
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
|
||||||
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! like going from `&Vec<T>` to `&[T]`.
|
//! like going from `&Vec<T>` to `&[T]`.
|
||||||
//!
|
//!
|
||||||
//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
|
//! See <https://doc.rust-lang.org/nomicon/coercions.html> and
|
||||||
//! `librustc_typeck/check/coercion.rs`.
|
//! `rustc_hir_analysis/check/coercion.rs`.
|
||||||
|
|
||||||
use std::{iter, sync::Arc};
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
|
|
|
@ -10,30 +10,33 @@ use chalk_ir::{
|
||||||
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
|
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
|
||||||
};
|
};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
|
expr::{
|
||||||
|
ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
|
||||||
|
UnaryOp,
|
||||||
|
},
|
||||||
generics::TypeOrConstParamData,
|
generics::TypeOrConstParamData,
|
||||||
path::{GenericArg, GenericArgs},
|
path::{GenericArg, GenericArgs},
|
||||||
resolver::resolver_for_expr,
|
resolver::resolver_for_expr,
|
||||||
ConstParamId, FieldId, ItemContainerId, Lookup,
|
ConstParamId, FieldId, ItemContainerId, Lookup,
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::{name, name::Name};
|
||||||
use stdx::always;
|
use stdx::always;
|
||||||
use syntax::ast::RangeOp;
|
use syntax::ast::RangeOp;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
autoderef::{self, Autoderef},
|
autoderef::{self, Autoderef},
|
||||||
consteval,
|
consteval,
|
||||||
infer::{coerce::CoerceMany, find_continuable, BreakableKind},
|
infer::{coerce::CoerceMany, find_continuable, path, BreakableKind},
|
||||||
lower::{
|
lower::{
|
||||||
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
|
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
|
||||||
},
|
},
|
||||||
mapping::{from_chalk, ToChalk},
|
mapping::{from_chalk, ToChalk},
|
||||||
method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
|
method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
|
||||||
primitive::{self, UintTy},
|
primitive::{self, UintTy},
|
||||||
static_lifetime, to_chalk_trait_id,
|
static_lifetime, to_assoc_type_id, to_chalk_trait_id,
|
||||||
utils::{generics, Generics},
|
utils::{generics, Generics},
|
||||||
AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
|
AdtId, AliasEq, AliasTy, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner,
|
||||||
Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
ProjectionTy, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -204,8 +207,10 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
&Expr::For { iterable, body, pat, label } => {
|
&Expr::For { iterable, body, pat, label } => {
|
||||||
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
|
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
|
||||||
let pat_ty =
|
let into_iter_ty =
|
||||||
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
||||||
|
let pat_ty =
|
||||||
|
self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
|
||||||
|
|
||||||
self.infer_pat(pat, &pat_ty, BindingMode::default());
|
self.infer_pat(pat, &pat_ty, BindingMode::default());
|
||||||
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
|
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
|
||||||
|
@ -216,7 +221,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
self.diverges = Diverges::Maybe;
|
self.diverges = Diverges::Maybe;
|
||||||
TyBuilder::unit()
|
TyBuilder::unit()
|
||||||
}
|
}
|
||||||
Expr::Closure { body, args, ret_type, arg_types } => {
|
Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
|
||||||
assert_eq!(args.len(), arg_types.len());
|
assert_eq!(args.len(), arg_types.len());
|
||||||
|
|
||||||
let mut sig_tys = Vec::new();
|
let mut sig_tys = Vec::new();
|
||||||
|
@ -244,20 +249,40 @@ impl<'a> InferenceContext<'a> {
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.intern(Interner);
|
.intern(Interner);
|
||||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
|
||||||
let closure_ty =
|
let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
|
||||||
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
// FIXME: report error when there are more than 1 parameter.
|
||||||
.intern(Interner);
|
let resume_ty = match sig_tys.first() {
|
||||||
|
// When `sig_tys.len() == 1` the first type is the return type, not the
|
||||||
|
// first parameter type.
|
||||||
|
Some(ty) if sig_tys.len() > 1 => ty.clone(),
|
||||||
|
_ => self.result.standard_types.unit.clone(),
|
||||||
|
};
|
||||||
|
let yield_ty = self.table.new_type_var();
|
||||||
|
|
||||||
|
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
|
||||||
|
.push(resume_ty.clone())
|
||||||
|
.push(yield_ty.clone())
|
||||||
|
.push(ret_ty.clone())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
|
||||||
|
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
|
||||||
|
|
||||||
|
(generator_ty, Some((resume_ty, yield_ty)))
|
||||||
|
} else {
|
||||||
|
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||||
|
let closure_ty =
|
||||||
|
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
||||||
|
.intern(Interner);
|
||||||
|
|
||||||
|
(closure_ty, None)
|
||||||
|
};
|
||||||
|
|
||||||
// Eagerly try to relate the closure type with the expected
|
// Eagerly try to relate the closure type with the expected
|
||||||
// type, otherwise we often won't have enough information to
|
// type, otherwise we often won't have enough information to
|
||||||
// infer the body.
|
// infer the body.
|
||||||
self.deduce_closure_type_from_expectations(
|
self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
|
||||||
tgt_expr,
|
|
||||||
&closure_ty,
|
|
||||||
&sig_ty,
|
|
||||||
expected,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now go through the argument patterns
|
// Now go through the argument patterns
|
||||||
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
||||||
|
@ -266,6 +291,8 @@ impl<'a> InferenceContext<'a> {
|
||||||
|
|
||||||
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
||||||
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
|
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
|
||||||
|
let prev_resume_yield_tys =
|
||||||
|
mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
|
||||||
|
|
||||||
self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
|
self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
|
||||||
this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
|
this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
|
||||||
|
@ -273,8 +300,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
|
|
||||||
self.diverges = prev_diverges;
|
self.diverges = prev_diverges;
|
||||||
self.return_ty = prev_ret_ty;
|
self.return_ty = prev_ret_ty;
|
||||||
|
self.resume_yield_tys = prev_resume_yield_tys;
|
||||||
|
|
||||||
closure_ty
|
ty
|
||||||
}
|
}
|
||||||
Expr::Call { callee, args, .. } => {
|
Expr::Call { callee, args, .. } => {
|
||||||
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
||||||
|
@ -423,11 +451,18 @@ impl<'a> InferenceContext<'a> {
|
||||||
TyKind::Never.intern(Interner)
|
TyKind::Never.intern(Interner)
|
||||||
}
|
}
|
||||||
Expr::Yield { expr } => {
|
Expr::Yield { expr } => {
|
||||||
// FIXME: track yield type for coercion
|
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
self.infer_expr(*expr, &Expectation::none());
|
self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
|
||||||
|
} else {
|
||||||
|
let unit = self.result.standard_types.unit.clone();
|
||||||
|
let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
|
||||||
|
}
|
||||||
|
resume_ty
|
||||||
|
} else {
|
||||||
|
// FIXME: report error (yield expr in non-generator)
|
||||||
|
TyKind::Error.intern(Interner)
|
||||||
}
|
}
|
||||||
TyKind::Never.intern(Interner)
|
|
||||||
}
|
}
|
||||||
Expr::RecordLit { path, fields, spread, .. } => {
|
Expr::RecordLit { path, fields, spread, .. } => {
|
||||||
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
|
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
|
||||||
|
@ -529,9 +564,29 @@ impl<'a> InferenceContext<'a> {
|
||||||
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
|
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
|
||||||
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
|
self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
|
||||||
}
|
}
|
||||||
Expr::Try { expr } => {
|
&Expr::Try { expr } => {
|
||||||
let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
|
let inner_ty = self.infer_expr_inner(expr, &Expectation::none());
|
||||||
self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
|
match self.resolve_try_impl_for(inner_ty.clone()) {
|
||||||
|
Some((_, Some((output, residual)))) => {
|
||||||
|
if let Some((_trait, false)) =
|
||||||
|
self.implements_from_residual(self.return_ty.clone(), residual)
|
||||||
|
{
|
||||||
|
self.push_diagnostic(InferenceDiagnostic::IncorrectTryTarget {
|
||||||
|
expr: tgt_expr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
Some((trait_, None)) => {
|
||||||
|
self.push_diagnostic(InferenceDiagnostic::DoesNotImplement {
|
||||||
|
expr,
|
||||||
|
trait_,
|
||||||
|
ty: inner_ty,
|
||||||
|
});
|
||||||
|
self.err_ty()
|
||||||
|
}
|
||||||
|
None => self.err_ty(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Cast { expr, type_ref } => {
|
Expr::Cast { expr, type_ref } => {
|
||||||
// FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
|
// FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
|
||||||
|
@ -952,11 +1007,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
|
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
|
||||||
let rhs_ty = self.table.new_type_var();
|
let rhs_ty = self.table.new_type_var();
|
||||||
|
|
||||||
let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||||
self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
|
let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
|
||||||
|
let func = self.db.trait_data(trait_id).method_by_name(&name)?;
|
||||||
|
Some((trait_id, func))
|
||||||
});
|
});
|
||||||
let func = match func {
|
let (trait_, func) = match trait_func {
|
||||||
Some(func) => func,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
|
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
|
||||||
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
|
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
|
||||||
|
@ -966,7 +1023,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let subst = TyBuilder::subst_for_def(self.db, func)
|
// HACK: We can use this substitution for the function because the function itself doesn't
|
||||||
|
// have its own generic parameters.
|
||||||
|
let subst = TyBuilder::subst_for_def(self.db, trait_, None)
|
||||||
.push(lhs_ty.clone())
|
.push(lhs_ty.clone())
|
||||||
.push(rhs_ty.clone())
|
.push(rhs_ty.clone())
|
||||||
.build();
|
.build();
|
||||||
|
@ -1245,19 +1304,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
assert_eq!(self_params, 0); // method shouldn't have another Self param
|
assert_eq!(self_params, 0); // method shouldn't have another Self param
|
||||||
let total_len = parent_params + type_params + const_params + impl_trait_params;
|
let total_len = parent_params + type_params + const_params + impl_trait_params;
|
||||||
let mut substs = Vec::with_capacity(total_len);
|
let mut substs = Vec::with_capacity(total_len);
|
||||||
// Parent arguments are unknown
|
|
||||||
for (id, param) in def_generics.iter_parent() {
|
|
||||||
match param {
|
|
||||||
TypeOrConstParamData::TypeParamData(_) => {
|
|
||||||
substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
|
|
||||||
}
|
|
||||||
TypeOrConstParamData::ConstParamData(_) => {
|
|
||||||
let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
|
|
||||||
substs
|
|
||||||
.push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// handle provided arguments
|
// handle provided arguments
|
||||||
if let Some(generic_args) = generic_args {
|
if let Some(generic_args) = generic_args {
|
||||||
// if args are provided, it should be all of them, but we can't rely on that
|
// if args are provided, it should be all of them, but we can't rely on that
|
||||||
|
@ -1266,7 +1313,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
||||||
.take(type_params + const_params)
|
.take(type_params + const_params)
|
||||||
.zip(def_generics.iter_id().skip(parent_params))
|
.zip(def_generics.iter_id())
|
||||||
{
|
{
|
||||||
if let Some(g) = generic_arg_to_chalk(
|
if let Some(g) = generic_arg_to_chalk(
|
||||||
self.db,
|
self.db,
|
||||||
|
@ -1290,6 +1337,9 @@ impl<'a> InferenceContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle everything else as unknown. This also handles generic arguments for the method's
|
||||||
|
// parent (impl or trait), which should come after those for the method.
|
||||||
for (id, data) in def_generics.iter().skip(substs.len()) {
|
for (id, data) in def_generics.iter().skip(substs.len()) {
|
||||||
match data {
|
match data {
|
||||||
TypeOrConstParamData::TypeParamData(_) => {
|
TypeOrConstParamData::TypeParamData(_) => {
|
||||||
|
@ -1327,9 +1377,13 @@ impl<'a> InferenceContext<'a> {
|
||||||
CallableDefId::FunctionId(f) => {
|
CallableDefId::FunctionId(f) => {
|
||||||
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
|
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
|
||||||
// construct a TraitRef
|
// construct a TraitRef
|
||||||
let substs = crate::subst_prefix(
|
let params_len = parameters.len(Interner);
|
||||||
&*parameters,
|
let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
|
||||||
generics(self.db.upcast(), trait_.into()).len(),
|
let substs = Substitution::from_iter(
|
||||||
|
Interner,
|
||||||
|
// The generic parameters for the trait come after those for the
|
||||||
|
// function.
|
||||||
|
¶meters.as_slice(Interner)[params_len - trait_params_len..],
|
||||||
);
|
);
|
||||||
self.push_obligation(
|
self.push_obligation(
|
||||||
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
|
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
|
||||||
|
@ -1496,4 +1550,67 @@ impl<'a> InferenceContext<'a> {
|
||||||
let ctx = self.breakables.pop().expect("breakable stack broken");
|
let ctx = self.breakables.pop().expect("breakable stack broken");
|
||||||
(ctx.may_break.then(|| ctx.coerce.complete()), res)
|
(ctx.may_break.then(|| ctx.coerce.complete()), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether `ty` implements `FromResidual<r>`
|
||||||
|
fn implements_from_residual(&mut self, ty: Ty, r: Ty) -> Option<(hir_def::TraitId, bool)> {
|
||||||
|
let from_residual_trait = self
|
||||||
|
.resolver
|
||||||
|
.resolve_known_trait(self.db.upcast(), &(super::path![core::ops::FromResidual]))?;
|
||||||
|
let r = GenericArgData::Ty(r).intern(Interner);
|
||||||
|
let b = TyBuilder::trait_ref(self.db, from_residual_trait);
|
||||||
|
if b.remaining() != 2 {
|
||||||
|
return Some((from_residual_trait, false));
|
||||||
|
}
|
||||||
|
let trait_ref = b.push(ty).push(r).build();
|
||||||
|
Some((from_residual_trait, self.table.try_obligation(trait_ref.cast(Interner)).is_some()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_try_impl_for(&mut self, ty: Ty) -> Option<(hir_def::TraitId, Option<(Ty, Ty)>)> {
|
||||||
|
let path = path![core::ops::Try];
|
||||||
|
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||||
|
|
||||||
|
let trait_ref = TyBuilder::trait_ref(self.db, trait_).push(ty).build();
|
||||||
|
let substitution = trait_ref.substitution.clone();
|
||||||
|
self.push_obligation(trait_ref.clone().cast(Interner));
|
||||||
|
|
||||||
|
let trait_data = self.db.trait_data(trait_);
|
||||||
|
let output = trait_data.associated_type_by_name(&name![Output]);
|
||||||
|
let residual = trait_data.associated_type_by_name(&name![Residual]);
|
||||||
|
|
||||||
|
let output_ty = match output {
|
||||||
|
Some(output) => {
|
||||||
|
let output_ty = self.table.new_type_var();
|
||||||
|
let alias_eq = AliasEq {
|
||||||
|
alias: AliasTy::Projection(ProjectionTy {
|
||||||
|
associated_ty_id: to_assoc_type_id(output),
|
||||||
|
substitution: substitution.clone(),
|
||||||
|
}),
|
||||||
|
ty: output_ty.clone(),
|
||||||
|
};
|
||||||
|
self.push_obligation(alias_eq.cast(Interner));
|
||||||
|
output_ty
|
||||||
|
}
|
||||||
|
None => self.err_ty(),
|
||||||
|
};
|
||||||
|
let residual_ty = match residual {
|
||||||
|
Some(residual) => {
|
||||||
|
let residual_ty = self.table.new_type_var();
|
||||||
|
let alias_eq = AliasEq {
|
||||||
|
alias: AliasTy::Projection(ProjectionTy {
|
||||||
|
associated_ty_id: to_assoc_type_id(residual),
|
||||||
|
substitution,
|
||||||
|
}),
|
||||||
|
ty: residual_ty.clone(),
|
||||||
|
};
|
||||||
|
self.push_obligation(alias_eq.cast(Interner));
|
||||||
|
residual_ty
|
||||||
|
}
|
||||||
|
None => self.err_ty(),
|
||||||
|
};
|
||||||
|
// FIXME: We are doing the work twice here I think?
|
||||||
|
Some((
|
||||||
|
trait_,
|
||||||
|
self.table.try_obligation(trait_ref.cast(Interner)).map(|_| (output_ty, residual_ty)),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
||||||
builder::ParamKind,
|
builder::ParamKind,
|
||||||
consteval,
|
consteval,
|
||||||
method_resolution::{self, VisibleFromModule},
|
method_resolution::{self, VisibleFromModule},
|
||||||
GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
|
utils::generics,
|
||||||
ValueTyDefId,
|
Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
||||||
|
@ -96,17 +96,21 @@ impl<'a> InferenceContext<'a> {
|
||||||
ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
|
ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
|
||||||
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
||||||
let substs = ctx.substs_from_path(path, typable, true);
|
let substs = ctx.substs_from_path(path, typable, true);
|
||||||
let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
|
let substs = substs.as_slice(Interner);
|
||||||
let ty = TyBuilder::value_ty(self.db, typable)
|
let parent_substs = self_subst.or_else(|| {
|
||||||
.use_parent_substs(&parent_substs)
|
let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
|
||||||
|
let parent_params_len = generics.parent_generics()?.len();
|
||||||
|
let parent_args = &substs[substs.len() - parent_params_len..];
|
||||||
|
Some(Substitution::from_iter(Interner, parent_args))
|
||||||
|
});
|
||||||
|
let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
|
||||||
|
let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
|
||||||
|
let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
|
||||||
.fill(|x| {
|
.fill(|x| {
|
||||||
it.next().unwrap_or_else(|| match x {
|
it.next().unwrap_or_else(|| match x {
|
||||||
ParamKind::Type => {
|
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
|
||||||
}
|
|
||||||
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
|
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -249,7 +253,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
};
|
};
|
||||||
let substs = match container {
|
let substs = match container {
|
||||||
ItemContainerId::ImplId(impl_id) => {
|
ItemContainerId::ImplId(impl_id) => {
|
||||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
|
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
|
||||||
.fill_with_inference_vars(&mut self.table)
|
.fill_with_inference_vars(&mut self.table)
|
||||||
.build();
|
.build();
|
||||||
let impl_self_ty =
|
let impl_self_ty =
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{fmt, mem, sync::Arc};
|
||||||
|
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
|
cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
|
||||||
IntTy, NoSolution, TyVariableKind, UniverseIndex,
|
IntTy, TyVariableKind, UniverseIndex,
|
||||||
};
|
};
|
||||||
use chalk_solve::infer::ParameterEnaVariableExt;
|
use chalk_solve::infer::ParameterEnaVariableExt;
|
||||||
use ena::unify::UnifyKey;
|
use ena::unify::UnifyKey;
|
||||||
|
@ -331,7 +331,6 @@ impl<'a> InferenceTable<'a> {
|
||||||
&mut resolve::Resolver { table: self, var_stack, fallback },
|
&mut resolve::Resolver { table: self, var_stack, fallback },
|
||||||
DebruijnIndex::INNERMOST,
|
DebruijnIndex::INNERMOST,
|
||||||
)
|
)
|
||||||
.expect("fold failed unexpectedly")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
|
pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T
|
||||||
|
@ -452,13 +451,14 @@ impl<'a> InferenceTable<'a> {
|
||||||
f: impl FnOnce(&mut Self) -> T,
|
f: impl FnOnce(&mut Self) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
use chalk_ir::fold::TypeFolder;
|
use chalk_ir::fold::TypeFolder;
|
||||||
|
|
||||||
|
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||||
|
#[has_interner(Interner)]
|
||||||
struct VarFudger<'a, 'b> {
|
struct VarFudger<'a, 'b> {
|
||||||
table: &'a mut InferenceTable<'b>,
|
table: &'a mut InferenceTable<'b>,
|
||||||
highest_known_var: InferenceVar,
|
highest_known_var: InferenceVar,
|
||||||
}
|
}
|
||||||
impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
|
impl<'a, 'b> TypeFolder<Interner> for VarFudger<'a, 'b> {
|
||||||
type Error = NoSolution;
|
|
||||||
|
|
||||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -472,24 +472,24 @@ impl<'a> InferenceTable<'a> {
|
||||||
var: chalk_ir::InferenceVar,
|
var: chalk_ir::InferenceVar,
|
||||||
kind: TyVariableKind,
|
kind: TyVariableKind,
|
||||||
_outer_binder: chalk_ir::DebruijnIndex,
|
_outer_binder: chalk_ir::DebruijnIndex,
|
||||||
) -> chalk_ir::Fallible<chalk_ir::Ty<Interner>> {
|
) -> chalk_ir::Ty<Interner> {
|
||||||
Ok(if var < self.highest_known_var {
|
if var < self.highest_known_var {
|
||||||
var.to_ty(Interner, kind)
|
var.to_ty(Interner, kind)
|
||||||
} else {
|
} else {
|
||||||
self.table.new_type_var()
|
self.table.new_type_var()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_lifetime(
|
fn fold_inference_lifetime(
|
||||||
&mut self,
|
&mut self,
|
||||||
var: chalk_ir::InferenceVar,
|
var: chalk_ir::InferenceVar,
|
||||||
_outer_binder: chalk_ir::DebruijnIndex,
|
_outer_binder: chalk_ir::DebruijnIndex,
|
||||||
) -> chalk_ir::Fallible<chalk_ir::Lifetime<Interner>> {
|
) -> chalk_ir::Lifetime<Interner> {
|
||||||
Ok(if var < self.highest_known_var {
|
if var < self.highest_known_var {
|
||||||
var.to_lifetime(Interner)
|
var.to_lifetime(Interner)
|
||||||
} else {
|
} else {
|
||||||
self.table.new_lifetime_var()
|
self.table.new_lifetime_var()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_const(
|
fn fold_inference_const(
|
||||||
|
@ -497,12 +497,12 @@ impl<'a> InferenceTable<'a> {
|
||||||
ty: chalk_ir::Ty<Interner>,
|
ty: chalk_ir::Ty<Interner>,
|
||||||
var: chalk_ir::InferenceVar,
|
var: chalk_ir::InferenceVar,
|
||||||
_outer_binder: chalk_ir::DebruijnIndex,
|
_outer_binder: chalk_ir::DebruijnIndex,
|
||||||
) -> chalk_ir::Fallible<chalk_ir::Const<Interner>> {
|
) -> chalk_ir::Const<Interner> {
|
||||||
Ok(if var < self.highest_known_var {
|
if var < self.highest_known_var {
|
||||||
var.to_const(Interner, ty)
|
var.to_const(Interner, ty)
|
||||||
} else {
|
} else {
|
||||||
self.table.new_const_var(ty)
|
self.table.new_const_var(ty)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +512,6 @@ impl<'a> InferenceTable<'a> {
|
||||||
self.rollback_to(snapshot);
|
self.rollback_to(snapshot);
|
||||||
result
|
result
|
||||||
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
|
.fold_with(&mut VarFudger { table: self, highest_known_var }, DebruijnIndex::INNERMOST)
|
||||||
.expect("fold_with with VarFudger")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This checks whether any of the free variables in the `canonicalized`
|
/// This checks whether any of the free variables in the `canonicalized`
|
||||||
|
@ -598,11 +597,14 @@ impl<'a> InferenceTable<'a> {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let projection = {
|
let projection = {
|
||||||
let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
|
let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
|
||||||
if b.remaining() != 2 {
|
if b.remaining() != 2 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
b.push(ty.clone()).push(arg_ty).build()
|
let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
|
||||||
|
|
||||||
|
TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
|
||||||
|
.build()
|
||||||
};
|
};
|
||||||
|
|
||||||
let trait_env = self.trait_env.env.clone();
|
let trait_env = self.trait_env.env.clone();
|
||||||
|
@ -636,21 +638,24 @@ mod resolve {
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast,
|
cast::Cast,
|
||||||
fold::{TypeFoldable, TypeFolder},
|
fold::{TypeFoldable, TypeFolder},
|
||||||
Fallible, NoSolution,
|
|
||||||
};
|
};
|
||||||
use hir_def::type_ref::ConstScalar;
|
use hir_def::type_ref::ConstScalar;
|
||||||
|
|
||||||
pub(super) struct Resolver<'a, 'b, F> {
|
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||||
|
#[has_interner(Interner)]
|
||||||
|
pub(super) struct Resolver<
|
||||||
|
'a,
|
||||||
|
'b,
|
||||||
|
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
|
||||||
|
> {
|
||||||
pub(super) table: &'a mut InferenceTable<'b>,
|
pub(super) table: &'a mut InferenceTable<'b>,
|
||||||
pub(super) var_stack: &'a mut Vec<InferenceVar>,
|
pub(super) var_stack: &'a mut Vec<InferenceVar>,
|
||||||
pub(super) fallback: F,
|
pub(super) fallback: F,
|
||||||
}
|
}
|
||||||
impl<'a, 'b, 'i, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
|
impl<'a, 'b, F> TypeFolder<Interner> for Resolver<'a, 'b, F>
|
||||||
where
|
where
|
||||||
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
|
F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
|
||||||
{
|
{
|
||||||
type Error = NoSolution;
|
|
||||||
|
|
||||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -664,20 +669,19 @@ mod resolve {
|
||||||
var: InferenceVar,
|
var: InferenceVar,
|
||||||
kind: TyVariableKind,
|
kind: TyVariableKind,
|
||||||
outer_binder: DebruijnIndex,
|
outer_binder: DebruijnIndex,
|
||||||
) -> Fallible<Ty> {
|
) -> Ty {
|
||||||
let var = self.table.var_unification_table.inference_var_root(var);
|
let var = self.table.var_unification_table.inference_var_root(var);
|
||||||
if self.var_stack.contains(&var) {
|
if self.var_stack.contains(&var) {
|
||||||
// recursive type
|
// recursive type
|
||||||
let default = self.table.fallback_value(var, kind).cast(Interner);
|
let default = self.table.fallback_value(var, kind).cast(Interner);
|
||||||
return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
|
return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
|
||||||
.assert_ty_ref(Interner)
|
.assert_ty_ref(Interner)
|
||||||
.clone());
|
.clone();
|
||||||
}
|
}
|
||||||
let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
||||||
// known_ty may contain other variables that are known by now
|
// known_ty may contain other variables that are known by now
|
||||||
self.var_stack.push(var);
|
self.var_stack.push(var);
|
||||||
let result =
|
let result = known_ty.fold_with(self, outer_binder);
|
||||||
known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
|
|
||||||
self.var_stack.pop();
|
self.var_stack.pop();
|
||||||
result.assert_ty_ref(Interner).clone()
|
result.assert_ty_ref(Interner).clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -686,7 +690,7 @@ mod resolve {
|
||||||
.assert_ty_ref(Interner)
|
.assert_ty_ref(Interner)
|
||||||
.clone()
|
.clone()
|
||||||
};
|
};
|
||||||
Ok(result)
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_const(
|
fn fold_inference_const(
|
||||||
|
@ -694,7 +698,7 @@ mod resolve {
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
var: InferenceVar,
|
var: InferenceVar,
|
||||||
outer_binder: DebruijnIndex,
|
outer_binder: DebruijnIndex,
|
||||||
) -> Fallible<Const> {
|
) -> Const {
|
||||||
let var = self.table.var_unification_table.inference_var_root(var);
|
let var = self.table.var_unification_table.inference_var_root(var);
|
||||||
let default = ConstData {
|
let default = ConstData {
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
|
@ -704,35 +708,33 @@ mod resolve {
|
||||||
.cast(Interner);
|
.cast(Interner);
|
||||||
if self.var_stack.contains(&var) {
|
if self.var_stack.contains(&var) {
|
||||||
// recursive
|
// recursive
|
||||||
return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
||||||
.assert_const_ref(Interner)
|
.assert_const_ref(Interner)
|
||||||
.clone());
|
.clone();
|
||||||
}
|
}
|
||||||
let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
|
||||||
// known_ty may contain other variables that are known by now
|
// known_ty may contain other variables that are known by now
|
||||||
self.var_stack.push(var);
|
self.var_stack.push(var);
|
||||||
let result =
|
let result = known_ty.fold_with(self, outer_binder);
|
||||||
known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
|
|
||||||
self.var_stack.pop();
|
self.var_stack.pop();
|
||||||
result.assert_const_ref(Interner).clone()
|
result.assert_const_ref(Interner).clone()
|
||||||
} else {
|
} else {
|
||||||
(self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
(self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
|
||||||
.assert_const_ref(Interner)
|
.assert_const_ref(Interner)
|
||||||
.clone()
|
.clone()
|
||||||
};
|
}
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_lifetime(
|
fn fold_inference_lifetime(
|
||||||
&mut self,
|
&mut self,
|
||||||
_var: InferenceVar,
|
_var: InferenceVar,
|
||||||
_outer_binder: DebruijnIndex,
|
_outer_binder: DebruijnIndex,
|
||||||
) -> Fallible<Lifetime> {
|
) -> Lifetime {
|
||||||
// fall back all lifetimes to 'static -- currently we don't deal
|
// fall back all lifetimes to 'static -- currently we don't deal
|
||||||
// with any lifetimes, but we can sometimes get some lifetime
|
// with any lifetimes, but we can sometimes get some lifetime
|
||||||
// variables through Chalk's unification, and this at least makes
|
// variables through Chalk's unification, and this at least makes
|
||||||
// sure we don't leak them outside of inference
|
// sure we don't leak them outside of inference
|
||||||
Ok(crate::static_lifetime())
|
crate::static_lifetime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,13 +254,13 @@ impl CallableSig {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeFoldable<Interner> for CallableSig {
|
impl TypeFoldable<Interner> for CallableSig {
|
||||||
fn fold_with<E>(
|
fn try_fold_with<E>(
|
||||||
self,
|
self,
|
||||||
folder: &mut dyn chalk_ir::fold::TypeFolder<Interner, Error = E>,
|
folder: &mut dyn chalk_ir::fold::FallibleTypeFolder<Interner, Error = E>,
|
||||||
outer_binder: DebruijnIndex,
|
outer_binder: DebruijnIndex,
|
||||||
) -> Result<Self, E> {
|
) -> Result<Self, E> {
|
||||||
let vec = self.params_and_return.to_vec();
|
let vec = self.params_and_return.to_vec();
|
||||||
let folded = vec.fold_with(folder, outer_binder)?;
|
let folded = vec.try_fold_with(folder, outer_binder)?;
|
||||||
Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
|
Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,16 +292,19 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
|
||||||
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||||
for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||||
) -> T {
|
) -> T {
|
||||||
use chalk_ir::{fold::TypeFolder, Fallible};
|
use chalk_ir::fold::TypeFolder;
|
||||||
struct FreeVarFolder<F1, F2>(F1, F2);
|
|
||||||
|
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||||
|
#[has_interner(Interner)]
|
||||||
|
struct FreeVarFolder<
|
||||||
|
F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||||
|
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||||
|
>(F1, F2);
|
||||||
impl<
|
impl<
|
||||||
'i,
|
F1: FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||||
F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
|
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||||
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
|
|
||||||
> TypeFolder<Interner> for FreeVarFolder<F1, F2>
|
> TypeFolder<Interner> for FreeVarFolder<F1, F2>
|
||||||
{
|
{
|
||||||
type Error = NoSolution;
|
|
||||||
|
|
||||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -310,12 +313,8 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
|
||||||
Interner
|
Interner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_free_var_ty(
|
fn fold_free_var_ty(&mut self, bound_var: BoundVar, outer_binder: DebruijnIndex) -> Ty {
|
||||||
&mut self,
|
self.0(bound_var, outer_binder)
|
||||||
bound_var: BoundVar,
|
|
||||||
outer_binder: DebruijnIndex,
|
|
||||||
) -> Fallible<Ty> {
|
|
||||||
Ok(self.0(bound_var, outer_binder))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_free_var_const(
|
fn fold_free_var_const(
|
||||||
|
@ -323,12 +322,11 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
bound_var: BoundVar,
|
bound_var: BoundVar,
|
||||||
outer_binder: DebruijnIndex,
|
outer_binder: DebruijnIndex,
|
||||||
) -> Fallible<Const> {
|
) -> Const {
|
||||||
Ok(self.1(ty, bound_var, outer_binder))
|
self.1(ty, bound_var, outer_binder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
|
t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
|
||||||
.expect("fold failed unexpectedly")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
|
pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
|
||||||
|
@ -351,16 +349,13 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
|
||||||
f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
|
f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
|
||||||
binders: DebruijnIndex,
|
binders: DebruijnIndex,
|
||||||
) -> T {
|
) -> T {
|
||||||
use chalk_ir::{
|
use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
|
||||||
fold::{TypeFolder, TypeSuperFoldable},
|
#[derive(chalk_derive::FallibleTypeFolder)]
|
||||||
Fallible,
|
#[has_interner(Interner)]
|
||||||
};
|
struct TyFolder<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>>(F);
|
||||||
struct TyFolder<F>(F);
|
impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner>
|
||||||
impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i>
|
for TyFolder<F>
|
||||||
TypeFolder<Interner> for TyFolder<F>
|
|
||||||
{
|
{
|
||||||
type Error = NoSolution;
|
|
||||||
|
|
||||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -369,16 +364,16 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
|
||||||
Interner
|
Interner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
|
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
|
||||||
let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
|
let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
|
||||||
Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
|
self.0(Either::Left(ty), outer_binder).left().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
|
fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
|
||||||
Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
|
self.0(Either::Right(c), outer_binder).right().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
|
t.fold_with(&mut TyFolder(f), binders)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
|
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
|
||||||
|
@ -390,16 +385,16 @@ where
|
||||||
T: HasInterner<Interner = Interner>,
|
T: HasInterner<Interner = Interner>,
|
||||||
{
|
{
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
fold::{TypeFolder, TypeSuperFoldable},
|
fold::{FallibleTypeFolder, TypeSuperFoldable},
|
||||||
Fallible,
|
Fallible,
|
||||||
};
|
};
|
||||||
struct ErrorReplacer {
|
struct ErrorReplacer {
|
||||||
vars: usize,
|
vars: usize,
|
||||||
}
|
}
|
||||||
impl TypeFolder<Interner> for ErrorReplacer {
|
impl FallibleTypeFolder<Interner> for ErrorReplacer {
|
||||||
type Error = NoSolution;
|
type Error = NoSolution;
|
||||||
|
|
||||||
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> {
|
fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = Self::Error> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,18 +402,17 @@ where
|
||||||
Interner
|
Interner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
|
fn try_fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
|
||||||
if let TyKind::Error = ty.kind(Interner) {
|
if let TyKind::Error = ty.kind(Interner) {
|
||||||
let index = self.vars;
|
let index = self.vars;
|
||||||
self.vars += 1;
|
self.vars += 1;
|
||||||
Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
|
Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(Interner))
|
||||||
} else {
|
} else {
|
||||||
let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
|
ty.try_super_fold_with(self.as_dyn(), outer_binder)
|
||||||
Ok(ty)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_ty(
|
fn try_fold_inference_ty(
|
||||||
&mut self,
|
&mut self,
|
||||||
_var: InferenceVar,
|
_var: InferenceVar,
|
||||||
_kind: TyVariableKind,
|
_kind: TyVariableKind,
|
||||||
|
@ -433,7 +427,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_free_var_ty(
|
fn try_fold_free_var_ty(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bound_var: BoundVar,
|
_bound_var: BoundVar,
|
||||||
_outer_binder: DebruijnIndex,
|
_outer_binder: DebruijnIndex,
|
||||||
|
@ -447,7 +441,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_const(
|
fn try_fold_inference_const(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
_var: InferenceVar,
|
_var: InferenceVar,
|
||||||
|
@ -460,7 +454,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_free_var_const(
|
fn try_fold_free_var_const(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
_bound_var: BoundVar,
|
_bound_var: BoundVar,
|
||||||
|
@ -473,7 +467,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_inference_lifetime(
|
fn try_fold_inference_lifetime(
|
||||||
&mut self,
|
&mut self,
|
||||||
_var: InferenceVar,
|
_var: InferenceVar,
|
||||||
_outer_binder: DebruijnIndex,
|
_outer_binder: DebruijnIndex,
|
||||||
|
@ -485,7 +479,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_free_var_lifetime(
|
fn try_fold_free_var_lifetime(
|
||||||
&mut self,
|
&mut self,
|
||||||
_bound_var: BoundVar,
|
_bound_var: BoundVar,
|
||||||
_outer_binder: DebruijnIndex,
|
_outer_binder: DebruijnIndex,
|
||||||
|
@ -498,7 +492,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut error_replacer = ErrorReplacer { vars: 0 };
|
let mut error_replacer = ErrorReplacer { vars: 0 };
|
||||||
let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
|
let value = match t.clone().try_fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
|
Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
|
||||||
};
|
};
|
||||||
|
|
|
@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
// FIXME we're probably doing something wrong here
|
// FIXME we're probably doing something wrong here
|
||||||
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
|
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
|
||||||
let (
|
let (
|
||||||
parent_params,
|
_parent_params,
|
||||||
self_params,
|
self_params,
|
||||||
list_params,
|
list_params,
|
||||||
const_params,
|
const_params,
|
||||||
|
@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
};
|
};
|
||||||
TyKind::BoundVar(BoundVar::new(
|
TyKind::BoundVar(BoundVar::new(
|
||||||
self.in_binders,
|
self.in_binders,
|
||||||
idx as usize + parent_params + self_params + list_params + const_params,
|
idx as usize + self_params + list_params + const_params,
|
||||||
))
|
))
|
||||||
.intern(Interner)
|
.intern(Interner)
|
||||||
}
|
}
|
||||||
|
@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
.intern(Interner)
|
.intern(Interner)
|
||||||
}
|
}
|
||||||
TypeNs::SelfType(impl_id) => {
|
TypeNs::SelfType(impl_id) => {
|
||||||
let generics = generics(self.db.upcast(), impl_id.into());
|
let def =
|
||||||
let substs = match self.type_param_mode {
|
self.resolver.generic_def().expect("impl should have generic param scope");
|
||||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
let generics = generics(self.db.upcast(), def);
|
||||||
ParamLoweringMode::Variable => {
|
|
||||||
generics.bound_vars_subst(self.db, self.in_binders)
|
match self.type_param_mode {
|
||||||
|
ParamLoweringMode::Placeholder => {
|
||||||
|
// `def` can be either impl itself or item within, and we need impl itself
|
||||||
|
// now.
|
||||||
|
let generics = generics.parent_generics().unwrap_or(&generics);
|
||||||
|
let subst = generics.placeholder_subst(self.db);
|
||||||
|
self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
|
||||||
}
|
}
|
||||||
};
|
ParamLoweringMode::Variable => {
|
||||||
self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
|
let starting_from = match def {
|
||||||
|
GenericDefId::ImplId(_) => 0,
|
||||||
|
// `def` is an item within impl. We need to substitute `BoundVar`s but
|
||||||
|
// remember that they are for parent (i.e. impl) generic params so they
|
||||||
|
// come after our own params.
|
||||||
|
_ => generics.len_self(),
|
||||||
|
};
|
||||||
|
TyBuilder::impl_self_ty(self.db, impl_id)
|
||||||
|
.fill_with_bound_vars(self.in_binders, starting_from)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TypeNs::AdtSelfType(adt) => {
|
TypeNs::AdtSelfType(adt) => {
|
||||||
let generics = generics(self.db.upcast(), adt.into());
|
let generics = generics(self.db.upcast(), adt.into());
|
||||||
|
@ -663,40 +680,31 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
fn substs_from_path_segment(
|
fn substs_from_path_segment(
|
||||||
&self,
|
&self,
|
||||||
segment: PathSegment<'_>,
|
segment: PathSegment<'_>,
|
||||||
def_generic: Option<GenericDefId>,
|
def: Option<GenericDefId>,
|
||||||
infer_args: bool,
|
infer_args: bool,
|
||||||
explicit_self_ty: Option<Ty>,
|
explicit_self_ty: Option<Ty>,
|
||||||
) -> Substitution {
|
) -> Substitution {
|
||||||
|
// Remember that the item's own generic args come before its parent's.
|
||||||
let mut substs = Vec::new();
|
let mut substs = Vec::new();
|
||||||
let def_generics = if let Some(def) = def_generic {
|
let def = if let Some(d) = def {
|
||||||
generics(self.db.upcast(), def)
|
d
|
||||||
} else {
|
} else {
|
||||||
return Substitution::empty(Interner);
|
return Substitution::empty(Interner);
|
||||||
};
|
};
|
||||||
|
let def_generics = generics(self.db.upcast(), def);
|
||||||
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
|
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
|
||||||
def_generics.provenance_split();
|
def_generics.provenance_split();
|
||||||
let total_len =
|
let item_len = self_params + type_params + const_params + impl_trait_params;
|
||||||
parent_params + self_params + type_params + const_params + impl_trait_params;
|
let total_len = parent_params + item_len;
|
||||||
|
|
||||||
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
|
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
|
||||||
|
|
||||||
let mut def_generic_iter = def_generics.iter_id();
|
let mut def_generic_iter = def_generics.iter_id();
|
||||||
|
|
||||||
for _ in 0..parent_params {
|
|
||||||
if let Some(eid) = def_generic_iter.next() {
|
|
||||||
match eid {
|
|
||||||
Either::Left(_) => substs.push(ty_error.clone()),
|
|
||||||
Either::Right(x) => {
|
|
||||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fill_self_params = || {
|
let fill_self_params = || {
|
||||||
for x in explicit_self_ty
|
for x in explicit_self_ty
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| GenericArgData::Ty(x).intern(Interner))
|
.map(|x| x.cast(Interner))
|
||||||
.chain(iter::repeat(ty_error.clone()))
|
.chain(iter::repeat(ty_error.clone()))
|
||||||
.take(self_params)
|
.take(self_params)
|
||||||
{
|
{
|
||||||
|
@ -757,37 +765,40 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
fill_self_params();
|
fill_self_params();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These params include those of parent.
|
||||||
|
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
|
||||||
|
.map(|eid| match eid {
|
||||||
|
Either::Left(_) => ty_error.clone(),
|
||||||
|
Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
assert_eq!(remaining_params.len() + substs.len(), total_len);
|
||||||
|
|
||||||
// handle defaults. In expression or pattern path segments without
|
// handle defaults. In expression or pattern path segments without
|
||||||
// explicitly specified type arguments, missing type arguments are inferred
|
// explicitly specified type arguments, missing type arguments are inferred
|
||||||
// (i.e. defaults aren't used).
|
// (i.e. defaults aren't used).
|
||||||
if !infer_args || had_explicit_args {
|
if !infer_args || had_explicit_args {
|
||||||
if let Some(def_generic) = def_generic {
|
let defaults = self.db.generic_defaults(def);
|
||||||
let defaults = self.db.generic_defaults(def_generic);
|
assert_eq!(total_len, defaults.len());
|
||||||
assert_eq!(total_len, defaults.len());
|
let parent_from = item_len - substs.len();
|
||||||
|
|
||||||
for default_ty in defaults.iter().skip(substs.len()) {
|
for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
|
||||||
// each default can depend on the previous parameters
|
// each default can depend on the previous parameters
|
||||||
let substs_so_far = Substitution::from_iter(Interner, substs.clone());
|
let substs_so_far = Substitution::from_iter(
|
||||||
if let Some(_id) = def_generic_iter.next() {
|
Interner,
|
||||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
|
||||||
}
|
);
|
||||||
}
|
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep parent's params as unknown.
|
||||||
|
let mut remaining_params = remaining_params;
|
||||||
|
substs.extend(remaining_params.drain(parent_from..));
|
||||||
|
} else {
|
||||||
|
substs.extend(remaining_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add placeholders for args that were not provided
|
|
||||||
// FIXME: emit diagnostics in contexts where this is not allowed
|
|
||||||
for eid in def_generic_iter {
|
|
||||||
match eid {
|
|
||||||
Either::Left(_) => substs.push(ty_error.clone()),
|
|
||||||
Either::Right(x) => {
|
|
||||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
|
|
||||||
assert_eq!(substs.len(), total_len);
|
assert_eq!(substs.len(), total_len);
|
||||||
|
|
||||||
Substitution::from_iter(Interner, substs)
|
Substitution::from_iter(Interner, substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,10 +992,11 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
|
|
||||||
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
||||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||||
// INVARIANT: The principal trait bound must come first. Others may be in any order but
|
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
|
||||||
// should be in the same order for the same set but possibly different order of bounds in
|
// order but should be in the same order for the same set but possibly different order of
|
||||||
// the input.
|
// bounds in the input.
|
||||||
// This invariant is used by `TyExt::dyn_trait()` and chalk.
|
// INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
|
||||||
|
// These invariants are utilized by `TyExt::dyn_trait()` and chalk.
|
||||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||||
let mut bounds: Vec<_> = bounds
|
let mut bounds: Vec<_> = bounds
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1035,6 +1047,12 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bounds.first().and_then(|b| b.trait_id()).is_none() {
|
||||||
|
// When there's no trait bound, that's an error. This happens when the trait refs
|
||||||
|
// are unresolved.
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
|
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
|
||||||
// bounds. We shouldn't have repeated elements besides auto traits at this point.
|
// bounds. We shouldn't have repeated elements besides auto traits at this point.
|
||||||
bounds.dedup();
|
bounds.dedup();
|
||||||
|
@ -1046,7 +1064,8 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
let bounds = crate::make_single_type_binders(bounds);
|
let bounds = crate::make_single_type_binders(bounds);
|
||||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||||
} else {
|
} else {
|
||||||
// FIXME: report error (additional non-auto traits or associated type rebound)
|
// FIXME: report error
|
||||||
|
// (additional non-auto traits, associated type rebound, or no resolved trait)
|
||||||
TyKind::Error.intern(Interner)
|
TyKind::Error.intern(Interner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1139,11 +1158,28 @@ fn named_associated_type_shorthand_candidates<R>(
|
||||||
};
|
};
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
TypeNs::SelfType(impl_id) => search(
|
TypeNs::SelfType(impl_id) => {
|
||||||
// we're _in_ the impl -- the binders get added back later. Correct,
|
// we're _in_ the impl -- the binders get added back later. Correct,
|
||||||
// but it would be nice to make this more explicit
|
// but it would be nice to make this more explicit
|
||||||
db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
|
let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
|
||||||
),
|
|
||||||
|
let impl_id_as_generic_def: GenericDefId = impl_id.into();
|
||||||
|
if impl_id_as_generic_def != def {
|
||||||
|
// `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
|
||||||
|
// `BoundVar`s from `def`'s point of view.
|
||||||
|
// FIXME: A `HirDatabase` query may be handy if this process is needed in more
|
||||||
|
// places. It'd be almost identical as `impl_trait_query` where `resolver` would be
|
||||||
|
// of `def` instead of `impl_id`.
|
||||||
|
let starting_idx = generics(db.upcast(), def).len_self();
|
||||||
|
let subst = TyBuilder::subst_for_def(db, impl_id, None)
|
||||||
|
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||||
|
.build();
|
||||||
|
let trait_ref = subst.apply(trait_ref, Interner);
|
||||||
|
search(trait_ref)
|
||||||
|
} else {
|
||||||
|
search(trait_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
TypeNs::GenericParam(param_id) => {
|
TypeNs::GenericParam(param_id) => {
|
||||||
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
|
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
|
||||||
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
|
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
|
||||||
|
@ -1160,10 +1196,18 @@ fn named_associated_type_shorthand_candidates<R>(
|
||||||
}
|
}
|
||||||
// Handle `Self::Type` referring to own associated type in trait definitions
|
// Handle `Self::Type` referring to own associated type in trait definitions
|
||||||
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
|
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
|
||||||
let generics = generics(db.upcast(), trait_id.into());
|
let trait_generics = generics(db.upcast(), trait_id.into());
|
||||||
if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||||
|
let def_generics = generics(db.upcast(), def);
|
||||||
|
let starting_idx = match def {
|
||||||
|
GenericDefId::TraitId(_) => 0,
|
||||||
|
// `def` is an item within trait. We need to substitute `BoundVar`s but
|
||||||
|
// remember that they are for parent (i.e. trait) generic params so they
|
||||||
|
// come after our own params.
|
||||||
|
_ => def_generics.len_self(),
|
||||||
|
};
|
||||||
let trait_ref = TyBuilder::trait_ref(db, trait_id)
|
let trait_ref = TyBuilder::trait_ref(db, trait_id)
|
||||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
|
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||||
.build();
|
.build();
|
||||||
return search(trait_ref);
|
return search(trait_ref);
|
||||||
}
|
}
|
||||||
|
@ -1405,6 +1449,7 @@ pub(crate) fn generic_defaults_query(
|
||||||
let ctx =
|
let ctx =
|
||||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||||
let generic_params = generics(db.upcast(), def);
|
let generic_params = generics(db.upcast(), def);
|
||||||
|
let parent_start_idx = generic_params.len_self();
|
||||||
|
|
||||||
let defaults = generic_params
|
let defaults = generic_params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1417,19 +1462,17 @@ pub(crate) fn generic_defaults_query(
|
||||||
let val = unknown_const_as_generic(
|
let val = unknown_const_as_generic(
|
||||||
db.const_param_ty(ConstParamId::from_unchecked(id)),
|
db.const_param_ty(ConstParamId::from_unchecked(id)),
|
||||||
);
|
);
|
||||||
return crate::make_binders_with_count(db, idx, &generic_params, val);
|
return make_binders(db, &generic_params, val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut ty =
|
let mut ty =
|
||||||
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
|
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
|
||||||
|
|
||||||
// Each default can only refer to previous parameters.
|
// Each default can only refer to previous parameters.
|
||||||
// type variable default referring to parameter coming
|
// Type variable default referring to parameter coming
|
||||||
// after it. This is forbidden (FIXME: report
|
// after it is forbidden (FIXME: report diagnostic)
|
||||||
// diagnostic)
|
ty = fallback_bound_vars(ty, idx, parent_start_idx);
|
||||||
ty = fallback_bound_vars(ty, idx);
|
crate::make_binders(db, &generic_params, ty.cast(Interner))
|
||||||
let val = GenericArgData::Ty(ty).intern(Interner);
|
|
||||||
crate::make_binders_with_count(db, idx, &generic_params, val)
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -1446,15 +1489,14 @@ pub(crate) fn generic_defaults_recover(
|
||||||
// we still need one default per parameter
|
// we still need one default per parameter
|
||||||
let defaults = generic_params
|
let defaults = generic_params
|
||||||
.iter_id()
|
.iter_id()
|
||||||
.enumerate()
|
.map(|id| {
|
||||||
.map(|(count, id)| {
|
|
||||||
let val = match id {
|
let val = match id {
|
||||||
itertools::Either::Left(_) => {
|
itertools::Either::Left(_) => {
|
||||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||||
}
|
}
|
||||||
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
|
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
|
||||||
};
|
};
|
||||||
crate::make_binders_with_count(db, count, &generic_params, val)
|
crate::make_binders(db, &generic_params, val)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -1633,6 +1675,19 @@ pub enum ValueTyDefId {
|
||||||
}
|
}
|
||||||
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
|
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
|
||||||
|
|
||||||
|
impl ValueTyDefId {
|
||||||
|
pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
|
||||||
|
match self {
|
||||||
|
Self::FunctionId(id) => Some(id.into()),
|
||||||
|
Self::StructId(id) => Some(id.into()),
|
||||||
|
Self::UnionId(id) => Some(id.into()),
|
||||||
|
Self::EnumVariantId(var) => Some(var.into()),
|
||||||
|
Self::ConstId(id) => Some(id.into()),
|
||||||
|
Self::StaticId(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Build the declared type of an item. This depends on the namespace; e.g. for
|
/// Build the declared type of an item. This depends on the namespace; e.g. for
|
||||||
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
|
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
|
||||||
/// the constructor function `(usize) -> Foo` which lives in the values
|
/// the constructor function `(usize) -> Foo` which lives in the values
|
||||||
|
@ -1816,26 +1871,48 @@ pub(crate) fn const_or_path_to_chalk(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
|
||||||
/// num_vars_to_keep) by `TyKind::Unknown`.
|
/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
|
||||||
|
/// appears after the generic parameter of `param_index`.
|
||||||
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
|
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
|
||||||
s: T,
|
s: T,
|
||||||
num_vars_to_keep: usize,
|
param_index: usize,
|
||||||
|
parent_start: usize,
|
||||||
) -> T {
|
) -> T {
|
||||||
|
// Keep in mind that parent generic parameters, if any, come *after* those of the item in
|
||||||
|
// question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
|
||||||
|
// its parent respectively.
|
||||||
|
let is_allowed = |index| {
|
||||||
|
if param_index < parent_start {
|
||||||
|
// The parameter of `param_index` is one from the item in question. Any parent generic
|
||||||
|
// parameters or the item's generic parameters that come before `param_index` is
|
||||||
|
// allowed.
|
||||||
|
// [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
|
||||||
|
// ^^^^^^ ^^^^^^^^^^ these are allowed
|
||||||
|
!(param_index..parent_start).contains(&index)
|
||||||
|
} else {
|
||||||
|
// The parameter of `param_index` is one from the parent generics. Only parent generic
|
||||||
|
// parameters that come before `param_index` are allowed.
|
||||||
|
// [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
|
||||||
|
// ^^^^^^ these are allowed
|
||||||
|
(parent_start..param_index).contains(&index)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
crate::fold_free_vars(
|
crate::fold_free_vars(
|
||||||
s,
|
s,
|
||||||
|bound, binders| {
|
|bound, binders| {
|
||||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||||
TyKind::Error.intern(Interner)
|
|
||||||
} else {
|
|
||||||
bound.shifted_in_from(binders).to_ty(Interner)
|
bound.shifted_in_from(binders).to_ty(Interner)
|
||||||
|
} else {
|
||||||
|
TyKind::Error.intern(Interner)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|ty, bound, binders| {
|
|ty, bound, binders| {
|
||||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||||
unknown_const(ty.clone())
|
|
||||||
} else {
|
|
||||||
bound.shifted_in_from(binders).to_const(Interner, ty)
|
bound.shifted_in_from(binders).to_const(Interner, ty)
|
||||||
|
} else {
|
||||||
|
unknown_const(ty.clone())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -103,6 +103,18 @@ impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<chalk_ir::GeneratorId<Interner>> for crate::db::InternedGeneratorId {
|
||||||
|
fn from(id: chalk_ir::GeneratorId<Interner>) -> Self {
|
||||||
|
Self::from_intern_id(id.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crate::db::InternedGeneratorId> for chalk_ir::GeneratorId<Interner> {
|
||||||
|
fn from(id: crate::db::InternedGeneratorId) -> Self {
|
||||||
|
chalk_ir::GeneratorId(id.as_intern_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
|
pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
|
||||||
chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
|
chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! This module is concerned with finding methods that a given type provides.
|
//! This module is concerned with finding methods that a given type provides.
|
||||||
//! For details about how this works in rustc, see the method lookup page in the
|
//! For details about how this works in rustc, see the method lookup page in the
|
||||||
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
|
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
|
||||||
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
|
//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
|
||||||
use std::{iter, ops::ControlFlow, sync::Arc};
|
use std::{iter, ops::ControlFlow, sync::Arc};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
@ -654,7 +654,7 @@ fn find_matching_impl(
|
||||||
let r = table.run_in_snapshot(|table| {
|
let r = table.run_in_snapshot(|table| {
|
||||||
let impl_data = db.impl_data(impl_);
|
let impl_data = db.impl_data(impl_);
|
||||||
let substs =
|
let substs =
|
||||||
TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
|
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
|
||||||
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
|
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
|
||||||
|
|
||||||
table
|
table
|
||||||
|
@ -1111,6 +1111,24 @@ pub fn resolve_indexing_op(
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
/// Returns the receiver type for the try branch trait call.
|
||||||
|
pub fn resolve_branch_op(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
env: Arc<TraitEnvironment>,
|
||||||
|
ty: Canonical<Ty>,
|
||||||
|
try_trait: TraitId,
|
||||||
|
) -> Option<ReceiverAdjustments> {
|
||||||
|
let mut table = InferenceTable::new(db, env.clone());
|
||||||
|
let ty = table.instantiate_canonical(ty);
|
||||||
|
let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
|
||||||
|
for (ty, adj) in deref_chain.into_iter().zip(adj) {
|
||||||
|
let goal = generic_implements_goal(db, env.clone(), try_trait, &ty);
|
||||||
|
if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
|
||||||
|
return Some(adj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! check_that {
|
macro_rules! check_that {
|
||||||
($cond:expr) => {
|
($cond:expr) => {
|
||||||
|
@ -1147,10 +1165,9 @@ fn is_valid_candidate(
|
||||||
}));
|
}));
|
||||||
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
|
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
|
||||||
let self_ty_matches = table.run_in_snapshot(|table| {
|
let self_ty_matches = table.run_in_snapshot(|table| {
|
||||||
let subst =
|
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
|
||||||
TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
|
.fill_with_inference_vars(table)
|
||||||
let expected_self_ty =
|
.build();
|
||||||
subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
|
|
||||||
table.unify(&expected_self_ty, &self_ty)
|
table.unify(&expected_self_ty, &self_ty)
|
||||||
});
|
});
|
||||||
if !self_ty_matches {
|
if !self_ty_matches {
|
||||||
|
@ -1186,31 +1203,26 @@ fn is_valid_fn_candidate(
|
||||||
|
|
||||||
table.run_in_snapshot(|table| {
|
table.run_in_snapshot(|table| {
|
||||||
let container = fn_id.lookup(db.upcast()).container;
|
let container = fn_id.lookup(db.upcast()).container;
|
||||||
let impl_subst = match container {
|
let (impl_subst, expect_self_ty) = match container {
|
||||||
ItemContainerId::ImplId(it) => {
|
ItemContainerId::ImplId(it) => {
|
||||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
let subst =
|
||||||
|
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||||
|
let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
|
||||||
|
(subst, self_ty)
|
||||||
}
|
}
|
||||||
ItemContainerId::TraitId(it) => {
|
ItemContainerId::TraitId(it) => {
|
||||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
let subst =
|
||||||
|
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||||
|
let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
|
||||||
|
(subst, self_ty)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id)
|
let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
|
||||||
.use_parent_substs(&impl_subst)
|
|
||||||
.fill_with_inference_vars(table)
|
.fill_with_inference_vars(table)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let expect_self_ty = match container {
|
|
||||||
ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
|
|
||||||
ItemContainerId::ImplId(impl_id) => {
|
|
||||||
fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
|
|
||||||
}
|
|
||||||
// We should only get called for associated items (impl/trait)
|
|
||||||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
check_that!(table.unify(&expect_self_ty, self_ty));
|
check_that!(table.unify(&expect_self_ty, self_ty));
|
||||||
|
|
||||||
if let Some(receiver_ty) = receiver_ty {
|
if let Some(receiver_ty) = receiver_ty {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
|
||||||
use expect_test::Expect;
|
use expect_test::Expect;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body::{Body, BodySourceMap, SyntheticSyntax},
|
body::{Body, BodySourceMap, SyntheticSyntax},
|
||||||
db::DefDatabase,
|
db::{DefDatabase, InternDatabase},
|
||||||
expr::{ExprId, PatId},
|
expr::{ExprId, PatId},
|
||||||
item_scope::ItemScope,
|
item_scope::ItemScope,
|
||||||
nameres::DefMap,
|
nameres::DefMap,
|
||||||
|
@ -135,6 +135,10 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
|
||||||
let loc = it.lookup(&db);
|
let loc = it.lookup(&db);
|
||||||
loc.source(&db).value.syntax().text_range().start()
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
}
|
}
|
||||||
|
DefWithBodyId::VariantId(it) => {
|
||||||
|
let loc = db.lookup_intern_enum(it.parent);
|
||||||
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
let mut unexpected_type_mismatches = String::new();
|
let mut unexpected_type_mismatches = String::new();
|
||||||
for def in defs {
|
for def in defs {
|
||||||
|
@ -388,6 +392,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||||
let loc = it.lookup(&db);
|
let loc = it.lookup(&db);
|
||||||
loc.source(&db).value.syntax().text_range().start()
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
}
|
}
|
||||||
|
DefWithBodyId::VariantId(it) => {
|
||||||
|
let loc = db.lookup_intern_enum(it.parent);
|
||||||
|
loc.source(&db).value.syntax().text_range().start()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
for def in defs {
|
for def in defs {
|
||||||
let (_body, source_map) = db.body_with_source_map(def);
|
let (_body, source_map) = db.body_with_source_map(def);
|
||||||
|
@ -453,6 +461,18 @@ fn visit_module(
|
||||||
let body = db.body(def);
|
let body = db.body(def);
|
||||||
visit_body(db, &body, cb);
|
visit_body(db, &body, cb);
|
||||||
}
|
}
|
||||||
|
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
||||||
|
db.enum_data(it)
|
||||||
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
|
||||||
|
.for_each(|it| {
|
||||||
|
let def = it.into();
|
||||||
|
cb(def);
|
||||||
|
let body = db.body(def);
|
||||||
|
visit_body(db, &body, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
ModuleDefId::TraitId(it) => {
|
ModuleDefId::TraitId(it) => {
|
||||||
let trait_data = db.trait_data(it);
|
let trait_data = db.trait_data(it);
|
||||||
for &(_, item) in trait_data.items.iter() {
|
for &(_, item) in trait_data.items.iter() {
|
||||||
|
|
|
@ -294,6 +294,24 @@ fn foo() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generator_yield_return_coerce() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
fn test() {
|
||||||
|
let g = || {
|
||||||
|
yield &1u32;
|
||||||
|
yield &&1u32;
|
||||||
|
if true {
|
||||||
|
return &1u32;
|
||||||
|
}
|
||||||
|
&&1u32
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assign_coerce() {
|
fn assign_coerce() {
|
||||||
check_no_mismatches(
|
check_no_mismatches(
|
||||||
|
|
|
@ -55,6 +55,28 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_dyn_ty_independent_of_order() {
|
||||||
|
check_types_source_code(
|
||||||
|
r#"
|
||||||
|
auto trait Send {}
|
||||||
|
trait A {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
trait B: A {}
|
||||||
|
|
||||||
|
fn test(
|
||||||
|
_: &(dyn A<Assoc = ()> + Send),
|
||||||
|
//^ &(dyn A<Assoc = ()> + Send)
|
||||||
|
_: &(dyn Send + A<Assoc = ()>),
|
||||||
|
//^ &(dyn A<Assoc = ()> + Send)
|
||||||
|
_: &dyn B<Assoc = ()>,
|
||||||
|
//^ &(dyn B<Assoc = ()>)
|
||||||
|
) {}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn render_dyn_for_ty() {
|
fn render_dyn_for_ty() {
|
||||||
// FIXME
|
// FIXME
|
||||||
|
|
|
@ -1070,3 +1070,13 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cfg_params() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {}
|
||||||
|
//^^^ u32
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1488,7 +1488,6 @@ fn regression_11688_4() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gat_crash_1() {
|
fn gat_crash_1() {
|
||||||
cov_mark::check!(ignore_gats);
|
|
||||||
check_no_mismatches(
|
check_no_mismatches(
|
||||||
r#"
|
r#"
|
||||||
trait ATrait {}
|
trait ATrait {}
|
||||||
|
@ -1527,30 +1526,22 @@ unsafe impl Storage for InlineStorage {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gat_crash_3() {
|
fn gat_crash_3() {
|
||||||
// FIXME: This test currently crashes rust analyzer in a debug build but not in a
|
check_no_mismatches(
|
||||||
// release build (i.e. for the user). With the assumption that tests will always be run
|
r#"
|
||||||
// in debug mode, we catch the unwind and expect that it panicked. See the
|
|
||||||
// [`crate::utils::generics`] function for more information.
|
|
||||||
cov_mark::check!(ignore_gats);
|
|
||||||
std::panic::catch_unwind(|| {
|
|
||||||
check_no_mismatches(
|
|
||||||
r#"
|
|
||||||
trait Collection {
|
trait Collection {
|
||||||
type Item;
|
type Item;
|
||||||
type Member<T>: Collection<Item = T>;
|
type Member<T>: Collection<Item = T>;
|
||||||
fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
|
fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
struct ConstGen<T, const N: usize> {
|
struct ConstGen<T, const N: usize> {
|
||||||
data: [T; N],
|
data: [T; N],
|
||||||
}
|
}
|
||||||
impl<T, const N: usize> Collection for ConstGen<T, N> {
|
impl<T, const N: usize> Collection for ConstGen<T, N> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type Member<U> = ConstGen<U, N>;
|
type Member<U> = ConstGen<U, N>;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
})
|
|
||||||
.expect_err("must panic");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1691,3 +1682,28 @@ fn macrostmts() -> u8 {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dyn_with_unresolved_trait() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
fn foo(a: &dyn DoesNotExist) {
|
||||||
|
a.bar();
|
||||||
|
//^&{unknown}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn self_assoc_with_const_generics_crash() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
trait Trait { type Item; }
|
||||||
|
impl<T, const N: usize> Trait for [T; N] {
|
||||||
|
type Item = ();
|
||||||
|
fn f<U>(_: Self::Item) {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1693,16 +1693,16 @@ fn infer_type_param() {
|
||||||
fn infer_const() {
|
fn infer_const() {
|
||||||
check_infer(
|
check_infer(
|
||||||
r#"
|
r#"
|
||||||
struct Foo;
|
struct Foo;
|
||||||
impl Foo { const ASSOC_CONST: u32 = 0; }
|
impl Foo { const ASSOC_CONST: u32 = 0; }
|
||||||
const GLOBAL_CONST: u32 = 101;
|
const GLOBAL_CONST: u32 = 101;
|
||||||
fn test() {
|
fn test() {
|
||||||
const LOCAL_CONST: u32 = 99;
|
const LOCAL_CONST: u32 = 99;
|
||||||
let x = LOCAL_CONST;
|
let x = LOCAL_CONST;
|
||||||
let z = GLOBAL_CONST;
|
let z = GLOBAL_CONST;
|
||||||
let id = Foo::ASSOC_CONST;
|
let id = Foo::ASSOC_CONST;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
48..49 '0': u32
|
48..49 '0': u32
|
||||||
79..82 '101': u32
|
79..82 '101': u32
|
||||||
|
@ -1722,17 +1722,17 @@ fn infer_const() {
|
||||||
fn infer_static() {
|
fn infer_static() {
|
||||||
check_infer(
|
check_infer(
|
||||||
r#"
|
r#"
|
||||||
static GLOBAL_STATIC: u32 = 101;
|
static GLOBAL_STATIC: u32 = 101;
|
||||||
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
||||||
fn test() {
|
fn test() {
|
||||||
static LOCAL_STATIC: u32 = 99;
|
static LOCAL_STATIC: u32 = 99;
|
||||||
static mut LOCAL_STATIC_MUT: u32 = 99;
|
static mut LOCAL_STATIC_MUT: u32 = 99;
|
||||||
let x = LOCAL_STATIC;
|
let x = LOCAL_STATIC;
|
||||||
let y = LOCAL_STATIC_MUT;
|
let y = LOCAL_STATIC_MUT;
|
||||||
let z = GLOBAL_STATIC;
|
let z = GLOBAL_STATIC;
|
||||||
let w = GLOBAL_STATIC_MUT;
|
let w = GLOBAL_STATIC_MUT;
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
28..31 '101': u32
|
28..31 '101': u32
|
||||||
69..72 '101': u32
|
69..72 '101': u32
|
||||||
|
@ -1751,6 +1751,41 @@ fn infer_static() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_enum_variant() {
|
||||||
|
check_infer(
|
||||||
|
r#"
|
||||||
|
enum Foo {
|
||||||
|
A = 15,
|
||||||
|
B = Foo::A as isize + 1
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
19..21 '15': isize
|
||||||
|
31..37 'Foo::A': Foo
|
||||||
|
31..46 'Foo::A as isize': isize
|
||||||
|
31..50 'Foo::A...ze + 1': isize
|
||||||
|
49..50 '1': isize
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check_infer(
|
||||||
|
r#"
|
||||||
|
#[repr(u32)]
|
||||||
|
enum Foo {
|
||||||
|
A = 15,
|
||||||
|
B = Foo::A as u32 + 1
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
32..34 '15': u32
|
||||||
|
44..50 'Foo::A': Foo
|
||||||
|
44..57 'Foo::A as u32': u32
|
||||||
|
44..61 'Foo::A...32 + 1': u32
|
||||||
|
60..61 '1': u32
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shadowing_primitive() {
|
fn shadowing_primitive() {
|
||||||
check_types(
|
check_types(
|
||||||
|
@ -1917,6 +1952,88 @@ fn closure_return_inferred() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generator_types_inferred() {
|
||||||
|
check_infer(
|
||||||
|
r#"
|
||||||
|
//- minicore: generator, deref
|
||||||
|
use core::ops::{Generator, GeneratorState};
|
||||||
|
use core::pin::Pin;
|
||||||
|
|
||||||
|
fn f(v: i64) {}
|
||||||
|
fn test() {
|
||||||
|
let mut g = |r| {
|
||||||
|
let a = yield 0;
|
||||||
|
let a = yield 1;
|
||||||
|
let a = yield 2;
|
||||||
|
"return value"
|
||||||
|
};
|
||||||
|
|
||||||
|
match Pin::new(&mut g).resume(0usize) {
|
||||||
|
GeneratorState::Yielded(y) => { f(y); }
|
||||||
|
GeneratorState::Complete(r) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
70..71 'v': i64
|
||||||
|
78..80 '{}': ()
|
||||||
|
91..362 '{ ... } }': ()
|
||||||
|
101..106 'mut g': |usize| yields i64 -> &str
|
||||||
|
109..218 '|r| { ... }': |usize| yields i64 -> &str
|
||||||
|
110..111 'r': usize
|
||||||
|
113..218 '{ ... }': &str
|
||||||
|
127..128 'a': usize
|
||||||
|
131..138 'yield 0': usize
|
||||||
|
137..138 '0': i64
|
||||||
|
152..153 'a': usize
|
||||||
|
156..163 'yield 1': usize
|
||||||
|
162..163 '1': i64
|
||||||
|
177..178 'a': usize
|
||||||
|
181..188 'yield 2': usize
|
||||||
|
187..188 '2': i64
|
||||||
|
198..212 '"return value"': &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)': GeneratorState<i64, &str>
|
||||||
|
240..246 '&mut g': &mut |usize| yields i64 -> &str
|
||||||
|
245..246 'g': |usize| yields i64 -> &str
|
||||||
|
255..261 '0usize': usize
|
||||||
|
273..299 'Genera...ded(y)': GeneratorState<i64, &str>
|
||||||
|
297..298 'y': i64
|
||||||
|
303..312 '{ f(y); }': ()
|
||||||
|
305..306 'f': fn f(i64)
|
||||||
|
305..309 'f(y)': ()
|
||||||
|
307..308 'y': i64
|
||||||
|
321..348 'Genera...ete(r)': GeneratorState<i64, &str>
|
||||||
|
346..347 'r': &str
|
||||||
|
352..354 '{}': ()
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generator_resume_yield_return_unit() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
//- minicore: generator, deref
|
||||||
|
use core::ops::{Generator, GeneratorState};
|
||||||
|
use core::pin::Pin;
|
||||||
|
fn test() {
|
||||||
|
let mut g = || {
|
||||||
|
let () = yield;
|
||||||
|
};
|
||||||
|
|
||||||
|
match Pin::new(&mut g).resume(()) {
|
||||||
|
GeneratorState::Yielded(()) => {}
|
||||||
|
GeneratorState::Complete(()) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fn_pointer_return() {
|
fn fn_pointer_return() {
|
||||||
check_infer(
|
check_infer(
|
||||||
|
|
|
@ -162,98 +162,16 @@ fn test() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn infer_try() {
|
|
||||||
check_types(
|
|
||||||
r#"
|
|
||||||
//- /main.rs crate:main deps:core
|
|
||||||
fn test() {
|
|
||||||
let r: Result<i32, u64> = Result::Ok(1);
|
|
||||||
let v = r?;
|
|
||||||
v;
|
|
||||||
} //^ i32
|
|
||||||
|
|
||||||
//- /core.rs crate:core
|
|
||||||
pub mod ops {
|
|
||||||
pub trait Try {
|
|
||||||
type Ok;
|
|
||||||
type Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod result {
|
|
||||||
pub enum Result<O, E> {
|
|
||||||
Ok(O),
|
|
||||||
Err(E)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O, E> crate::ops::Try for Result<O, E> {
|
|
||||||
type Ok = O;
|
|
||||||
type Error = E;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod prelude {
|
|
||||||
pub mod rust_2018 {
|
|
||||||
pub use crate::{result::*, ops::*};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_try_trait_v2() {
|
fn infer_try_trait_v2() {
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs crate:main deps:core
|
//- minicore: try
|
||||||
fn test() {
|
fn test() -> core::ops::ControlFlow<u32, f32> {
|
||||||
let r: Result<i32, u64> = Result::Ok(1);
|
let r: core::ops::ControlFlow<u32, f32> = core::ops::ControlFlow::Continue(1.0);
|
||||||
let v = r?;
|
let v = r?;
|
||||||
v;
|
//^ f32
|
||||||
} //^ i32
|
r
|
||||||
|
|
||||||
//- /core.rs crate:core
|
|
||||||
mod ops {
|
|
||||||
mod try_trait {
|
|
||||||
pub trait Try: FromResidual {
|
|
||||||
type Output;
|
|
||||||
type Residual;
|
|
||||||
}
|
|
||||||
pub trait FromResidual<R = <Self as Try>::Residual> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::try_trait::FromResidual;
|
|
||||||
pub use self::try_trait::Try;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod convert {
|
|
||||||
pub trait From<T> {}
|
|
||||||
impl<T> From<T> for T {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod result {
|
|
||||||
use crate::convert::From;
|
|
||||||
use crate::ops::{Try, FromResidual};
|
|
||||||
|
|
||||||
pub enum Infallible {}
|
|
||||||
pub enum Result<O, E> {
|
|
||||||
Ok(O),
|
|
||||||
Err(E)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O, E> Try for Result<O, E> {
|
|
||||||
type Output = O;
|
|
||||||
type Error = Result<Infallible, E>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E, F: From<E>> FromResidual<Result<Infallible, E>> for Result<T, F> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod prelude {
|
|
||||||
pub mod rust_2018 {
|
|
||||||
pub use crate::result::*;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
@ -279,6 +197,10 @@ fn test() {
|
||||||
pub mod iter {
|
pub mod iter {
|
||||||
pub trait IntoIterator {
|
pub trait IntoIterator {
|
||||||
type Item;
|
type Item;
|
||||||
|
type IntoIter: Iterator<Item = Self::Item>;
|
||||||
|
}
|
||||||
|
pub trait Iterator {
|
||||||
|
type Item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
|
@ -297,7 +219,13 @@ pub mod collections {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> IntoIterator for Vec<T> {
|
impl<T> IntoIterator for Vec<T> {
|
||||||
type Item=T;
|
type Item = T;
|
||||||
|
type IntoIter = IntoIter<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IntoIter<T> {}
|
||||||
|
impl<T> Iterator for IntoIter<T> {
|
||||||
|
type Item = T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
|
|
@ -13,8 +13,8 @@ use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
|
db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
|
||||||
Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
|
Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
|
||||||
WhereClause,
|
TyKind, WhereClause,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This controls how much 'time' we give the Chalk solver before giving up.
|
/// This controls how much 'time' we give the Chalk solver before giving up.
|
||||||
|
@ -95,7 +95,7 @@ pub(crate) fn trait_solve_query(
|
||||||
..
|
..
|
||||||
}))) = &goal.value.goal.data(Interner)
|
}))) = &goal.value.goal.data(Interner)
|
||||||
{
|
{
|
||||||
if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(Interner).kind(Interner) {
|
if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) {
|
||||||
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
|
// Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
|
||||||
return Some(Solution::Ambig(Guidance::Unknown));
|
return Some(Solution::Ambig(Guidance::Unknown));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
|
use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
generics::{
|
generics::{
|
||||||
|
@ -24,8 +24,7 @@ use smallvec::{smallvec, SmallVec};
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
|
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
|
||||||
TraitRef, TraitRefExt, TyKind, WhereClause,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
|
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
|
||||||
|
@ -174,31 +173,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
|
||||||
|
|
||||||
pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
|
pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
|
||||||
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
|
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
|
||||||
if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
|
|
||||||
let params = db.generic_params(def);
|
|
||||||
let parent_params = &parent_generics.as_ref().unwrap().params;
|
|
||||||
let has_consts =
|
|
||||||
params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
|
||||||
let parent_has_consts =
|
|
||||||
parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
|
||||||
return if has_consts || parent_has_consts {
|
|
||||||
// XXX: treat const generic associated types as not existing to avoid crashes
|
|
||||||
// (#11769)
|
|
||||||
//
|
|
||||||
// Note: Also crashes when the parent has const generics (also even if the GAT
|
|
||||||
// doesn't use them), see `tests::regression::gat_crash_3` for an example.
|
|
||||||
// Avoids that by disabling GATs when the parent (i.e. `impl` block) has
|
|
||||||
// const generics (#12193).
|
|
||||||
//
|
|
||||||
// Chalk expects the inner associated type's parameters to come
|
|
||||||
// *before*, not after the trait's generics as we've always done it.
|
|
||||||
// Adapting to this requires a larger refactoring
|
|
||||||
cov_mark::hit!(ignore_gats);
|
|
||||||
Generics { def, params: Interned::new(Default::default()), parent_generics }
|
|
||||||
} else {
|
|
||||||
Generics { def, params, parent_generics }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Generics { def, params: db.generic_params(def), parent_generics }
|
Generics { def, params: db.generic_params(def), parent_generics }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,23 +195,30 @@ impl Generics {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator over types and const params of parent, then self.
|
/// Iterator over types and const params of self, then parent.
|
||||||
pub(crate) fn iter<'a>(
|
pub(crate) fn iter<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||||
let to_toc_id = |it: &'a Generics| {
|
let to_toc_id = |it: &'a Generics| {
|
||||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
||||||
};
|
};
|
||||||
self.parent_generics()
|
self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
|
||||||
.into_iter()
|
}
|
||||||
.flat_map(move |it| it.params.iter().map(to_toc_id(it)))
|
|
||||||
.chain(self.params.iter().map(to_toc_id(self)))
|
/// Iterate over types and const params without parent params.
|
||||||
|
pub(crate) fn iter_self<'a>(
|
||||||
|
&'a self,
|
||||||
|
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||||
|
let to_toc_id = |it: &'a Generics| {
|
||||||
|
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
||||||
|
};
|
||||||
|
self.params.iter().map(to_toc_id(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator over types and const params of parent.
|
/// Iterator over types and const params of parent.
|
||||||
pub(crate) fn iter_parent<'a>(
|
pub(crate) fn iter_parent<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||||
self.parent_generics().into_iter().flat_map(|it| {
|
self.parent_generics().into_iter().flat_map(|it| {
|
||||||
let to_toc_id =
|
let to_toc_id =
|
||||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
|
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
|
||||||
|
@ -245,12 +226,18 @@ impl Generics {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns total number of generic parameters in scope, including those from parent.
|
||||||
pub(crate) fn len(&self) -> usize {
|
pub(crate) fn len(&self) -> usize {
|
||||||
let parent = self.parent_generics().map_or(0, Generics::len);
|
let parent = self.parent_generics().map_or(0, Generics::len);
|
||||||
let child = self.params.type_or_consts.len();
|
let child = self.params.type_or_consts.len();
|
||||||
parent + child
|
parent + child
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns numbers of generic parameters excluding those from parent.
|
||||||
|
pub(crate) fn len_self(&self) -> usize {
|
||||||
|
self.params.type_or_consts.len()
|
||||||
|
}
|
||||||
|
|
||||||
/// (parent total, self param, type param list, const param list, impl trait)
|
/// (parent total, self param, type param list, const param list, impl trait)
|
||||||
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
|
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
|
||||||
let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
|
let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
|
||||||
|
@ -275,15 +262,17 @@ impl Generics {
|
||||||
if param.parent == self.def {
|
if param.parent == self.def {
|
||||||
let (idx, (_local_id, data)) =
|
let (idx, (_local_id, data)) =
|
||||||
self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
|
self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
|
||||||
let parent_len = self.parent_generics().map_or(0, Generics::len);
|
Some((idx, data))
|
||||||
Some((parent_len + idx, data))
|
|
||||||
} else {
|
} else {
|
||||||
self.parent_generics().and_then(|g| g.find_param(param))
|
self.parent_generics()
|
||||||
|
.and_then(|g| g.find_param(param))
|
||||||
|
// Remember that parent parameters come after parameters for self.
|
||||||
|
.map(|(idx, data)| (self.len_self() + idx, data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_generics(&self) -> Option<&Generics> {
|
pub(crate) fn parent_generics(&self) -> Option<&Generics> {
|
||||||
self.parent_generics.as_ref().map(|it| &**it)
|
self.parent_generics.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a Substitution that replaces each parameter by a bound variable.
|
/// Returns a Substitution that replaces each parameter by a bound variable.
|
||||||
|
@ -295,18 +284,10 @@ impl Generics {
|
||||||
Substitution::from_iter(
|
Substitution::from_iter(
|
||||||
Interner,
|
Interner,
|
||||||
self.iter_id().enumerate().map(|(idx, id)| match id {
|
self.iter_id().enumerate().map(|(idx, id)| match id {
|
||||||
Either::Left(_) => GenericArgData::Ty(
|
Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
|
||||||
TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
|
Either::Right(id) => BoundVar::new(debruijn, idx)
|
||||||
)
|
.to_const(Interner, db.const_param_ty(id))
|
||||||
.intern(Interner),
|
.cast(Interner),
|
||||||
Either::Right(id) => GenericArgData::Const(
|
|
||||||
ConstData {
|
|
||||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
|
||||||
ty: db.const_param_ty(id),
|
|
||||||
}
|
|
||||||
.intern(Interner),
|
|
||||||
)
|
|
||||||
.intern(Interner),
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -316,18 +297,12 @@ impl Generics {
|
||||||
Substitution::from_iter(
|
Substitution::from_iter(
|
||||||
Interner,
|
Interner,
|
||||||
self.iter_id().map(|id| match id {
|
self.iter_id().map(|id| match id {
|
||||||
Either::Left(id) => GenericArgData::Ty(
|
Either::Left(id) => {
|
||||||
TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
|
crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
|
||||||
)
|
}
|
||||||
.intern(Interner),
|
Either::Right(id) => crate::to_placeholder_idx(db, id.into())
|
||||||
Either::Right(id) => GenericArgData::Const(
|
.to_const(Interner, db.const_param_ty(id))
|
||||||
ConstData {
|
.cast(Interner),
|
||||||
value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
|
|
||||||
ty: db.const_param_ty(id),
|
|
||||||
}
|
|
||||||
.intern(Interner),
|
|
||||||
)
|
|
||||||
.intern(Interner),
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ doctest = false
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
either = "1.7.0"
|
either = "1.7.0"
|
||||||
arrayvec = "0.7.2"
|
arrayvec = "0.7.2"
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
smallvec = "1.9.0"
|
smallvec = "1.10.0"
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.15.0"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! Re-export diagnostics such that clients of `hir` don't have to depend on
|
//! Re-export diagnostics such that clients of `hir` don't have to depend on
|
||||||
//! low-level crates.
|
//! low-level crates.
|
||||||
//!
|
//!
|
||||||
//! This probably isn't the best way to do this -- ideally, diagnistics should
|
//! This probably isn't the best way to do this -- ideally, diagnostics should
|
||||||
//! be expressed in terms of hir types themselves.
|
//! be expressed in terms of hir types themselves.
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use cfg::{CfgExpr, CfgOptions};
|
use cfg::{CfgExpr, CfgOptions};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::path::ModPath;
|
use hir_def::{path::ModPath, TraitId};
|
||||||
use hir_expand::{name::Name, HirFileId, InFile};
|
use hir_expand::{name::Name, HirFileId, InFile};
|
||||||
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
|
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ diagnostics![
|
||||||
BreakOutsideOfLoop,
|
BreakOutsideOfLoop,
|
||||||
InactiveCode,
|
InactiveCode,
|
||||||
IncorrectCase,
|
IncorrectCase,
|
||||||
|
IncorrectTryExpr,
|
||||||
InvalidDeriveTarget,
|
InvalidDeriveTarget,
|
||||||
MacroError,
|
MacroError,
|
||||||
MalformedDerive,
|
MalformedDerive,
|
||||||
|
@ -40,6 +41,7 @@ diagnostics![
|
||||||
MissingFields,
|
MissingFields,
|
||||||
MissingMatchArms,
|
MissingMatchArms,
|
||||||
MissingUnsafe,
|
MissingUnsafe,
|
||||||
|
NotImplemented,
|
||||||
NoSuchField,
|
NoSuchField,
|
||||||
ReplaceFilterMapNextWithFindMap,
|
ReplaceFilterMapNextWithFindMap,
|
||||||
TypeMismatch,
|
TypeMismatch,
|
||||||
|
@ -153,6 +155,16 @@ pub struct MismatchedArgCount {
|
||||||
pub expected: usize,
|
pub expected: usize,
|
||||||
pub found: usize,
|
pub found: usize,
|
||||||
}
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IncorrectTryExpr {
|
||||||
|
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NotImplemented {
|
||||||
|
pub expr: InFile<AstPtr<ast::Expr>>,
|
||||||
|
pub trait_: TraitId,
|
||||||
|
pub ty: Type,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MissingMatchArms {
|
pub struct MissingMatchArms {
|
||||||
|
|
|
@ -492,6 +492,9 @@ impl HirDisplay for TypeAlias {
|
||||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||||
let data = f.db.type_alias_data(self.id);
|
let data = f.db.type_alias_data(self.id);
|
||||||
write!(f, "type {}", data.name)?;
|
write!(f, "type {}", data.name)?;
|
||||||
|
let def_id = GenericDefId::TypeAliasId(self.id);
|
||||||
|
write_generic_params(def_id, f)?;
|
||||||
|
write_where_clause(def_id, f)?;
|
||||||
if !data.bounds.is_empty() {
|
if !data.bounds.is_empty() {
|
||||||
f.write_str(": ")?;
|
f.write_str(": ")?;
|
||||||
f.write_joined(&data.bounds, " + ")?;
|
f.write_joined(&data.bounds, " + ")?;
|
||||||
|
|
|
@ -140,6 +140,7 @@ impl From<DefWithBody> for DefWithBodyId {
|
||||||
DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
|
DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
|
||||||
DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
|
DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
|
||||||
DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
|
DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
|
||||||
|
DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,6 +151,7 @@ impl From<DefWithBodyId> for DefWithBody {
|
||||||
DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()),
|
DefWithBodyId::FunctionId(it) => DefWithBody::Function(it.into()),
|
||||||
DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()),
|
DefWithBodyId::StaticId(it) => DefWithBody::Static(it.into()),
|
||||||
DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()),
|
DefWithBodyId::ConstId(it) => DefWithBody::Const(it.into()),
|
||||||
|
DefWithBodyId::VariantId(it) => DefWithBody::Variant(it.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,9 +174,7 @@ impl From<GenericDef> for GenericDefId {
|
||||||
GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
|
GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
|
||||||
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
|
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
|
||||||
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
|
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
|
||||||
GenericDef::Variant(it) => {
|
GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()),
|
||||||
GenericDefId::EnumVariantId(EnumVariantId { parent: it.parent.id, local_id: it.id })
|
|
||||||
}
|
|
||||||
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
|
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,9 +188,7 @@ impl From<GenericDefId> for GenericDef {
|
||||||
GenericDefId::TraitId(it) => GenericDef::Trait(it.into()),
|
GenericDefId::TraitId(it) => GenericDef::Trait(it.into()),
|
||||||
GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
|
GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
|
||||||
GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
|
GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
|
||||||
GenericDefId::EnumVariantId(it) => {
|
GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()),
|
||||||
GenericDef::Variant(Variant { parent: it.parent.into(), id: it.local_id })
|
|
||||||
}
|
|
||||||
GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
|
GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ use arrayvec::ArrayVec;
|
||||||
use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
|
use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
adt::{ReprKind, VariantData},
|
adt::{ReprData, VariantData},
|
||||||
body::{BodyDiagnostic, SyntheticSyntax},
|
body::{BodyDiagnostic, SyntheticSyntax},
|
||||||
expr::{BindingAnnotation, LabelId, Pat, PatId},
|
expr::{BindingAnnotation, LabelId, Pat, PatId},
|
||||||
generics::{TypeOrConstParamData, TypeParamProvenance},
|
generics::{TypeOrConstParamData, TypeParamProvenance},
|
||||||
|
@ -50,7 +50,7 @@ use hir_def::{
|
||||||
resolver::{HasResolver, Resolver},
|
resolver::{HasResolver, Resolver},
|
||||||
src::HasSource as _,
|
src::HasSource as _,
|
||||||
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
|
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
|
||||||
FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
|
EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
|
||||||
LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
|
LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
|
||||||
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
|
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
|
||||||
};
|
};
|
||||||
|
@ -61,7 +61,6 @@ use hir_ty::{
|
||||||
diagnostics::BodyValidationDiagnostic,
|
diagnostics::BodyValidationDiagnostic,
|
||||||
method_resolution::{self, TyFingerprint},
|
method_resolution::{self, TyFingerprint},
|
||||||
primitive::UintTy,
|
primitive::UintTy,
|
||||||
subst_prefix,
|
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
|
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
|
||||||
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
||||||
|
@ -73,7 +72,7 @@ use once_cell::unsync::Lazy;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use stdx::{impl_from, never};
|
use stdx::{impl_from, never};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasAttrs as _, HasDocComments, HasName},
|
ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
|
||||||
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
|
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,11 +81,12 @@ use crate::db::{DefDatabase, HirDatabase};
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
attrs::{HasAttrs, Namespace},
|
attrs::{HasAttrs, Namespace},
|
||||||
diagnostics::{
|
diagnostics::{
|
||||||
AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
|
AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, IncorrectTryExpr,
|
||||||
MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
|
InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
|
||||||
MissingUnsafe, NoSuchField, ReplaceFilterMapNextWithFindMap, TypeMismatch,
|
MissingMatchArms, MissingUnsafe, NoSuchField, NotImplemented,
|
||||||
UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
|
ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
|
||||||
UnresolvedModule, UnresolvedProcMacro,
|
UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
|
||||||
|
UnresolvedProcMacro,
|
||||||
},
|
},
|
||||||
has_source::HasSource,
|
has_source::HasSource,
|
||||||
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits},
|
||||||
|
@ -348,7 +348,10 @@ impl ModuleDef {
|
||||||
ModuleDef::Module(it) => it.id.into(),
|
ModuleDef::Module(it) => it.id.into(),
|
||||||
ModuleDef::Const(it) => it.id.into(),
|
ModuleDef::Const(it) => it.id.into(),
|
||||||
ModuleDef::Static(it) => it.id.into(),
|
ModuleDef::Static(it) => it.id.into(),
|
||||||
_ => return Vec::new(),
|
ModuleDef::Variant(it) => {
|
||||||
|
EnumVariantId { parent: it.parent.into(), local_id: it.id }.into()
|
||||||
|
}
|
||||||
|
ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let module = match self.module(db) {
|
let module = match self.module(db) {
|
||||||
|
@ -377,10 +380,10 @@ impl ModuleDef {
|
||||||
ModuleDef::Function(it) => Some(it.into()),
|
ModuleDef::Function(it) => Some(it.into()),
|
||||||
ModuleDef::Const(it) => Some(it.into()),
|
ModuleDef::Const(it) => Some(it.into()),
|
||||||
ModuleDef::Static(it) => Some(it.into()),
|
ModuleDef::Static(it) => Some(it.into()),
|
||||||
|
ModuleDef::Variant(it) => Some(it.into()),
|
||||||
|
|
||||||
ModuleDef::Module(_)
|
ModuleDef::Module(_)
|
||||||
| ModuleDef::Adt(_)
|
| ModuleDef::Adt(_)
|
||||||
| ModuleDef::Variant(_)
|
|
||||||
| ModuleDef::Trait(_)
|
| ModuleDef::Trait(_)
|
||||||
| ModuleDef::TypeAlias(_)
|
| ModuleDef::TypeAlias(_)
|
||||||
| ModuleDef::Macro(_)
|
| ModuleDef::Macro(_)
|
||||||
|
@ -537,6 +540,30 @@ impl Module {
|
||||||
}
|
}
|
||||||
acc.extend(decl.diagnostics(db))
|
acc.extend(decl.diagnostics(db))
|
||||||
}
|
}
|
||||||
|
ModuleDef::Adt(adt) => {
|
||||||
|
match adt {
|
||||||
|
Adt::Struct(s) => {
|
||||||
|
for diag in db.struct_data_with_diagnostics(s.id).1.iter() {
|
||||||
|
emit_def_diagnostic(db, acc, diag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Adt::Union(u) => {
|
||||||
|
for diag in db.union_data_with_diagnostics(u.id).1.iter() {
|
||||||
|
emit_def_diagnostic(db, acc, diag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Adt::Enum(e) => {
|
||||||
|
for v in e.variants(db) {
|
||||||
|
acc.extend(ModuleDef::Variant(v).diagnostics(db));
|
||||||
|
}
|
||||||
|
|
||||||
|
for diag in db.enum_data_with_diagnostics(e.id).1.iter() {
|
||||||
|
emit_def_diagnostic(db, acc, diag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc.extend(decl.diagnostics(db))
|
||||||
|
}
|
||||||
_ => acc.extend(decl.diagnostics(db)),
|
_ => acc.extend(decl.diagnostics(db)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -874,7 +901,7 @@ impl Struct {
|
||||||
Type::from_def(db, self.id)
|
Type::from_def(db, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
|
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprData> {
|
||||||
db.struct_data(self.id).repr.clone()
|
db.struct_data(self.id).repr.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -952,6 +979,21 @@ impl Enum {
|
||||||
pub fn ty(self, db: &dyn HirDatabase) -> Type {
|
pub fn ty(self, db: &dyn HirDatabase) -> Type {
|
||||||
Type::from_def(db, self.id)
|
Type::from_def(db, self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The type of the enum variant bodies.
|
||||||
|
pub fn variant_body_ty(self, db: &dyn HirDatabase) -> Type {
|
||||||
|
Type::new_for_crate(
|
||||||
|
self.id.lookup(db.upcast()).container.krate(),
|
||||||
|
TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
|
||||||
|
Either::Left(builtin) => hir_def::builtin_type::BuiltinType::Int(builtin),
|
||||||
|
Either::Right(builtin) => hir_def::builtin_type::BuiltinType::Uint(builtin),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
|
||||||
|
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasVisibility for Enum {
|
impl HasVisibility for Enum {
|
||||||
|
@ -960,6 +1002,12 @@ impl HasVisibility for Enum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Variant> for DefWithBodyId {
|
||||||
|
fn from(&v: &Variant) -> Self {
|
||||||
|
DefWithBodyId::VariantId(v.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct Variant {
|
pub struct Variant {
|
||||||
pub(crate) parent: Enum,
|
pub(crate) parent: Enum,
|
||||||
|
@ -994,6 +1042,14 @@ impl Variant {
|
||||||
pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
|
pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
|
||||||
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
|
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
|
||||||
|
self.source(db)?.value.expr()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
|
||||||
|
db.const_eval_variant(self.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Variants inherit visibility from the parent enum.
|
/// Variants inherit visibility from the parent enum.
|
||||||
|
@ -1034,7 +1090,7 @@ impl Adt {
|
||||||
pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
|
pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
|
||||||
let id = AdtId::from(self);
|
let id = AdtId::from(self);
|
||||||
let mut it = args.iter().map(|t| t.ty.clone());
|
let mut it = args.iter().map(|t| t.ty.clone());
|
||||||
let ty = TyBuilder::def_ty(db, id.into())
|
let ty = TyBuilder::def_ty(db, id.into(), None)
|
||||||
.fill(|x| {
|
.fill(|x| {
|
||||||
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
|
let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
|
||||||
match x {
|
match x {
|
||||||
|
@ -1129,8 +1185,9 @@ pub enum DefWithBody {
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Static(Static),
|
Static(Static),
|
||||||
Const(Const),
|
Const(Const),
|
||||||
|
Variant(Variant),
|
||||||
}
|
}
|
||||||
impl_from!(Function, Const, Static for DefWithBody);
|
impl_from!(Function, Const, Static, Variant for DefWithBody);
|
||||||
|
|
||||||
impl DefWithBody {
|
impl DefWithBody {
|
||||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||||
|
@ -1138,6 +1195,7 @@ impl DefWithBody {
|
||||||
DefWithBody::Const(c) => c.module(db),
|
DefWithBody::Const(c) => c.module(db),
|
||||||
DefWithBody::Function(f) => f.module(db),
|
DefWithBody::Function(f) => f.module(db),
|
||||||
DefWithBody::Static(s) => s.module(db),
|
DefWithBody::Static(s) => s.module(db),
|
||||||
|
DefWithBody::Variant(v) => v.module(db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1146,6 +1204,7 @@ impl DefWithBody {
|
||||||
DefWithBody::Function(f) => Some(f.name(db)),
|
DefWithBody::Function(f) => Some(f.name(db)),
|
||||||
DefWithBody::Static(s) => Some(s.name(db)),
|
DefWithBody::Static(s) => Some(s.name(db)),
|
||||||
DefWithBody::Const(c) => c.name(db),
|
DefWithBody::Const(c) => c.name(db),
|
||||||
|
DefWithBody::Variant(v) => Some(v.name(db)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1155,6 +1214,7 @@ impl DefWithBody {
|
||||||
DefWithBody::Function(it) => it.ret_type(db),
|
DefWithBody::Function(it) => it.ret_type(db),
|
||||||
DefWithBody::Static(it) => it.ty(db),
|
DefWithBody::Static(it) => it.ty(db),
|
||||||
DefWithBody::Const(it) => it.ty(db),
|
DefWithBody::Const(it) => it.ty(db),
|
||||||
|
DefWithBody::Variant(it) => it.parent.variant_body_ty(db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,6 +1223,7 @@ impl DefWithBody {
|
||||||
DefWithBody::Function(it) => it.id.into(),
|
DefWithBody::Function(it) => it.id.into(),
|
||||||
DefWithBody::Static(it) => it.id.into(),
|
DefWithBody::Static(it) => it.id.into(),
|
||||||
DefWithBody::Const(it) => it.id.into(),
|
DefWithBody::Const(it) => it.id.into(),
|
||||||
|
DefWithBody::Variant(it) => it.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1222,30 +1283,45 @@ impl DefWithBody {
|
||||||
let infer = db.infer(self.into());
|
let infer = db.infer(self.into());
|
||||||
let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
|
let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
|
||||||
for d in &infer.diagnostics {
|
for d in &infer.diagnostics {
|
||||||
match d {
|
match *d {
|
||||||
hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
|
hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
|
||||||
let field = source_map.field_syntax(*expr);
|
let field = source_map.field_syntax(expr);
|
||||||
acc.push(NoSuchField { field }.into())
|
acc.push(NoSuchField { field }.into())
|
||||||
}
|
}
|
||||||
&hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
|
hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
|
||||||
let expr = source_map
|
let expr = source_map
|
||||||
.expr_syntax(expr)
|
.expr_syntax(expr)
|
||||||
.expect("break outside of loop in synthetic syntax");
|
.expect("break outside of loop in synthetic syntax");
|
||||||
acc.push(BreakOutsideOfLoop { expr, is_break }.into())
|
acc.push(BreakOutsideOfLoop { expr, is_break }.into())
|
||||||
}
|
}
|
||||||
hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
|
hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
|
||||||
match source_map.expr_syntax(*call_expr) {
|
match source_map.expr_syntax(call_expr) {
|
||||||
Ok(source_ptr) => acc.push(
|
Ok(source_ptr) => acc.push(
|
||||||
MismatchedArgCount {
|
MismatchedArgCount {
|
||||||
call_expr: source_ptr,
|
call_expr: source_ptr,
|
||||||
expected: *expected,
|
expected: expected,
|
||||||
found: *found,
|
found: found,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
Err(SyntheticSyntax) => (),
|
Err(SyntheticSyntax) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hir_ty::InferenceDiagnostic::IncorrectTryTarget { expr } => {
|
||||||
|
let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
|
||||||
|
acc.push(IncorrectTryExpr { expr }.into())
|
||||||
|
}
|
||||||
|
hir_ty::InferenceDiagnostic::DoesNotImplement { expr, trait_, ref ty } => {
|
||||||
|
let expr = source_map.expr_syntax(expr).expect("try in synthetic syntax");
|
||||||
|
acc.push(
|
||||||
|
NotImplemented {
|
||||||
|
expr,
|
||||||
|
trait_,
|
||||||
|
ty: Type::new(db, DefWithBodyId::from(self), ty.clone()),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (expr, mismatch) in infer.expr_type_mismatches() {
|
for (expr, mismatch) in infer.expr_type_mismatches() {
|
||||||
|
@ -1379,6 +1455,7 @@ impl DefWithBody {
|
||||||
DefWithBody::Function(it) => it.into(),
|
DefWithBody::Function(it) => it.into(),
|
||||||
DefWithBody::Static(it) => it.into(),
|
DefWithBody::Static(it) => it.into(),
|
||||||
DefWithBody::Const(it) => it.into(),
|
DefWithBody::Const(it) => it.into(),
|
||||||
|
DefWithBody::Variant(it) => it.into(),
|
||||||
};
|
};
|
||||||
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
|
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
|
||||||
acc.push(diag.into())
|
acc.push(diag.into())
|
||||||
|
@ -2485,7 +2562,7 @@ impl TypeParam {
|
||||||
let resolver = self.id.parent().resolver(db.upcast());
|
let resolver = self.id.parent().resolver(db.upcast());
|
||||||
let ty = params.get(local_idx)?.clone();
|
let ty = params.get(local_idx)?.clone();
|
||||||
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
|
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
|
||||||
let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
|
let ty = ty.substitute(Interner, &subst);
|
||||||
match ty.data(Interner) {
|
match ty.data(Interner) {
|
||||||
GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
|
GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -2739,7 +2816,22 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
|
fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
|
||||||
let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
|
let ty_def = def.into();
|
||||||
|
let parent_subst = match ty_def {
|
||||||
|
TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
|
||||||
|
ItemContainerId::TraitId(id) => {
|
||||||
|
let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
|
||||||
|
Some(subst)
|
||||||
|
}
|
||||||
|
ItemContainerId::ImplId(id) => {
|
||||||
|
let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
|
||||||
|
Some(subst)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
|
||||||
Type::new(db, def, ty)
|
Type::new(db, def, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2879,7 +2971,11 @@ impl Type {
|
||||||
alias: TypeAlias,
|
alias: TypeAlias,
|
||||||
) -> Option<Type> {
|
) -> Option<Type> {
|
||||||
let mut args = args.iter();
|
let mut args = args.iter();
|
||||||
let projection = TyBuilder::assoc_type_projection(db, alias.id)
|
let trait_id = match alias.id.lookup(db.upcast()).container {
|
||||||
|
ItemContainerId::TraitId(id) => id,
|
||||||
|
_ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
|
||||||
|
};
|
||||||
|
let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
|
||||||
.push(self.ty.clone())
|
.push(self.ty.clone())
|
||||||
.fill(|x| {
|
.fill(|x| {
|
||||||
// FIXME: this code is not covered in tests.
|
// FIXME: this code is not covered in tests.
|
||||||
|
@ -2891,6 +2987,8 @@ impl Type {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
// FIXME: We don't handle GATs yet.
|
||||||
|
let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
|
||||||
|
|
||||||
let ty = db.normalize_projection(projection, self.env.clone());
|
let ty = db.normalize_projection(projection, self.env.clone());
|
||||||
if ty.is_unknown() {
|
if ty.is_unknown() {
|
||||||
|
@ -2940,7 +3038,7 @@ impl Type {
|
||||||
|
|
||||||
let adt = adt_id.into();
|
let adt = adt_id.into();
|
||||||
match adt {
|
match adt {
|
||||||
Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
|
Adt::Struct(s) => matches!(s.repr(db), Some(ReprData { packed: true, .. })),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,6 +257,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
|
pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
|
||||||
self.imp.original_ast_node(node)
|
self.imp.original_ast_node(node)
|
||||||
}
|
}
|
||||||
|
/// Attempts to map the node out of macro expanded files.
|
||||||
|
/// This only work for attribute expansions, as other ones do not have nodes as input.
|
||||||
|
pub fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
|
||||||
|
self.imp.original_syntax_node(node)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
|
pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
|
||||||
self.imp.diagnostics_display_range(diagnostics)
|
self.imp.diagnostics_display_range(diagnostics)
|
||||||
|
@ -956,6 +961,16 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn original_syntax_node(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
|
||||||
|
let InFile { file_id, .. } = self.find_file(node);
|
||||||
|
InFile::new(file_id, node).original_syntax_node(self.db.upcast()).map(
|
||||||
|
|InFile { file_id, value }| {
|
||||||
|
self.cache(find_root(&value), file_id);
|
||||||
|
value
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
|
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
|
||||||
let root = self.parse_or_expand(src.file_id).unwrap();
|
let root = self.parse_or_expand(src.file_id).unwrap();
|
||||||
let node = src.map(|it| it.to_node(&root));
|
let node = src.map(|it| it.to_node(&root));
|
||||||
|
|
|
@ -115,7 +115,7 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceToDefCtx<'_, '_> {
|
impl SourceToDefCtx<'_, '_> {
|
||||||
pub(super) fn file_to_def(&mut self, file: FileId) -> SmallVec<[ModuleId; 1]> {
|
pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
|
||||||
let _p = profile::span("SourceBinder::to_module_def");
|
let _p = profile::span("SourceBinder::to_module_def");
|
||||||
let mut mods = SmallVec::new();
|
let mut mods = SmallVec::new();
|
||||||
for &crate_id in self.db.relevant_crates(file).iter() {
|
for &crate_id in self.db.relevant_crates(file).iter() {
|
||||||
|
@ -130,7 +130,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
mods
|
mods
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
|
pub(super) fn module_to_def(&self, src: InFile<ast::Module>) -> Option<ModuleId> {
|
||||||
let _p = profile::span("module_to_def");
|
let _p = profile::span("module_to_def");
|
||||||
let parent_declaration = src
|
let parent_declaration = src
|
||||||
.syntax()
|
.syntax()
|
||||||
|
@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
Some(def_map.module_id(child_id))
|
Some(def_map.module_id(child_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn source_file_to_def(&mut self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
|
pub(super) fn source_file_to_def(&self, src: InFile<ast::SourceFile>) -> Option<ModuleId> {
|
||||||
let _p = profile::span("source_file_to_def");
|
let _p = profile::span("source_file_to_def");
|
||||||
let file_id = src.file_id.original_file(self.db.upcast());
|
let file_id = src.file_id.original_file(self.db.upcast());
|
||||||
self.file_to_def(file_id).get(0).copied()
|
self.file_to_def(file_id).get(0).copied()
|
||||||
|
@ -384,7 +384,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||||
} else {
|
} else {
|
||||||
let it = ast::Variant::cast(container.value)?;
|
let it = ast::Variant::cast(container.value)?;
|
||||||
let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
|
let def = self.enum_variant_to_def(InFile::new(container.file_id, it))?;
|
||||||
VariantId::from(def).into()
|
DefWithBodyId::from(def).into()
|
||||||
};
|
};
|
||||||
Some(cont)
|
Some(cont)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use hir_def::{
|
||||||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||||
type_ref::Mutability,
|
type_ref::Mutability,
|
||||||
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
|
AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
|
||||||
Lookup, ModuleDefId, VariantId,
|
Lookup, ModuleDefId, TraitId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
builtin_fn_macro::BuiltinFnLikeExpander,
|
builtin_fn_macro::BuiltinFnLikeExpander,
|
||||||
|
@ -302,10 +302,15 @@ impl SourceAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let future_trait = db
|
||||||
|
.lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
|
||||||
|
.as_trait()?;
|
||||||
let poll_fn = db
|
let poll_fn = db
|
||||||
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
|
.lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
|
||||||
.as_function()?;
|
.as_function()?;
|
||||||
let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
|
// HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
|
||||||
|
// doesn't have any generic parameters, so we skip building another subst for `poll()`.
|
||||||
|
let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
|
||||||
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
|
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,8 +326,10 @@ impl SourceAnalyzer {
|
||||||
};
|
};
|
||||||
let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
|
let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
|
||||||
|
|
||||||
let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||||
|
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||||
|
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||||
|
|
||||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||||
}
|
}
|
||||||
|
@ -337,8 +344,10 @@ impl SourceAnalyzer {
|
||||||
|
|
||||||
let lang_item_name = name![index];
|
let lang_item_name = name![index];
|
||||||
|
|
||||||
let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
|
||||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
|
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||||
|
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||||
|
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
|
||||||
.push(base_ty.clone())
|
.push(base_ty.clone())
|
||||||
.push(index_ty.clone())
|
.push(index_ty.clone())
|
||||||
.build();
|
.build();
|
||||||
|
@ -354,10 +363,14 @@ impl SourceAnalyzer {
|
||||||
let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
|
let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
|
||||||
let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
|
let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
|
||||||
|
|
||||||
let op_fn = lang_names_for_bin_op(op)
|
let (op_trait, op_fn) = lang_names_for_bin_op(op)
|
||||||
.and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
|
.and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
|
||||||
let substs =
|
// HACK: subst for `index()` coincides with that for `Index` because `index()` itself
|
||||||
hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
|
// doesn't have any generic parameters, so we skip building another subst for `index()`.
|
||||||
|
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
|
||||||
|
.push(lhs.clone())
|
||||||
|
.push(rhs.clone())
|
||||||
|
.build();
|
||||||
|
|
||||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||||
}
|
}
|
||||||
|
@ -371,7 +384,13 @@ impl SourceAnalyzer {
|
||||||
|
|
||||||
let op_fn =
|
let op_fn =
|
||||||
db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
|
db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
|
||||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
|
let op_trait = match op_fn.lookup(db.upcast()).container {
|
||||||
|
ItemContainerId::TraitId(id) => id,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
// HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
|
||||||
|
// doesn't have any generic parameters, so we skip building another subst for `branch()`.
|
||||||
|
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||||
|
|
||||||
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
|
||||||
}
|
}
|
||||||
|
@ -799,9 +818,10 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
lang_trait: &Name,
|
lang_trait: &Name,
|
||||||
method_name: &Name,
|
method_name: &Name,
|
||||||
) -> Option<FunctionId> {
|
) -> Option<(TraitId, FunctionId)> {
|
||||||
db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
|
let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
|
||||||
.method_by_name(method_name)
|
let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
|
||||||
|
Some((trait_id, fn_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
|
fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
|
||||||
|
|
|
@ -244,6 +244,10 @@ impl<'a> SymbolCollector<'a> {
|
||||||
DefWithBodyId::ConstId(id) => Some(
|
DefWithBodyId::ConstId(id) => Some(
|
||||||
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
|
id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
|
||||||
),
|
),
|
||||||
|
DefWithBodyId::VariantId(id) => Some({
|
||||||
|
let db = self.db.upcast();
|
||||||
|
id.parent.lookup(db).source(db).value.name()?.text().into()
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ doctest = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cov-mark = "2.0.0-pre.1"
|
cov-mark = "2.0.0-pre.1"
|
||||||
|
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
either = "1.7.0"
|
either = "1.7.0"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
|
|
|
@ -156,6 +156,8 @@ pub(super) fn find_importable_node(
|
||||||
{
|
{
|
||||||
ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
|
ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
|
||||||
.zip(Some(method_under_caret.syntax().clone().into()))
|
.zip(Some(method_under_caret.syntax().clone().into()))
|
||||||
|
} else if let Some(_) = ctx.find_node_at_offset_with_descend::<ast::Param>() {
|
||||||
|
None
|
||||||
} else if let Some(pat) = ctx
|
} else if let Some(pat) = ctx
|
||||||
.find_node_at_offset_with_descend::<ast::IdentPat>()
|
.find_node_at_offset_with_descend::<ast::IdentPat>()
|
||||||
.filter(ast::IdentPat::is_simple_ident)
|
.filter(ast::IdentPat::is_simple_ident)
|
||||||
|
@ -268,6 +270,20 @@ mod tests {
|
||||||
assert_eq!(labels, order);
|
assert_eq!(labels, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ignore_parameter_name() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
auto_import,
|
||||||
|
r"
|
||||||
|
mod foo {
|
||||||
|
pub mod bar {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(bar$0: &str) {}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prefer_shorter_paths() {
|
fn prefer_shorter_paths() {
|
||||||
let before = r"
|
let before = r"
|
||||||
|
|
|
@ -0,0 +1,822 @@
|
||||||
|
use either::Either;
|
||||||
|
use ide_db::defs::Definition;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use syntax::{
|
||||||
|
ast::{self, AstNode, HasGenericParams, HasVisibility},
|
||||||
|
match_ast, SyntaxKind, SyntaxNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
|
||||||
|
|
||||||
|
// Assist: convert_named_struct_to_tuple_struct
|
||||||
|
//
|
||||||
|
// Converts struct with named fields to tuple struct, and analogously for enum variants with named
|
||||||
|
// fields.
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// struct Point$0 { x: f32, y: f32 }
|
||||||
|
//
|
||||||
|
// impl Point {
|
||||||
|
// pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
// Point { x, y }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn x(&self) -> f32 {
|
||||||
|
// self.x
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn y(&self) -> f32 {
|
||||||
|
// self.y
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// ->
|
||||||
|
// ```
|
||||||
|
// struct Point(f32, f32);
|
||||||
|
//
|
||||||
|
// impl Point {
|
||||||
|
// pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
// Point(x, y)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn x(&self) -> f32 {
|
||||||
|
// self.0
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pub fn y(&self) -> f32 {
|
||||||
|
// self.1
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
pub(crate) fn convert_named_struct_to_tuple_struct(
|
||||||
|
acc: &mut Assists,
|
||||||
|
ctx: &AssistContext<'_>,
|
||||||
|
) -> Option<()> {
|
||||||
|
let strukt = ctx
|
||||||
|
.find_node_at_offset::<ast::Struct>()
|
||||||
|
.map(Either::Left)
|
||||||
|
.or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
|
||||||
|
let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
|
||||||
|
let record_fields = match field_list {
|
||||||
|
ast::FieldList::RecordFieldList(it) => it,
|
||||||
|
ast::FieldList::TupleFieldList(_) => return None,
|
||||||
|
};
|
||||||
|
let strukt_def = match &strukt {
|
||||||
|
Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
|
||||||
|
Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
|
||||||
|
};
|
||||||
|
let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
|
||||||
|
|
||||||
|
acc.add(
|
||||||
|
AssistId("convert_named_struct_to_tuple_struct", AssistKind::RefactorRewrite),
|
||||||
|
"Convert to tuple struct",
|
||||||
|
target,
|
||||||
|
|edit| {
|
||||||
|
edit_field_references(ctx, edit, record_fields.fields());
|
||||||
|
edit_struct_references(ctx, edit, strukt_def);
|
||||||
|
edit_struct_def(ctx, edit, &strukt, record_fields);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit_struct_def(
|
||||||
|
ctx: &AssistContext<'_>,
|
||||||
|
edit: &mut SourceChangeBuilder,
|
||||||
|
strukt: &Either<ast::Struct, ast::Variant>,
|
||||||
|
record_fields: ast::RecordFieldList,
|
||||||
|
) {
|
||||||
|
let tuple_fields = record_fields
|
||||||
|
.fields()
|
||||||
|
.filter_map(|f| Some(ast::make::tuple_field(f.visibility(), f.ty()?)));
|
||||||
|
let tuple_fields = ast::make::tuple_field_list(tuple_fields);
|
||||||
|
let record_fields_text_range = record_fields.syntax().text_range();
|
||||||
|
|
||||||
|
edit.edit_file(ctx.file_id());
|
||||||
|
edit.replace(record_fields_text_range, tuple_fields.syntax().text());
|
||||||
|
|
||||||
|
if let Either::Left(strukt) = strukt {
|
||||||
|
if let Some(w) = strukt.where_clause() {
|
||||||
|
let mut where_clause = w.to_string();
|
||||||
|
if where_clause.ends_with(',') {
|
||||||
|
where_clause.pop();
|
||||||
|
}
|
||||||
|
where_clause.push(';');
|
||||||
|
|
||||||
|
edit.delete(w.syntax().text_range());
|
||||||
|
edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
|
||||||
|
edit.insert(record_fields_text_range.end(), where_clause);
|
||||||
|
edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
|
||||||
|
|
||||||
|
if let Some(tok) = strukt
|
||||||
|
.generic_param_list()
|
||||||
|
.and_then(|l| l.r_angle_token())
|
||||||
|
.and_then(|tok| tok.next_token())
|
||||||
|
.filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
|
||||||
|
{
|
||||||
|
edit.delete(tok.text_range());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
edit.insert(record_fields_text_range.end(), ";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(tok) = record_fields
|
||||||
|
.l_curly_token()
|
||||||
|
.and_then(|tok| tok.prev_token())
|
||||||
|
.filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
|
||||||
|
{
|
||||||
|
edit.delete(tok.text_range())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit_struct_references(
|
||||||
|
ctx: &AssistContext<'_>,
|
||||||
|
edit: &mut SourceChangeBuilder,
|
||||||
|
strukt: Either<hir::Struct, hir::Variant>,
|
||||||
|
) {
|
||||||
|
let strukt_def = match strukt {
|
||||||
|
Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)),
|
||||||
|
Either::Right(v) => Definition::Variant(v),
|
||||||
|
};
|
||||||
|
let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
|
||||||
|
|
||||||
|
let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> {
|
||||||
|
match_ast! {
|
||||||
|
match node {
|
||||||
|
ast::RecordPat(record_struct_pat) => {
|
||||||
|
edit.replace(
|
||||||
|
record_struct_pat.syntax().text_range(),
|
||||||
|
ast::make::tuple_struct_pat(
|
||||||
|
record_struct_pat.path()?,
|
||||||
|
record_struct_pat
|
||||||
|
.record_pat_field_list()?
|
||||||
|
.fields()
|
||||||
|
.filter_map(|pat| pat.pat())
|
||||||
|
)
|
||||||
|
.to_string()
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ast::RecordExpr(record_expr) => {
|
||||||
|
let path = record_expr.path()?;
|
||||||
|
let args = record_expr
|
||||||
|
.record_expr_field_list()?
|
||||||
|
.fields()
|
||||||
|
.filter_map(|f| f.expr())
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
edit.replace(record_expr.syntax().text_range(), format!("{path}({args})"));
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(())
|
||||||
|
};
|
||||||
|
|
||||||
|
for (file_id, refs) in usages {
|
||||||
|
edit.edit_file(file_id);
|
||||||
|
for r in refs {
|
||||||
|
for node in r.name.syntax().ancestors() {
|
||||||
|
if edit_node(edit, node).is_some() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit_field_references(
|
||||||
|
ctx: &AssistContext<'_>,
|
||||||
|
edit: &mut SourceChangeBuilder,
|
||||||
|
fields: impl Iterator<Item = ast::RecordField>,
|
||||||
|
) {
|
||||||
|
for (index, field) in fields.enumerate() {
|
||||||
|
let field = match ctx.sema.to_def(&field) {
|
||||||
|
Some(it) => it,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let def = Definition::Field(field);
|
||||||
|
let usages = def.usages(&ctx.sema).all();
|
||||||
|
for (file_id, refs) in usages {
|
||||||
|
edit.edit_file(file_id);
|
||||||
|
for r in refs {
|
||||||
|
if let Some(name_ref) = r.name.as_name_ref() {
|
||||||
|
// Only edit the field reference if it's part of a `.field` access
|
||||||
|
if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() {
|
||||||
|
edit.replace(name_ref.syntax().text_range(), index.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_applicable_other_than_record_struct() {
|
||||||
|
check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0(u32)"#);
|
||||||
|
check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0;"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_simple_struct() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct Inner;
|
||||||
|
struct A$0 { inner: Inner }
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(inner: Inner) -> A {
|
||||||
|
A { inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> A {
|
||||||
|
A::new(Inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> Inner {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct Inner;
|
||||||
|
struct A(Inner);
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(inner: Inner) -> A {
|
||||||
|
A(inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> A {
|
||||||
|
A::new(Inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> Inner {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_struct_referenced_via_self_kw() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct Inner;
|
||||||
|
struct A$0 { inner: Inner }
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(inner: Inner) -> Self {
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> Self {
|
||||||
|
Self::new(Inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> Inner {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct Inner;
|
||||||
|
struct A(Inner);
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(inner: Inner) -> Self {
|
||||||
|
Self(inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> Self {
|
||||||
|
Self::new(Inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> Inner {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_destructured_struct() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct Inner;
|
||||||
|
struct A$0 { inner: Inner }
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn into_inner(self) -> Inner {
|
||||||
|
let A { inner: a } = self;
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_via_self(self) -> Inner {
|
||||||
|
let Self { inner } = self;
|
||||||
|
inner
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct Inner;
|
||||||
|
struct A(Inner);
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn into_inner(self) -> Inner {
|
||||||
|
let A(a) = self;
|
||||||
|
a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_via_self(self) -> Inner {
|
||||||
|
let Self(inner) = self;
|
||||||
|
inner
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_struct_with_visibility() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct A$0 {
|
||||||
|
pub first: u32,
|
||||||
|
pub(crate) second: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new() -> A {
|
||||||
|
A { first: 42, second: 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_first(self) -> u32 {
|
||||||
|
self.first
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_second(self) -> u64 {
|
||||||
|
self.second
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct A(pub u32, pub(crate) u64);
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new() -> A {
|
||||||
|
A(42, 42)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_first(self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_second(self) -> u64 {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_struct_with_wrapped_references() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct Inner$0 { uint: u32 }
|
||||||
|
struct Outer { inner: Inner }
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { inner: Inner { uint: 42 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> u32 {
|
||||||
|
self.inner.uint
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer { inner: Inner { uint: x } } = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct Inner(u32);
|
||||||
|
struct Outer { inner: Inner }
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { inner: Inner(42) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> u32 {
|
||||||
|
self.inner.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer { inner: Inner(x) } = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct Inner { uint: u32 }
|
||||||
|
struct Outer$0 { inner: Inner }
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { inner: Inner { uint: 42 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> u32 {
|
||||||
|
self.inner.uint
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer { inner: Inner { uint: x } } = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
struct Inner { uint: u32 }
|
||||||
|
struct Outer(Inner);
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(Inner { uint: 42 })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> u32 {
|
||||||
|
self.0.uint
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer(Inner { uint: x }) = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_struct_with_multi_file_references() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Inner;
|
||||||
|
struct A$0 { inner: Inner }
|
||||||
|
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
use crate::{A, Inner};
|
||||||
|
fn f() {
|
||||||
|
let a = A { inner: Inner };
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Inner;
|
||||||
|
struct A(Inner);
|
||||||
|
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
use crate::{A, Inner};
|
||||||
|
fn f() {
|
||||||
|
let a = A(Inner);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_struct_with_where_clause() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
struct Wrap$0<T>
|
||||||
|
where
|
||||||
|
T: Display,
|
||||||
|
{ field1: T }
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
struct Wrap<T>(T)
|
||||||
|
where
|
||||||
|
T: Display;
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn not_applicable_other_than_record_variant() {
|
||||||
|
check_assist_not_applicable(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"enum Enum { Variant$0(usize) };"#,
|
||||||
|
);
|
||||||
|
check_assist_not_applicable(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"enum Enum { Variant$0 }"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_simple_variant() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
enum A {
|
||||||
|
$0Variant { field1: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(value: usize) -> A {
|
||||||
|
A::Variant { field1: value }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> A {
|
||||||
|
A::new(Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(self) -> usize {
|
||||||
|
match self {
|
||||||
|
A::Variant { field1: value } => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
enum A {
|
||||||
|
Variant(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(value: usize) -> A {
|
||||||
|
A::Variant(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> A {
|
||||||
|
A::new(Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(self) -> usize {
|
||||||
|
match self {
|
||||||
|
A::Variant(value) => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_variant_referenced_via_self_kw() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
enum A {
|
||||||
|
$0Variant { field1: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(value: usize) -> A {
|
||||||
|
Self::Variant { field1: value }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> A {
|
||||||
|
Self::new(Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Variant { field1: value } => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
enum A {
|
||||||
|
Variant(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn new(value: usize) -> A {
|
||||||
|
Self::Variant(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_default() -> A {
|
||||||
|
Self::new(Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Variant(value) => value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_destructured_variant() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
enum A {
|
||||||
|
$0Variant { field1: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn into_inner(self) -> usize {
|
||||||
|
let A::Variant { field1: first } = self;
|
||||||
|
first
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_via_self(self) -> usize {
|
||||||
|
let Self::Variant { field1: first } = self;
|
||||||
|
first
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
enum A {
|
||||||
|
Variant(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn into_inner(self) -> usize {
|
||||||
|
let A::Variant(first) = self;
|
||||||
|
first
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_via_self(self) -> usize {
|
||||||
|
let Self::Variant(first) = self;
|
||||||
|
first
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_variant_with_wrapped_references() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
enum Inner {
|
||||||
|
$0Variant { field1: usize },
|
||||||
|
}
|
||||||
|
enum Outer {
|
||||||
|
Variant(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::Variant(Inner::Variant { field1: 42 })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer::Variant(Inner::Variant { field1: x }) = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
enum Inner {
|
||||||
|
Variant(usize),
|
||||||
|
}
|
||||||
|
enum Outer {
|
||||||
|
Variant(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::Variant(Inner::Variant(42))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer::Variant(Inner::Variant(x)) = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
enum Inner {
|
||||||
|
Variant(usize),
|
||||||
|
}
|
||||||
|
enum Outer {
|
||||||
|
$0Variant { field1: Inner },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::Variant { field1: Inner::Variant(42) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer::Variant { field1: Inner::Variant(x) } = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
r#"
|
||||||
|
enum Inner {
|
||||||
|
Variant(usize),
|
||||||
|
}
|
||||||
|
enum Outer {
|
||||||
|
Variant(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Outer {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::Variant(Inner::Variant(42))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner_destructed(self) -> u32 {
|
||||||
|
let Outer::Variant(Inner::Variant(x)) = self;
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_variant_with_multi_file_references() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Inner;
|
||||||
|
enum A {
|
||||||
|
$0Variant { field1: Inner },
|
||||||
|
}
|
||||||
|
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
use crate::{A, Inner};
|
||||||
|
fn f() {
|
||||||
|
let a = A::Variant { field1: Inner };
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Inner;
|
||||||
|
enum A {
|
||||||
|
Variant(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
use crate::{A, Inner};
|
||||||
|
fn f() {
|
||||||
|
let a = A::Variant(Inner);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn convert_directly_used_variant() {
|
||||||
|
check_assist(
|
||||||
|
convert_named_struct_to_tuple_struct,
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Inner;
|
||||||
|
enum A {
|
||||||
|
$0Variant { field1: Inner },
|
||||||
|
}
|
||||||
|
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
use crate::{A::Variant, Inner};
|
||||||
|
fn f() {
|
||||||
|
let a = Variant { field1: Inner };
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct Inner;
|
||||||
|
enum A {
|
||||||
|
Variant(Inner),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod foo;
|
||||||
|
|
||||||
|
//- /foo.rs
|
||||||
|
use crate::{A::Variant, Inner};
|
||||||
|
fn f() {
|
||||||
|
let a = Variant(Inner);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ use ide_db::{
|
||||||
search::FileReference,
|
search::FileReference,
|
||||||
FxHashSet, RootDatabase,
|
FxHashSet, RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::{Itertools, Position};
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
|
self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
|
||||||
|
@ -298,37 +298,7 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
|
||||||
let name = variant.name()?;
|
let name = variant.name()?;
|
||||||
let ty = generics
|
let ty = generics
|
||||||
.filter(|generics| generics.generic_params().count() > 0)
|
.filter(|generics| generics.generic_params().count() > 0)
|
||||||
.map(|generics| {
|
.map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args())))
|
||||||
let mut generic_str = String::with_capacity(8);
|
|
||||||
|
|
||||||
for (p, more) in generics.generic_params().with_position().map(|p| match p {
|
|
||||||
Position::First(p) | Position::Middle(p) => (p, true),
|
|
||||||
Position::Last(p) | Position::Only(p) => (p, false),
|
|
||||||
}) {
|
|
||||||
match p {
|
|
||||||
ast::GenericParam::ConstParam(konst) => {
|
|
||||||
if let Some(name) = konst.name() {
|
|
||||||
generic_str.push_str(name.text().as_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::GenericParam::LifetimeParam(lt) => {
|
|
||||||
if let Some(lt) = lt.lifetime() {
|
|
||||||
generic_str.push_str(lt.text().as_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::GenericParam::TypeParam(ty) => {
|
|
||||||
if let Some(name) = ty.name() {
|
|
||||||
generic_str.push_str(name.text().as_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if more {
|
|
||||||
generic_str.push_str(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
make::ty(&format!("{}<{}>", &name.text(), &generic_str))
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| make::ty(&name.text()));
|
.unwrap_or_else(|| make::ty(&name.text()));
|
||||||
|
|
||||||
// change from a record to a tuple field list
|
// change from a record to a tuple field list
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use hir::{HasSource, HirDisplay, Module, Semantics, TypeInfo};
|
use hir::{Adt, HasSource, HirDisplay, Module, Semantics, TypeInfo};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::FileId,
|
base_db::FileId,
|
||||||
defs::{Definition, NameRefClass},
|
defs::{Definition, NameRefClass},
|
||||||
|
@ -145,7 +145,8 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
|
let (impl_, file) = get_adt_source(ctx, &adt, fn_name.text().as_str())?;
|
||||||
let (target, insert_offset) = get_method_target(ctx, &target_module, &impl_)?;
|
let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
|
||||||
|
|
||||||
let function_builder =
|
let function_builder =
|
||||||
FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
|
FunctionBuilder::from_method_call(ctx, &call, &fn_name, target_module, target)?;
|
||||||
let text_range = call.syntax().text_range();
|
let text_range = call.syntax().text_range();
|
||||||
|
@ -174,10 +175,11 @@ fn add_func_to_accumulator(
|
||||||
label: String,
|
label: String,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
|
acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |builder| {
|
||||||
let function_template = function_builder.render();
|
let indent = IndentLevel::from_node(function_builder.target.syntax());
|
||||||
|
let function_template = function_builder.render(adt_name.is_some());
|
||||||
let mut func = function_template.to_string(ctx.config.snippet_cap);
|
let mut func = function_template.to_string(ctx.config.snippet_cap);
|
||||||
if let Some(name) = adt_name {
|
if let Some(name) = adt_name {
|
||||||
func = format!("\nimpl {} {{\n{}\n}}", name, func);
|
func = format!("\n{}impl {} {{\n{}\n{}}}", indent, name, func, indent);
|
||||||
}
|
}
|
||||||
builder.edit_file(file);
|
builder.edit_file(file);
|
||||||
match ctx.config.snippet_cap {
|
match ctx.config.snippet_cap {
|
||||||
|
@ -307,7 +309,7 @@ impl FunctionBuilder {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(self) -> FunctionTemplate {
|
fn render(self, is_method: bool) -> FunctionTemplate {
|
||||||
let placeholder_expr = make::ext::expr_todo();
|
let placeholder_expr = make::ext::expr_todo();
|
||||||
let fn_body = make::block_expr(vec![], Some(placeholder_expr));
|
let fn_body = make::block_expr(vec![], Some(placeholder_expr));
|
||||||
let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
|
let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
|
||||||
|
@ -325,8 +327,14 @@ impl FunctionBuilder {
|
||||||
|
|
||||||
match self.target {
|
match self.target {
|
||||||
GeneratedFunctionTarget::BehindItem(it) => {
|
GeneratedFunctionTarget::BehindItem(it) => {
|
||||||
let indent = IndentLevel::from_node(&it);
|
let mut indent = IndentLevel::from_node(&it);
|
||||||
leading_ws = format!("\n\n{}", indent);
|
if is_method {
|
||||||
|
indent = indent + 1;
|
||||||
|
leading_ws = format!("{}", indent);
|
||||||
|
} else {
|
||||||
|
leading_ws = format!("\n\n{}", indent);
|
||||||
|
}
|
||||||
|
|
||||||
fn_def = fn_def.indent(indent);
|
fn_def = fn_def.indent(indent);
|
||||||
trailing_ws = String::new();
|
trailing_ws = String::new();
|
||||||
}
|
}
|
||||||
|
@ -411,14 +419,13 @@ fn get_fn_target(
|
||||||
|
|
||||||
fn get_method_target(
|
fn get_method_target(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
target_module: &Module,
|
|
||||||
impl_: &Option<ast::Impl>,
|
impl_: &Option<ast::Impl>,
|
||||||
|
adt: &Adt,
|
||||||
) -> Option<(GeneratedFunctionTarget, TextSize)> {
|
) -> Option<(GeneratedFunctionTarget, TextSize)> {
|
||||||
let target = match impl_ {
|
let target = match impl_ {
|
||||||
Some(impl_) => next_space_for_fn_in_impl(impl_)?,
|
Some(impl_) => next_space_for_fn_in_impl(impl_)?,
|
||||||
None => {
|
None => {
|
||||||
next_space_for_fn_in_module(ctx.sema.db, &target_module.definition_source(ctx.sema.db))?
|
GeneratedFunctionTarget::BehindItem(adt.source(ctx.sema.db)?.syntax().value.clone())
|
||||||
.1
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some((target.clone(), get_insert_offset(&target)))
|
Some((target.clone(), get_insert_offset(&target)))
|
||||||
|
@ -437,7 +444,7 @@ fn assoc_fn_target_info(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
|
let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
|
||||||
let (target, insert_offset) = get_method_target(ctx, &module, &impl_)?;
|
let (target, insert_offset) = get_method_target(ctx, &impl_, &adt)?;
|
||||||
let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
|
let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
|
||||||
Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset))
|
Some(TargetInfo::new(target_module, adt_name, target, file, insert_offset))
|
||||||
}
|
}
|
||||||
|
@ -1468,14 +1475,12 @@ fn foo() {S.bar$0();}
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
struct S;
|
struct S;
|
||||||
fn foo() {S.bar();}
|
|
||||||
impl S {
|
impl S {
|
||||||
|
fn bar(&self) ${0:-> _} {
|
||||||
|
todo!()
|
||||||
fn bar(&self) ${0:-> _} {
|
}
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn foo() {S.bar();}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1516,14 +1521,12 @@ fn foo() {s::S.bar$0();}
|
||||||
r"
|
r"
|
||||||
mod s {
|
mod s {
|
||||||
pub struct S;
|
pub struct S;
|
||||||
impl S {
|
impl S {
|
||||||
|
pub(crate) fn bar(&self) ${0:-> _} {
|
||||||
|
todo!()
|
||||||
pub(crate) fn bar(&self) ${0:-> _} {
|
}
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fn foo() {s::S.bar();}
|
fn foo() {s::S.bar();}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
|
@ -1544,18 +1547,16 @@ mod s {
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
struct S;
|
struct S;
|
||||||
|
impl S {
|
||||||
|
fn bar(&self) ${0:-> _} {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
mod s {
|
mod s {
|
||||||
fn foo() {
|
fn foo() {
|
||||||
super::S.bar();
|
super::S.bar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl S {
|
|
||||||
|
|
||||||
|
|
||||||
fn bar(&self) ${0:-> _} {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
|
@ -1571,14 +1572,12 @@ fn foo() {$0S.bar();}
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
struct S;
|
struct S;
|
||||||
fn foo() {S.bar();}
|
|
||||||
impl S {
|
impl S {
|
||||||
|
fn bar(&self) ${0:-> _} {
|
||||||
|
todo!()
|
||||||
fn bar(&self) ${0:-> _} {
|
}
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn foo() {S.bar();}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1593,14 +1592,12 @@ fn foo() {S::bar$0();}
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
struct S;
|
struct S;
|
||||||
fn foo() {S::bar();}
|
|
||||||
impl S {
|
impl S {
|
||||||
|
fn bar() ${0:-> _} {
|
||||||
|
todo!()
|
||||||
fn bar() ${0:-> _} {
|
}
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn foo() {S::bar();}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1641,14 +1638,12 @@ fn foo() {s::S::bar$0();}
|
||||||
r"
|
r"
|
||||||
mod s {
|
mod s {
|
||||||
pub struct S;
|
pub struct S;
|
||||||
impl S {
|
impl S {
|
||||||
|
pub(crate) fn bar() ${0:-> _} {
|
||||||
|
todo!()
|
||||||
pub(crate) fn bar() ${0:-> _} {
|
}
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fn foo() {s::S::bar();}
|
fn foo() {s::S::bar();}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
|
@ -1664,14 +1659,12 @@ fn foo() {$0S::bar();}
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
struct S;
|
struct S;
|
||||||
fn foo() {S::bar();}
|
|
||||||
impl S {
|
impl S {
|
||||||
|
fn bar() ${0:-> _} {
|
||||||
|
todo!()
|
||||||
fn bar() ${0:-> _} {
|
}
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn foo() {S::bar();}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1841,16 +1834,14 @@ fn main() {
|
||||||
",
|
",
|
||||||
r"
|
r"
|
||||||
enum Foo {}
|
enum Foo {}
|
||||||
|
impl Foo {
|
||||||
|
fn new() ${0:-> _} {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
Foo::new();
|
Foo::new();
|
||||||
}
|
}
|
||||||
impl Foo {
|
|
||||||
|
|
||||||
|
|
||||||
fn new() ${0:-> _} {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// FIXME: break up into separate test fns
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_impl() {
|
fn test_add_impl() {
|
||||||
check_assist(
|
check_assist(
|
||||||
|
@ -134,6 +135,18 @@ mod tests {
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
check_assist(
|
||||||
|
generate_impl,
|
||||||
|
r#"
|
||||||
|
struct Defaulted<const N: i32 = 0> {}$0"#,
|
||||||
|
r#"
|
||||||
|
struct Defaulted<const N: i32 = 0> {}
|
||||||
|
|
||||||
|
impl<const N: i32> Defaulted<N> {
|
||||||
|
$0
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
check_assist(
|
check_assist(
|
||||||
generate_impl,
|
generate_impl,
|
||||||
r#"pub trait Trait {}
|
r#"pub trait Trait {}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use ide_db::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use stdx::format_to;
|
||||||
use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
|
use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
|
||||||
|
|
||||||
// Assist: move_format_string_arg
|
// Assist: move_format_string_arg
|
||||||
|
@ -78,20 +79,26 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
|
|
||||||
// Extract existing arguments in macro
|
// Extract existing arguments in macro
|
||||||
let tokens =
|
let tokens =
|
||||||
tt.token_trees_and_tokens().filter_map(NodeOrToken::into_token).collect_vec();
|
tt.token_trees_and_tokens().collect_vec();
|
||||||
|
|
||||||
let mut existing_args: Vec<String> = vec![];
|
let mut existing_args: Vec<String> = vec![];
|
||||||
|
|
||||||
let mut current_arg = String::new();
|
let mut current_arg = String::new();
|
||||||
if let [_opening_bracket, format_string, _args_start_comma, tokens @ .., end_bracket] =
|
if let [_opening_bracket, NodeOrToken::Token(format_string), _args_start_comma, tokens @ .., NodeOrToken::Token(end_bracket)] =
|
||||||
tokens.as_slice()
|
tokens.as_slice()
|
||||||
{
|
{
|
||||||
for t in tokens {
|
for t in tokens {
|
||||||
if t.kind() == COMMA {
|
match t {
|
||||||
existing_args.push(current_arg.trim().into());
|
NodeOrToken::Node(n) => {
|
||||||
current_arg.clear();
|
format_to!(current_arg, "{n}");
|
||||||
} else {
|
},
|
||||||
current_arg.push_str(t.text());
|
NodeOrToken::Token(t) if t.kind() == COMMA=> {
|
||||||
|
existing_args.push(current_arg.trim().into());
|
||||||
|
current_arg.clear();
|
||||||
|
},
|
||||||
|
NodeOrToken::Token(t) => {
|
||||||
|
current_arg.push_str(t.text());
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
existing_args.push(current_arg.trim().into());
|
existing_args.push(current_arg.trim().into());
|
||||||
|
@ -261,6 +268,27 @@ fn main() {
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_tt() {
|
||||||
|
check_assist(
|
||||||
|
move_format_string_arg,
|
||||||
|
&add_macro_decl(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
print!("My name is {} {x$0 + x}", stringify!(Paperino))
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
),
|
||||||
|
&add_macro_decl(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
print!("My name is {} {}"$0, stringify!(Paperino), x + x)
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
159
crates/ide-assists/src/handlers/unwrap_tuple.rs
Normal file
159
crates/ide-assists/src/handlers/unwrap_tuple.rs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
use syntax::{
|
||||||
|
ast::{self, edit::AstNodeEdit},
|
||||||
|
AstNode, T,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||||
|
|
||||||
|
// Assist: unwrap_tuple
|
||||||
|
//
|
||||||
|
// Unwrap the tuple to different variables.
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// # //- minicore: result
|
||||||
|
// fn main() {
|
||||||
|
// $0let (foo, bar) = ("Foo", "Bar");
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// ->
|
||||||
|
// ```
|
||||||
|
// fn main() {
|
||||||
|
// let foo = "Foo";
|
||||||
|
// let bar = "Bar";
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||||
|
let let_kw = ctx.find_token_syntax_at_offset(T![let])?;
|
||||||
|
let let_stmt = let_kw.parent().and_then(ast::LetStmt::cast)?;
|
||||||
|
let indent_level = let_stmt.indent_level().0 as usize;
|
||||||
|
let pat = let_stmt.pat()?;
|
||||||
|
let ty = let_stmt.ty();
|
||||||
|
let init = let_stmt.initializer()?;
|
||||||
|
|
||||||
|
// This only applies for tuple patterns, types, and initializers.
|
||||||
|
let tuple_pat = match pat {
|
||||||
|
ast::Pat::TuplePat(pat) => pat,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let tuple_ty = ty.and_then(|it| match it {
|
||||||
|
ast::Type::TupleType(ty) => Some(ty),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let tuple_init = match init {
|
||||||
|
ast::Expr::TupleExpr(expr) => expr,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if tuple_pat.fields().count() != tuple_init.fields().count() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Some(tys) = &tuple_ty {
|
||||||
|
if tuple_pat.fields().count() != tys.fields().count() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent = let_kw.parent()?;
|
||||||
|
|
||||||
|
acc.add(
|
||||||
|
AssistId("unwrap_tuple", AssistKind::RefactorRewrite),
|
||||||
|
"Unwrap tuple",
|
||||||
|
let_kw.text_range(),
|
||||||
|
|edit| {
|
||||||
|
let indents = " ".repeat(indent_level);
|
||||||
|
|
||||||
|
// If there is an ascribed type, insert that type for each declaration,
|
||||||
|
// otherwise, omit that type.
|
||||||
|
if let Some(tys) = tuple_ty {
|
||||||
|
let mut zipped_decls = String::new();
|
||||||
|
for (pat, ty, expr) in
|
||||||
|
itertools::izip!(tuple_pat.fields(), tys.fields(), tuple_init.fields())
|
||||||
|
{
|
||||||
|
zipped_decls.push_str(&format!("{}let {pat}: {ty} = {expr};\n", indents))
|
||||||
|
}
|
||||||
|
edit.replace(parent.text_range(), zipped_decls.trim());
|
||||||
|
} else {
|
||||||
|
let mut zipped_decls = String::new();
|
||||||
|
for (pat, expr) in itertools::izip!(tuple_pat.fields(), tuple_init.fields()) {
|
||||||
|
zipped_decls.push_str(&format!("{}let {pat} = {expr};\n", indents));
|
||||||
|
}
|
||||||
|
edit.replace(parent.text_range(), zipped_decls.trim());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::check_assist;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unwrap_tuples() {
|
||||||
|
check_assist(
|
||||||
|
unwrap_tuple,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0let (foo, bar) = ("Foo", "Bar");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let foo = "Foo";
|
||||||
|
let bar = "Bar";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_assist(
|
||||||
|
unwrap_tuple,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0let (foo, bar, baz) = ("Foo", "Bar", "Baz");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let foo = "Foo";
|
||||||
|
let bar = "Bar";
|
||||||
|
let baz = "Baz";
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unwrap_tuple_with_types() {
|
||||||
|
check_assist(
|
||||||
|
unwrap_tuple,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0let (foo, bar): (u8, i32) = (5, 10);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let foo: u8 = 5;
|
||||||
|
let bar: i32 = 10;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
check_assist(
|
||||||
|
unwrap_tuple,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
$0let (foo, bar, baz): (u8, i32, f64) = (5, 10, 17.5);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let foo: u8 = 5;
|
||||||
|
let bar: i32 = 10;
|
||||||
|
let baz: f64 = 17.5;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,6 +121,7 @@ mod handlers {
|
||||||
mod convert_iter_for_each_to_for;
|
mod convert_iter_for_each_to_for;
|
||||||
mod convert_let_else_to_match;
|
mod convert_let_else_to_match;
|
||||||
mod convert_tuple_struct_to_named_struct;
|
mod convert_tuple_struct_to_named_struct;
|
||||||
|
mod convert_named_struct_to_tuple_struct;
|
||||||
mod convert_to_guarded_return;
|
mod convert_to_guarded_return;
|
||||||
mod convert_two_arm_bool_match_to_matches_macro;
|
mod convert_two_arm_bool_match_to_matches_macro;
|
||||||
mod convert_while_to_loop;
|
mod convert_while_to_loop;
|
||||||
|
@ -189,6 +190,7 @@ mod handlers {
|
||||||
mod replace_turbofish_with_explicit_type;
|
mod replace_turbofish_with_explicit_type;
|
||||||
mod split_import;
|
mod split_import;
|
||||||
mod unmerge_match_arm;
|
mod unmerge_match_arm;
|
||||||
|
mod unwrap_tuple;
|
||||||
mod sort_items;
|
mod sort_items;
|
||||||
mod toggle_ignore;
|
mod toggle_ignore;
|
||||||
mod unmerge_use;
|
mod unmerge_use;
|
||||||
|
@ -217,6 +219,7 @@ mod handlers {
|
||||||
convert_iter_for_each_to_for::convert_iter_for_each_to_for,
|
convert_iter_for_each_to_for::convert_iter_for_each_to_for,
|
||||||
convert_iter_for_each_to_for::convert_for_loop_with_for_each,
|
convert_iter_for_each_to_for::convert_for_loop_with_for_each,
|
||||||
convert_let_else_to_match::convert_let_else_to_match,
|
convert_let_else_to_match::convert_let_else_to_match,
|
||||||
|
convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
|
||||||
convert_to_guarded_return::convert_to_guarded_return,
|
convert_to_guarded_return::convert_to_guarded_return,
|
||||||
convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
|
convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
|
||||||
convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
|
convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
|
||||||
|
@ -291,6 +294,7 @@ mod handlers {
|
||||||
unnecessary_async::unnecessary_async,
|
unnecessary_async::unnecessary_async,
|
||||||
unwrap_block::unwrap_block,
|
unwrap_block::unwrap_block,
|
||||||
unwrap_result_return_type::unwrap_result_return_type,
|
unwrap_result_return_type::unwrap_result_return_type,
|
||||||
|
unwrap_tuple::unwrap_tuple,
|
||||||
wrap_return_type_in_result::wrap_return_type_in_result,
|
wrap_return_type_in_result::wrap_return_type_in_result,
|
||||||
// These are manually sorted for better priorities. By default,
|
// These are manually sorted for better priorities. By default,
|
||||||
// priority is determined by the size of the target range (smaller
|
// priority is determined by the size of the target range (smaller
|
||||||
|
|
|
@ -96,8 +96,10 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
|
||||||
});
|
});
|
||||||
|
|
||||||
let actual = {
|
let actual = {
|
||||||
let source_change =
|
let source_change = assist
|
||||||
assist.source_change.expect("Assist did not contain any source changes");
|
.source_change
|
||||||
|
.filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
|
||||||
|
.expect("Assist did not contain any source changes");
|
||||||
let mut actual = before;
|
let mut actual = before;
|
||||||
if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
|
if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
|
||||||
source_file_edit.apply(&mut actual);
|
source_file_edit.apply(&mut actual);
|
||||||
|
@ -140,8 +142,10 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult<'_>, assist_la
|
||||||
|
|
||||||
match (assist, expected) {
|
match (assist, expected) {
|
||||||
(Some(assist), ExpectedResult::After(after)) => {
|
(Some(assist), ExpectedResult::After(after)) => {
|
||||||
let source_change =
|
let source_change = assist
|
||||||
assist.source_change.expect("Assist did not contain any source changes");
|
.source_change
|
||||||
|
.filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty())
|
||||||
|
.expect("Assist did not contain any source changes");
|
||||||
let skip_header = source_change.source_file_edits.len() == 1
|
let skip_header = source_change.source_file_edits.len() == 1
|
||||||
&& source_change.file_system_edits.len() == 0;
|
&& source_change.file_system_edits.len() == 0;
|
||||||
|
|
||||||
|
@ -228,6 +232,7 @@ fn assist_order_field_struct() {
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
|
assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
|
assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
|
assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
|
||||||
|
assert_eq!(assists.next().expect("expected assist").label, "Convert to tuple struct");
|
||||||
assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
|
assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -407,6 +407,47 @@ fn main() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doctest_convert_named_struct_to_tuple_struct() {
|
||||||
|
check_doc_test(
|
||||||
|
"convert_named_struct_to_tuple_struct",
|
||||||
|
r#####"
|
||||||
|
struct Point$0 { x: f32, y: f32 }
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Point { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn x(&self) -> f32 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn y(&self) -> f32 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
r#####"
|
||||||
|
struct Point(f32, f32);
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Point(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn x(&self) -> f32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn y(&self) -> f32 {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doctest_convert_to_guarded_return() {
|
fn doctest_convert_to_guarded_return() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
|
@ -2386,6 +2427,25 @@ fn foo() -> i32 { 42i32 }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doctest_unwrap_tuple() {
|
||||||
|
check_doc_test(
|
||||||
|
"unwrap_tuple",
|
||||||
|
r#####"
|
||||||
|
//- minicore: result
|
||||||
|
fn main() {
|
||||||
|
$0let (foo, bar) = ("Foo", "Bar");
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
r#####"
|
||||||
|
fn main() {
|
||||||
|
let foo = "Foo";
|
||||||
|
let bar = "Bar";
|
||||||
|
}
|
||||||
|
"#####,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doctest_wrap_return_type_in_result() {
|
fn doctest_wrap_return_type_in_result() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
|
pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
|
||||||
use hir::{db::HirDatabase, HirDisplay, Semantics};
|
use hir::{db::HirDatabase, HirDisplay, Semantics};
|
||||||
use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
|
use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
|
||||||
|
@ -15,7 +13,7 @@ use syntax::{
|
||||||
edit_in_place::{AttrsOwnerEdit, Removable},
|
edit_in_place::{AttrsOwnerEdit, Removable},
|
||||||
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
|
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
|
||||||
},
|
},
|
||||||
ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
|
ted, AstNode, AstToken, Direction, SourceFile,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, TextRange, TextSize, T,
|
SyntaxNode, TextRange, TextSize, T,
|
||||||
};
|
};
|
||||||
|
@ -424,34 +422,44 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
|
fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
|
||||||
let generic_params = adt.generic_param_list();
|
// Ensure lifetime params are before type & const params
|
||||||
|
let generic_params = adt.generic_param_list().map(|generic_params| {
|
||||||
|
let lifetime_params =
|
||||||
|
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
|
||||||
|
let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
|
||||||
|
// remove defaults since they can't be specified in impls
|
||||||
|
match param {
|
||||||
|
ast::TypeOrConstParam::Type(param) => {
|
||||||
|
let param = param.clone_for_update();
|
||||||
|
param.remove_default();
|
||||||
|
Some(ast::GenericParam::TypeParam(param))
|
||||||
|
}
|
||||||
|
ast::TypeOrConstParam::Const(param) => {
|
||||||
|
let param = param.clone_for_update();
|
||||||
|
param.remove_default();
|
||||||
|
Some(ast::GenericParam::ConstParam(param))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: use syntax::make & mutable AST apis instead
|
||||||
|
// `trait_text` and `code` can't be opaque blobs of text
|
||||||
let mut buf = String::with_capacity(code.len());
|
let mut buf = String::with_capacity(code.len());
|
||||||
|
|
||||||
|
// Copy any cfg attrs from the original adt
|
||||||
buf.push_str("\n\n");
|
buf.push_str("\n\n");
|
||||||
adt.attrs()
|
let cfg_attrs = adt
|
||||||
.filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
|
.attrs()
|
||||||
.for_each(|attr| buf.push_str(format!("{}\n", attr).as_str()));
|
.filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
|
||||||
|
cfg_attrs.for_each(|attr| buf.push_str(&format!("{attr}\n")));
|
||||||
|
|
||||||
|
// `impl{generic_params} {trait_text} for {name}{generic_params.to_generic_args()}`
|
||||||
buf.push_str("impl");
|
buf.push_str("impl");
|
||||||
if let Some(generic_params) = &generic_params {
|
if let Some(generic_params) = &generic_params {
|
||||||
let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
|
format_to!(buf, "{generic_params}");
|
||||||
let toc_params = generic_params.type_or_const_params().map(|toc_param| {
|
|
||||||
let type_param = match toc_param {
|
|
||||||
ast::TypeOrConstParam::Type(x) => x,
|
|
||||||
ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(),
|
|
||||||
};
|
|
||||||
let mut buf = String::new();
|
|
||||||
if let Some(it) = type_param.name() {
|
|
||||||
format_to!(buf, "{}", it.syntax());
|
|
||||||
}
|
|
||||||
if let Some(it) = type_param.colon_token() {
|
|
||||||
format_to!(buf, "{} ", it);
|
|
||||||
}
|
|
||||||
if let Some(it) = type_param.type_bound_list() {
|
|
||||||
format_to!(buf, "{}", it.syntax());
|
|
||||||
}
|
|
||||||
buf
|
|
||||||
});
|
|
||||||
let generics = lifetimes.chain(toc_params).format(", ");
|
|
||||||
format_to!(buf, "<{}>", generics);
|
|
||||||
}
|
}
|
||||||
buf.push(' ');
|
buf.push(' ');
|
||||||
if let Some(trait_text) = trait_text {
|
if let Some(trait_text) = trait_text {
|
||||||
|
@ -460,23 +468,15 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
|
||||||
}
|
}
|
||||||
buf.push_str(&adt.name().unwrap().text());
|
buf.push_str(&adt.name().unwrap().text());
|
||||||
if let Some(generic_params) = generic_params {
|
if let Some(generic_params) = generic_params {
|
||||||
let lifetime_params = generic_params
|
format_to!(buf, "{}", generic_params.to_generic_args());
|
||||||
.lifetime_params()
|
|
||||||
.filter_map(|it| it.lifetime())
|
|
||||||
.map(|it| SmolStr::from(it.text()));
|
|
||||||
let toc_params = generic_params
|
|
||||||
.type_or_const_params()
|
|
||||||
.filter_map(|it| it.name())
|
|
||||||
.map(|it| SmolStr::from(it.text()));
|
|
||||||
format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", "))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match adt.where_clause() {
|
match adt.where_clause() {
|
||||||
Some(where_clause) => {
|
Some(where_clause) => {
|
||||||
format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
|
format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
format_to!(buf, " {{\n{}\n}}", code);
|
format_to!(buf, " {{\n{code}\n}}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,10 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cov-mark = "2.0.0-pre.1"
|
cov-mark = "2.0.0-pre.1"
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
|
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.15.0"
|
||||||
smallvec = "1.9.0"
|
smallvec = "1.10.0"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub(crate) mod snippet;
|
||||||
pub(crate) mod r#type;
|
pub(crate) mod r#type;
|
||||||
pub(crate) mod use_;
|
pub(crate) mod use_;
|
||||||
pub(crate) mod vis;
|
pub(crate) mod vis;
|
||||||
|
pub(crate) mod env_vars;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
|
150
crates/ide-completion/src/completions/env_vars.rs
Normal file
150
crates/ide-completion/src/completions/env_vars.rs
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
//! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
|
||||||
|
use hir::Semantics;
|
||||||
|
use ide_db::{syntax_helpers::node_ext::macro_call_for_string_token, RootDatabase};
|
||||||
|
use syntax::ast::{self, IsString};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
|
||||||
|
("CARGO","Path to the cargo binary performing the build"),
|
||||||
|
("CARGO_MANIFEST_DIR","The directory containing the manifest of your package"),
|
||||||
|
("CARGO_PKG_VERSION","The full version of your package"),
|
||||||
|
("CARGO_PKG_VERSION_MAJOR","The major version of your package"),
|
||||||
|
("CARGO_PKG_VERSION_MINOR","The minor version of your package"),
|
||||||
|
("CARGO_PKG_VERSION_PATCH","The patch version of your package"),
|
||||||
|
("CARGO_PKG_VERSION_PRE","The pre-release version of your package"),
|
||||||
|
("CARGO_PKG_AUTHORS","Colon separated list of authors from the manifest of your package"),
|
||||||
|
("CARGO_PKG_NAME","The name of your package"),
|
||||||
|
("CARGO_PKG_DESCRIPTION","The description from the manifest of your package"),
|
||||||
|
("CARGO_PKG_HOMEPAGE","The home page from the manifest of your package"),
|
||||||
|
("CARGO_PKG_REPOSITORY","The repository from the manifest of your package"),
|
||||||
|
("CARGO_PKG_LICENSE","The license from the manifest of your package"),
|
||||||
|
("CARGO_PKG_LICENSE_FILE","The license file from the manifest of your package"),
|
||||||
|
("CARGO_PKG_RUST_VERSION","The Rust version from the manifest of your package. Note that this is the minimum Rust version supported by the package, not the current Rust version"),
|
||||||
|
("CARGO_CRATE_NAME","The name of the crate that is currently being compiled"),
|
||||||
|
("CARGO_BIN_NAME","The name of the binary that is currently being compiled (if it is a binary). This name does not include any file extension, such as .exe"),
|
||||||
|
("CARGO_PRIMARY_PACKAGE","This environment variable will be set if the package being built is primary. Primary packages are the ones the user selected on the command-line, either with -p flags or the defaults based on the current directory and the default workspace members. This environment variable will not be set when building dependencies. This is only set when compiling the package (not when running binaries or tests)"),
|
||||||
|
("CARGO_TARGET_TMPDIR","Only set when building integration test or benchmark code. This is a path to a directory inside the target directory where integration tests or benchmarks are free to put any data needed by the tests/benches. Cargo initially creates this directory but doesn't manage its content in any way, this is the responsibility of the test code")
|
||||||
|
];
|
||||||
|
|
||||||
|
pub(crate) fn complete_cargo_env_vars(
|
||||||
|
acc: &mut Completions,
|
||||||
|
ctx: &CompletionContext<'_>,
|
||||||
|
expanded: &ast::String,
|
||||||
|
) -> Option<()> {
|
||||||
|
guard_env_macro(expanded, &ctx.sema)?;
|
||||||
|
let range = expanded.text_range_between_quotes()?;
|
||||||
|
|
||||||
|
CARGO_DEFINED_VARS.iter().for_each(|(var, detail)| {
|
||||||
|
let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var);
|
||||||
|
item.detail(*detail);
|
||||||
|
item.add_to(acc);
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guard_env_macro(string: &ast::String, semantics: &Semantics<'_, RootDatabase>) -> Option<()> {
|
||||||
|
let call = macro_call_for_string_token(string)?;
|
||||||
|
let name = call.path()?.segment()?.name_ref()?;
|
||||||
|
let makro = semantics.resolve_macro_call(&call)?;
|
||||||
|
let db = semantics.db;
|
||||||
|
|
||||||
|
match name.text().as_str() {
|
||||||
|
"env" | "option_env" if makro.kind(db) == hir::MacroKind::BuiltIn => Some(()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::{check_edit, completion_list};
|
||||||
|
|
||||||
|
fn check(macro_name: &str) {
|
||||||
|
check_edit(
|
||||||
|
"CARGO_BIN_NAME",
|
||||||
|
&format!(
|
||||||
|
r#"
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro_rules! {} {{
|
||||||
|
($var:literal) => {{ 0 }}
|
||||||
|
}}
|
||||||
|
|
||||||
|
fn main() {{
|
||||||
|
let foo = {}!("CAR$0");
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
macro_name, macro_name
|
||||||
|
),
|
||||||
|
&format!(
|
||||||
|
r#"
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro_rules! {} {{
|
||||||
|
($var:literal) => {{ 0 }}
|
||||||
|
}}
|
||||||
|
|
||||||
|
fn main() {{
|
||||||
|
let foo = {}!("CARGO_BIN_NAME");
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
macro_name, macro_name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn completes_env_variable_in_env() {
|
||||||
|
check("env")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_env_variable_in_option_env() {
|
||||||
|
check("option_env");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doesnt_complete_in_random_strings() {
|
||||||
|
let fixture = r#"
|
||||||
|
fn main() {
|
||||||
|
let foo = "CA$0";
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let completions = completion_list(fixture);
|
||||||
|
assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doesnt_complete_in_random_macro() {
|
||||||
|
let fixture = r#"
|
||||||
|
macro_rules! bar {
|
||||||
|
($($arg:tt)*) => { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = bar!("CA$0");
|
||||||
|
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let completions = completion_list(fixture);
|
||||||
|
assert!(completions.is_empty(), "Completions weren't empty: {}", completions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn doesnt_complete_for_shadowed_macro() {
|
||||||
|
let fixture = r#"
|
||||||
|
macro_rules! env {
|
||||||
|
($var:literal) => { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = env!("CA$0");
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let completions = completion_list(fixture);
|
||||||
|
assert!(completions.is_empty(), "Completions weren't empty: {}", completions)
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ use ide_db::{
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, edit_in_place::AttrsOwnerEdit},
|
ast::{self, edit_in_place::AttrsOwnerEdit},
|
||||||
AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
|
AstNode, SyntaxElement, SyntaxKind, TextRange, T,
|
||||||
};
|
};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
|
@ -85,20 +85,36 @@ fn complete_trait_impl_name(
|
||||||
name: &Option<ast::Name>,
|
name: &Option<ast::Name>,
|
||||||
kind: ImplCompletionKind,
|
kind: ImplCompletionKind,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let token = ctx.token.clone();
|
|
||||||
let item = match name {
|
let item = match name {
|
||||||
Some(name) => name.syntax().parent(),
|
Some(name) => name.syntax().parent(),
|
||||||
None => if token.kind() == SyntaxKind::WHITESPACE { token.prev_token()? } else { token }
|
None => {
|
||||||
.parent(),
|
let token = &ctx.token;
|
||||||
|
match token.kind() {
|
||||||
|
SyntaxKind::WHITESPACE => token.prev_token()?,
|
||||||
|
_ => token.clone(),
|
||||||
|
}
|
||||||
|
.parent()
|
||||||
|
}
|
||||||
}?;
|
}?;
|
||||||
complete_trait_impl(
|
let item = ctx.sema.original_syntax_node(&item)?;
|
||||||
acc,
|
// item -> ASSOC_ITEM_LIST -> IMPL
|
||||||
ctx,
|
let impl_def = ast::Impl::cast(item.parent()?.parent()?)?;
|
||||||
kind,
|
let replacement_range = {
|
||||||
replacement_range(ctx, &item),
|
// ctx.sema.original_ast_node(item)?;
|
||||||
// item -> ASSOC_ITEM_LIST -> IMPL
|
let first_child = item
|
||||||
&ast::Impl::cast(item.parent()?.parent()?)?,
|
.children_with_tokens()
|
||||||
);
|
.find(|child| {
|
||||||
|
!matches!(
|
||||||
|
child.kind(),
|
||||||
|
SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| SyntaxElement::Node(item.clone()));
|
||||||
|
|
||||||
|
TextRange::new(first_child.text_range().start(), ctx.source_range().end())
|
||||||
|
};
|
||||||
|
|
||||||
|
complete_trait_impl(acc, ctx, kind, replacement_range, &impl_def);
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,17 +357,6 @@ fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String {
|
||||||
syntax.trim_end().to_owned()
|
syntax.trim_end().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replacement_range(ctx: &CompletionContext<'_>, item: &SyntaxNode) -> TextRange {
|
|
||||||
let first_child = item
|
|
||||||
.children_with_tokens()
|
|
||||||
.find(|child| {
|
|
||||||
!matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| SyntaxElement::Node(item.clone()));
|
|
||||||
|
|
||||||
TextRange::new(first_child.text_range().start(), ctx.source_range().end())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! See `CompletionContext` structure.
|
//! See [`CompletionContext`] structure.
|
||||||
|
|
||||||
mod analysis;
|
mod analysis;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -23,7 +23,10 @@ use syntax::{
|
||||||
};
|
};
|
||||||
use text_edit::Indel;
|
use text_edit::Indel;
|
||||||
|
|
||||||
use crate::CompletionConfig;
|
use crate::{
|
||||||
|
context::analysis::{expand_and_analyze, AnalysisResult},
|
||||||
|
CompletionConfig,
|
||||||
|
};
|
||||||
|
|
||||||
const COMPLETION_MARKER: &str = "intellijRulezz";
|
const COMPLETION_MARKER: &str = "intellijRulezz";
|
||||||
|
|
||||||
|
@ -561,15 +564,27 @@ impl<'a> CompletionContext<'a> {
|
||||||
let edit = Indel::insert(offset, COMPLETION_MARKER.to_string());
|
let edit = Indel::insert(offset, COMPLETION_MARKER.to_string());
|
||||||
parse.reparse(&edit).tree()
|
parse.reparse(&edit).tree()
|
||||||
};
|
};
|
||||||
let fake_ident_token =
|
|
||||||
file_with_fake_ident.syntax().token_at_offset(offset).right_biased()?;
|
|
||||||
|
|
||||||
|
// always pick the token to the immediate left of the cursor, as that is what we are actually
|
||||||
|
// completing on
|
||||||
let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
|
let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
|
||||||
let token = sema.descend_into_macros_single(original_token.clone());
|
|
||||||
|
let AnalysisResult {
|
||||||
|
analysis,
|
||||||
|
expected: (expected_type, expected_name),
|
||||||
|
qualifier_ctx,
|
||||||
|
token,
|
||||||
|
offset,
|
||||||
|
} = expand_and_analyze(
|
||||||
|
&sema,
|
||||||
|
original_file.syntax().clone(),
|
||||||
|
file_with_fake_ident.syntax().clone(),
|
||||||
|
offset,
|
||||||
|
&original_token,
|
||||||
|
)?;
|
||||||
|
|
||||||
// adjust for macro input, this still fails if there is no token written yet
|
// adjust for macro input, this still fails if there is no token written yet
|
||||||
let scope_offset = if original_token == token { offset } else { token.text_range().end() };
|
let scope = sema.scope_at_offset(&token.parent()?, offset)?;
|
||||||
let scope = sema.scope_at_offset(&token.parent()?, scope_offset)?;
|
|
||||||
|
|
||||||
let krate = scope.krate();
|
let krate = scope.krate();
|
||||||
let module = scope.module();
|
let module = scope.module();
|
||||||
|
@ -583,7 +598,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
|
|
||||||
let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count();
|
let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count();
|
||||||
|
|
||||||
let mut ctx = CompletionContext {
|
let ctx = CompletionContext {
|
||||||
sema,
|
sema,
|
||||||
scope,
|
scope,
|
||||||
db,
|
db,
|
||||||
|
@ -593,19 +608,13 @@ impl<'a> CompletionContext<'a> {
|
||||||
token,
|
token,
|
||||||
krate,
|
krate,
|
||||||
module,
|
module,
|
||||||
expected_name: None,
|
expected_name,
|
||||||
expected_type: None,
|
expected_type,
|
||||||
qualifier_ctx: Default::default(),
|
qualifier_ctx,
|
||||||
locals,
|
locals,
|
||||||
depth_from_crate_root,
|
depth_from_crate_root,
|
||||||
};
|
};
|
||||||
let ident_ctx = ctx.expand_and_analyze(
|
Some((ctx, analysis))
|
||||||
original_file.syntax().clone(),
|
|
||||||
file_with_fake_ident.syntax().clone(),
|
|
||||||
offset,
|
|
||||||
fake_ident_token,
|
|
||||||
)?;
|
|
||||||
Some((ctx, ident_ctx))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -183,6 +183,7 @@ pub fn completions(
|
||||||
CompletionAnalysis::String { original, expanded: Some(expanded) } => {
|
CompletionAnalysis::String { original, expanded: Some(expanded) } => {
|
||||||
completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
|
completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
|
||||||
completions::format_string::format_string(acc, ctx, original, expanded);
|
completions::format_string::format_string(acc, ctx, original, expanded);
|
||||||
|
completions::env_vars::complete_cargo_env_vars(acc, ctx, expanded);
|
||||||
}
|
}
|
||||||
CompletionAnalysis::UnexpandedAttrTT {
|
CompletionAnalysis::UnexpandedAttrTT {
|
||||||
colon_prefix,
|
colon_prefix,
|
||||||
|
|
|
@ -15,9 +15,9 @@ tracing = "0.1.35"
|
||||||
rayon = "1.5.3"
|
rayon = "1.5.3"
|
||||||
fst = { version = "0.4.7", default-features = false }
|
fst = { version = "0.4.7", default-features = false }
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
once_cell = "1.12.0"
|
once_cell = "1.15.0"
|
||||||
either = "1.7.0"
|
either = "1.7.0"
|
||||||
itertools = "0.10.3"
|
itertools = "0.10.5"
|
||||||
arrayvec = "0.7.2"
|
arrayvec = "0.7.2"
|
||||||
indexmap = "1.9.1"
|
indexmap = "1.9.1"
|
||||||
memchr = "2.5.0"
|
memchr = "2.5.0"
|
||||||
|
|
|
@ -225,7 +225,7 @@ fn path_cmp_short(a: &ast::Path, b: &ast::Path) -> Ordering {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compares two paths, if one ends earlier than the other the has_tl parameters decide which is
|
/// Compares two paths, if one ends earlier than the other the has_tl parameters decide which is
|
||||||
/// greater as a a path that has a tree list should be greater, while one that just ends without
|
/// greater as a path that has a tree list should be greater, while one that just ends without
|
||||||
/// a tree list should be considered less.
|
/// a tree list should be considered less.
|
||||||
pub(super) fn use_tree_path_cmp(
|
pub(super) fn use_tree_path_cmp(
|
||||||
a: &ast::Path,
|
a: &ast::Path,
|
||||||
|
|
|
@ -239,6 +239,7 @@ impl Definition {
|
||||||
DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()),
|
DefWithBody::Function(f) => f.source(db).map(|src| src.syntax().cloned()),
|
||||||
DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
|
DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
|
||||||
DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
|
DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
|
||||||
|
DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()),
|
||||||
};
|
};
|
||||||
return match def {
|
return match def {
|
||||||
Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
|
Some(def) => SearchScope::file_range(def.as_ref().original_file_range(db)),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
//! Tools to work with format string literals for the `format_args!` family of macros.
|
//! Tools to work with format string literals for the `format_args!` family of macros.
|
||||||
|
use crate::syntax_helpers::node_ext::macro_call_for_string_token;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, IsString},
|
ast::{self, IsString},
|
||||||
AstNode, AstToken, TextRange, TextSize,
|
TextRange, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn is_format_string(string: &ast::String) -> bool {
|
pub fn is_format_string(string: &ast::String) -> bool {
|
||||||
|
@ -14,8 +15,7 @@ pub fn is_format_string(string: &ast::String) -> bool {
|
||||||
// This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
|
// This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
|
||||||
// strings. It still fails for `concat!("{", "}")`, but that is rare.
|
// strings. It still fails for `concat!("{", "}")`, but that is rare.
|
||||||
(|| {
|
(|| {
|
||||||
let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
|
let name = macro_call_for_string_token(string)?.path()?.segment()?.name_ref()?;
|
||||||
let name = macro_call.path()?.segment()?.name_ref()?;
|
|
||||||
|
|
||||||
if !matches!(
|
if !matches!(
|
||||||
name.text().as_str(),
|
name.text().as_str(),
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parser::T;
|
use parser::T;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasLoopBody, PathSegmentKind, VisibilityKind},
|
ast::{self, HasLoopBody, MacroCall, PathSegmentKind, VisibilityKind},
|
||||||
AstNode, Preorder, RustLanguage, WalkEvent,
|
AstNode, AstToken, Preorder, RustLanguage, WalkEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
|
pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
|
||||||
|
@ -457,3 +457,8 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Pat
|
||||||
.collect();
|
.collect();
|
||||||
Some(paths)
|
Some(paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn macro_call_for_string_token(string: &ast::String) -> Option<MacroCall> {
|
||||||
|
let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
|
||||||
|
Some(macro_call)
|
||||||
|
}
|
||||||
|
|
|
@ -11,11 +11,9 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cov-mark = "2.0.0-pre.1"
|
cov-mark = "2.0.0-pre.1"
|
||||||
itertools = "0.10.3"
|
|
||||||
|
|
||||||
|
|
||||||
either = "1.7.0"
|
either = "1.7.0"
|
||||||
serde_json = "1.0.82"
|
itertools = "0.10.5"
|
||||||
|
serde_json = "1.0.86"
|
||||||
|
|
||||||
profile = { path = "../profile", version = "0.0.0" }
|
profile = { path = "../profile", version = "0.0.0" }
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
|
|
|
@ -137,6 +137,37 @@ trait Bar {
|
||||||
|
|
||||||
#[cfg_attr(not(never), inline, cfg(no))] fn h() {}
|
#[cfg_attr(not(never), inline, cfg(no))] fn h() {}
|
||||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
|
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inactive_fields_and_variants() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
enum Foo {
|
||||||
|
#[cfg(a)] Bar,
|
||||||
|
//^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
|
||||||
|
Baz {
|
||||||
|
#[cfg(a)] baz: String,
|
||||||
|
//^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
|
||||||
|
},
|
||||||
|
Qux(#[cfg(a)] String),
|
||||||
|
//^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Baz {
|
||||||
|
#[cfg(a)] baz: String,
|
||||||
|
//^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Qux(#[cfg(a)] String);
|
||||||
|
//^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
|
||||||
|
|
||||||
|
union FooBar {
|
||||||
|
#[cfg(a)] baz: u32,
|
||||||
|
//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
37
crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
Normal file
37
crates/ide-diagnostics/src/handlers/incorrect_try_expr.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use hir::InFile;
|
||||||
|
|
||||||
|
use crate::{Diagnostic, DiagnosticsContext};
|
||||||
|
|
||||||
|
// Diagnostic: incorrect-try-target
|
||||||
|
//
|
||||||
|
// This diagnostic is triggered if a question mark operator was used in a context where it is not applicable.
|
||||||
|
pub(crate) fn incorrect_try_expr(
|
||||||
|
ctx: &DiagnosticsContext<'_>,
|
||||||
|
d: &hir::IncorrectTryExpr,
|
||||||
|
) -> Diagnostic {
|
||||||
|
Diagnostic::new(
|
||||||
|
"incorrect-try-target",
|
||||||
|
format!("the return type of the containing function does not implement `FromResidual`"),
|
||||||
|
ctx.sema
|
||||||
|
.diagnostics_display_range(InFile::new(d.expr.file_id, d.expr.value.clone().into()))
|
||||||
|
.range,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::tests::check_diagnostics;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_ops_diag() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
//- minicore: try
|
||||||
|
fn test() {
|
||||||
|
core::ops::ControlFlow::<u32, f32>::Continue(1.0)?;
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the return type of the containing function does not implement `FromResidual`
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue