Auto merge of #125272 - lnicola:sync-from-ra, r=lnicola

Subtree update of `rust-analyzer`

r? `@ghost`
This commit is contained in:
bors 2024-05-19 12:56:35 +00:00
commit 48826c85fd
204 changed files with 5515 additions and 2911 deletions

View file

@ -6,3 +6,10 @@
# prettier format
f247090558c9ba3c551566eae5882b7ca865225f
# subtree syncs
932d85b52946d917deab2c23ead552f7f713b828
3e358a6827d83e8d6473913a5e304734aadfed04
9d2cb42a413e51deb50b36794a2e1605381878fc
f532576ac53ddcc666bc8d59e0b6437065e2f599
c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1

View file

@ -63,15 +63,15 @@ jobs:
- name: Install Rust toolchain
run: |
rustup update --no-self-update ${{ env.RUST_CHANNEL }}
rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
rustup default ${{ env.RUST_CHANNEL }}
rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
# https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
- name: Install Rust Problem Matcher
if: matrix.os == 'ubuntu-latest'
run: echo "::add-matcher::.github/rust.json"
- name: Cache Dependencies
uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
with:
key: ${{ env.RUST_CHANNEL }}
@ -140,7 +140,7 @@ jobs:
rustup target add ${{ env.targets }} ${{ env.targets_ide }}
- name: Cache Dependencies
uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
- name: Check
run: |

View file

@ -11,34 +11,21 @@ env:
RUSTUP_MAX_RETRIES: 10
jobs:
setup_cargo:
build_metrics:
if: github.repository == 'rust-lang/rust-analyzer'
runs-on: ubuntu-latest
steps:
- name: Install Rust toolchain
run: |
rustup update --no-self-update stable
rustup component add rustfmt rust-src
rustup default stable
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-${{ github.sha }}
rustup component add --toolchain stable rust-src
build_metrics:
runs-on: ubuntu-latest
needs: setup_cargo
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore cargo cache
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
@ -69,22 +56,18 @@ jobs:
matrix:
names: [self, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18]
runs-on: ubuntu-latest
needs: [setup_cargo, build_metrics]
needs: build_metrics
steps:
- name: Install Rust toolchain
run: |
rustup update --no-self-update stable
rustup default stable
rustup component add --toolchain stable rust-src
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore cargo cache
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-${{ github.sha }}
- name: Restore target cache
uses: actions/cache@v4
with:

View file

@ -26,7 +26,7 @@ jobs:
run: cargo doc --all --no-deps
- name: Deploy Docs
uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages

406
Cargo.lock generated
View file

@ -28,9 +28,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.80"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
[[package]]
name = "arbitrary"
@ -46,15 +46,15 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "autocfg"
version = "1.1.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backtrace"
version = "0.3.69"
version = "0.3.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
dependencies = [
"addr2line",
"cc",
@ -91,9 +91,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "byteorder"
@ -112,9 +112,9 @@ dependencies = [
[[package]]
name = "cargo-platform"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
dependencies = [
"serde",
]
@ -135,9 +135,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.90"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
[[package]]
name = "cfg"
@ -159,6 +159,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chalk-derive"
version = "0.97.0"
@ -177,7 +183,7 @@ version = "0.97.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
"chalk-derive",
]
@ -282,11 +288,11 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "ctrlc"
version = "3.4.2"
version = "3.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345"
dependencies = [
"nix 0.27.1",
"nix 0.28.0",
"windows-sys 0.52.0",
]
@ -324,10 +330,31 @@ dependencies = [
]
[[package]]
name = "dissimilar"
version = "1.0.7"
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]]
name = "dissimilar"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
[[package]]
name = "dot"
@ -343,15 +370,15 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
[[package]]
name = "either"
version = "1.10.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
[[package]]
name = "ena"
version = "0.14.2"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
dependencies = [
"log",
]
@ -364,9 +391,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "expect-test"
version = "1.4.1"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3"
checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
dependencies = [
"dissimilar",
"once_cell",
@ -380,7 +407,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"redox_syscall 0.4.1",
"windows-sys 0.52.0",
]
@ -392,9 +419,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flate2"
version = "1.0.28"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
dependencies = [
"crc32fast",
"miniz_oxide",
@ -442,9 +469,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
[[package]]
name = "getrandom"
version = "0.2.12"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
@ -459,9 +486,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "hashbrown"
version = "0.14.3"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "heck"
@ -504,7 +531,7 @@ version = "0.0.0"
dependencies = [
"arrayvec",
"base-db",
"bitflags 2.4.2",
"bitflags 2.5.0",
"cfg",
"cov-mark",
"dashmap",
@ -568,7 +595,7 @@ version = "0.0.0"
dependencies = [
"arrayvec",
"base-db",
"bitflags 2.4.2",
"bitflags 2.5.0",
"chalk-derive",
"chalk-ir",
"chalk-recursive",
@ -589,7 +616,7 @@ dependencies = [
"oorandom",
"project-model",
"ra-ap-rustc_abi",
"ra-ap-rustc_index",
"ra-ap-rustc_index 0.53.0",
"ra-ap-rustc_pattern_analysis",
"rustc-hash",
"scoped-tls",
@ -695,7 +722,7 @@ version = "0.0.0"
dependencies = [
"arrayvec",
"base-db",
"bitflags 2.4.2",
"bitflags 2.5.0",
"cov-mark",
"crossbeam-channel",
"either",
@ -776,9 +803,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.2.5"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
@ -826,9 +853,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jod-thread"
@ -874,9 +901,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.153"
version = "0.2.154"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
[[package]]
name = "libloading"
@ -885,19 +912,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
dependencies = [
"cfg-if",
"windows-targets 0.52.4",
"windows-targets 0.52.5",
]
[[package]]
name = "libmimalloc-sys"
version = "0.1.35"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664"
checksum = "81eb4061c0582dedea1cbc7aff2240300dd6982e0239d1c99e65c1dbf4a30ba7"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.5.0",
"libc",
]
[[package]]
name = "limit"
version = "0.0.0"
@ -948,9 +985,9 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.11"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
@ -1001,9 +1038,9 @@ dependencies = [
[[package]]
name = "lz4_flex"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
[[package]]
name = "mbe"
@ -1023,9 +1060,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.1"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "memmap2"
@ -1038,18 +1075,18 @@ dependencies = [
[[package]]
name = "memoffset"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "mimalloc"
version = "0.1.39"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c"
checksum = "9f41a2280ded0da56c8cf898babb86e8f10651a34adcfff190ae9a1159c6908d"
dependencies = [
"libmimalloc-sys",
]
@ -1097,12 +1134,13 @@ dependencies = [
[[package]]
name = "nix"
version = "0.27.1"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
"cfg-if",
"cfg_aliases",
"libc",
]
@ -1118,7 +1156,7 @@ version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
"crossbeam-channel",
"filetime",
"fsevent-sys",
@ -1187,10 +1225,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "parking_lot"
version = "0.12.1"
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "parking_lot"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
dependencies = [
"lock_api",
"parking_lot_core",
@ -1198,15 +1242,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.9"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"redox_syscall 0.5.1",
"smallvec",
"windows-targets 0.48.5",
"windows-targets 0.52.5",
]
[[package]]
@ -1224,9 +1268,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.14"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "paths"
@ -1262,9 +1306,9 @@ dependencies = [
[[package]]
name = "petgraph"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap",
@ -1272,9 +1316,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.13"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "powerfmt"
@ -1346,9 +1390,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.78"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
dependencies = [
"unicode-ident",
]
@ -1365,7 +1409,7 @@ dependencies = [
"perf-event",
"tikv-jemalloc-ctl",
"tracing",
"winapi",
"windows-sys 0.52.0",
]
[[package]]
@ -1417,7 +1461,7 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
"memchr",
"unicase",
]
@ -1433,21 +1477,21 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ra-ap-rustc_abi"
version = "0.44.0"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8709df2a746f055316bc0c62bd30948695a25e734863bf6e1f9755403e010ab"
checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46"
dependencies = [
"bitflags 2.4.2",
"ra-ap-rustc_index",
"bitflags 2.5.0",
"ra-ap-rustc_index 0.53.0",
"tracing",
]
@ -1458,7 +1502,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros",
"ra-ap-rustc_index_macros 0.44.0",
"smallvec",
]
[[package]]
name = "ra-ap-rustc_index"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros 0.53.0",
"smallvec",
]
@ -1475,10 +1530,22 @@ dependencies = [
]
[[package]]
name = "ra-ap-rustc_lexer"
version = "0.44.0"
name = "ra-ap-rustc_index_macros"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aab683fc8579d09eb72033bd5dc9ba6d701aa9645b5fed087ef19af71184dff3"
checksum = "82f3d6dcb30a66905388e14756b8f2216131d9f8004922c07f13335840e058d1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "ra-ap-rustc_lexer"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbd8a2b0bdcba9892cbce0b25f6c953d31b0febc1f3420fc692884fce5a23ad8"
dependencies = [
"unicode-properties",
"unicode-xid",
@ -1486,11 +1553,11 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_parse_format"
version = "0.44.0"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bcf9ff5edbf784b67b8ad5e03a068f1300fcc24062c0d476b3018965135d933"
checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135"
dependencies = [
"ra-ap-rustc_index",
"ra-ap-rustc_index 0.53.0",
"ra-ap-rustc_lexer",
]
@ -1500,7 +1567,7 @@ version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334"
dependencies = [
"ra-ap-rustc_index",
"ra-ap-rustc_index 0.44.0",
"rustc-hash",
"rustc_apfloat",
"smallvec",
@ -1539,9 +1606,9 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
@ -1566,6 +1633,26 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "redox_users"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "rowan"
version = "0.15.15"
@ -1634,16 +1721,16 @@ dependencies = [
"vfs",
"vfs-notify",
"walkdir",
"winapi",
"windows-sys 0.52.0",
"xflags",
"xshell",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
@ -1663,9 +1750,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "salsa"
@ -1729,27 +1816,27 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.22"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.197"
version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
version = "1.0.201"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
dependencies = [
"proc-macro2",
"quote",
@ -1758,9 +1845,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.114"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
dependencies = [
"indexmap",
"itoa",
@ -1770,9 +1857,9 @@ dependencies = [
[[package]]
name = "serde_repr"
version = "0.1.18"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
@ -1799,9 +1886,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.13.1"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "smol_str"
@ -1856,14 +1943,14 @@ dependencies = [
"jod-thread",
"libc",
"miow",
"winapi",
"windows-sys 0.52.0",
]
[[package]]
name = "syn"
version = "2.0.52"
version = "2.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
dependencies = [
"proc-macro2",
"quote",
@ -1946,18 +2033,18 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
[[package]]
name = "thiserror"
version = "1.0.57"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.57"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
dependencies = [
"proc-macro2",
"quote",
@ -2007,9 +2094,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.34"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"num-conv",
@ -2041,9 +2128,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
version = "0.8.8"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
@ -2062,9 +2149,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.21.0"
version = "0.22.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
dependencies = [
"indexmap",
"serde",
@ -2255,6 +2342,7 @@ dependencies = [
"paths",
"rustc-hash",
"stdx",
"tracing",
]
[[package]]
@ -2304,11 +2392,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
dependencies = [
"winapi",
"windows-sys 0.52.0",
]
[[package]]
@ -2332,7 +2420,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
"windows-targets 0.52.5",
]
[[package]]
@ -2352,17 +2440,18 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
"windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.5",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.5",
"windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
]
[[package]]
@ -2373,9 +2462,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
@ -2385,9 +2474,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
@ -2397,9 +2486,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
@ -2409,9 +2504,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
@ -2421,9 +2516,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
@ -2433,9 +2528,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
@ -2445,15 +2540,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "winnow"
version = "0.5.32"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6"
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
dependencies = [
"memchr",
]
@ -2481,24 +2576,25 @@ checksum = "672423d4fea7ffa2f6c25ba60031ea13dc6258070556f125cc4d790007d4a155"
[[package]]
name = "xshell"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad"
checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
dependencies = [
"xshell-macros",
]
[[package]]
name = "xshell-macros"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e"
checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
[[package]]
name = "xtask"
version = "0.1.0"
dependencies = [
"anyhow",
"directories",
"flate2",
"itertools",
"proc-macro2",

View file

@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"
[workspace.package]
rust-version = "1.76"
rust-version = "1.78"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
@ -85,10 +85,10 @@ tt = { path = "./crates/tt", version = "0.0.0" }
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
vfs = { path = "./crates/vfs", version = "0.0.0" }
ra-ap-rustc_lexer = { version = "0.44.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.44.0", default-features = false }
ra-ap-rustc_index = { version = "0.44.0", default-features = false }
ra-ap-rustc_abi = { version = "0.44.0", default-features = false }
ra-ap-rustc_lexer = { version = "0.53.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false }
ra-ap-rustc_index = { version = "0.53.0", default-features = false }
ra-ap-rustc_abi = { version = "0.53.0", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.

View file

@ -51,7 +51,7 @@ impl FileChange {
}
pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered();
let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered();
if let Some(roots) = self.roots {
for (idx, root) in roots.into_iter().enumerate() {
let root_id = SourceRootId(idx as u32);

View file

@ -324,21 +324,27 @@ pub struct Dependency {
pub crate_id: CrateId,
pub name: CrateName,
prelude: bool,
sysroot: bool,
}
impl Dependency {
pub fn new(name: CrateName, crate_id: CrateId) -> Self {
Self { name, crate_id, prelude: true }
Self { name, crate_id, prelude: true, sysroot: false }
}
pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self {
Self { name, crate_id, prelude }
pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool, sysroot: bool) -> Self {
Self { name, crate_id, prelude, sysroot }
}
/// Whether this dependency is to be added to the depending crate's extern prelude.
pub fn is_prelude(&self) -> bool {
self.prelude
}
/// Whether this dependency is a sysroot injected one.
pub fn is_sysroot(&self) -> bool {
self.sysroot
}
}
impl CrateGraph {

View file

@ -8,7 +8,7 @@ mod input;
use std::panic;
use salsa::Durability;
use syntax::{ast, Parse, SourceFile};
use syntax::{ast, Parse, SourceFile, SyntaxError};
use triomphe::Arc;
pub use crate::{
@ -51,6 +51,7 @@ pub trait FileLoader {
/// Text of the file.
fn file_text(&self, file_id: FileId) -> Arc<str>;
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
/// Crates whose root's source root is the same as the source root of `file_id`
fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>;
}
@ -61,6 +62,9 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
/// Parses the file into the syntax tree.
fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
/// Returns the set of errors obtained from parsing the file including validation errors.
fn parse_errors(&self, file_id: FileId) -> Option<Arc<[SyntaxError]>>;
/// The crate graph.
#[salsa::input]
fn crate_graph(&self) -> Arc<CrateGraph>;
@ -81,12 +85,20 @@ fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option<ReleaseC
}
fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
let _p = tracing::span!(tracing::Level::INFO, "parse_query", ?file_id).entered();
let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered();
let text = db.file_text(file_id);
// FIXME: Edition based parsing
SourceFile::parse(&text, span::Edition::CURRENT)
}
fn parse_errors(db: &dyn SourceDatabase, file_id: FileId) -> Option<Arc<[SyntaxError]>> {
let errors = db.parse(file_id).errors();
match &*errors {
[] => None,
[..] => Some(errors.into()),
}
}
/// We don't want to give HIR knowledge of source roots, hence we extract these
/// methods into a separate DB.
#[salsa::query_group(SourceDatabaseExtStorage)]
@ -104,6 +116,7 @@ pub trait SourceDatabaseExt: SourceDatabase {
#[salsa::input]
fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
/// Crates whose root fool is in `id`.
fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
}

View file

@ -1,6 +1,6 @@
use arbitrary::{Arbitrary, Unstructured};
use expect_test::{expect, Expect};
use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
use syntax::{ast, AstNode, Edition};
use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr};
@ -8,7 +8,12 @@ use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr};
fn assert_parse_result(input: &str, expected: CfgExpr) {
let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
let tt = syntax_node_to_token_tree(
tt.syntax(),
DummyTestSpanMap,
DUMMY,
DocCommentDesugarMode::ProcMacro,
);
let cfg = CfgExpr::parse(&tt);
assert_eq!(cfg, expected);
}
@ -16,7 +21,12 @@ fn assert_parse_result(input: &str, expected: CfgExpr) {
fn check_dnf(input: &str, expect: Expect) {
let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
let tt = syntax_node_to_token_tree(
tt.syntax(),
DummyTestSpanMap,
DUMMY,
DocCommentDesugarMode::ProcMacro,
);
let cfg = CfgExpr::parse(&tt);
let actual = format!("#![cfg({})]", DnfExpr::new(cfg));
expect.assert_eq(&actual);
@ -25,7 +35,12 @@ fn check_dnf(input: &str, expect: Expect) {
fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) {
let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
let tt = syntax_node_to_token_tree(
tt.syntax(),
DummyTestSpanMap,
DUMMY,
DocCommentDesugarMode::ProcMacro,
);
let cfg = CfgExpr::parse(&tt);
let dnf = DnfExpr::new(cfg);
let why_inactive = dnf.why_inactive(opts).unwrap().to_string();
@ -36,7 +51,12 @@ fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) {
fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) {
let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
let tt = syntax_node_to_token_tree(
tt.syntax(),
DummyTestSpanMap,
DUMMY,
DocCommentDesugarMode::ProcMacro,
);
let cfg = CfgExpr::parse(&tt);
let dnf = DnfExpr::new(cfg);
let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::<Vec<_>>();

View file

@ -125,8 +125,10 @@ impl FlycheckHandle {
config: FlycheckConfig,
sysroot_root: Option<AbsPathBuf>,
workspace_root: AbsPathBuf,
manifest_path: Option<AbsPathBuf>,
) -> FlycheckHandle {
let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root);
let actor =
FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path);
let (sender, receiver) = unbounded::<StateChange>();
let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
.name("Flycheck".to_owned())
@ -205,6 +207,7 @@ struct FlycheckActor {
id: usize,
sender: Box<dyn Fn(Message) + Send>,
config: FlycheckConfig,
manifest_path: Option<AbsPathBuf>,
/// Either the workspace root of the workspace we are flychecking,
/// or the project root of the project.
root: AbsPathBuf,
@ -233,6 +236,7 @@ impl FlycheckActor {
config: FlycheckConfig,
sysroot_root: Option<AbsPathBuf>,
workspace_root: AbsPathBuf,
manifest_path: Option<AbsPathBuf>,
) -> FlycheckActor {
tracing::info!(%id, ?workspace_root, "Spawning flycheck");
FlycheckActor {
@ -241,6 +245,7 @@ impl FlycheckActor {
config,
sysroot_root,
root: workspace_root,
manifest_path,
command_handle: None,
command_receiver: None,
}
@ -388,8 +393,13 @@ impl FlycheckActor {
"--message-format=json"
});
cmd.arg("--manifest-path");
cmd.arg(self.root.join("Cargo.toml"));
if let Some(manifest_path) = &self.manifest_path {
cmd.arg("--manifest-path");
cmd.arg(manifest_path);
if manifest_path.extension().map_or(false, |ext| ext == "rs") {
cmd.arg("-Zscript");
}
}
options.apply_on_command(&mut cmd);
(cmd, options.extra_args.clone())

View file

@ -5,7 +5,7 @@ use triomphe::Arc;
use base_db::FileId;
use hir_expand::span_map::{RealSpanMap, SpanMap};
use mbe::syntax_node_to_token_tree;
use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode};
use syntax::{ast, AstNode, TextRange};
use crate::attr::{DocAtom, DocExpr};
@ -18,6 +18,7 @@ fn assert_parse_result(input: &str, expected: DocExpr) {
tt.syntax(),
map.as_ref(),
map.span_for_range(TextRange::empty(0.into())),
DocCommentDesugarMode::ProcMacro,
);
let cfg = DocExpr::parse(&tt);
assert_eq!(cfg, expected);

View file

@ -10,9 +10,10 @@ use std::ops::Index;
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use hir_expand::{name::Name, HirFileId, InFile};
use hir_expand::{name::Name, InFile};
use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashMap;
use span::MacroFileId;
use syntax::{ast, AstPtr, SyntaxNodePtr};
use triomphe::Arc;
@ -98,7 +99,7 @@ pub struct BodySourceMap {
format_args_template_map: FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,
/// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
/// the source map (since they're just as volatile).
@ -349,11 +350,17 @@ impl BodySourceMap {
self.expr_map.get(&src).cloned()
}
pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroFileId> {
let src = node.map(AstPtr::new);
self.expansions.get(&src).cloned()
}
pub fn macro_calls(
&self,
) -> impl Iterator<Item = (InFile<AstPtr<ast::MacroCall>>, MacroFileId)> + '_ {
self.expansions.iter().map(|(&a, &b)| (a, b))
}
pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
}

View file

@ -1006,7 +1006,9 @@ impl ExprCollector<'_> {
Some((mark, expansion)) => {
// Keep collecting even with expansion errors so we can provide completions and
// other services in incomplete macro expressions.
self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id());
self.source_map
.expansions
.insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap());
let prev_ast_id_map = mem::replace(
&mut self.ast_id_map,
self.db.ast_id_map(self.expander.current_file_id()),
@ -1869,42 +1871,45 @@ impl ExprCollector<'_> {
) -> ExprId {
match count {
Some(FormatCount::Literal(n)) => {
match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
Some(count_is) => {
let count_is = self.alloc_expr_desugared(Expr::Path(count_is));
let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
*n as u128,
Some(BuiltinUint::Usize),
)));
self.alloc_expr_desugared(Expr::Call {
callee: count_is,
args: Box::new([args]),
is_assignee_expr: false,
})
}
None => self.missing_expr(),
}
let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
*n as u128,
Some(BuiltinUint::Usize),
)));
let count_is =
match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
None => self.missing_expr(),
};
self.alloc_expr_desugared(Expr::Call {
callee: count_is,
args: Box::new([args]),
is_assignee_expr: false,
})
}
Some(FormatCount::Argument(arg)) => {
if let Ok(arg_index) = arg.index {
let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) {
Some(count_param) => {
let count_param = self.alloc_expr_desugared(Expr::Path(count_param));
let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
i as u128,
Some(BuiltinUint::Usize),
)));
self.alloc_expr_desugared(Expr::Call {
callee: count_param,
args: Box::new([args]),
is_assignee_expr: false,
})
}
let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
i as u128,
Some(BuiltinUint::Usize),
)));
let count_param = match LangItem::FormatCount.ty_rel_path(
self.db,
self.krate,
name![Param],
) {
Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
None => self.missing_expr(),
}
};
self.alloc_expr_desugared(Expr::Call {
callee: count_param,
args: Box::new([args]),
is_assignee_expr: false,
})
} else {
// FIXME: This drops arg causing it to potentially not be resolved/type checked
// when typing?
self.missing_expr()
}
}
@ -1925,7 +1930,8 @@ impl ExprCollector<'_> {
fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
use ArgumentType::*;
use FormatTrait::*;
match LangItem::FormatArgument.ty_rel_path(
let new_fn = match LangItem::FormatArgument.ty_rel_path(
self.db,
self.krate,
match ty {
@ -1941,16 +1947,14 @@ impl ExprCollector<'_> {
Usize => name![from_usize],
},
) {
Some(new_fn) => {
let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn));
self.alloc_expr_desugared(Expr::Call {
callee: new_fn,
args: Box::new([arg]),
is_assignee_expr: false,
})
}
Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
None => self.missing_expr(),
}
};
self.alloc_expr_desugared(Expr::Call {
callee: new_fn,
args: Box::new([arg]),
is_assignee_expr: false,
})
}
// endregion: format
}

View file

@ -7,7 +7,7 @@ use crate::{
body::Body,
db::DefDatabase,
hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
BlockId, DefWithBodyId,
BlockId, ConstBlockId, DefWithBodyId,
};
pub type ScopeId = Idx<ScopeData>;
@ -46,7 +46,9 @@ pub struct ScopeData {
impl ExprScopes {
pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
let body = db.body(def);
let mut scopes = ExprScopes::new(&body);
let mut scopes = ExprScopes::new(&body, |const_block| {
db.lookup_intern_anonymous_const(const_block).root
});
scopes.shrink_to_fit();
Arc::new(scopes)
}
@ -89,7 +91,10 @@ fn empty_entries(idx: usize) -> IdxRange<ScopeEntry> {
}
impl ExprScopes {
fn new(body: &Body) -> ExprScopes {
fn new(
body: &Body,
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
) -> ExprScopes {
let mut scopes = ExprScopes {
scopes: Arena::default(),
scope_entries: Arena::default(),
@ -100,7 +105,7 @@ impl ExprScopes {
scopes.add_bindings(body, root, self_param);
}
scopes.add_params_bindings(body, root, &body.params);
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
scopes
}
@ -183,35 +188,46 @@ fn compute_block_scopes(
body: &Body,
scopes: &mut ExprScopes,
scope: &mut ScopeId,
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
) {
for stmt in statements {
match stmt {
Statement::Let { pat, initializer, else_branch, .. } => {
if let Some(expr) = initializer {
compute_expr_scopes(*expr, body, scopes, scope);
compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
}
if let Some(expr) = else_branch {
compute_expr_scopes(*expr, body, scopes, scope);
compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
}
*scope = scopes.new_scope(*scope);
scopes.add_pat_bindings(body, *scope, *pat);
}
Statement::Expr { expr, .. } => {
compute_expr_scopes(*expr, body, scopes, scope);
compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
}
Statement::Item => (),
}
}
if let Some(expr) = tail {
compute_expr_scopes(expr, body, scopes, scope);
compute_expr_scopes(expr, body, scopes, scope, resolve_const_block);
}
}
fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) {
fn compute_expr_scopes(
expr: ExprId,
body: &Body,
scopes: &mut ExprScopes,
scope: &mut ScopeId,
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
) {
let make_label =
|label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
compute_expr_scopes(expr, body, scopes, scope, resolve_const_block)
};
scopes.set_scope(expr, *scope);
match &body[expr] {
Expr::Block { statements, tail, id, label } => {
@ -219,53 +235,54 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
// Overwrite the old scope for the block expr, so that every block scope can be found
// via the block itself (important for blocks that only contain items, no expressions).
scopes.set_scope(expr, scope);
compute_block_scopes(statements, *tail, body, scopes, &mut scope);
compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
}
Expr::Const(_) => {
// FIXME: This is broken.
Expr::Const(id) => {
let mut scope = scopes.root_scope();
compute_expr_scopes(scopes, resolve_const_block(*id), &mut scope);
}
Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => {
let mut scope = scopes.new_block_scope(*scope, *id, None);
// Overwrite the old scope for the block expr, so that every block scope can be found
// via the block itself (important for blocks that only contain items, no expressions).
scopes.set_scope(expr, scope);
compute_block_scopes(statements, *tail, body, scopes, &mut scope);
compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
}
Expr::Loop { body: body_expr, label } => {
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
compute_expr_scopes(scopes, *body_expr, &mut scope);
}
Expr::Closure { args, body: body_expr, .. } => {
let mut scope = scopes.new_scope(*scope);
scopes.add_params_bindings(body, scope, args);
compute_expr_scopes(*body_expr, body, scopes, &mut scope);
compute_expr_scopes(scopes, *body_expr, &mut scope);
}
Expr::Match { expr, arms } => {
compute_expr_scopes(*expr, body, scopes, scope);
compute_expr_scopes(scopes, *expr, scope);
for arm in arms.iter() {
let mut scope = scopes.new_scope(*scope);
scopes.add_pat_bindings(body, scope, arm.pat);
if let Some(guard) = arm.guard {
scope = scopes.new_scope(scope);
compute_expr_scopes(guard, body, scopes, &mut scope);
compute_expr_scopes(scopes, guard, &mut scope);
}
compute_expr_scopes(arm.expr, body, scopes, &mut scope);
compute_expr_scopes(scopes, arm.expr, &mut scope);
}
}
&Expr::If { condition, then_branch, else_branch } => {
let mut then_branch_scope = scopes.new_scope(*scope);
compute_expr_scopes(condition, body, scopes, &mut then_branch_scope);
compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope);
compute_expr_scopes(scopes, condition, &mut then_branch_scope);
compute_expr_scopes(scopes, then_branch, &mut then_branch_scope);
if let Some(else_branch) = else_branch {
compute_expr_scopes(else_branch, body, scopes, scope);
compute_expr_scopes(scopes, else_branch, scope);
}
}
&Expr::Let { pat, expr } => {
compute_expr_scopes(expr, body, scopes, scope);
compute_expr_scopes(scopes, expr, scope);
*scope = scopes.new_scope(*scope);
scopes.add_pat_bindings(body, *scope, pat);
}
e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
};
}

View file

@ -318,18 +318,20 @@ fn f() {
expect![[r#"
fn f() {
$crate::panicking::panic_fmt(
builtin#lang(Arguments::new_v1_formatted)(
&[
"cc",
],
&[],
&[],
unsafe {
builtin#lang(UnsafeArg::new)()
},
),
);
{
$crate::panicking::panic_fmt(
builtin#lang(Arguments::new_v1_formatted)(
&[
"cc",
],
&[],
&[],
unsafe {
builtin#lang(UnsafeArg::new)()
},
),
);
};
}"#]]
.assert_eq(&body.pretty_print(&db, def))
}

View file

@ -229,7 +229,7 @@ pub struct TraitData {
/// method calls to this trait's methods when the receiver is an array and the crate edition is
/// 2015 or 2018.
// box it as the vec is usually empty anyways
pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
}
impl TraitData {
@ -258,12 +258,12 @@ impl TraitData {
let mut collector =
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
let (items, attribute_calls, diagnostics) = collector.finish();
let (items, macro_calls, diagnostics) = collector.finish();
(
Arc::new(TraitData {
name,
attribute_calls,
macro_calls,
items,
is_auto,
is_unsafe,
@ -298,7 +298,7 @@ impl TraitData {
}
pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
self.macro_calls.iter().flat_map(|it| it.iter()).copied()
}
}
@ -319,7 +319,7 @@ impl TraitAliasData {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq)]
pub struct ImplData {
pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>,
@ -327,7 +327,7 @@ pub struct ImplData {
pub is_negative: bool,
pub is_unsafe: bool,
// box it as the vec is usually empty anyways
pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
}
impl ImplData {
@ -354,7 +354,7 @@ impl ImplData {
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id));
collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
let (items, attribute_calls, diagnostics) = collector.finish();
let (items, macro_calls, diagnostics) = collector.finish();
let items = items.into_iter().map(|(_, item)| item).collect();
(
@ -364,14 +364,14 @@ impl ImplData {
items,
is_negative,
is_unsafe,
attribute_calls,
macro_calls,
}),
DefDiagnostics::new(diagnostics),
)
}
pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
self.macro_calls.iter().flat_map(|it| it.iter()).copied()
}
}
@ -573,7 +573,7 @@ struct AssocItemCollector<'a> {
expander: Expander,
items: Vec<(Name, AssocItemId)>,
attr_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
}
impl<'a> AssocItemCollector<'a> {
@ -590,7 +590,7 @@ impl<'a> AssocItemCollector<'a> {
container,
expander: Expander::new(db, file_id, module_id),
items: Vec::new(),
attr_calls: Vec::new(),
macro_calls: Vec::new(),
diagnostics: Vec::new(),
}
}
@ -604,7 +604,7 @@ impl<'a> AssocItemCollector<'a> {
) {
(
self.items,
if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) },
if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
self.diagnostics,
)
}
@ -662,11 +662,11 @@ impl<'a> AssocItemCollector<'a> {
}
}
self.attr_calls.push((ast_id, call_id));
self.macro_calls.push((ast_id, call_id));
let res =
self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
self.collect_macro_items(res, &|| loc.kind.clone());
self.collect_macro_items(res);
continue 'items;
}
Ok(_) => (),
@ -698,24 +698,22 @@ impl<'a> AssocItemCollector<'a> {
match item {
AssocItem::Function(id) => {
let item = &item_tree[id];
let def =
FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::TypeAlias(id) => {
let item = &item_tree[id];
let def =
TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::Const(id) => {
let item = &item_tree[id];
let Some(name) = item.name.clone() else { return };
let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((name, def.into()));
}
AssocItem::TypeAlias(id) => {
let item = &item_tree[id];
let def =
TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::MacroCall(call) => {
let file_id = self.expander.current_file_id();
let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
@ -745,11 +743,8 @@ impl<'a> AssocItemCollector<'a> {
Ok(Some(call_id)) => {
let res =
self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
ast_id: InFile::new(file_id, ast_id),
expand_to: hir_expand::ExpandTo::Items,
eager: None,
});
self.macro_calls.push((InFile::new(file_id, ast_id.upcast()), call_id));
self.collect_macro_items(res);
}
Ok(None) => (),
Err(_) => {
@ -768,39 +763,8 @@ impl<'a> AssocItemCollector<'a> {
}
}
fn collect_macro_items(
&mut self,
ExpandResult { value, err }: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>,
error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind,
) {
let Some((mark, parse)) = value else { return };
if let Some(err) = err {
let diag = match err {
// why is this reported here?
hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
DefDiagnostic::unresolved_proc_macro(
self.module_id.local_id,
error_call_kind(),
krate,
)
}
_ => DefDiagnostic::macro_error(
self.module_id.local_id,
error_call_kind(),
err.to_string(),
),
};
self.diagnostics.push(diag);
}
let errors = parse.errors();
if !errors.is_empty() {
self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
self.module_id.local_id,
error_call_kind(),
errors.into_boxed_slice(),
));
}
fn collect_macro_items(&mut self, res: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>) {
let Some((mark, _parse)) = res.value else { return };
let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
let item_tree = tree_id.item_tree(self.db);

View file

@ -1177,6 +1177,8 @@ pub mod fmt {
//- /main.rs crate:main deps:alloc,std
#![no_std]
extern crate alloc;
$0
//- /std.rs crate:std deps:alloc

View file

@ -20,7 +20,7 @@ use triomphe::Arc;
use crate::{
db::DefDatabase,
expander::Expander,
item_tree::{GenericsItemTreeNode, ItemTree},
item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
@ -339,6 +339,7 @@ impl GenericParamsCollector {
target: Either<TypeRef, LifetimeRef>,
) {
let bound = TypeBound::from_ast(lower_ctx, bound);
self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
let predicate = match (target, bound) {
(Either::Left(type_ref), bound) => match hrtb_lifetimes {
Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
@ -359,7 +360,24 @@ impl GenericParamsCollector {
self.where_predicates.push(predicate);
}
pub(crate) fn fill_implicit_impl_trait_args(
fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
for bounds in impl_bounds {
let param = TypeParamData {
name: None,
default: None,
provenance: TypeParamProvenance::ArgumentImplTrait,
};
let param_id = self.type_or_consts.alloc(param.into());
for bound in bounds {
self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
bound,
});
}
}
}
fn fill_implicit_impl_trait_args(
&mut self,
db: &dyn DefDatabase,
exp: &mut Lazy<(Arc<DefMap>, Expander), impl FnOnce() -> (Arc<DefMap>, Expander)>,
@ -456,56 +474,67 @@ impl GenericParams {
let cfg_options = &cfg_options[krate].cfg_options;
// Returns the generic parameters that are enabled under the current `#[cfg]` options
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let enabled_params =
|params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
// Therefore, make a first pass to check if all parameters are enabled and, if so,
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
let all_type_or_consts_enabled =
params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
let all_lifetimes_enabled =
params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter(|(idx, _)| enabled((*idx).into()))
.map(|(_, param)| param.clone())
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter(|(idx, _)| enabled((*idx).into()))
.map(|(_, param)| param.clone())
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
if all_type_or_consts_enabled && all_lifetimes_enabled {
params.clone()
} else {
Interned::new(GenericParams {
type_or_consts: all_type_or_consts_enabled
.then(|| params.type_or_consts.clone())
.unwrap_or_else(|| {
params
.type_or_consts
.iter()
.filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
lifetimes: all_lifetimes_enabled
.then(|| params.lifetimes.clone())
.unwrap_or_else(|| {
params
.lifetimes
.iter()
.filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
.map(|(_, param)| param.clone())
.collect()
}),
where_predicates: params.where_predicates.clone(),
})
}
};
fn id_to_generics<Id: GenericsItemTreeNode>(
db: &dyn DefDatabase,
id: impl for<'db> Lookup<
Database<'db> = dyn DefDatabase + 'db,
Data = impl ItemTreeLoc<Id = Id>,
>,
enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>,
) -> Interned<GenericParams> {
enabled_params: impl Fn(
&Interned<GenericParams>,
&ItemTree,
GenericModItem,
) -> Interned<GenericParams>,
) -> Interned<GenericParams>
where
FileItemTreeId<Id>: Into<GenericModItem>,
{
let id = id.lookup(db).item_tree_id();
let tree = id.item_tree(db);
let item = &tree[id.value];
enabled_params(item.generic_params(), &tree)
enabled_params(item.generic_params(), &tree, id.value.into())
}
match def {
@ -514,7 +543,8 @@ impl GenericParams {
let tree = loc.id.item_tree(db);
let item = &tree[loc.id.value];
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
let enabled_params =
enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
let module = loc.container.module(db);
let func_data = db.function_data(id);

View file

@ -136,15 +136,15 @@ impl From<ast::LiteralKind> for Literal {
Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
}
LiteralKind::ByteString(bs) => {
let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
let text = bs.value().map_or_else(|_| Default::default(), Box::from);
Literal::ByteString(text)
}
LiteralKind::String(s) => {
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
let text = s.value().map_or_else(|_| Default::default(), Box::from);
Literal::String(text)
}
LiteralKind::CString(s) => {
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
let text = s.value().map_or_else(|_| Default::default(), Box::from);
Literal::CString(text)
}
LiteralKind::Byte(b) => {

View file

@ -234,6 +234,14 @@ impl ItemScope {
self.impls.iter().copied()
}
pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
self.derive_macros.values().flat_map(|it| {
it.iter().flat_map(|it| it.derive_call_ids.iter().copied().flatten())
}),
)
}
pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
self.types.values().copied().filter_map(|(def, vis, _)| match def {
ModuleDefId::ModuleId(module) => Some((module, vis)),

View file

@ -29,6 +29,7 @@
//!
//! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
//! surface syntax.
#![allow(unexpected_cfgs)]
mod lower;
mod pretty;
@ -57,21 +58,21 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
db::DefDatabase,
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
generics::GenericParams,
path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
visibility::{RawVisibility, VisibilityExplicitness},
BlockId, Lookup,
BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
};
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct RawVisibilityId(u32);
impl RawVisibilityId {
pub const PUB: Self = RawVisibilityId(u32::max_value());
pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2);
pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3);
pub const PUB: Self = RawVisibilityId(u32::MAX);
pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
}
impl fmt::Debug for RawVisibilityId {
@ -293,8 +294,8 @@ pub enum AttrOwner {
Variant(FileItemTreeId<Variant>),
Field(Idx<Field>),
Param(Idx<Param>),
TypeOrConstParamData(Idx<TypeOrConstParamData>),
LifetimeParamData(Idx<LifetimeParamData>),
TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId),
LifetimeParamData(GenericModItem, LocalLifetimeParamId),
}
macro_rules! from_attrs {
@ -314,8 +315,6 @@ from_attrs!(
Variant(FileItemTreeId<Variant>),
Field(Idx<Field>),
Param(Idx<Param>),
TypeOrConstParamData(Idx<TypeOrConstParamData>),
LifetimeParamData(Idx<LifetimeParamData>),
);
/// Trait implemented by all nodes in the item tree.
@ -465,12 +464,49 @@ macro_rules! mod_items {
)+
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum GenericModItem {
$(
$(
#[cfg_attr(ignore_fragment, $generic_params)]
$typ(FileItemTreeId<$typ>),
)?
)+
}
impl From<GenericModItem> for ModItem {
fn from(id: GenericModItem) -> ModItem {
match id {
$(
$(
#[cfg_attr(ignore_fragment, $generic_params)]
GenericModItem::$typ(id) => ModItem::$typ(id),
)?
)+
}
}
}
impl From<GenericModItem> for AttrOwner {
fn from(t: GenericModItem) -> AttrOwner {
AttrOwner::ModItem(t.into())
}
}
$(
impl From<FileItemTreeId<$typ>> for ModItem {
fn from(id: FileItemTreeId<$typ>) -> ModItem {
ModItem::$typ(id)
}
}
$(
#[cfg_attr(ignore_fragment, $generic_params)]
impl From<FileItemTreeId<$typ>> for GenericModItem {
fn from(id: FileItemTreeId<$typ>) -> GenericModItem {
GenericModItem::$typ(id)
}
}
)?
)+
$(

View file

@ -4,6 +4,7 @@ use std::collections::hash_map::Entry;
use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId};
use la_arena::Arena;
use rustc_hash::FxHashMap;
use span::{AstIdMap, SyntaxContextId};
use syntax::{
ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
@ -16,11 +17,11 @@ use crate::{
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
item_tree::{
AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId,
Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias,
Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod,
ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs,
RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union,
Use, UseTree, UseTreeKind, Variant,
Fields, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, IdxRange,
Impl, ImportAlias, Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall,
MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path,
Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias,
TypeAlias, Union, Use, UseTree, UseTreeKind, Variant,
},
path::AssociatedTypeBinding,
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
@ -36,6 +37,8 @@ pub(super) struct Ctx<'a> {
db: &'a dyn DefDatabase,
tree: ItemTree,
source_ast_id_map: Arc<AstIdMap>,
generic_param_attr_buffer:
FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
body_ctx: crate::lower::LowerCtx<'a>,
}
@ -44,6 +47,7 @@ impl<'a> Ctx<'a> {
Self {
db,
tree: ItemTree::default(),
generic_param_attr_buffer: FxHashMap::default(),
source_ast_id_map: db.ast_id_map(file),
body_ctx: crate::lower::LowerCtx::new(db, file),
}
@ -56,6 +60,7 @@ impl<'a> Ctx<'a> {
pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
self.tree.top_level =
item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
}
@ -89,6 +94,7 @@ impl<'a> Ctx<'a> {
}
}
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
}
@ -117,6 +123,7 @@ impl<'a> Ctx<'a> {
}
}
assert!(self.generic_param_attr_buffer.is_empty());
self.tree
}
@ -185,10 +192,12 @@ impl<'a> Ctx<'a> {
let visibility = self.lower_visibility(strukt);
let name = strukt.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(strukt);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
let fields = self.lower_fields(&strukt.kind());
let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
let res = Struct { name, visibility, generic_params, fields, ast_id };
Some(id(self.data().structs.alloc(res)))
let id = id(self.data().structs.alloc(res));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
@ -252,28 +261,32 @@ impl<'a> Ctx<'a> {
let visibility = self.lower_visibility(union);
let name = union.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(union);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
let fields = match union.record_field_list() {
Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())),
};
let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
let res = Union { name, visibility, generic_params, fields, ast_id };
Some(id(self.data().unions.alloc(res)))
let id = id(self.data().unions.alloc(res));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
let visibility = self.lower_visibility(enum_);
let name = enum_.name()?.as_name();
let ast_id = self.source_ast_id_map.ast_id(enum_);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
let variants = match &enum_.variant_list() {
Some(variant_list) => self.lower_variants(variant_list),
None => {
FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
}
};
let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
let res = Enum { name, visibility, generic_params, variants, ast_id };
Some(id(self.data().enums.alloc(res)))
let id = id(self.data().enums.alloc(res));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
@ -414,7 +427,9 @@ impl<'a> Ctx<'a> {
flags,
};
Some(id(self.data().functions.alloc(res)))
let id = id(self.data().functions.alloc(res));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_type_alias(
@ -428,7 +443,9 @@ impl<'a> Ctx<'a> {
let ast_id = self.source_ast_id_map.ast_id(type_alias);
let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
Some(id(self.data().type_aliases.alloc(res)))
let id = id(self.data().type_aliases.alloc(res));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
@ -475,8 +492,6 @@ impl<'a> Ctx<'a> {
let name = trait_def.name()?.as_name();
let visibility = self.lower_visibility(trait_def);
let ast_id = self.source_ast_id_map.ast_id(trait_def);
let generic_params =
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
let is_auto = trait_def.auto_token().is_some();
let is_unsafe = trait_def.unsafe_token().is_some();
@ -487,8 +502,12 @@ impl<'a> Ctx<'a> {
.filter_map(|item_node| self.lower_assoc_item(&item_node))
.collect();
let generic_params =
self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
Some(id(self.data().traits.alloc(def)))
let id = id(self.data().traits.alloc(def));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_trait_alias(
@ -504,19 +523,18 @@ impl<'a> Ctx<'a> {
);
let alias = TraitAlias { name, visibility, generic_params, ast_id };
Some(id(self.data().trait_aliases.alloc(alias)))
let id = id(self.data().trait_aliases.alloc(alias));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
let ast_id = self.source_ast_id_map.ast_id(impl_def);
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
// FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
// as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
// equals itself.
let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
let is_negative = impl_def.excl_token().is_some();
let is_unsafe = impl_def.unsafe_token().is_some();
@ -527,9 +545,14 @@ impl<'a> Ctx<'a> {
.flat_map(|it| it.assoc_items())
.filter_map(|item| self.lower_assoc_item(&item))
.collect();
// Note that trait impls don't get implicit `Self` unlike traits, because here they are a
// type alias rather than a type parameter, so this is handled by the resolver.
let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
let res =
Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
Some(id(self.data().impls.alloc(res)))
let id = id(self.data().impls.alloc(res));
self.write_generic_params_attributes(id.into());
Some(id)
}
fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@ -616,11 +639,30 @@ impl<'a> Ctx<'a> {
id(self.data().extern_blocks.alloc(res))
}
fn write_generic_params_attributes(&mut self, parent: GenericModItem) {
self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| {
self.tree.attrs.insert(
match idx {
Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id),
Either::Right(id) => AttrOwner::LifetimeParamData(parent, id),
},
attrs,
);
})
}
fn lower_generic_params(
&mut self,
has_implicit_self: HasImplicitSelf,
node: &dyn ast::HasGenericParams,
) -> Interned<GenericParams> {
debug_assert!(self.generic_param_attr_buffer.is_empty(),);
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
param| {
let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
};
self.body_ctx.take_impl_traits_bounds();
let mut generics = GenericParamsCollector::default();
if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@ -635,28 +677,13 @@ impl<'a> Ctx<'a> {
);
// add super traits as bounds on Self
// i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
let self_param = TypeRef::Path(name![Self].into());
generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
generics.fill_bounds(
&self.body_ctx,
bounds,
Either::Left(TypeRef::Path(name![Self].into())),
);
}
let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
param| {
let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
// This is identical to the body of `Ctx::add_attrs()` but we can't call that here
// because it requires `&mut self` and the call to `generics.fill()` below also
// references `self`.
match self.tree.attrs.entry(match item {
Either::Right(id) => id.into(),
Either::Left(id) => id.into(),
}) {
Entry::Occupied(mut entry) => {
*entry.get_mut() = entry.get().merge(attrs);
}
Entry::Vacant(entry) => {
entry.insert(attrs);
}
}
};
generics.fill(&self.body_ctx, node, add_param_attrs);
Interned::new(generics.finish())

View file

@ -8,8 +8,8 @@ use crate::{
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
item_tree::{
AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields,
FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2,
MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, Interned, ItemTree,
Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union,
Use, UseTree, UseTreeKind, Variant,
},
@ -276,7 +276,7 @@ impl Printer<'_> {
w!(self, "extern \"{}\" ", abi);
}
w!(self, "fn {}", name.display(self.db.upcast()));
self.print_generic_params(explicit_generic_params);
self.print_generic_params(explicit_generic_params, it.into());
w!(self, "(");
if !params.is_empty() {
self.indented(|this| {
@ -316,7 +316,7 @@ impl Printer<'_> {
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "struct {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
self.print_fields_and_where_clause(fields, generic_params);
if matches!(fields, Fields::Record(_)) {
wln!(self);
@ -329,7 +329,7 @@ impl Printer<'_> {
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "union {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
self.print_fields_and_where_clause(fields, generic_params);
if matches!(fields, Fields::Record(_)) {
wln!(self);
@ -342,7 +342,7 @@ impl Printer<'_> {
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "enum {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for variant in FileItemTreeId::range_iter(variants.clone()) {
@ -394,7 +394,7 @@ impl Printer<'_> {
w!(self, "auto ");
}
w!(self, "trait {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
self.print_where_clause_and_opening_brace(generic_params);
self.indented(|this| {
for item in &**items {
@ -408,7 +408,7 @@ impl Printer<'_> {
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "trait {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
w!(self, " = ");
self.print_where_clause(generic_params);
w!(self, ";");
@ -429,7 +429,7 @@ impl Printer<'_> {
w!(self, "unsafe");
}
w!(self, "impl");
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
w!(self, " ");
if *is_negative {
w!(self, "!");
@ -453,7 +453,7 @@ impl Printer<'_> {
self.print_ast_id(ast_id.erase());
self.print_visibility(*visibility);
w!(self, "type {}", name.display(self.db.upcast()));
self.print_generic_params(generic_params);
self.print_generic_params(generic_params, it.into());
if !bounds.is_empty() {
w!(self, ": ");
self.print_type_bounds(bounds);
@ -525,7 +525,7 @@ impl Printer<'_> {
print_path(self.db, path, self).unwrap();
}
fn print_generic_params(&mut self, params: &GenericParams) {
fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
if params.is_empty() {
return;
}
@ -537,7 +537,7 @@ impl Printer<'_> {
w!(self, ", ");
}
first = false;
self.print_attrs_of(idx, " ");
self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
w!(self, "{}", lt.name.display(self.db.upcast()));
}
for (idx, x) in params.type_or_consts.iter() {
@ -545,7 +545,7 @@ impl Printer<'_> {
w!(self, ", ");
}
first = false;
self.print_attrs_of(idx, " ");
self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
match x {
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
Some(name) => w!(self, "{}", name.display(self.db.upcast())),

View file

@ -427,10 +427,18 @@ fn generics_with_attributes() {
check(
r#"
struct S<#[cfg(never)] T>;
struct S<A, B, #[cfg(never)] C>;
struct S<A, #[cfg(never)] B, C>;
"#,
expect![[r#"
// AstId: 1
pub(self) struct S<#[cfg(never)] T>;
// AstId: 2
pub(self) struct S<A, B, #[cfg(never)] C>;
// AstId: 3
pub(self) struct S<A, #[cfg(never)] B, C>;
"#]],
)
}

View file

@ -1,26 +1,34 @@
//! Context for lowering paths.
use std::cell::OnceCell;
use std::cell::{OnceCell, RefCell};
use hir_expand::{
span_map::{SpanMap, SpanMapRef},
AstId, HirFileId, InFile,
};
use intern::Interned;
use span::{AstIdMap, AstIdNode};
use syntax::ast;
use triomphe::Arc;
use crate::{db::DefDatabase, path::Path};
use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
pub struct LowerCtx<'a> {
pub db: &'a dyn DefDatabase,
file_id: HirFileId,
span_map: OnceCell<SpanMap>,
ast_id_map: OnceCell<Arc<AstIdMap>>,
impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
}
impl<'a> LowerCtx<'a> {
pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() }
LowerCtx {
db,
file_id,
span_map: OnceCell::new(),
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
}
}
pub fn with_span_map_cell(
@ -28,7 +36,13 @@ impl<'a> LowerCtx<'a> {
file_id: HirFileId,
span_map: OnceCell<SpanMap>,
) -> Self {
LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() }
LowerCtx {
db,
file_id,
span_map,
ast_id_map: OnceCell::new(),
impl_trait_bounds: RefCell::new(Vec::new()),
}
}
pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
@ -45,4 +59,12 @@ impl<'a> LowerCtx<'a> {
self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
)
}
pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
self.impl_trait_bounds.borrow_mut().push(bounds);
}
pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
self.impl_trait_bounds.take()
}
}

View file

@ -186,3 +186,33 @@ fn#0:1@45..47#0# foo#0:1@48..51#0#(#0:1@51..52#0#&#0:1@52..53#0#self#0:1@53..57#
}#0:1@76..77#0#"#]],
);
}
#[test]
fn attribute_macro_doc_desugaring() {
check(
r#"
//- proc_macros: identity
#[proc_macros::identity]
/// doc string \n with newline
/**
MultiLines Doc
MultiLines Doc
*/
#[doc = "doc attr"]
struct S;
"#,
expect![[r##"
#[proc_macros::identity]
/// doc string \n with newline
/**
MultiLines Doc
MultiLines Doc
*/
#[doc = "doc attr"]
struct S;
#[doc = " doc string \\n with newline"]
#[doc = "\n MultiLines Doc\n MultiLines Doc\n"]
#[doc = "doc attr"] struct S;"##]],
);
}

View file

@ -5,7 +5,7 @@
use std::{cmp::Ordering, iter, mem, ops::Not};
use base_db::{CrateId, Dependency, FileId};
use base_db::{CrateId, CrateOrigin, Dependency, FileId, LangCrateOrigin};
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{
@ -15,15 +15,13 @@ use hir_expand::{
builtin_fn_macro::find_builtin_macro,
name::{name, AsName, Name},
proc_macro::CustomProcMacroExpander,
ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
MacroDefId, MacroDefKind,
ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
};
use itertools::{izip, Itertools};
use la_arena::Idx;
use limit::Limit;
use rustc_hash::{FxHashMap, FxHashSet};
use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
use stdx::always;
use syntax::ast;
use triomphe::Arc;
@ -279,7 +277,8 @@ impl DefCollector<'_> {
fn seed_with_top_level(&mut self) {
let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered();
let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
let crate_graph = self.db.crate_graph();
let file_id = crate_graph[self.def_map.krate].root_file_id;
let item_tree = self.db.file_item_tree(file_id.into());
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
@ -288,19 +287,14 @@ impl DefCollector<'_> {
crate_data.proc_macro_loading_error = Some(e.clone());
}
for (name, dep) in &self.deps {
if dep.is_prelude() {
crate_data
.extern_prelude
.insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
}
}
let mut process = true;
// Process other crate-level attributes.
for attr in &*attrs {
if let Some(cfg) = attr.cfg() {
if self.cfg_options.check(&cfg) == Some(false) {
return;
process = false;
break;
}
}
let Some(attr_name) = attr.path.as_ident() else { continue };
@ -350,9 +344,38 @@ impl DefCollector<'_> {
}
}
crate_data.shrink_to_fit();
for (name, dep) in &self.deps {
if dep.is_prelude() {
// This is a bit confusing but the gist is that `no_core` and `no_std` remove the
// sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly
// constructed with them in place no matter what though, since at that point we
// don't do pre-configured attribute resolution yet.
// So here check if we are no_core / no_std and we are trying to add the
// corresponding dep from the sysroot
let skip = match crate_graph[dep.crate_id].origin {
CrateOrigin::Lang(LangCrateOrigin::Core) => {
crate_data.no_core && dep.is_sysroot()
}
CrateOrigin::Lang(LangCrateOrigin::Std) => {
crate_data.no_std && dep.is_sysroot()
}
_ => false,
};
if skip {
continue;
}
crate_data
.extern_prelude
.insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
}
}
self.inject_prelude();
if !process {
return;
}
ModCollector {
def_collector: self,
macro_depth: 0,
@ -362,6 +385,7 @@ impl DefCollector<'_> {
mod_dir: ModDir::root(),
}
.collect_in_top_module(item_tree.top_level_items());
Arc::get_mut(&mut self.def_map.data).unwrap().shrink_to_fit();
}
fn seed_with_inner(&mut self, tree_id: TreeId) {
@ -519,15 +543,12 @@ impl DefCollector<'_> {
let krate = if self.def_map.data.no_std {
name![core]
} else if self.def_map.extern_prelude().any(|(name, _)| *name == name![std]) {
name![std]
} else {
let std = name![std];
if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
std
} else {
// If `std` does not exist for some reason, fall back to core. This mostly helps
// keep r-a's own tests minimal.
name![core]
}
// If `std` does not exist for some reason, fall back to core. This mostly helps
// keep r-a's own tests minimal.
name![core]
};
let edition = match self.def_map.data.edition {
@ -1389,31 +1410,6 @@ impl DefCollector<'_> {
}
let file_id = macro_call_id.as_file();
// First, fetch the raw expansion result for purposes of error reporting. This goes through
// `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
// incrementality).
// FIXME: This kind of error fetching feels a bit odd?
let ExpandResult { value: errors, err } =
self.db.parse_macro_expansion_error(macro_call_id);
if let Some(err) = err {
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
let diag = match err {
// why is this reported here?
hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
always!(krate == loc.def.krate);
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
}
_ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
};
self.def_map.diagnostics.push(diag);
}
if !errors.is_empty() {
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
self.def_map.diagnostics.push(diag);
}
// Then, fetch and process the item tree. This will reuse the expansion result from above.
let item_tree = self.db.file_item_tree(file_id);

View file

@ -6,7 +6,7 @@ use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind};
use la_arena::Idx;
use syntax::{ast, SyntaxError};
use syntax::ast;
use crate::{
item_tree::{self, ItemTreeId},
@ -23,8 +23,6 @@ pub enum DefDiagnosticKind {
UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
MacroError { ast: MacroCallKind, message: String },
MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> },
UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
MalformedDerive { ast: AstId<ast::Adt>, id: usize },
@ -98,7 +96,7 @@ impl DefDiagnostic {
// FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
// yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
// struct loses all that information!
pub(crate) fn unresolved_proc_macro(
pub fn unresolved_proc_macro(
container: LocalModuleId,
ast: MacroCallKind,
krate: CrateId,
@ -106,25 +104,6 @@ impl DefDiagnostic {
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
}
pub(crate) fn macro_error(
container: LocalModuleId,
ast: MacroCallKind,
message: String,
) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } }
}
pub(crate) fn macro_expansion_parse_error(
container: LocalModuleId,
ast: MacroCallKind,
errors: Box<[SyntaxError]>,
) -> Self {
Self {
in_module: container,
kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors },
}
}
// FIXME: Whats the difference between this and unresolved_proc_macro
pub(crate) fn unresolved_macro_call(
container: LocalModuleId,

View file

@ -208,6 +208,13 @@ pub(super) fn lower_generic_args(
.and_then(|args| lower_generic_args(lower_ctx, args))
.map(Interned::new);
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
let type_ref = type_ref.inspect(|tr| {
tr.walk(&mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
});
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
l.bounds()
.map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))

View file

@ -1,5 +1,5 @@
//! Name resolution façade.
use std::{fmt, hash::BuildHasherDefault, mem};
use std::{fmt, hash::BuildHasherDefault, iter, mem};
use base_db::CrateId;
use hir_expand::{
@ -591,13 +591,13 @@ impl Resolver {
pub fn where_predicates_in_scope(
&self,
) -> impl Iterator<Item = &crate::generics::WherePredicate> {
) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
self.scopes()
.filter_map(|scope| match scope {
Scope::GenericParams { params, .. } => Some(params),
Scope::GenericParams { params, def } => Some((params, def)),
_ => None,
})
.flat_map(|params| params.where_predicates.iter())
.flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def)))
}
pub fn generic_def(&self) -> Option<GenericDefId> {

View file

@ -5,7 +5,7 @@ use base_db::CrateId;
use cfg::CfgExpr;
use either::Either;
use intern::Interned;
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct};
use smallvec::{smallvec, SmallVec};
use span::{Span, SyntaxContextId};
use syntax::unescape;
@ -239,7 +239,12 @@ impl Attr {
span,
})))
} else if let Some(tt) = ast.token_tree() {
let tree = syntax_node_to_token_tree(tt.syntax(), span_map, span);
let tree = syntax_node_to_token_tree(
tt.syntax(),
span_map,
span,
DocCommentDesugarMode::ProcMacro,
);
Some(Interned::new(AttrInput::TokenTree(Box::new(tree))))
} else {
None
@ -247,8 +252,18 @@ impl Attr {
Some(Attr { id, path, input, ctxt: span.ctx })
}
fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
let ctxt = tt.first()?.first_span().ctx;
fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
if matches!(tt,
[tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, .. })), ..]
if text == "unsafe"
) {
match tt.get(1) {
Some(tt::TokenTree::Subtree(subtree)) => tt = &subtree.token_trees,
_ => return None,
}
}
let first = &tt.first()?;
let ctxt = first.first_span().ctx;
let path_end = tt
.iter()
.position(|tt| {
@ -430,7 +445,7 @@ fn inner_attributes(
// Input subtree is: `(cfg, $(attr),+)`
// Split it up into a `cfg` subtree and the `attr` subtrees.
pub fn parse_cfg_attr_input(
fn parse_cfg_attr_input(
subtree: &Subtree,
) -> Option<(&[tt::TokenTree], impl Iterator<Item = &[tt::TokenTree]>)> {
let mut parts = subtree

View file

@ -1,6 +1,7 @@
//! Builtin derives.
use itertools::izip;
use mbe::DocCommentDesugarMode;
use rustc_hash::FxHashSet;
use span::{MacroCallId, Span};
use stdx::never;
@ -262,7 +263,12 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
match this {
Some(it) => {
param_type_set.insert(it.as_name());
mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)
mbe::syntax_node_to_token_tree(
it.syntax(),
tm,
call_site,
DocCommentDesugarMode::ProcMacro,
)
}
None => {
tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
@ -270,15 +276,27 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
}
};
let bounds = match &param {
ast::TypeOrConstParam::Type(it) => it
.type_bound_list()
.map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)),
ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| {
mbe::syntax_node_to_token_tree(
it.syntax(),
tm,
call_site,
DocCommentDesugarMode::ProcMacro,
)
}),
ast::TypeOrConstParam::Const(_) => None,
};
let ty = if let ast::TypeOrConstParam::Const(param) = param {
let ty = param
.ty()
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax(), tm, call_site))
.map(|ty| {
mbe::syntax_node_to_token_tree(
ty.syntax(),
tm,
call_site,
DocCommentDesugarMode::ProcMacro,
)
})
.unwrap_or_else(|| {
tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
});
@ -292,7 +310,14 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
let where_clause = if let Some(w) = where_clause {
w.predicates()
.map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
.map(|it| {
mbe::syntax_node_to_token_tree(
it.syntax(),
tm,
call_site,
DocCommentDesugarMode::ProcMacro,
)
})
.collect()
} else {
vec![]
@ -322,7 +347,14 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name();
param_type_set.contains(&name).then_some(p)
})
.map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
.map(|it| {
mbe::syntax_node_to_token_tree(
it.syntax(),
tm,
call_site,
DocCommentDesugarMode::ProcMacro,
)
})
.collect();
let name_token = name_to_token(tm, name)?;
Ok(BasicAdtInfo { name: name_token, shape, param_types, where_clause, associated_types })

View file

@ -441,21 +441,21 @@ fn unquote_str(lit: &tt::Literal) -> Option<(String, Span)> {
let span = lit.span;
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::String::cast(lit)?;
token.value().map(|it| (it.into_owned(), span))
token.value().ok().map(|it| (it.into_owned(), span))
}
fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> {
let span = lit.span;
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::Char::cast(lit)?;
token.value().zip(Some(span))
token.value().ok().zip(Some(span))
}
fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec<u8>, Span)> {
let span = lit.span;
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::ByteString::cast(lit)?;
token.value().map(|it| (it.into_owned(), span))
token.value().ok().map(|it| (it.into_owned(), span))
}
fn compile_error_expand(

View file

@ -3,7 +3,7 @@
use base_db::{salsa, CrateId, FileId, SourceDatabase};
use either::Either;
use limit::Limit;
use mbe::{syntax_node_to_token_tree, MatchedArmIndex};
use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, MatchedArmIndex};
use rustc_hash::FxHashSet;
use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
@ -132,7 +132,7 @@ pub trait ExpandDatabase: SourceDatabase {
fn parse_macro_expansion_error(
&self,
macro_call: MacroCallId,
) -> ExpandResult<Box<[SyntaxError]>>;
) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
}
/// This expands the given macro call, but with different arguments. This is
@ -156,11 +156,25 @@ pub fn expand_speculative(
// Build the subtree and token mapping for the speculative args
let (mut tt, undo_info) = match loc.kind {
MacroCallKind::FnLike { .. } => (
mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
mbe::syntax_node_to_token_tree(
speculative_args,
span_map,
span,
if loc.def.is_proc_macro() {
DocCommentDesugarMode::ProcMacro
} else {
DocCommentDesugarMode::Mbe
},
),
SyntaxFixupUndoInfo::NONE,
),
MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
mbe::syntax_node_to_token_tree(
speculative_args,
span_map,
span,
DocCommentDesugarMode::ProcMacro,
),
SyntaxFixupUndoInfo::NONE,
),
MacroCallKind::Derive { derive_attr_index: index, .. }
@ -176,7 +190,12 @@ pub fn expand_speculative(
let censor_cfg =
cfg_process::process_cfg_attrs(db, speculative_args, &loc).unwrap_or_default();
let mut fixups = fixup::fixup_syntax(span_map, speculative_args, span);
let mut fixups = fixup::fixup_syntax(
span_map,
speculative_args,
span,
DocCommentDesugarMode::ProcMacro,
);
fixups.append.retain(|it, _| match it {
syntax::NodeOrToken::Token(_) => true,
it => !censor.contains(it) && !censor_cfg.contains(it),
@ -191,6 +210,7 @@ pub fn expand_speculative(
fixups.append,
fixups.remove,
span,
DocCommentDesugarMode::ProcMacro,
),
fixups.undo_info,
)
@ -212,7 +232,12 @@ pub fn expand_speculative(
}?;
match attr.token_tree() {
Some(token_tree) => {
let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map, span);
let mut tree = syntax_node_to_token_tree(
token_tree.syntax(),
span_map,
span,
DocCommentDesugarMode::ProcMacro,
);
tree.delimiter = tt::Delimiter::invisible_spanned(span);
Some(tree)
@ -332,9 +357,14 @@ fn parse_macro_expansion(
fn parse_macro_expansion_error(
db: &dyn ExpandDatabase,
macro_call_id: MacroCallId,
) -> ExpandResult<Box<[SyntaxError]>> {
db.parse_macro_expansion(MacroFileId { macro_call_id })
.map(|it| it.0.errors().into_boxed_slice())
) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>> {
let e: ExpandResult<Arc<[SyntaxError]>> =
db.parse_macro_expansion(MacroFileId { macro_call_id }).map(|it| Arc::from(it.0.errors()));
if e.value.is_empty() && e.err.is_none() {
None
} else {
Some(Arc::new(e))
}
}
pub(crate) fn parse_with_map(
@ -432,7 +462,16 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
return dummy_tt(kind);
}
let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), span);
let mut tt = mbe::syntax_node_to_token_tree(
tt.syntax(),
map.as_ref(),
span,
if loc.def.is_proc_macro() {
DocCommentDesugarMode::ProcMacro
} else {
DocCommentDesugarMode::Mbe
},
);
if loc.def.is_proc_macro() {
// proc macros expect their inputs without parentheses, MBEs expect it with them included
tt.delimiter.kind = tt::DelimiterKind::Invisible;
@ -469,7 +508,8 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
let (mut tt, undo_info) = {
let syntax = item_node.syntax();
let censor_cfg = cfg_process::process_cfg_attrs(db, syntax, &loc).unwrap_or_default();
let mut fixups = fixup::fixup_syntax(map.as_ref(), syntax, span);
let mut fixups =
fixup::fixup_syntax(map.as_ref(), syntax, span, DocCommentDesugarMode::ProcMacro);
fixups.append.retain(|it, _| match it {
syntax::NodeOrToken::Token(_) => true,
it => !censor.contains(it) && !censor_cfg.contains(it),
@ -484,6 +524,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
fixups.append,
fixups.remove,
span,
DocCommentDesugarMode::ProcMacro,
),
fixups.undo_info,
)

View file

@ -2,6 +2,7 @@
use std::sync::OnceLock;
use base_db::{CrateId, VersionReq};
use mbe::DocCommentDesugarMode;
use span::{Edition, MacroCallId, Span, SyntaxContextId};
use stdx::TupleExt;
use syntax::{ast, AstNode};
@ -158,6 +159,7 @@ impl DeclarativeMacroExpander {
map.span_for_range(
macro_rules.macro_rules_token().unwrap().text_range(),
),
DocCommentDesugarMode::Mbe,
);
mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars)
@ -175,6 +177,7 @@ impl DeclarativeMacroExpander {
arg.syntax(),
map.as_ref(),
map.span_for_range(macro_def.macro_token().unwrap().text_range()),
DocCommentDesugarMode::Mbe,
);
mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)

View file

@ -19,6 +19,7 @@
//!
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
use base_db::CrateId;
use mbe::DocCommentDesugarMode;
use span::SyntaxContextId;
use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent};
use triomphe::Arc;
@ -80,7 +81,12 @@ pub fn expand_eager_macro_input(
return ExpandResult { value: None, err };
};
let mut subtree = mbe::syntax_node_to_token_tree(&expanded_eager_input, arg_map, span);
let mut subtree = mbe::syntax_node_to_token_tree(
&expanded_eager_input,
arg_map,
span,
DocCommentDesugarMode::Mbe,
);
subtree.delimiter.kind = crate::tt::DelimiterKind::Invisible;

View file

@ -1,6 +1,7 @@
//! To make attribute macros work reliably when typing, we need to take care to
//! fix up syntax errors in the code we're passing to them.
use mbe::DocCommentDesugarMode;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::SmallVec;
use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER};
@ -49,6 +50,7 @@ pub(crate) fn fixup_syntax(
span_map: SpanMapRef<'_>,
node: &SyntaxNode,
call_site: Span,
mode: DocCommentDesugarMode,
) -> SyntaxFixups {
let mut append = FxHashMap::<SyntaxElement, _>::default();
let mut remove = FxHashSet::<SyntaxElement>::default();
@ -70,7 +72,7 @@ pub(crate) fn fixup_syntax(
if can_handle_error(&node) && has_error_to_handle(&node) {
remove.insert(node.clone().into());
// the node contains an error node, we have to completely replace it by something valid
let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site);
let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site, mode);
let idx = original.len() as u32;
original.push(original_tree);
let span = span_map.span_for_range(node_range);
@ -360,6 +362,7 @@ fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
mod tests {
use base_db::FileId;
use expect_test::{expect, Expect};
use mbe::DocCommentDesugarMode;
use syntax::TextRange;
use triomphe::Arc;
@ -402,6 +405,7 @@ mod tests {
span_map.as_ref(),
&parsed.syntax_node(),
span_map.span_for_range(TextRange::empty(0.into())),
DocCommentDesugarMode::Mbe,
);
let mut tt = mbe::syntax_node_to_token_tree_modified(
&parsed.syntax_node(),
@ -409,6 +413,7 @@ mod tests {
fixups.append,
fixups.remove,
span_map.span_for_range(TextRange::empty(0.into())),
DocCommentDesugarMode::Mbe,
);
let actual = format!("{tt}\n");
@ -436,6 +441,7 @@ mod tests {
&parsed.syntax_node(),
span_map.as_ref(),
span_map.span_for_range(TextRange::empty(0.into())),
DocCommentDesugarMode::Mbe,
);
assert!(
check_subtree_eq(&tt, &original_as_tt),

View file

@ -132,13 +132,13 @@ pub enum ExpandError {
MacroDefinition,
Mbe(mbe::ExpandError),
RecursionOverflow,
Other(Box<Box<str>>),
ProcMacroPanic(Box<Box<str>>),
Other(Arc<Box<str>>),
ProcMacroPanic(Arc<Box<str>>),
}
impl ExpandError {
pub fn other(msg: impl Into<Box<str>>) -> Self {
ExpandError::Other(Box::new(msg.into()))
ExpandError::Other(Arc::new(msg.into()))
}
}

View file

@ -8,6 +8,7 @@ use rustc_hash::FxHashMap;
use span::Span;
use stdx::never;
use syntax::SmolStr;
use triomphe::Arc;
use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
@ -157,7 +158,7 @@ impl CustomProcMacroExpander {
ProcMacroExpansionError::System(text)
| ProcMacroExpansionError::Panic(text) => ExpandResult::new(
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
ExpandError::ProcMacroPanic(Box::new(text.into_boxed_str())),
ExpandError::ProcMacroPanic(Arc::new(text.into_boxed_str())),
),
},
}

View file

@ -806,7 +806,7 @@ pub(crate) fn impl_datum_query(
krate: CrateId,
impl_id: ImplId,
) -> Arc<ImplDatum> {
let _p = tracing::span!(tracing::Level::INFO, "impl_datum").entered();
let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered();
debug!("impl_datum {:?}", impl_id);
let impl_: hir_def::ImplId = from_chalk(db, impl_id);
impl_def_datum(db, krate, impl_id, impl_)

View file

@ -27,6 +27,7 @@ pub trait TyExt {
fn is_scalar(&self) -> bool;
fn is_floating_point(&self) -> bool;
fn is_never(&self) -> bool;
fn is_str(&self) -> bool;
fn is_unknown(&self) -> bool;
fn contains_unknown(&self) -> bool;
fn is_ty_var(&self) -> bool;
@ -87,6 +88,10 @@ impl TyExt for Ty {
matches!(self.kind(Interner), TyKind::Never)
}
fn is_str(&self) -> bool {
matches!(self.kind(Interner), TyKind::Str)
}
fn is_unknown(&self) -> bool {
matches!(self.kind(Interner), TyKind::Error)
}

View file

@ -797,8 +797,20 @@ impl HirDisplay for Ty {
c.hir_fmt(f)?;
write!(f, "]")?;
}
TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
if matches!(self.kind(Interner), TyKind::Raw(..)) {
kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => {
if let TyKind::Ref(_, l, _) = kind {
f.write_char('&')?;
if cfg!(test) {
// rendering these unconditionally is probably too much (at least for inlay
// hints) so we gate it to testing only for the time being
l.hir_fmt(f)?;
f.write_char(' ')?;
}
match m {
Mutability::Not => (),
Mutability::Mut => f.write_str("mut ")?,
}
} else {
write!(
f,
"*{}",
@ -807,15 +819,6 @@ impl HirDisplay for Ty {
Mutability::Mut => "mut ",
}
)?;
} else {
write!(
f,
"&{}",
match m {
Mutability::Not => "",
Mutability::Mut => "mut ",
}
)?;
}
// FIXME: all this just to decide whether to use parentheses...
@ -1330,7 +1333,18 @@ fn hir_fmt_generics(
}
let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
if !parameters_to_write.is_empty() {
// FIXME: Remote this
// most of our lifetimes will be errors as we lack elision and inference
// so don't render them for now
let only_err_lifetimes = !cfg!(test)
&& parameters_to_write.iter().all(|arg| {
matches!(
arg.data(Interner),
chalk_ir::GenericArgData::Lifetime(it) if *it.data(Interner) == LifetimeData::Error
)
});
if !parameters_to_write.is_empty() && !only_err_lifetimes {
write!(f, "<")?;
hir_fmt_generic_arguments(f, parameters_to_write)?;
write!(f, ">")?;
@ -1403,6 +1417,18 @@ fn hir_fmt_generic_arguments(
None => (parameters, &[][..]),
};
for generic_arg in lifetimes.iter().chain(ty_or_const) {
// FIXME: Remove this
// most of our lifetimes will be errors as we lack elision and inference
// so don't render them for now
if !cfg!(test)
&& matches!(
generic_arg.lifetime(Interner),
Some(l) if ***l.interned() == LifetimeData::Error
)
{
continue;
}
if !first {
write!(f, ", ")?;
}
@ -1728,9 +1754,9 @@ impl HirDisplay for LifetimeData {
LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
LifetimeData::InferenceVar(_) => write!(f, "_"),
LifetimeData::Static => write!(f, "'static"),
LifetimeData::Error => write!(f, "'{{error}}"),
LifetimeData::Erased => Ok(()),
LifetimeData::Phantom(_, _) => Ok(()),
LifetimeData::Error => write!(f, "'?"),
LifetimeData::Erased => write!(f, "'<erased>"),
LifetimeData::Phantom(void, _) => match *void {},
}
}
}

View file

@ -198,6 +198,7 @@ pub enum InferenceDiagnostic {
NoSuchField {
field: ExprOrPatId,
private: bool,
variant: VariantId,
},
PrivateField {
expr: ExprId,

View file

@ -563,6 +563,7 @@ impl InferenceContext<'_> {
InferenceDiagnostic::NoSuchField {
field: field.expr.into(),
private: true,
variant: def,
},
);
}
@ -572,6 +573,7 @@ impl InferenceContext<'_> {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
field: field.expr.into(),
private: false,
variant: def,
});
None
}

View file

@ -177,6 +177,7 @@ impl InferenceContext<'_> {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
field: inner.into(),
private: true,
variant: def,
});
}
let f = field_types[local_id].clone();
@ -190,6 +191,7 @@ impl InferenceContext<'_> {
self.push_diagnostic(InferenceDiagnostic::NoSuchField {
field: inner.into(),
private: false,
variant: def,
});
self.err_ty()
}

View file

@ -345,51 +345,47 @@ impl<'a> TyLoweringContext<'a> {
}
ImplTraitLoweringState::Param(counter) => {
let idx = counter.get();
// FIXME we're probably doing something wrong here
// Count the number of `impl Trait` things that appear within our bounds.
// Since t hose have been emitted as implicit type args already.
counter.set(idx + count_impl_traits(type_ref) as u16);
if let Some(generics) = self.generics() {
let param = generics
.iter()
.filter(|(_, data)| {
matches!(
data,
GenericParamDataRef::TypeParamData(data)
if data.provenance == TypeParamProvenance::ArgumentImplTrait
)
})
.nth(idx as usize)
.map_or(TyKind::Error, |(id, _)| {
if let GenericParamId::TypeParamId(id) = id {
TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
} else {
// we just filtered them out
unreachable!("Unexpected lifetime or const argument");
}
});
param.intern(Interner)
} else {
TyKind::Error.intern(Interner)
}
let kind = self
.generics()
.expect("param impl trait lowering must be in a generic def")
.iter()
.filter_map(|(id, data)| match (id, data) {
(
GenericParamId::TypeParamId(id),
GenericParamDataRef::TypeParamData(data),
) if data.provenance == TypeParamProvenance::ArgumentImplTrait => {
Some(id)
}
_ => None,
})
.nth(idx as usize)
.map_or(TyKind::Error, |id| {
TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
});
kind.intern(Interner)
}
ImplTraitLoweringState::Variable(counter) => {
let idx = counter.get();
// FIXME we're probably doing something wrong here
// Count the number of `impl Trait` things that appear within our bounds.
// Since t hose have been emitted as implicit type args already.
counter.set(idx + count_impl_traits(type_ref) as u16);
let (
_parent_params,
self_params,
list_params,
type_params,
const_params,
_impl_trait_params,
_lifetime_params,
) = if let Some(generics) = self.generics() {
generics.provenance_split()
} else {
(0, 0, 0, 0, 0, 0)
};
) = self
.generics()
.expect("variable impl trait lowering must be in a generic def")
.provenance_split();
TyKind::BoundVar(BoundVar::new(
self.in_binders,
idx as usize + self_params + list_params + const_params,
idx as usize + self_params + type_params + const_params,
))
.intern(Interner)
}
@ -1010,6 +1006,7 @@ impl<'a> TyLoweringContext<'a> {
pub(crate) fn lower_where_predicate<'b>(
&'b self,
where_predicate: &'b WherePredicate,
&def: &GenericDefId,
ignore_bindings: bool,
) -> impl Iterator<Item = QuantifiedWhereClause> + 'b {
match where_predicate {
@ -1018,7 +1015,6 @@ impl<'a> TyLoweringContext<'a> {
let self_ty = match target {
WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
&WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
let def = self.resolver.generic_def().expect("generics in scope");
let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
match self.type_param_mode {
ParamLoweringMode::Placeholder => {
@ -1056,23 +1052,7 @@ impl<'a> TyLoweringContext<'a> {
let clause = match bound.as_ref() {
TypeBound::Path(path, TraitBoundModifier::None) => {
trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
trait_ref
.clone()
.filter(|tr| {
// ignore `T: Drop` or `T: Destruct` bounds.
// - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement.
// (So ideally, we'd only ignore `~const Drop` here)
// - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until
// the builtin impls are supported by Chalk, we ignore them here.
if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) {
if matches!(lang, LangItem::Drop | LangItem::Destruct) {
return false;
}
}
true
})
.map(WhereClause::Implemented)
.map(crate::wrap_empty_binders)
trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
}
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
let sized_trait = self
@ -1166,84 +1146,77 @@ impl<'a> TyLoweringContext<'a> {
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
);
if let Some(type_ref) = &binding.type_ref {
if let (
TypeRef::ImplTrait(bounds),
ImplTraitLoweringState::Param(_)
| ImplTraitLoweringState::Variable(_)
| ImplTraitLoweringState::Disallowed,
) = (type_ref, &self.impl_trait_mode)
{
for bound in bounds {
predicates.extend(
self.lower_type_bound(
bound,
TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
.intern(Interner),
false,
),
);
match (type_ref, &self.impl_trait_mode) {
(TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
(
_,
ImplTraitLoweringState::Disallowed | ImplTraitLoweringState::Opaque(_),
) => {
let ty = self.lower_ty(type_ref);
let alias_eq =
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
predicates
.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
}
} else {
let ty = 'ty: {
if matches!(
self.impl_trait_mode,
ImplTraitLoweringState::Param(_)
| ImplTraitLoweringState::Variable(_)
) {
// Find the generic index for the target of our `bound`
let target_param_idx = self
.resolver
.where_predicates_in_scope()
.find_map(|p| match p {
WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(idx),
bound: b,
} if b == bound => Some(idx),
_ => None,
});
if let Some(target_param_idx) = target_param_idx {
let mut counter = 0;
let generics = self.generics().expect("generics in scope");
for (idx, data) in generics.params.type_or_consts.iter() {
// Count the number of `impl Trait` things that appear before
// the target of our `bound`.
// Our counter within `impl_trait_mode` should be that number
// to properly lower each types within `type_ref`
if data.type_param().is_some_and(|p| {
p.provenance == TypeParamProvenance::ArgumentImplTrait
}) {
counter += 1;
}
if idx == *target_param_idx {
break;
}
(
_,
ImplTraitLoweringState::Param(_) | ImplTraitLoweringState::Variable(_),
) => {
// Find the generic index for the target of our `bound`
let target_param_idx = self
.resolver
.where_predicates_in_scope()
.find_map(|(p, _)| match p {
WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(idx),
bound: b,
} if b == bound => Some(idx),
_ => None,
});
let ty = if let Some(target_param_idx) = target_param_idx {
let mut counter = 0;
let generics = self.generics().expect("generics in scope");
for (idx, data) in generics.params.type_or_consts.iter() {
// Count the number of `impl Trait` things that appear before
// the target of our `bound`.
// Our counter within `impl_trait_mode` should be that number
// to properly lower each types within `type_ref`
if data.type_param().is_some_and(|p| {
p.provenance == TypeParamProvenance::ArgumentImplTrait
}) {
counter += 1;
}
let mut ext = TyLoweringContext::new_maybe_unowned(
self.db,
self.resolver,
self.owner,
)
.with_type_param_mode(self.type_param_mode);
match &self.impl_trait_mode {
ImplTraitLoweringState::Param(_) => {
ext.impl_trait_mode =
ImplTraitLoweringState::Param(Cell::new(counter));
}
ImplTraitLoweringState::Variable(_) => {
ext.impl_trait_mode = ImplTraitLoweringState::Variable(
Cell::new(counter),
);
}
_ => unreachable!(),
if idx == *target_param_idx {
break;
}
break 'ty ext.lower_ty(type_ref);
}
}
self.lower_ty(type_ref)
};
let alias_eq =
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
let mut ext = TyLoweringContext::new_maybe_unowned(
self.db,
self.resolver,
self.owner,
)
.with_type_param_mode(self.type_param_mode);
match &self.impl_trait_mode {
ImplTraitLoweringState::Param(_) => {
ext.impl_trait_mode =
ImplTraitLoweringState::Param(Cell::new(counter));
}
ImplTraitLoweringState::Variable(_) => {
ext.impl_trait_mode =
ImplTraitLoweringState::Variable(Cell::new(counter));
}
_ => unreachable!(),
}
ext.lower_ty(type_ref)
} else {
self.lower_ty(type_ref)
};
let alias_eq =
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
predicates
.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
}
}
}
for bound in binding.bounds.iter() {
@ -1338,11 +1311,10 @@ impl<'a> TyLoweringContext<'a> {
bounds,
lifetime: match lifetime {
Some(it) => match it.bound_var(Interner) {
Some(bound_var) => LifetimeData::BoundVar(BoundVar::new(
DebruijnIndex::INNERMOST,
bound_var.index,
))
.intern(Interner),
Some(bound_var) => bound_var
.shifted_out_to(DebruijnIndex::new(2))
.map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner))
.unwrap_or(it),
None => it,
},
None => static_lifetime(),
@ -1410,16 +1382,6 @@ impl<'a> TyLoweringContext<'a> {
}
}
fn count_impl_traits(type_ref: &TypeRef) -> usize {
let mut count = 0;
type_ref.walk(&mut |type_ref| {
if matches!(type_ref, TypeRef::ImplTrait(_)) {
count += 1;
}
});
count
}
/// Build the signature of a callable item (function, struct or enum variant).
pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
match def {
@ -1438,6 +1400,17 @@ pub fn associated_type_shorthand_candidates<R>(
named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
}
// FIXME: This does not handle macros!
fn count_impl_traits(type_ref: &TypeRef) -> usize {
let mut count = 0;
type_ref.walk(&mut |type_ref| {
if matches!(type_ref, TypeRef::ImplTrait(_)) {
count += 1;
}
});
count
}
fn named_associated_type_shorthand_candidates<R>(
db: &dyn HirDatabase,
// If the type parameter is defined in an impl and we're in a method, there
@ -1575,7 +1548,7 @@ pub(crate) fn generic_predicates_for_param_query(
let generics = generics(db.upcast(), def);
// we have to filter out all other predicates *first*, before attempting to lower them
let predicate = |pred: &&_| match pred {
let predicate = |(pred, &def): &(&_, _)| match pred {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound, .. } => {
let invalid_target = match target {
@ -1617,8 +1590,8 @@ pub(crate) fn generic_predicates_for_param_query(
let mut predicates: Vec<_> = resolver
.where_predicates_in_scope()
.filter(predicate)
.flat_map(|pred| {
ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
.flat_map(|(pred, def)| {
ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
})
.collect();
@ -1671,8 +1644,8 @@ pub(crate) fn trait_environment_query(
};
let mut traits_in_scope = Vec::new();
let mut clauses = Vec::new();
for pred in resolver.where_predicates_in_scope() {
for pred in ctx.lower_where_predicate(pred, false) {
for (pred, def) in resolver.where_predicates_in_scope() {
for pred in ctx.lower_where_predicate(pred, def, false) {
if let WhereClause::Implemented(tr) = &pred.skip_binders() {
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
}
@ -1726,8 +1699,8 @@ pub(crate) fn generic_predicates_query(
let mut predicates = resolver
.where_predicates_in_scope()
.flat_map(|pred| {
ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
.flat_map(|(pred, def)| {
ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
})
.collect::<Vec<_>>();

View file

@ -368,7 +368,7 @@ pub(crate) fn incoherent_inherent_impl_crates(
krate: CrateId,
fp: TyFingerprint,
) -> SmallVec<[CrateId; 2]> {
let _p = tracing::span!(tracing::Level::INFO, "inherent_impl_crates_query").entered();
let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered();
let mut res = SmallVec::new();
let crate_graph = db.crate_graph();

View file

@ -428,6 +428,17 @@ impl MirEvalError {
}
Ok(())
}
pub fn is_panic(&self) -> Option<&str> {
let mut err = self;
while let MirEvalError::InFunction(e, _) = err {
err = e;
}
match err {
MirEvalError::Panic(msg) => Some(msg),
_ => None,
}
}
}
impl std::fmt::Debug for MirEvalError {
@ -1138,7 +1149,7 @@ impl Evaluator<'_> {
let mut ty = self.operand_ty(lhs, locals)?;
while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
ty = z.clone();
let size = if ty.kind(Interner) == &TyKind::Str {
let size = if ty.is_str() {
if *op != BinOp::Eq {
never!("Only eq is builtin for `str`");
}

View file

@ -49,6 +49,7 @@ impl Evaluator<'_> {
if self.not_special_fn_cache.borrow().contains(&def) {
return Ok(false);
}
let function_data = self.db.function_data(def);
let is_intrinsic = match &function_data.abi {
Some(abi) => *abi == Interned::new_str("rust-intrinsic"),
@ -131,9 +132,7 @@ impl Evaluator<'_> {
return Ok(true);
}
if let Some(it) = self.detect_lang_function(def) {
let arg_bytes =
args.iter().map(|it| Ok(it.get(self)?.to_owned())).collect::<Result<Vec<_>>>()?;
let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?;
let result = self.exec_lang_item(it, generic_args, args, locals, span)?;
destination.write_from_bytes(self, &result)?;
return Ok(true);
}
@ -311,16 +310,20 @@ impl Evaluator<'_> {
fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
use LangItem::*;
let candidate = self.db.lang_attr(def.into())?;
let attrs = self.db.attrs(def.into());
if attrs.by_key("rustc_const_panic_str").exists() {
// `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
return Some(LangItem::BeginPanic);
}
let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?;
// We want to execute these functions with special logic
// `PanicFmt` is not detected here as it's redirected later.
if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
return Some(candidate);
}
if self.db.attrs(def.into()).by_key("rustc_const_panic_str").exists() {
// `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
return Some(LangItem::BeginPanic);
}
None
}
@ -328,18 +331,52 @@ impl Evaluator<'_> {
&mut self,
it: LangItem,
generic_args: &Substitution,
args: &[Vec<u8>],
args: &[IntervalAndTy],
locals: &Locals,
span: MirSpan,
) -> Result<Vec<u8>> {
use LangItem::*;
let mut args = args.iter();
match it {
BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_owned())),
BeginPanic => {
let mut arg = args
.next()
.ok_or(MirEvalError::InternalError(
"argument of BeginPanic is not provided".into(),
))?
.clone();
while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) {
if ty.is_str() {
let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size());
let len = from_bytes!(usize, metadata);
return {
Err(MirEvalError::Panic(
std::str::from_utf8(
self.read_memory(Address::from_bytes(pointee)?, len)?,
)
.unwrap()
.to_owned(),
))
};
}
let size = self.size_of_sized(ty, locals, "begin panic arg")?;
let pointee = arg.interval.get(self)?;
arg = IntervalAndTy {
interval: Interval::new(Address::from_bytes(pointee)?, size),
ty: ty.clone(),
};
}
Err(MirEvalError::Panic(format!(
"unknown-panic-payload: {:?}",
arg.ty.kind(Interner)
)))
}
SliceLen => {
let arg = args.next().ok_or(MirEvalError::InternalError(
"argument of <[T]>::len() is not provided".into(),
))?;
let arg = arg.get(self)?;
let ptr_size = arg.len() / 2;
Ok(arg[ptr_size..].into())
}
@ -353,6 +390,7 @@ impl Evaluator<'_> {
let arg = args.next().ok_or(MirEvalError::InternalError(
"argument of drop_in_place is not provided".into(),
))?;
let arg = arg.interval.get(self)?.to_owned();
self.run_drop_glue_deep(
ty.clone(),
locals,

View file

@ -31,6 +31,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
db.trait_environment(func_id.into()),
)
.map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
let (result, output) = interpret_mir(db, body, false, None);
result?;
Ok((output.stdout().into_owned(), output.stderr().into_owned()))
@ -72,6 +73,13 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr
}
}
fn check_panic(ra_fixture: &str, expected_panic: &str) {
let (db, file_ids) = TestDB::with_many_files(ra_fixture);
let file_id = *file_ids.last().unwrap();
let e = eval_main(&db, file_id).unwrap_err();
assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic);
}
#[test]
fn function_with_extern_c_abi() {
check_pass(
@ -87,6 +95,43 @@ fn main() {
);
}
#[test]
fn panic_fmt() {
// panic!
// -> panic_2021 (builtin macro redirection)
// -> #[lang = "panic_fmt"] core::panicking::panic_fmt (hooked by CTFE for redirection)
// -> core::panicking::const_panic_fmt
// -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
// -> Err(ConstEvalError::Panic)
check_panic(
r#"
//- minicore: fmt, panic
fn main() {
panic!("hello, world!");
}
"#,
"hello, world!",
);
}
#[test]
fn panic_display() {
// panic!
// -> panic_2021 (builtin macro redirection)
// -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
// -> Err(ConstEvalError::Panic)
check_panic(
r#"
//- minicore: fmt, panic
fn main() {
panic!("{}", "hello, world!");
}
"#,
"hello, world!",
);
}
#[test]
fn drop_basic() {
check_pass(

View file

@ -186,7 +186,7 @@ fn test() {
let x = match 1 {
1 => t as *mut i32,
2 => t as &i32,
//^^^^^^^^^ expected *mut i32, got &i32
//^^^^^^^^^ expected *mut i32, got &'? i32
_ => t as *const i32,
// ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
@ -307,7 +307,7 @@ fn test() {
let foo = Foo;
//^^^ type: Foo<{unknown}>
let _: &u32 = &Foo;
//^^^^ expected &u32, got &Foo<{unknown}>
//^^^^ expected &'? u32, got &'? Foo<{unknown}>
}",
);
}
@ -544,9 +544,9 @@ struct Bar<T>(Foo<T>);
fn test() {
let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
//^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]>
//^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]>
let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
//^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
//^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]>
}
"#,
);
@ -562,7 +562,7 @@ trait Foo {}
fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
let _: &dyn Foo = &f;
let _: &dyn Foo = g;
//^ expected &dyn Foo, got &impl Foo + ?Sized
//^ expected &'? dyn Foo, got &'? impl Foo + ?Sized
}
"#,
);
@ -828,11 +828,11 @@ struct V<T> { t: T }
fn main() {
let a: V<&dyn Tr>;
(a,) = V { t: &S };
//^^^^expected V<&S>, got (V<&dyn Tr>,)
//^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
let mut a: V<&dyn Tr> = V { t: &S };
(a,) = V { t: &S };
//^^^^expected V<&S>, got (V<&dyn Tr>,)
//^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
}
"#,
);

View file

@ -8,7 +8,7 @@ fn function_return_type_mismatch_1() {
r#"
fn test() -> &'static str {
5
//^ expected &str, got i32
//^ expected &'static str, got i32
}
"#,
);
@ -21,7 +21,7 @@ fn function_return_type_mismatch_2() {
fn test(x: bool) -> &'static str {
if x {
return 1;
//^ expected &str, got i32
//^ expected &'static str, got i32
}
"ok"
}
@ -38,7 +38,7 @@ fn test(x: bool) -> &'static str {
return "ok";
}
1
//^ expected &str, got i32
//^ expected &'static str, got i32
}
"#,
);
@ -53,7 +53,7 @@ fn test(x: bool) -> &'static str {
"ok"
} else {
1
//^ expected &str, got i32
//^ expected &'static str, got i32
}
}
"#,
@ -67,7 +67,7 @@ fn function_return_type_mismatch_5() {
fn test(x: bool) -> &'static str {
if x {
1
//^ expected &str, got i32
//^ expected &'static str, got i32
} else {
"ok"
}
@ -83,10 +83,10 @@ fn non_unit_block_expr_stmt_no_semi() {
fn test(x: bool) {
if x {
"notok"
//^^^^^^^ expected (), got &str
//^^^^^^^ expected (), got &'static str
} else {
"ok"
//^^^^ expected (), got &str
//^^^^ expected (), got &'static str
}
match x { true => true, false => 0 }
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), got bool

View file

@ -67,11 +67,11 @@ trait B: A {}
fn test(
_: &(dyn A<Assoc = ()> + Send),
//^ &(dyn A<Assoc = ()> + Send)
//^ &'_ (dyn A<Assoc = ()> + Send)
_: &(dyn Send + A<Assoc = ()>),
//^ &(dyn A<Assoc = ()> + Send)
//^ &'_ (dyn A<Assoc = ()> + Send)
_: &dyn B<Assoc = ()>,
//^ &(dyn B<Assoc = ()>)
//^ &'_ (dyn B<Assoc = ()>)
) {}
"#,
);
@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
trait Foo<'a> {}
fn foo(foo: &dyn for<'a> Foo<'a>) {}
// ^^^ &dyn Foo<'_>
// ^^^ &'_ dyn Foo<'_>
"#,
);
}
@ -111,11 +111,11 @@ fn test(
b;
//^ impl Foo
c;
//^ &impl Foo + ?Sized
//^ &'_ impl Foo + ?Sized
d;
//^ S<impl Foo>
ref_any;
//^^^^^^^ &impl ?Sized
//^^^^^^^ &'_ impl ?Sized
empty;
} //^^^^^ impl Sized
"#,
@ -192,7 +192,7 @@ fn test(
b;
//^ fn(impl Foo) -> impl Foo
c;
} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized
"#,
);
}

View file

@ -200,8 +200,8 @@ fn expr_macro_def_expanded_in_various_places() {
100..119 'for _ ...!() {}': IntoIterator::IntoIter<isize>
100..119 'for _ ...!() {}': !
100..119 'for _ ...!() {}': IntoIterator::IntoIter<isize>
100..119 'for _ ...!() {}': &mut IntoIterator::IntoIter<isize>
100..119 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
100..119 'for _ ...!() {}': &'? mut IntoIterator::IntoIter<isize>
100..119 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&'? mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
100..119 'for _ ...!() {}': Option<IntoIterator::Item<isize>>
100..119 'for _ ...!() {}': ()
100..119 'for _ ...!() {}': ()
@ -221,7 +221,7 @@ fn expr_macro_def_expanded_in_various_places() {
281..303 'Spam {...m!() }': {unknown}
309..325 'spam!(...am!()]': {unknown}
350..366 'spam!(... usize': usize
372..380 '&spam!()': &isize
372..380 '&spam!()': &'? isize
386..394 '-spam!()': isize
400..416 'spam!(...pam!()': {unknown}
422..439 'spam!(...pam!()': isize
@ -293,8 +293,8 @@ fn expr_macro_rules_expanded_in_various_places() {
114..133 'for _ ...!() {}': IntoIterator::IntoIter<isize>
114..133 'for _ ...!() {}': !
114..133 'for _ ...!() {}': IntoIterator::IntoIter<isize>
114..133 'for _ ...!() {}': &mut IntoIterator::IntoIter<isize>
114..133 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
114..133 'for _ ...!() {}': &'? mut IntoIterator::IntoIter<isize>
114..133 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&'? mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
114..133 'for _ ...!() {}': Option<IntoIterator::Item<isize>>
114..133 'for _ ...!() {}': ()
114..133 'for _ ...!() {}': ()
@ -314,7 +314,7 @@ fn expr_macro_rules_expanded_in_various_places() {
295..317 'Spam {...m!() }': {unknown}
323..339 'spam!(...am!()]': {unknown}
364..380 'spam!(... usize': usize
386..394 '&spam!()': &isize
386..394 '&spam!()': &'? isize
400..408 '-spam!()': isize
414..430 'spam!(...pam!()': {unknown}
436..453 'spam!(...pam!()': isize
@ -539,7 +539,7 @@ fn test() {
let msg = foo::Message(foo::MessageRef);
let r = msg.deref();
r;
//^ &MessageRef
//^ &'? MessageRef
}
//- /lib.rs crate:foo
@ -703,9 +703,9 @@ fn infer_builtin_macros_file() {
}
"#,
expect![[r#"
!0..2 '""': &str
!0..2 '""': &'static str
63..87 '{ ...!(); }': ()
73..74 'x': &str
73..74 'x': &'static str
"#]],
);
}
@ -741,9 +741,9 @@ fn infer_builtin_macros_concat() {
}
"#,
expect![[r#"
!0..13 '"helloworld!"': &str
!0..13 '"helloworld!"': &'static str
65..121 '{ ...")); }': ()
75..76 'x': &str
75..76 'x': &'static str
"#]],
);
}
@ -820,7 +820,7 @@ macro_rules! include_str {() => {}}
fn main() {
let a = include_str!("foo.rs");
a;
} //^ &str
} //^ &'static str
//- /foo.rs
hello
@ -847,7 +847,7 @@ macro_rules! m {
fn main() {
let a = include_str!(m!(".rs"));
a;
} //^ &str
} //^ &'static str
//- /foo.rs
hello
@ -960,9 +960,9 @@ fn infer_builtin_macros_concat_with_lazy() {
}
"#,
expect![[r#"
!0..13 '"helloworld!"': &str
!0..13 '"helloworld!"': &'static str
103..160 '{ ...")); }': ()
113..114 'x': &str
113..114 'x': &'static str
"#]],
);
}
@ -977,7 +977,7 @@ fn infer_builtin_macros_env() {
fn main() {
let x = env!("foo");
//^ &str
//^ &'static str
}
"#,
);
@ -991,7 +991,7 @@ fn infer_builtin_macros_option_env() {
//- /main.rs env:foo=bar
fn main() {
let x = option_env!("foo");
//^ Option<&str>
//^ Option<&'static str>
}
"#,
);

View file

@ -658,7 +658,7 @@ fn infer_call_trait_method_on_generic_param_1() {
}
"#,
expect![[r#"
29..33 'self': &Self
29..33 'self': &'? Self
63..64 't': T
69..88 '{ ...d(); }': ()
75..76 't': T
@ -679,7 +679,7 @@ fn infer_call_trait_method_on_generic_param_2() {
}
"#,
expect![[r#"
32..36 'self': &Self
32..36 'self': &'? Self
70..71 't': T
76..95 '{ ...d(); }': ()
82..83 't': T
@ -757,7 +757,7 @@ struct S;
impl Clone for S {}
impl Clone for &S {}
fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &'? S)
"#,
);
}
@ -1150,12 +1150,12 @@ fn dyn_trait_super_trait_not_in_scope() {
}
"#,
expect![[r#"
51..55 'self': &Self
51..55 'self': &'? Self
64..69 '{ 0 }': u32
66..67 '0': u32
176..177 'd': &dyn Trait
176..177 'd': &'? dyn Trait
191..207 '{ ...o(); }': ()
197..198 'd': &dyn Trait
197..198 'd': &'? dyn Trait
197..204 'd.foo()': u32
"#]],
);
@ -1182,15 +1182,15 @@ fn test() {
}
"#,
expect![[r#"
75..79 'self': &S
75..79 'self': &'? S
89..109 '{ ... }': bool
99..103 'true': bool
123..167 '{ ...o(); }': ()
133..134 's': &S
137..151 'unsafe { f() }': &S
146..147 'f': fn f() -> &S
146..149 'f()': &S
157..158 's': &S
133..134 's': &'? S
137..151 'unsafe { f() }': &'static S
146..147 'f': fn f() -> &'static S
146..149 'f()': &'static S
157..158 's': &'? S
157..164 's.foo()': bool
"#]],
);
@ -1601,11 +1601,11 @@ use core::IntoIterator;
fn f() {
let v = [4].into_iter();
v;
//^ &i32
//^ &'? i32
let a = [0, 1].into_iter();
a;
//^ &i32
//^ &'? i32
}
//- /main2021.rs crate:main2021 deps:core edition:2021
@ -1618,7 +1618,7 @@ fn f() {
let a = [0, 1].into_iter();
a;
//^ &i32
//^ &'? i32
}
//- /core.rs crate:core
@ -1767,7 +1767,7 @@ fn test() {
let a2 = A(make(), 1i32);
let _: &str = a2.thing();
a2;
//^^ A<C<&str>, i32>
//^^ A<C<&'? str>, i32>
}
"#,
);

View file

@ -104,7 +104,7 @@ enum Option<T> { None, Some(T) }
fn test() {
let a = if true { Option::None } else { Option::Some(return) };
a;
//^ Option<&str>
//^ Option<&'static str>
match 42 {
42 => a,
_ => Option::Some("str"),
@ -317,8 +317,8 @@ fn diverging_expression_2() {
63..81 '{ loop...foo" }': u32
65..72 'loop {}': !
70..72 '{}': ()
74..79 '"foo"': &str
74..79: expected u32, got &str
74..79 '"foo"': &'static str
74..79: expected u32, got &'static str
"#]],
);
}
@ -365,8 +365,8 @@ fn diverging_expression_3_break() {
151..172 'for a ...eak; }': {unknown}
151..172 'for a ...eak; }': !
151..172 'for a ...eak; }': {unknown}
151..172 'for a ...eak; }': &mut {unknown}
151..172 'for a ...eak; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
151..172 'for a ...eak; }': &'? mut {unknown}
151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
151..172 'for a ...eak; }': Option<{unknown}>
151..172 'for a ...eak; }': ()
151..172 'for a ...eak; }': ()
@ -381,8 +381,8 @@ fn diverging_expression_3_break() {
237..250 'for a in b {}': {unknown}
237..250 'for a in b {}': !
237..250 'for a in b {}': {unknown}
237..250 'for a in b {}': &mut {unknown}
237..250 'for a in b {}': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
237..250 'for a in b {}': &'? mut {unknown}
237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
237..250 'for a in b {}': Option<{unknown}>
237..250 'for a in b {}': ()
237..250 'for a in b {}': ()
@ -396,8 +396,8 @@ fn diverging_expression_3_break() {
315..337 'for a ...urn; }': {unknown}
315..337 'for a ...urn; }': !
315..337 'for a ...urn; }': {unknown}
315..337 'for a ...urn; }': &mut {unknown}
315..337 'for a ...urn; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
315..337 'for a ...urn; }': &'? mut {unknown}
315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
315..337 'for a ...urn; }': Option<{unknown}>
315..337 'for a ...urn; }': ()
315..337 'for a ...urn; }': ()

View file

@ -32,27 +32,27 @@ fn infer_pattern() {
}
"#,
expect![[r#"
8..9 'x': &i32
8..9 'x': &'? i32
17..400 '{ ...o_x; }': ()
27..28 'y': &i32
31..32 'x': &i32
42..44 '&z': &i32
27..28 'y': &'? i32
31..32 'x': &'? i32
42..44 '&z': &'? i32
43..44 'z': i32
47..48 'x': &i32
47..48 'x': &'? i32
58..59 'a': i32
62..63 'z': i32
73..79 '(c, d)': (i32, &str)
73..79 '(c, d)': (i32, &'static str)
74..75 'c': i32
77..78 'd': &str
82..94 '(1, "hello")': (i32, &str)
77..78 'd': &'static str
82..94 '(1, "hello")': (i32, &'static str)
83..84 '1': i32
86..93 '"hello"': &str
86..93 '"hello"': &'static str
101..151 'for (e... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
101..151 'for (e... }': {unknown}
101..151 'for (e... }': !
101..151 'for (e... }': {unknown}
101..151 'for (e... }': &mut {unknown}
101..151 'for (e... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
101..151 'for (e... }': &'? mut {unknown}
101..151 'for (e... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
101..151 'for (e... }': Option<({unknown}, {unknown})>
101..151 'for (e... }': ()
101..151 'for (e... }': ()
@ -74,10 +74,10 @@ fn infer_pattern() {
194..197 'val': {unknown}
210..236 'if let...rue {}': ()
213..233 'let x ... &true': bool
217..225 'x @ true': &bool
217..225 'x @ true': &'? bool
221..225 'true': bool
221..225 'true': bool
228..233 '&true': &bool
228..233 '&true': &'? bool
229..233 'true': bool
234..236 '{}': ()
246..252 'lambda': impl Fn(u64, u64, i32) -> i32
@ -90,14 +90,14 @@ fn infer_pattern() {
277..282 'a + b': u64
281..282 'b': u64
284..285 'c': i32
298..310 'ref ref_to_x': &&i32
313..314 'x': &i32
324..333 'mut mut_x': &i32
336..337 'x': &i32
347..367 'ref mu...f_to_x': &mut &i32
370..371 'x': &i32
381..382 'k': &mut &i32
385..397 'mut_ref_to_x': &mut &i32
298..310 'ref ref_to_x': &'? &'? i32
313..314 'x': &'? i32
324..333 'mut mut_x': &'? i32
336..337 'x': &'? i32
347..367 'ref mu...f_to_x': &'? mut &'? i32
370..371 'x': &'? i32
381..382 'k': &'? mut &'? i32
385..397 'mut_ref_to_x': &'? mut &'? i32
"#]],
);
}
@ -120,14 +120,14 @@ fn infer_literal_pattern() {
17..28 '{ loop {} }': T
19..26 'loop {}': !
24..26 '{}': ()
37..38 'x': &i32
37..38 'x': &'? i32
46..208 '{ ...) {} }': ()
52..75 'if let...y() {}': ()
55..72 'let "f... any()': bool
59..64 '"foo"': &str
59..64 '"foo"': &str
67..70 'any': fn any<&str>() -> &str
67..72 'any()': &str
59..64 '"foo"': &'static str
59..64 '"foo"': &'static str
67..70 'any': fn any<&'static str>() -> &'static str
67..72 'any()': &'static str
73..75 '{}': ()
80..99 'if let...y() {}': ()
83..96 'let 1 = any()': bool
@ -178,7 +178,7 @@ fn infer_range_pattern() {
}
"#,
expect![[r#"
8..9 'x': &i32
8..9 'x': &'? i32
17..75 '{ ...2 {} }': ()
23..45 'if let...u32 {}': ()
26..42 'let 1....= 2u32': bool
@ -208,14 +208,14 @@ fn infer_pattern_match_ergonomics() {
expect![[r#"
27..78 '{ ...(1); }': ()
37..41 'A(n)': A<i32>
39..40 'n': &i32
44..49 '&A(1)': &A<i32>
39..40 'n': &'? i32
44..49 '&A(1)': &'? A<i32>
45..46 'A': extern "rust-call" A<i32>(i32) -> A<i32>
45..49 'A(1)': A<i32>
47..48 '1': i32
59..63 'A(n)': A<i32>
61..62 'n': &mut i32
66..75 '&mut A(1)': &mut A<i32>
61..62 'n': &'? mut i32
66..75 '&mut A(1)': &'? mut A<i32>
71..72 'A': extern "rust-call" A<i32>(i32) -> A<i32>
71..75 'A(1)': A<i32>
73..74 '1': i32
@ -235,17 +235,17 @@ fn infer_pattern_match_ergonomics_ref() {
"#,
expect![[r#"
10..56 '{ ...= v; }': ()
20..21 'v': &(i32, &i32)
24..32 '&(1, &2)': &(i32, &i32)
25..32 '(1, &2)': (i32, &i32)
20..21 'v': &'? (i32, &'? i32)
24..32 '&(1, &2)': &'? (i32, &'? i32)
25..32 '(1, &2)': (i32, &'? i32)
26..27 '1': i32
29..31 '&2': &i32
29..31 '&2': &'? i32
30..31 '2': i32
42..49 '(_, &w)': (i32, &i32)
42..49 '(_, &w)': (i32, &'? i32)
43..44 '_': i32
46..48 '&w': &i32
46..48 '&w': &'? i32
47..48 'w': i32
52..53 'v': &(i32, &i32)
52..53 'v': &'? (i32, &'? i32)
"#]],
);
}
@ -286,28 +286,28 @@ fn infer_pattern_match_slice() {
"#,
expect![[r#"
10..209 '{ ... } }': ()
20..25 'slice': &[f64]
36..42 '&[0.0]': &[f64; 1]
20..25 'slice': &'? [f64]
36..42 '&[0.0]': &'? [f64; 1]
37..42 '[0.0]': [f64; 1]
38..41 '0.0': f64
48..207 'match ... }': ()
54..59 'slice': &[f64]
70..73 '&[]': &[f64]
54..59 'slice': &'? [f64]
70..73 '&[]': &'? [f64]
71..73 '[]': [f64]
77..79 '{}': ()
89..93 '&[a]': &[f64]
89..93 '&[a]': &'? [f64]
90..93 '[a]': [f64]
91..92 'a': f64
97..123 '{ ... }': ()
111..112 'a': f64
133..140 '&[b, c]': &[f64]
133..140 '&[b, c]': &'? [f64]
134..140 '[b, c]': [f64]
135..136 'b': f64
138..139 'c': f64
144..185 '{ ... }': ()
158..159 'b': f64
173..174 'c': f64
194..195 '_': &[f64]
194..195 '_': &'? [f64]
199..201 '{}': ()
"#]],
);
@ -327,14 +327,14 @@ fn infer_pattern_match_string_literal() {
"#,
expect![[r#"
10..98 '{ ... } }': ()
20..21 's': &str
30..37 '"hello"': &str
20..21 's': &'? str
30..37 '"hello"': &'static str
43..96 'match ... }': ()
49..50 's': &str
61..68 '"hello"': &str
61..68 '"hello"': &str
49..50 's': &'? str
61..68 '"hello"': &'static str
61..68 '"hello"': &'static str
72..74 '{}': ()
83..84 '_': &str
83..84 '_': &'? str
88..90 '{}': ()
"#]],
);
@ -358,27 +358,27 @@ fn infer_pattern_match_byte_string_literal() {
}
"#,
expect![[r#"
105..109 'self': &[T; N]
105..109 'self': &'? [T; N]
111..116 'index': {unknown}
157..180 '{ ... }': &[u8]
157..180 '{ ... }': &'? [u8]
167..174 'loop {}': !
172..174 '{}': ()
191..192 'v': [u8; 3]
203..261 '{ ...v {} }': ()
209..233 'if let...[S] {}': ()
212..230 'let b"... &v[S]': bool
216..222 'b"foo"': &[u8]
216..222 'b"foo"': &[u8]
225..230 '&v[S]': &[u8]
216..222 'b"foo"': &'static [u8]
216..222 'b"foo"': &'static [u8]
225..230 '&v[S]': &'? [u8]
226..227 'v': [u8; 3]
226..230 'v[S]': [u8]
228..229 'S': S
231..233 '{}': ()
238..259 'if let... &v {}': ()
241..256 'let b"foo" = &v': bool
245..251 'b"foo"': &[u8; 3]
245..251 'b"foo"': &[u8; 3]
254..256 '&v': &[u8; 3]
245..251 'b"foo"': &'static [u8; 3]
245..251 'b"foo"': &'static [u8; 3]
254..256 '&v': &'? [u8; 3]
255..256 'v': [u8; 3]
257..259 '{}': ()
"#]],
@ -399,17 +399,17 @@ fn infer_pattern_match_or() {
"#,
expect![[r#"
10..108 '{ ... } }': ()
20..21 's': &str
30..37 '"hello"': &str
20..21 's': &'? str
30..37 '"hello"': &'static str
43..106 'match ... }': ()
49..50 's': &str
61..68 '"hello"': &str
61..68 '"hello"': &str
61..78 '"hello...world"': &str
71..78 '"world"': &str
71..78 '"world"': &str
49..50 's': &'? str
61..68 '"hello"': &'static str
61..68 '"hello"': &'static str
61..78 '"hello...world"': &'? str
71..78 '"world"': &'static str
71..78 '"world"': &'static str
82..84 '{}': ()
93..94 '_': &str
93..94 '_': &'? str
98..100 '{}': ()
"#]],
);
@ -505,10 +505,10 @@ fn infer_adt_pattern() {
216..217 '1': usize
227..231 'E::B': E
235..237 '10': usize
255..274 'ref d ...{ .. }': &E
255..274 'ref d ...{ .. }': &'? E
263..274 'E::A { .. }': E
277..278 'e': E
284..285 'd': &E
284..285 'd': &'? E
"#]],
);
}
@ -529,14 +529,14 @@ impl Foo {
expect![[r#"
42..151 '{ ... }': ()
56..64 'Self(s,)': Foo
61..62 's': &usize
67..75 '&Foo(0,)': &Foo
61..62 's': &'? usize
67..75 '&Foo(0,)': &'? Foo
68..71 'Foo': extern "rust-call" Foo(usize) -> Foo
68..75 'Foo(0,)': Foo
72..73 '0': usize
89..97 'Self(s,)': Foo
94..95 's': &mut usize
100..112 '&mut Foo(0,)': &mut Foo
94..95 's': &'? mut usize
100..112 '&mut Foo(0,)': &'? mut Foo
105..108 'Foo': extern "rust-call" Foo(usize) -> Foo
105..112 'Foo(0,)': Foo
109..110 '0': usize
@ -669,7 +669,7 @@ fn main() {
}
"#,
expect![[r#"
27..31 'self': &S
27..31 'self': &'? S
41..50 '{ false }': bool
43..48 'false': bool
64..115 '{ ... } }': ()
@ -679,7 +679,7 @@ fn main() {
93..94 's': S
93..100 's.foo()': bool
104..106 '()': ()
"#]],
"#]],
)
}
@ -702,29 +702,29 @@ fn test() {
51..58 'loop {}': !
56..58 '{}': ()
72..171 '{ ... x); }': ()
78..81 'foo': fn foo<&(i32, &str), i32, impl FnOnce(&(i32, &str)) -> i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> i32) -> i32
78..81 'foo': fn foo<&'? (i32, &'? str), i32, impl FnOnce(&'? (i32, &'? str)) -> i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> i32) -> i32
78..105 'foo(&(...y)| x)': i32
82..91 '&(1, "a")': &(i32, &str)
83..91 '(1, "a")': (i32, &str)
82..91 '&(1, "a")': &'? (i32, &'static str)
83..91 '(1, "a")': (i32, &'static str)
84..85 '1': i32
87..90 '"a"': &str
93..104 '|&(x, y)| x': impl FnOnce(&(i32, &str)) -> i32
94..101 '&(x, y)': &(i32, &str)
95..101 '(x, y)': (i32, &str)
87..90 '"a"': &'static str
93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> i32
94..101 '&(x, y)': &'? (i32, &'? str)
95..101 '(x, y)': (i32, &'? str)
96..97 'x': i32
99..100 'y': &str
99..100 'y': &'? str
103..104 'x': i32
142..145 'foo': fn foo<&(i32, &str), &i32, impl FnOnce(&(i32, &str)) -> &i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> &i32) -> &i32
142..168 'foo(&(...y)| x)': &i32
146..155 '&(1, "a")': &(i32, &str)
147..155 '(1, "a")': (i32, &str)
142..145 'foo': fn foo<&'? (i32, &'? str), &'? i32, impl FnOnce(&'? (i32, &'? str)) -> &'? i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> &'? i32) -> &'? i32
142..168 'foo(&(...y)| x)': &'? i32
146..155 '&(1, "a")': &'? (i32, &'static str)
147..155 '(1, "a")': (i32, &'static str)
148..149 '1': i32
151..154 '"a"': &str
157..167 '|(x, y)| x': impl FnOnce(&(i32, &str)) -> &i32
158..164 '(x, y)': (i32, &str)
159..160 'x': &i32
162..163 'y': &&str
166..167 'x': &i32
151..154 '"a"': &'static str
157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> &'? i32
158..164 '(x, y)': (i32, &'? str)
159..160 'x': &'? i32
162..163 'y': &'? &'? str
166..167 'x': &'? i32
"#]],
);
}
@ -741,13 +741,13 @@ fn slice_tail_pattern() {
}
"#,
expect![[r#"
7..13 'params': &[i32]
7..13 'params': &'? [i32]
23..92 '{ ... } }': ()
29..90 'match ... }': ()
35..41 'params': &[i32]
35..41 'params': &'? [i32]
52..69 '[head,... @ ..]': [i32]
53..57 'head': &i32
59..68 'tail @ ..': &[i32]
53..57 'head': &'? i32
59..68 'tail @ ..': &'? [i32]
66..68 '..': [i32]
73..84 '{ }': ()
"#]],
@ -1109,7 +1109,7 @@ fn var_args() {
#[lang = "va_list"]
pub struct VaListImpl<'f>;
fn my_fn(foo: ...) {}
//^^^ VaListImpl<'{error}>
//^^^ VaListImpl<'?>
"#,
);
}
@ -1122,9 +1122,9 @@ fn foo() {
let &() = &();
let &mut () = &mut ();
let &mut () = &();
//^^^^^^^ expected &(), got &mut ()
//^^^^^^^ expected &'? (), got &'? mut ()
let &() = &mut ();
//^^^ expected &mut (), got &()
//^^^ expected &'? mut (), got &'? ()
}
"#,
);
@ -1148,7 +1148,7 @@ fn main() {
};
if let Wrap::<X>::A { cool, ..} = &wrapped {}
//^^^^ &u32
//^^^^ &'? u32
}
"#,
);
@ -1182,7 +1182,7 @@ fn main() {
};
if let Wrap::<<S as Schematic>::Props>::A { cool, ..} = &wrapped {}
//^^^^ &u32
//^^^^ &'? u32
}
"#,
);
@ -1217,7 +1217,7 @@ fn main() {
match &6 {
Foo::<i32>::TEST_I32_REF => (),
Foo::<i32>::TEST_I32 => (),
//^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
//^^^^^^^^^^^^^^^^^^^^ expected &'? i32, got i32
_ => (),
}
}

View file

@ -99,7 +99,7 @@ fn recursive_vars() {
24..31 'unknown': {unknown}
37..44 '[y, &y]': [{unknown}; 2]
38..39 'y': {unknown}
41..43 '&y': &{unknown}
41..43 '&y': &'? {unknown}
42..43 'y': {unknown}
"#]],
);
@ -117,19 +117,19 @@ fn recursive_vars_2() {
"#,
expect![[r#"
10..79 '{ ...x)]; }': ()
20..21 'x': &{unknown}
24..31 'unknown': &{unknown}
20..21 'x': &'? {unknown}
24..31 'unknown': &'? {unknown}
41..42 'y': {unknown}
45..52 'unknown': {unknown}
58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2]
59..65 '(x, y)': (&{unknown}, {unknown})
60..61 'x': &{unknown}
58..76 '[(x, y..., &x)]': [(&'? {unknown}, {unknown}); 2]
59..65 '(x, y)': (&'? {unknown}, {unknown})
60..61 'x': &'? {unknown}
63..64 'y': {unknown}
67..75 '(&y, &x)': (&{unknown}, {unknown})
68..70 '&y': &{unknown}
67..75 '(&y, &x)': (&'? {unknown}, {unknown})
68..70 '&y': &'? {unknown}
69..70 'y': {unknown}
72..74 '&x': &&{unknown}
73..74 'x': &{unknown}
72..74 '&x': &'? &'? {unknown}
73..74 'x': &'? {unknown}
"#]],
);
}
@ -166,7 +166,7 @@ fn infer_std_crash_1() {
59..136 'match ... }': ()
65..82 'someth...nknown': Maybe<{unknown}>
93..123 'Maybe:...thing)': Maybe<{unknown}>
105..122 'ref mu...ething': &mut {unknown}
105..122 'ref mu...ething': &'? mut {unknown}
127..129 '()': ()
"#]],
);
@ -183,7 +183,7 @@ fn infer_std_crash_2() {
"#,
expect![[r#"
22..52 '{ ...n']; }': ()
28..49 '&[0, b...b'\n']': &[u8; 4]
28..49 '&[0, b...b'\n']': &'? [u8; 4]
29..49 '[0, b'...b'\n']': [u8; 4]
30..31 '0': u8
33..38 'b'\n'': u8
@ -269,8 +269,8 @@ fn infer_std_crash_5() {
32..320 'for co... }': {unknown}
32..320 'for co... }': !
32..320 'for co... }': {unknown}
32..320 'for co... }': &mut {unknown}
32..320 'for co... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
32..320 'for co... }': &'? mut {unknown}
32..320 'for co... }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
32..320 'for co... }': Option<{unknown}>
32..320 'for co... }': ()
32..320 'for co... }': ()
@ -278,22 +278,22 @@ fn infer_std_crash_5() {
36..43 'content': {unknown}
47..60 'doesnt_matter': {unknown}
61..320 '{ ... }': ()
75..79 'name': &{unknown}
82..166 'if doe... }': &{unknown}
75..79 'name': &'? {unknown}
82..166 'if doe... }': &'? {unknown}
85..98 'doesnt_matter': bool
99..128 '{ ... }': &{unknown}
113..118 'first': &{unknown}
134..166 '{ ... }': &{unknown}
148..156 '&content': &{unknown}
99..128 '{ ... }': &'? {unknown}
113..118 'first': &'? {unknown}
134..166 '{ ... }': &'? {unknown}
148..156 '&content': &'? {unknown}
149..156 'content': {unknown}
181..188 'content': &{unknown}
191..313 'if ICE... }': &{unknown}
181..188 'content': &'? {unknown}
191..313 'if ICE... }': &'? {unknown}
194..231 'ICE_RE..._VALUE': {unknown}
194..247 'ICE_RE...&name)': bool
241..246 '&name': &&{unknown}
242..246 'name': &{unknown}
248..276 '{ ... }': &{unknown}
262..266 'name': &{unknown}
241..246 '&name': &'? &'? {unknown}
242..246 'name': &'? {unknown}
248..276 '{ ... }': &'? {unknown}
262..266 'name': &'? {unknown}
282..313 '{ ... }': {unknown}
296..303 'content': {unknown}
"#]],
@ -318,7 +318,7 @@ fn infer_nested_generics_crash() {
expect![[r#"
91..105 'query_response': Canonical<QueryResponse<R>>
136..166 '{ ...lue; }': ()
142..163 '&query....value': &QueryResponse<R>
142..163 '&query....value': &'? QueryResponse<R>
143..157 'query_response': Canonical<QueryResponse<R>>
143..163 'query_....value': QueryResponse<R>
"#]],
@ -465,12 +465,12 @@ fn issue_3999_slice() {
}
"#,
expect![[r#"
7..13 'params': &[usize]
7..13 'params': &'? [usize]
25..80 '{ ... } }': ()
31..78 'match ... }': ()
37..43 'params': &[usize]
37..43 'params': &'? [usize]
54..66 '[ps @ .., _]': [usize]
55..62 'ps @ ..': &[usize]
55..62 'ps @ ..': &'? [usize]
60..62 '..': [usize]
64..65 '_': usize
70..72 '{}': ()
@ -523,13 +523,13 @@ fn issue_4235_name_conflicts() {
"#,
expect![[r#"
31..37 'FOO {}': FOO
63..67 'self': &FOO
63..67 'self': &'? FOO
69..71 '{}': ()
85..119 '{ ...o(); }': ()
95..96 'a': &FOO
99..103 '&FOO': &FOO
95..96 'a': &'? FOO
99..103 '&FOO': &'? FOO
100..103 'FOO': FOO
109..110 'a': &FOO
109..110 'a': &'? FOO
109..116 'a.foo()': ()
"#]],
);
@ -715,12 +715,12 @@ fn issue_4885() {
}
"#,
expect![[r#"
70..73 'key': &K
70..73 'key': &'? K
132..148 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
138..141 'bar': fn bar<R, K>(&'? K) -> impl Future<Output = <K as Foo<R>>::Bar>
138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
142..145 'key': &K
162..165 'key': &K
142..145 'key': &'? K
162..165 'key': &'? K
224..227 '{ }': ()
"#]],
);
@ -771,11 +771,11 @@ fn issue_4800() {
}
"#,
expect![[r#"
379..383 'self': &mut PeerSet<D>
379..383 'self': &'? mut PeerSet<D>
401..424 '{ ... }': dyn Future<Output = ()>
411..418 'loop {}': !
416..418 '{}': ()
575..579 'self': &mut Self
575..579 'self': &'? mut Self
"#]],
);
}
@ -815,19 +815,19 @@ fn issue_4966() {
225..229 'iter': T
244..246 '{}': Vec<A>
258..402 '{ ...r(); }': ()
268..273 'inner': Map<impl Fn(&f64) -> f64>
276..300 'Map { ... 0.0 }': Map<impl Fn(&f64) -> f64>
285..298 '|_: &f64| 0.0': impl Fn(&f64) -> f64
286..287 '_': &f64
268..273 'inner': Map<impl Fn(&'? f64) -> f64>
276..300 'Map { ... 0.0 }': Map<impl Fn(&'? f64) -> f64>
285..298 '|_: &f64| 0.0': impl Fn(&'? f64) -> f64
286..287 '_': &'? f64
295..298 '0.0': f64
311..317 'repeat': Repeat<Map<impl Fn(&f64) -> f64>>
320..345 'Repeat...nner }': Repeat<Map<impl Fn(&f64) -> f64>>
338..343 'inner': Map<impl Fn(&f64) -> f64>
356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>, Repeat<Map<impl Fn(&f64) -> f64>>>(Repeat<Map<impl Fn(&f64) -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
372..378 'repeat': Repeat<Map<impl Fn(&f64) -> f64>>
386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
311..317 'repeat': Repeat<Map<impl Fn(&'? f64) -> f64>>
320..345 'Repeat...nner }': Repeat<Map<impl Fn(&'? f64) -> f64>>
338..343 'inner': Map<impl Fn(&'? f64) -> f64>
356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>, Repeat<Map<impl Fn(&'? f64) -> f64>>>(Repeat<Map<impl Fn(&'? f64) -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
372..378 'repeat': Repeat<Map<impl Fn(&'? f64) -> f64>>
386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
386..399 'vec.foo_bar()': {unknown}
"#]],
);
@ -850,10 +850,10 @@ fn main() {
}
"#,
expect![[r#"
40..44 'self': &S<T>
40..44 'self': &'? S<T>
46..48 '_t': T
53..55 '{}': ()
81..85 'self': &S<T>
81..85 'self': &'? S<T>
87..89 '_f': F
94..96 '{}': ()
109..160 '{ ...10); }': ()
@ -862,8 +862,8 @@ fn main() {
123..126 'S()': S<i32>
132..133 's': S<i32>
132..144 's.g(|_x| {})': ()
136..143 '|_x| {}': impl FnOnce(&i32)
137..139 '_x': &i32
136..143 '|_x| {}': impl FnOnce(&'? i32)
137..139 '_x': &'? i32
141..143 '{}': ()
150..151 's': S<i32>
150..157 's.f(10)': ()
@ -895,14 +895,14 @@ fn flush(&self) {
}
"#,
expect![[r#"
123..127 'self': &Mutex<T>
150..152 '{}': MutexGuard<'{error}, T>
234..238 'self': &{unknown}
123..127 'self': &'? Mutex<T>
150..152 '{}': MutexGuard<'?, T>
234..238 'self': &'? {unknown}
240..290 '{ ...()); }': ()
250..251 'w': &Mutex<BufWriter>
250..251 'w': &'? Mutex<BufWriter>
276..287 '*(w.lock())': BufWriter
278..279 'w': &Mutex<BufWriter>
278..286 'w.lock()': MutexGuard<'{error}, BufWriter>
278..279 'w': &'? Mutex<BufWriter>
278..286 'w.lock()': MutexGuard<'?, BufWriter>
"#]],
);
}
@ -1023,20 +1023,20 @@ fn cfg_tail() {
expect![[r#"
14..53 '{ ...)] 9 }': ()
20..31 '{ "first" }': ()
22..29 '"first"': &str
22..29 '"first"': &'static str
72..190 '{ ...] 13 }': ()
78..88 '{ "fake" }': ()
80..86 '"fake"': &str
80..86 '"fake"': &'static str
93..103 '{ "fake" }': ()
95..101 '"fake"': &str
95..101 '"fake"': &'static str
108..120 '{ "second" }': ()
110..118 '"second"': &str
110..118 '"second"': &'static str
210..273 '{ ... 15; }': ()
216..227 '{ "third" }': ()
218..225 '"third"': &str
218..225 '"third"': &'static str
293..357 '{ ...] 15 }': ()
299..311 '{ "fourth" }': &str
301..309 '"fourth"': &str
299..311 '{ "fourth" }': &'static str
301..309 '"fourth"': &'static str
"#]],
)
}
@ -1238,8 +1238,8 @@ fn test() {
16..66 'for _ ... }': IntoIterator::IntoIter<()>
16..66 'for _ ... }': !
16..66 'for _ ... }': IntoIterator::IntoIter<()>
16..66 'for _ ... }': &mut IntoIterator::IntoIter<()>
16..66 'for _ ... }': fn next<IntoIterator::IntoIter<()>>(&mut IntoIterator::IntoIter<()>) -> Option<<IntoIterator::IntoIter<()> as Iterator>::Item>
16..66 'for _ ... }': &'? mut IntoIterator::IntoIter<()>
16..66 'for _ ... }': fn next<IntoIterator::IntoIter<()>>(&'? mut IntoIterator::IntoIter<()>) -> Option<<IntoIterator::IntoIter<()> as Iterator>::Item>
16..66 'for _ ... }': Option<IntoIterator::Item<()>>
16..66 'for _ ... }': ()
16..66 'for _ ... }': ()
@ -1599,85 +1599,6 @@ fn f(s: S) {
);
}
#[test]
fn rust_161_option_clone() {
check_types(
r#"
//- minicore: option, drop
fn test(o: &Option<i32>) {
o.my_clone();
//^^^^^^^^^^^^ Option<i32>
}
pub trait MyClone: Sized {
fn my_clone(&self) -> Self;
}
impl<T> const MyClone for Option<T>
where
T: ~const MyClone + ~const Drop + ~const Destruct,
{
fn my_clone(&self) -> Self {
match self {
Some(x) => Some(x.my_clone()),
None => None,
}
}
}
impl const MyClone for i32 {
fn my_clone(&self) -> Self {
*self
}
}
pub trait Destruct {}
impl<T: ?Sized> const Destruct for T {}
"#,
);
}
#[test]
fn rust_162_option_clone() {
check_types(
r#"
//- minicore: option, drop
fn test(o: &Option<i32>) {
o.my_clone();
//^^^^^^^^^^^^ Option<i32>
}
pub trait MyClone: Sized {
fn my_clone(&self) -> Self;
}
impl<T> const MyClone for Option<T>
where
T: ~const MyClone + ~const Destruct,
{
fn my_clone(&self) -> Self {
match self {
Some(x) => Some(x.my_clone()),
None => None,
}
}
}
impl const MyClone for i32 {
fn my_clone(&self) -> Self {
*self
}
}
#[lang = "destruct"]
pub trait Destruct {}
"#,
);
}
#[test]
fn tuple_struct_pattern_with_unmatched_args_crash() {
check_infer(
@ -1727,7 +1648,7 @@ fn dyn_with_unresolved_trait() {
r#"
fn foo(a: &dyn DoesNotExist) {
a.bar();
//^&{unknown}
//^&'? {unknown}
}
"#,
);
@ -1851,9 +1772,9 @@ fn foo() {
match &E::A {
b @ (x @ E::A | x) => {
b;
//^ &E
//^ &'? E
x;
//^ &E
//^ &'? E
}
}
}",
@ -2040,3 +1961,41 @@ fn main() {
"#,
)
}
#[test]
fn cfg_first_trait_param_16141() {
check_no_mismatches(
r#"
//- minicore: sized, coerce_unsized
trait Bar {
fn bar(&self) {}
}
impl<#[cfg(feature = "a-feature")] A> Bar for (){}
"#,
)
}
#[test]
fn nested_anon_generics_and_where_bounds_17173() {
check_types(
r#"
//- minicore: sized, fn
pub trait Lookup {
type Data;
fn lookup(&self) -> Self::Data;
}
pub trait ItemTreeLoc {
type Id;
}
fn id_to_generics(id: impl Lookup<Data = impl ItemTreeLoc<Id = ()>>,
//^^ impl Lookup<Data = impl ItemTreeLoc<Id = ()>>
enabled_params: impl Fn(),
//^^^^^^^^^^^^^^ impl Fn()
)
where
(): Sized,
{}
"#,
);
}

View file

@ -115,15 +115,15 @@ fn test(a: u32, b: isize, c: !, d: &str) {
8..9 'a': u32
16..17 'b': isize
26..27 'c': !
32..33 'd': &str
32..33 'd': &'? str
41..120 '{ ...f32; }': ()
47..48 'a': u32
54..55 'b': isize
61..62 'c': !
68..69 'd': &str
68..69 'd': &'? str
75..81 '1usize': usize
87..93 '1isize': isize
99..105 '"test"': &str
99..105 '"test"': &'static str
111..117 '1.0f32': f32
"#]],
);
@ -344,23 +344,23 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
}
"#,
expect![[r#"
8..9 'a': &u32
17..18 'b': &mut u32
8..9 'a': &'? u32
17..18 'b': &'? mut u32
30..31 'c': *const u32
45..46 'd': *mut u32
58..149 '{ ... *d; }': ()
64..65 'a': &u32
64..65 'a': &'? u32
71..73 '*a': u32
72..73 'a': &u32
79..81 '&a': &&u32
80..81 'a': &u32
87..93 '&mut a': &mut &u32
92..93 'a': &u32
99..100 'b': &mut u32
72..73 'a': &'? u32
79..81 '&a': &'? &'? u32
80..81 'a': &'? u32
87..93 '&mut a': &'? mut &'? u32
92..93 'a': &'? u32
99..100 'b': &'? mut u32
106..108 '*b': u32
107..108 'b': &mut u32
114..116 '&b': &&mut u32
115..116 'b': &mut u32
107..108 'b': &'? mut u32
114..116 '&b': &'? &'? mut u32
115..116 'b': &'? mut u32
122..123 'c': *const u32
129..131 '*c': u32
130..131 'c': *const u32
@ -425,22 +425,22 @@ h";
32..36 '5i32': i32
50..54 '5f32': f32
68..72 '5f64': f64
86..93 '"hello"': &str
107..115 'b"bytes"': &[u8; 5]
86..93 '"hello"': &'static str
107..115 'b"bytes"': &'static [u8; 5]
129..132 ''c'': char
146..150 'b'b'': u8
164..168 '3.14': f64
182..186 '5000': i32
200..205 'false': bool
219..223 'true': bool
237..333 'r#" ... "#': &str
347..357 'br#"yolo"#': &[u8; 4]
375..376 'a': &[u8; 4]
379..403 'b"a\x2... c"': &[u8; 4]
421..422 'b': &[u8; 4]
425..433 'br"g\ h"': &[u8; 4]
451..452 'c': &[u8; 6]
455..467 'br#"x"\"yb"#': &[u8; 6]
237..333 'r#" ... "#': &'static str
347..357 'br#"yolo"#': &'static [u8; 4]
375..376 'a': &'static [u8; 4]
379..403 'b"a\x2... c"': &'static [u8; 4]
421..422 'b': &'static [u8; 4]
425..433 'br"g\ h"': &'static [u8; 4]
451..452 'c': &'static [u8; 6]
455..467 'br#"x"\"yb"#': &'static [u8; 6]
"##]],
);
}
@ -508,9 +508,9 @@ fn test(x: SomeType) {
238..240 '!x': {unknown}
239..240 'x': SomeType
246..254 '-"hello"': {unknown}
247..254 '"hello"': &str
247..254 '"hello"': &'static str
260..268 '!"hello"': {unknown}
261..268 '"hello"': &str
261..268 '"hello"': &'static str
"#]],
);
}
@ -535,7 +535,7 @@ fn test() -> &mut &f64 {
expect![[r#"
13..14 'x': u32
21..23 '{}': ()
77..230 '{ ...t &c }': &mut &f64
77..230 '{ ...t &c }': &'? mut &'? f64
87..88 'a': u32
91..107 'unknow...nction': {unknown}
91..109 'unknow...tion()': u32
@ -550,8 +550,8 @@ fn test() -> &mut &f64 {
193..194 'c': f64
197..213 'unknow...nction': {unknown}
197..215 'unknow...tion()': f64
221..228 '&mut &c': &mut &f64
226..228 '&c': &f64
221..228 '&mut &c': &'? mut &'? f64
226..228 '&c': &'? f64
227..228 'c': f64
"#]],
);
@ -579,12 +579,12 @@ impl S {
}
"#,
expect![[r#"
33..37 'self': &S
33..37 'self': &'? S
39..60 '{ ... }': ()
49..53 'self': &S
74..78 'self': &S
49..53 'self': &'? S
74..78 'self': &'? S
87..108 '{ ... }': ()
97..101 'self': &S
97..101 'self': &'? S
132..152 '{ ... }': S
142..146 'S {}': S
176..199 '{ ... }': S
@ -771,35 +771,35 @@ fn test2(a1: *const A, a2: *mut A) {
64..65 'a': A
71..73 'a1': A
71..75 'a1.b': B
85..87 'a2': &A
90..92 '&a': &A
85..87 'a2': &'? A
90..92 '&a': &'? A
91..92 'a': A
98..100 'a2': &A
98..100 'a2': &'? A
98..102 'a2.b': B
112..114 'a3': &mut A
117..123 '&mut a': &mut A
112..114 'a3': &'? mut A
117..123 '&mut a': &'? mut A
122..123 'a': A
129..131 'a3': &mut A
129..131 'a3': &'? mut A
129..133 'a3.b': B
143..145 'a4': &&&&&&&A
148..156 '&&&&&&&a': &&&&&&&A
149..156 '&&&&&&a': &&&&&&A
150..156 '&&&&&a': &&&&&A
151..156 '&&&&a': &&&&A
152..156 '&&&a': &&&A
153..156 '&&a': &&A
154..156 '&a': &A
143..145 'a4': &'? &'? &'? &'? &'? &'? &'? A
148..156 '&&&&&&&a': &'? &'? &'? &'? &'? &'? &'? A
149..156 '&&&&&&a': &'? &'? &'? &'? &'? &'? A
150..156 '&&&&&a': &'? &'? &'? &'? &'? A
151..156 '&&&&a': &'? &'? &'? &'? A
152..156 '&&&a': &'? &'? &'? A
153..156 '&&a': &'? &'? A
154..156 '&a': &'? A
155..156 'a': A
162..164 'a4': &&&&&&&A
162..164 'a4': &'? &'? &'? &'? &'? &'? &'? A
162..166 'a4.b': B
176..178 'a5': &mut &&mut &&mut A
181..199 '&mut &...&mut a': &mut &&mut &&mut A
186..199 '&&mut &&mut a': &&mut &&mut A
187..199 '&mut &&mut a': &mut &&mut A
192..199 '&&mut a': &&mut A
193..199 '&mut a': &mut A
176..178 'a5': &'? mut &'? &'? mut &'? &'? mut A
181..199 '&mut &...&mut a': &'? mut &'? &'? mut &'? &'? mut A
186..199 '&&mut &&mut a': &'? &'? mut &'? &'? mut A
187..199 '&mut &&mut a': &'? mut &'? &'? mut A
192..199 '&&mut a': &'? &'? mut A
193..199 '&mut a': &'? mut A
198..199 'a': A
205..207 'a5': &mut &&mut &&mut A
205..207 'a5': &'? mut &'? &'? mut &'? &'? mut A
205..209 'a5.b': B
223..225 'a1': *const A
237..239 'a2': *mut A
@ -840,22 +840,22 @@ fn test() {
}
"#,
expect![[r#"
66..70 'self': &A<T>
78..101 '{ ... }': &T
88..95 '&self.0': &T
89..93 'self': &A<T>
66..70 'self': &'? A<T>
78..101 '{ ... }': &'? T
88..95 '&self.0': &'? T
89..93 'self': &'? A<T>
89..95 'self.0': T
182..186 'self': &B<T>
205..228 '{ ... }': &T
215..222 '&self.0': &T
216..220 'self': &B<T>
182..186 'self': &'? B<T>
205..228 '{ ... }': &'? T
215..222 '&self.0': &'? T
216..220 'self': &'? B<T>
216..222 'self.0': T
242..280 '{ ...))); }': ()
252..253 't': &i32
256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32
256..277 'A::foo...42))))': &i32
263..276 '&&B(B(A(42)))': &&B<B<A<i32>>>
264..276 '&B(B(A(42)))': &B<B<A<i32>>>
252..253 't': &'? i32
256..262 'A::foo': fn foo<i32>(&'? A<i32>) -> &'? i32
256..277 'A::foo...42))))': &'? i32
263..276 '&&B(B(A(42)))': &'? &'? B<B<A<i32>>>
264..276 '&B(B(A(42)))': &'? B<B<A<i32>>>
265..266 'B': extern "rust-call" B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
265..276 'B(B(A(42)))': B<B<A<i32>>>
267..268 'B': extern "rust-call" B<A<i32>>(A<i32>) -> B<A<i32>>
@ -895,28 +895,28 @@ fn test(a: A<i32>) {
}
"#,
expect![[r#"
71..75 'self': &A<T>
77..78 'x': &A<T>
93..114 '{ ... }': &T
103..108 '&*x.0': &T
71..75 'self': &'? A<T>
77..78 'x': &'? A<T>
93..114 '{ ... }': &'? T
103..108 '&*x.0': &'? T
104..108 '*x.0': T
105..106 'x': &A<T>
105..106 'x': &'? A<T>
105..108 'x.0': *mut T
195..199 'self': &B<T>
218..241 '{ ... }': &T
228..235 '&self.0': &T
229..233 'self': &B<T>
195..199 'self': &'? B<T>
218..241 '{ ... }': &'? T
228..235 '&self.0': &'? T
229..233 'self': &'? B<T>
229..235 'self.0': T
253..254 'a': A<i32>
264..310 '{ ...))); }': ()
274..275 't': &i32
274..275 't': &'? i32
278..279 'A': extern "rust-call" A<i32>(*mut i32) -> A<i32>
278..292 'A(0 as *mut _)': A<i32>
278..307 'A(0 as...B(a)))': &i32
278..307 'A(0 as...B(a)))': &'? i32
280..281 '0': i32
280..291 '0 as *mut _': *mut i32
297..306 '&&B(B(a))': &&B<B<A<i32>>>
298..306 '&B(B(a))': &B<B<A<i32>>>
297..306 '&&B(B(a))': &'? &'? B<B<A<i32>>>
298..306 '&B(B(a))': &'? B<B<A<i32>>>
299..300 'B': extern "rust-call" B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
299..306 'B(B(a))': B<B<A<i32>>>
301..302 'B': extern "rust-call" B<A<i32>>(A<i32>) -> B<A<i32>>
@ -1044,7 +1044,7 @@ fn infer_inherent_method() {
31..35 'self': A
37..38 'x': u32
52..54 '{}': i32
106..110 'self': &A
106..110 'self': &'? A
112..113 'x': u64
127..129 '{}': i64
147..148 'a': A
@ -1053,7 +1053,7 @@ fn infer_inherent_method() {
159..167 'a.foo(1)': i32
165..166 '1': u32
173..184 '(&a).bar(1)': i64
174..176 '&a': &A
174..176 '&a': &'? A
175..176 'a': A
182..183 '1': u64
190..191 'a': A
@ -1078,10 +1078,10 @@ fn test() {
}
"#,
expect![[r#"
67..71 'self': &str
67..71 'self': &'? str
80..82 '{}': i32
96..116 '{ ...o(); }': ()
102..107 '"foo"': &str
102..107 '"foo"': &'static str
102..113 '"foo".foo()': i32
"#]],
);
@ -1101,33 +1101,33 @@ fn infer_tuple() {
}
"#,
expect![[r#"
8..9 'x': &str
8..9 'x': &'? str
17..18 'y': isize
27..169 '{ ...d"); }': ()
37..38 'a': (u32, &str)
54..62 '(1, "a")': (u32, &str)
37..38 'a': (u32, &'? str)
54..62 '(1, "a")': (u32, &'? str)
55..56 '1': u32
58..61 '"a"': &str
72..73 'b': ((u32, &str), &str)
76..82 '(a, x)': ((u32, &str), &str)
77..78 'a': (u32, &str)
80..81 'x': &str
92..93 'c': (isize, &str)
96..102 '(y, x)': (isize, &str)
58..61 '"a"': &'static str
72..73 'b': ((u32, &'? str), &'? str)
76..82 '(a, x)': ((u32, &'? str), &'? str)
77..78 'a': (u32, &'? str)
80..81 'x': &'? str
92..93 'c': (isize, &'? str)
96..102 '(y, x)': (isize, &'? str)
97..98 'y': isize
100..101 'x': &str
112..113 'd': ((isize, &str), &str)
116..122 '(c, x)': ((isize, &str), &str)
117..118 'c': (isize, &str)
120..121 'x': &str
132..133 'e': (i32, &str)
136..144 '(1, "e")': (i32, &str)
100..101 'x': &'? str
112..113 'd': ((isize, &'? str), &'? str)
116..122 '(c, x)': ((isize, &'? str), &'? str)
117..118 'c': (isize, &'? str)
120..121 'x': &'? str
132..133 'e': (i32, &'static str)
136..144 '(1, "e")': (i32, &'static str)
137..138 '1': i32
140..143 '"e"': &str
154..155 'f': ((i32, &str), &str)
158..166 '(e, "d")': ((i32, &str), &str)
159..160 'e': (i32, &str)
162..165 '"d"': &str
140..143 '"e"': &'static str
154..155 'f': ((i32, &'static str), &'static str)
158..166 '(e, "d")': ((i32, &'static str), &'static str)
159..160 'e': (i32, &'static str)
162..165 '"d"': &'static str
"#]],
);
}
@ -1156,20 +1156,20 @@ fn infer_array() {
}
"#,
expect![[r#"
8..9 'x': &str
8..9 'x': &'? str
17..18 'y': isize
27..326 '{ ...,4]; }': ()
37..38 'a': [&str; 1]
41..44 '[x]': [&str; 1]
42..43 'x': &str
54..55 'b': [[&str; 1]; 2]
58..64 '[a, a]': [[&str; 1]; 2]
59..60 'a': [&str; 1]
62..63 'a': [&str; 1]
74..75 'c': [[[&str; 1]; 2]; 2]
78..84 '[b, b]': [[[&str; 1]; 2]; 2]
79..80 'b': [[&str; 1]; 2]
82..83 'b': [[&str; 1]; 2]
37..38 'a': [&'? str; 1]
41..44 '[x]': [&'? str; 1]
42..43 'x': &'? str
54..55 'b': [[&'? str; 1]; 2]
58..64 '[a, a]': [[&'? str; 1]; 2]
59..60 'a': [&'? str; 1]
62..63 'a': [&'? str; 1]
74..75 'c': [[[&'? str; 1]; 2]; 2]
78..84 '[b, b]': [[[&'? str; 1]; 2]; 2]
79..80 'b': [[&'? str; 1]; 2]
82..83 'b': [[&'? str; 1]; 2]
95..96 'd': [isize; 4]
99..111 '[y, 1, 2, 3]': [isize; 4]
100..101 'y': isize
@ -1197,15 +1197,15 @@ fn infer_array() {
209..215 '[1, 2]': [i32; 2]
210..211 '1': i32
213..214 '2': i32
225..226 'i': [&str; 2]
229..239 '["a", "b"]': [&str; 2]
230..233 '"a"': &str
235..238 '"b"': &str
250..251 'b': [[&str; 1]; 2]
254..264 '[a, ["b"]]': [[&str; 1]; 2]
255..256 'a': [&str; 1]
258..263 '["b"]': [&str; 1]
259..262 '"b"': &str
225..226 'i': [&'? str; 2]
229..239 '["a", "b"]': [&'? str; 2]
230..233 '"a"': &'static str
235..238 '"b"': &'static str
250..251 'b': [[&'? str; 1]; 2]
254..264 '[a, ["b"]]': [[&'? str; 1]; 2]
255..256 'a': [&'? str; 1]
258..263 '["b"]': [&'? str; 1]
259..262 '"b"': &'static str
274..275 'x': [u8; 0]
287..289 '[]': [u8; 0]
299..300 'y': [u8; 4]
@ -1279,12 +1279,12 @@ fn infer_tuple_struct_generics() {
92..93 'A': extern "rust-call" A<u128>(u128) -> A<u128>
92..101 'A(42u128)': A<u128>
94..100 '42u128': u128
107..111 'Some': extern "rust-call" Some<&str>(&str) -> Option<&str>
107..116 'Some("x")': Option<&str>
112..115 '"x"': &str
122..134 'Option::Some': extern "rust-call" Some<&str>(&str) -> Option<&str>
122..139 'Option...e("x")': Option<&str>
135..138 '"x"': &str
107..111 'Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str>
107..116 'Some("x")': Option<&'static str>
112..115 '"x"': &'static str
122..134 'Option::Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str>
122..139 'Option...e("x")': Option<&'static str>
135..138 '"x"': &'static str
145..149 'None': Option<{unknown}>
159..160 'x': Option<i64>
176..180 'None': Option<i64>
@ -1405,15 +1405,15 @@ fn infer_impl_generics_with_autoderef() {
}
"#,
expect![[r#"
77..81 'self': &Option<T>
97..99 '{}': Option<&T>
77..81 'self': &'? Option<T>
97..99 '{}': Option<&'? T>
110..111 'o': Option<u32>
126..164 '{ ...f(); }': ()
132..145 '(&o).as_ref()': Option<&u32>
133..135 '&o': &Option<u32>
132..145 '(&o).as_ref()': Option<&'? u32>
133..135 '&o': &'? Option<u32>
134..135 'o': Option<u32>
151..152 'o': Option<u32>
151..161 'o.as_ref()': Option<&u32>
151..161 'o.as_ref()': Option<&'? u32>
"#]],
);
}
@ -1551,16 +1551,16 @@ fn infer_type_alias() {
"#,
expect![[r#"
115..116 'x': A<u32, i128>
123..124 'y': A<&str, u128>
123..124 'y': A<&'? str, u128>
137..138 'z': A<u8, i8>
153..210 '{ ...z.y; }': ()
159..160 'x': A<u32, i128>
159..162 'x.x': u32
168..169 'x': A<u32, i128>
168..171 'x.y': i128
177..178 'y': A<&str, u128>
177..180 'y.x': &str
186..187 'y': A<&str, u128>
177..178 'y': A<&'? str, u128>
177..180 'y.x': &'? str
186..187 'y': A<&'? str, u128>
186..189 'y.y': u128
195..196 'z': A<u8, i8>
195..198 'z.x': u8
@ -1572,8 +1572,8 @@ fn infer_type_alias() {
312..328 'm::Ali...Foo(0)': Enum
326..327 '0': u8
338..354 'm::Ali...Foo(x)': Enum
352..353 'x': &u8
357..359 '&e': &Enum
352..353 'x': &'? u8
357..359 '&e': &'? Enum
358..359 'e': Enum
"#]],
)
@ -1618,10 +1618,10 @@ fn infer_type_param() {
9..10 'x': T
20..29 '{ x }': T
26..27 'x': T
43..44 'x': &T
43..44 'x': &'? T
55..65 '{ *x }': T
61..63 '*x': T
62..63 'x': &T
62..63 'x': &'? T
77..157 '{ ...(1); }': ()
87..88 'y': u32
91..96 '10u32': u32
@ -1629,9 +1629,9 @@ fn infer_type_param() {
102..107 'id(y)': u32
105..106 'y': u32
117..118 'x': bool
127..132 'clone': fn clone<bool>(&bool) -> bool
127..132 'clone': fn clone<bool>(&'? bool) -> bool
127..135 'clone(z)': bool
133..134 'z': &bool
133..134 'z': &'? bool
141..151 'id::<i128>': fn id<i128>(i128) -> i128
141..154 'id::<i128>(1)': i128
152..153 '1': i128
@ -1842,7 +1842,7 @@ fn foo() -> &'static str { "" }
fn main() {
foo();
//^^^^^ &str
//^^^^^ &'static str
}"#,
);
}
@ -1940,10 +1940,10 @@ fn closure_return_inferred() {
"#,
expect![[r#"
16..46 '{ ..." }; }': u32
26..27 'x': impl Fn() -> &str
30..43 '|| { "test" }': impl Fn() -> &str
33..43 '{ "test" }': &str
35..41 '"test"': &str
26..27 'x': impl Fn() -> &'static str
30..43 '|| { "test" }': impl Fn() -> &'static str
33..43 '{ "test" }': &'static str
35..41 '"test"': &'static str
"#]],
);
}
@ -1975,10 +1975,10 @@ fn test() {
70..71 'v': i64
78..80 '{}': ()
91..362 '{ ... } }': ()
101..106 'mut g': |usize| yields i64 -> &str
109..218 '|r| { ... }': |usize| yields i64 -> &str
101..106 'mut g': |usize| yields i64 -> &'static str
109..218 '|r| { ... }': |usize| yields i64 -> &'static str
110..111 'r': usize
113..218 '{ ... }': &str
113..218 '{ ... }': &'static str
127..128 'a': usize
131..138 'yield 0': usize
137..138 '0': i64
@ -1988,22 +1988,22 @@ fn test() {
177..178 'a': usize
181..188 'yield 2': usize
187..188 '2': i64
198..212 '"return value"': &str
198..212 '"return value"': &'static str
225..360 'match ... }': ()
231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
231..262 'Pin::n...usize)': CoroutineState<i64, &str>
240..246 '&mut g': &mut |usize| yields i64 -> &str
245..246 'g': |usize| yields i64 -> &str
231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str>
231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str>
231..262 'Pin::n...usize)': CoroutineState<i64, &'static str>
240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str
245..246 'g': |usize| yields i64 -> &'static str
255..261 '0usize': usize
273..299 'Corout...ded(y)': CoroutineState<i64, &str>
273..299 'Corout...ded(y)': CoroutineState<i64, &'static 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 'Corout...ete(r)': CoroutineState<i64, &str>
346..347 'r': &str
321..348 'Corout...ete(r)': CoroutineState<i64, &'static str>
346..347 'r': &'static str
352..354 '{}': ()
"#]],
);
@ -2050,7 +2050,7 @@ fn f(x: (&&&&i32, &&&i32)) {
_ => loop {},
};
f;
//^ (&&&&i32, &&&i32)
//^ (&'? &'? &'? &'? i32, &'? &'? &'? i32)
}
"#,
);
@ -2059,10 +2059,10 @@ fn f(x: (&&&&i32, &&&i32)) {
fn f() {
let x = &&&(&&&2, &&&&&3);
let (y, z) = x;
//^ &&&&i32
//^ &'? &'? &'? &'? i32
let t @ (y, z) = x;
t;
//^ &&&(&&&i32, &&&&&i32)
//^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32)
}
"#,
);
@ -2071,10 +2071,10 @@ fn f() {
fn f() {
let x = &&&(&&&2, &&&&&3);
let (y, z) = x;
//^ &&&&i32
//^ &'? &'? &'? &'? i32
let t @ (y, z) = x;
t;
//^ &&&(&&&i32, &&&&&i32)
//^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32)
}
"#,
);
@ -2761,23 +2761,23 @@ impl S {
fn f() {
let x = S;
let c1 = || x.read();
//^^ impl Fn() -> &S
//^^ impl Fn() -> &'? S
let c2 = || x.write();
//^^ impl FnMut() -> &mut S
//^^ impl FnMut() -> &'? mut S
let c3 = || x.consume();
//^^ impl FnOnce() -> S
let c3 = || x.consume().consume().consume();
//^^ impl FnOnce() -> S
let c3 = || x.consume().write().read();
//^^ impl FnOnce() -> &S
//^^ impl FnOnce() -> &'? S
let x = &mut x;
let c1 = || x.write();
//^^ impl FnMut() -> &mut S
//^^ impl FnMut() -> &'? mut S
let x = S;
let c1 = || { let ref t = x; t };
//^^ impl Fn() -> &S
//^^ impl Fn() -> &'? S
let c2 = || { let ref mut t = x; t };
//^^ impl FnMut() -> &mut S
//^^ impl FnMut() -> &'? mut S
let c3 = || { let t = x; t };
//^^ impl FnOnce() -> S
}
@ -3074,11 +3074,11 @@ fn main() {
}
"#,
expect![[r#"
104..108 'self': &Box<T>
188..192 'self': &Box<Foo<T>>
218..220 '{}': &T
242..246 'self': &Box<Foo<T>>
275..277 '{}': &Foo<T>
104..108 'self': &'? Box<T>
188..192 'self': &'a Box<Foo<T>>
218..220 '{}': &'a T
242..246 'self': &'a Box<Foo<T>>
275..277 '{}': &'a Foo<T>
297..301 'self': Box<Foo<T>>
322..324 '{}': Foo<T>
338..559 '{ ...r(); }': ()
@ -3088,21 +3088,21 @@ fn main() {
360..363 'Foo': extern "rust-call" Foo<i32>(i32) -> Foo<i32>
360..370 'Foo(0_i32)': Foo<i32>
364..369 '0_i32': i32
382..386 'bad1': &i32
382..386 'bad1': &'? i32
389..394 'boxed': Box<Foo<i32>>
389..406 'boxed....nner()': &i32
416..421 'good1': &i32
424..438 'Foo::get_inner': fn get_inner<i32, '{error}>(&Box<Foo<i32>>) -> &i32
424..446 'Foo::g...boxed)': &i32
439..445 '&boxed': &Box<Foo<i32>>
389..406 'boxed....nner()': &'? i32
416..421 'good1': &'? i32
424..438 'Foo::get_inner': fn get_inner<i32, '?>(&'? Box<Foo<i32>>) -> &'? i32
424..446 'Foo::g...boxed)': &'? i32
439..445 '&boxed': &'? Box<Foo<i32>>
440..445 'boxed': Box<Foo<i32>>
457..461 'bad2': &Foo<i32>
457..461 'bad2': &'? Foo<i32>
464..469 'boxed': Box<Foo<i32>>
464..480 'boxed....self()': &Foo<i32>
490..495 'good2': &Foo<i32>
498..511 'Foo::get_self': fn get_self<i32, '{error}>(&Box<Foo<i32>>) -> &Foo<i32>
498..519 'Foo::g...boxed)': &Foo<i32>
512..518 '&boxed': &Box<Foo<i32>>
464..480 'boxed....self()': &'? Foo<i32>
490..495 'good2': &'? Foo<i32>
498..511 'Foo::get_self': fn get_self<i32, '?>(&'? Box<Foo<i32>>) -> &'? Foo<i32>
498..519 'Foo::g...boxed)': &'? Foo<i32>
512..518 '&boxed': &'? Box<Foo<i32>>
513..518 'boxed': Box<Foo<i32>>
530..535 'inner': Foo<i32>
538..543 'boxed': Box<Foo<i32>>
@ -3414,31 +3414,31 @@ struct TS(usize);
fn main() {
let x;
[x,] = &[1,];
//^^^^expected &[i32; 1], got [{unknown}; _]
//^^^^expected &'? [i32; 1], got [{unknown}; _]
let x;
[(x,),] = &[(1,),];
//^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
//^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
let x;
((x,),) = &((1,),);
//^^^^^^^expected &((i32,),), got (({unknown},),)
//^^^^^^^expected &'? ((i32,),), got (({unknown},),)
let x;
(x,) = &(1,);
//^^^^expected &(i32,), got ({unknown},)
//^^^^expected &'? (i32,), got ({unknown},)
let x;
(S { a: x },) = &(S { a: 42 },);
//^^^^^^^^^^^^^expected &(S,), got (S,)
//^^^^^^^^^^^^^expected &'? (S,), got (S,)
let x;
S { a: x } = &S { a: 42 };
//^^^^^^^^^^expected &S, got S
//^^^^^^^^^^expected &'? S, got S
let x;
TS(x) = &TS(42);
//^^^^^expected &TS, got TS
//^^^^^expected &'? TS, got TS
}
"#,
);
@ -3548,17 +3548,17 @@ fn f<T>(t: Ark<T>) {
}
"#,
expect![[r#"
47..51 'self': &Ark<T>
47..51 'self': &'? Ark<T>
65..88 '{ ... }': *const T
75..82 '&self.0': &T
76..80 'self': &Ark<T>
75..82 '&self.0': &'? T
76..80 'self': &'? Ark<T>
76..82 'self.0': T
99..100 't': Ark<T>
110..144 '{ ... (); }': ()
116..124 'Ark::foo': fn foo<T>(&Ark<T>) -> *const T
116..124 'Ark::foo': fn foo<T>(&'? Ark<T>) -> *const T
116..128 'Ark::foo(&t)': *const T
116..141 'Ark::f...nst ()': *const ()
125..127 '&t': &Ark<T>
125..127 '&t': &'? Ark<T>
126..127 't': Ark<T>
"#]],
);
@ -3632,7 +3632,7 @@ pub struct CStr;
fn main() {
c"ello";
//^^^^^^^ &CStr
//^^^^^^^ &'static CStr
}
"#,
);
@ -3659,7 +3659,25 @@ fn main() {
let are = "are";
let count = 10;
builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'{error}>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'?>
}
"#,
);
}
#[test]
fn inline_const_expression() {
check(
r#"
fn main() {
let foo = 0;
const {
let bar = 1;
let unresolved = foo;
// ^^^^^^^^^^ type: {unknown}
let resolved = bar;
// ^^^^^^^^ type: i32
}
}
"#,
);

View file

@ -238,6 +238,7 @@ fn infer_for_loop() {
//- minicore: iterator
//- /main.rs crate:main deps:alloc
#![no_std]
extern crate alloc;
use alloc::collections::Vec;
fn test() {
@ -245,7 +246,7 @@ fn test() {
v.push("foo");
for x in v {
x;
} //^ &str
} //^ &'static str
}
//- /alloc.rs crate:alloc
@ -575,7 +576,7 @@ fn indexing_arrays() {
"fn main() { &mut [9][2]; }",
expect![[r#"
10..26 '{ &mut...[2]; }': ()
12..23 '&mut [9][2]': &mut {unknown}
12..23 '&mut [9][2]': &'? mut {unknown}
17..20 '[9]': [i32; 1]
17..23 '[9][2]': {unknown}
18..19 '9': i32
@ -873,7 +874,7 @@ impl<U, T: Trait<U>> O<T> {
fn test(o: O<S>) {
o.foo();
} //^^^^^^^ &str
} //^^^^^^^ &'? str
"#,
);
}
@ -1016,15 +1017,15 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
z.foo2();
}"#,
expect![[r#"
29..33 'self': &Self
54..58 'self': &Self
29..33 'self': &'? Self
54..58 'self': &'? Self
77..78 'x': impl Trait<u16>
97..99 '{}': ()
154..155 'x': impl Trait<u64>
174..175 'y': &impl Trait<u32>
174..175 'y': &'? impl Trait<u32>
195..323 '{ ...2(); }': ()
201..202 'x': impl Trait<u64>
208..209 'y': &impl Trait<u32>
208..209 'y': &'? impl Trait<u32>
219..220 'z': S<u16>
223..224 'S': extern "rust-call" S<u16>(u16) -> S<u16>
223..227 'S(1)': S<u16>
@ -1034,13 +1035,13 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
237..238 'z': S<u16>
245..246 'x': impl Trait<u64>
245..252 'x.foo()': u64
258..259 'y': &impl Trait<u32>
258..259 'y': &'? impl Trait<u32>
258..265 'y.foo()': u32
271..272 'z': S<u16>
271..278 'z.foo()': u16
284..285 'x': impl Trait<u64>
284..292 'x.foo2()': i64
298..299 'y': &impl Trait<u32>
298..299 'y': &'? impl Trait<u32>
298..306 'y.foo2()': i64
312..313 'z': S<u16>
312..320 'z.foo2()': i64
@ -1204,26 +1205,26 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
z.foo2();
}"#,
expect![[r#"
29..33 'self': &Self
54..58 'self': &Self
29..33 'self': &'? Self
54..58 'self': &'? Self
98..100 '{}': ()
110..111 'x': impl Trait<u64>
130..131 'y': &impl Trait<u64>
130..131 'y': &'? impl Trait<u64>
151..268 '{ ...2(); }': ()
157..158 'x': impl Trait<u64>
164..165 'y': &impl Trait<u64>
164..165 'y': &'? impl Trait<u64>
175..176 'z': impl Trait<u64>
179..182 'bar': fn bar() -> impl Trait<u64>
179..184 'bar()': impl Trait<u64>
190..191 'x': impl Trait<u64>
190..197 'x.foo()': u64
203..204 'y': &impl Trait<u64>
203..204 'y': &'? impl Trait<u64>
203..210 'y.foo()': u64
216..217 'z': impl Trait<u64>
216..223 'z.foo()': u64
229..230 'x': impl Trait<u64>
229..237 'x.foo2()': i64
243..244 'y': &impl Trait<u64>
243..244 'y': &'? impl Trait<u64>
243..251 'y.foo2()': i64
257..258 'z': impl Trait<u64>
257..265 'z.foo2()': i64
@ -1328,7 +1329,7 @@ fn test() {
a.foo();
}"#,
expect![[r#"
29..33 'self': &Self
29..33 'self': &'? Self
71..82 '{ loop {} }': !
73..80 'loop {}': !
78..80 '{}': ()
@ -1366,8 +1367,8 @@ fn test() {
d.foo();
}"#,
expect![[r#"
49..53 'self': &mut Self
101..105 'self': &Self
49..53 'self': &'? mut Self
101..105 'self': &'? Self
184..195 '{ loop {} }': ({unknown}, {unknown})
186..193 'loop {}': !
191..193 '{}': ()
@ -1414,10 +1415,10 @@ fn foo<const C: u8, T>() -> (impl FnOnce(&str, T), impl Trait<u8>) {
}
"#,
expect![[r#"
134..165 '{ ...(C)) }': (impl FnOnce(&str, T), Bar<u8>)
140..163 '(|inpu...ar(C))': (impl FnOnce(&str, T), Bar<u8>)
141..154 '|input, t| {}': impl FnOnce(&str, T)
142..147 'input': &str
134..165 '{ ...(C)) }': (impl FnOnce(&'? str, T), Bar<u8>)
140..163 '(|inpu...ar(C))': (impl FnOnce(&'? str, T), Bar<u8>)
141..154 '|input, t| {}': impl FnOnce(&'? str, T)
142..147 'input': &'? str
149..150 't': T
152..154 '{}': ()
156..159 'Bar': extern "rust-call" Bar<u8>(u8) -> Bar<u8>
@ -1466,26 +1467,26 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
z.foo2();
}"#,
expect![[r#"
29..33 'self': &Self
54..58 'self': &Self
29..33 'self': &'? Self
54..58 'self': &'? Self
97..99 '{}': dyn Trait<u64>
109..110 'x': dyn Trait<u64>
128..129 'y': &dyn Trait<u64>
128..129 'y': &'? dyn Trait<u64>
148..265 '{ ...2(); }': ()
154..155 'x': dyn Trait<u64>
161..162 'y': &dyn Trait<u64>
161..162 'y': &'? dyn Trait<u64>
172..173 'z': dyn Trait<u64>
176..179 'bar': fn bar() -> dyn Trait<u64>
176..181 'bar()': dyn Trait<u64>
187..188 'x': dyn Trait<u64>
187..194 'x.foo()': u64
200..201 'y': &dyn Trait<u64>
200..201 'y': &'? dyn Trait<u64>
200..207 'y.foo()': u64
213..214 'z': dyn Trait<u64>
213..220 'z.foo()': u64
226..227 'x': dyn Trait<u64>
226..234 'x.foo2()': i64
240..241 'y': &dyn Trait<u64>
240..241 'y': &'? dyn Trait<u64>
240..248 'y.foo2()': i64
254..255 'z': dyn Trait<u64>
254..262 'z.foo2()': i64
@ -1514,16 +1515,16 @@ fn test(s: S<u32, i32>) {
s.bar().baz();
}"#,
expect![[r#"
32..36 'self': &Self
102..106 'self': &S<T, U>
128..139 '{ loop {} }': &dyn Trait<T, U>
32..36 'self': &'? Self
102..106 'self': &'? S<T, U>
128..139 '{ loop {} }': &'? dyn Trait<T, U>
130..137 'loop {}': !
135..137 '{}': ()
175..179 'self': &Self
175..179 'self': &'? Self
251..252 's': S<u32, i32>
267..289 '{ ...z(); }': ()
273..274 's': S<u32, i32>
273..280 's.bar()': &dyn Trait<u32, i32>
273..280 's.bar()': &'? dyn Trait<u32, i32>
273..286 's.bar().baz()': (u32, i32)
"#]],
);
@ -1548,19 +1549,19 @@ fn test(x: Trait, y: &Trait) -> u64 {
z.foo();
}"#,
expect![[r#"
26..30 'self': &Self
26..30 'self': &'? Self
60..62 '{}': dyn Trait
72..73 'x': dyn Trait
82..83 'y': &dyn Trait
82..83 'y': &'? dyn Trait
100..175 '{ ...o(); }': u64
106..107 'x': dyn Trait
113..114 'y': &dyn Trait
113..114 'y': &'? dyn Trait
124..125 'z': dyn Trait
128..131 'bar': fn bar() -> dyn Trait
128..133 'bar()': dyn Trait
139..140 'x': dyn Trait
139..146 'x.foo()': u64
152..153 'y': &dyn Trait
152..153 'y': &'? dyn Trait
152..159 'y.foo()': u64
165..166 'z': dyn Trait
165..172 'z.foo()': u64
@ -1580,14 +1581,14 @@ fn main() {
}
"#,
expect![[r#"
31..35 'self': &S
31..35 'self': &'? S
37..39 '{}': ()
47..48 '_': &dyn Fn(S)
47..48 '_': &'? dyn Fn(S)
58..60 '{}': ()
71..105 '{ ...()); }': ()
77..78 'f': fn f(&dyn Fn(S))
77..78 'f': fn f(&'? dyn Fn(S))
77..102 'f(&|nu...foo())': ()
79..101 '&|numb....foo()': &impl Fn(S)
79..101 '&|numb....foo()': &'? impl Fn(S)
80..101 '|numbe....foo()': impl Fn(S)
81..87 'number': S
89..95 'number': S
@ -1790,7 +1791,7 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
y.foo();
}"#,
expect![[r#"
53..57 'self': &Self
53..57 'self': &'? Self
66..68 '{}': u32
185..186 'x': T
191..192 'y': U
@ -1819,11 +1820,11 @@ fn test(x: &impl Trait1) {
x.foo();
}"#,
expect![[r#"
53..57 'self': &Self
53..57 'self': &'? Self
66..68 '{}': u32
119..120 'x': &impl Trait1
119..120 'x': &'? impl Trait1
136..152 '{ ...o(); }': ()
142..143 'x': &impl Trait1
142..143 'x': &'? impl Trait1
142..149 'x.foo()': u32
"#]],
);
@ -1934,8 +1935,8 @@ fn test() {
opt.map(f);
}"#,
expect![[r#"
28..32 'self': &Self
132..136 'self': &Bar<F>
28..32 'self': &'? Self
132..136 'self': &'? Bar<F>
149..160 '{ loop {} }': (A1, R)
151..158 'loop {}': !
156..158 '{}': ()
@ -1988,7 +1989,7 @@ fn test() {
let r2 = lazy2.foo();
}"#,
expect![[r#"
36..40 'self': &Foo
36..40 'self': &'? Foo
51..53 '{}': usize
131..132 'f': F
151..153 '{}': Lazy<T, F>
@ -2262,14 +2263,14 @@ impl Trait for S2 {
fn f(&self, x: <Self>::Item) { let y = x; }
}"#,
expect![[r#"
40..44 'self': &Self
40..44 'self': &'? Self
46..47 'x': Trait::Item<Self>
126..130 'self': &S
126..130 'self': &'? S
132..133 'x': u32
147..161 '{ let y = x; }': ()
153..154 'y': u32
157..158 'x': u32
228..232 'self': &S2
228..232 'self': &'? S2
234..235 'x': i32
251..265 '{ let y = x; }': ()
257..258 'y': i32
@ -2643,12 +2644,12 @@ fn main() {
72..74 '_v': F
117..120 '{ }': ()
132..163 '{ ... }); }': ()
138..148 'f::<(), _>': fn f<(), impl FnOnce(&())>(impl FnOnce(&()))
138..148 'f::<(), _>': fn f<(), impl FnOnce(&'? ())>(impl FnOnce(&'? ()))
138..160 'f::<()... z; })': ()
149..159 '|z| { z; }': impl FnOnce(&())
150..151 'z': &()
149..159 '|z| { z; }': impl FnOnce(&'? ())
150..151 'z': &'? ()
153..159 '{ z; }': ()
155..156 'z': &()
155..156 'z': &'? ()
"#]],
);
}
@ -2897,13 +2898,13 @@ fn test(x: &dyn Foo) {
foo(x);
}"#,
expect![[r#"
21..22 'x': &dyn Foo
21..22 'x': &'? dyn Foo
34..36 '{}': ()
46..47 'x': &dyn Foo
46..47 'x': &'? dyn Foo
59..74 '{ foo(x); }': ()
65..68 'foo': fn foo(&dyn Foo)
65..68 'foo': fn foo(&'? dyn Foo)
65..71 'foo(x)': ()
69..70 'x': &dyn Foo
69..70 'x': &'? dyn Foo
"#]],
);
}
@ -2927,7 +2928,7 @@ fn test() {
(IsCopy, NotCopy).test();
}"#,
expect![[r#"
78..82 'self': &Self
78..82 'self': &'? Self
134..235 '{ ...t(); }': ()
140..146 'IsCopy': IsCopy
140..153 'IsCopy.test()': bool
@ -2969,7 +2970,7 @@ fn test() {
28..29 'T': {unknown}
36..38 '{}': T
36..38: expected T, got ()
113..117 'self': &Self
113..117 'self': &'? Self
169..249 '{ ...t(); }': ()
175..178 'foo': fn foo()
175..185 'foo.test()': bool
@ -2997,16 +2998,16 @@ fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
f3.test();
}"#,
expect![[r#"
22..26 'self': &Self
22..26 'self': &'? Self
76..78 'f1': fn()
86..88 'f2': fn(usize) -> u8
107..109 'f3': fn(u8, u8) -> &u8
107..109 'f3': fn(u8, u8) -> &'? u8
130..178 '{ ...t(); }': ()
136..138 'f1': fn()
136..145 'f1.test()': bool
151..153 'f2': fn(usize) -> u8
151..160 'f2.test()': bool
166..168 'f3': fn(u8, u8) -> &u8
166..168 'f3': fn(u8, u8) -> &'? u8
166..175 'f3.test()': bool
"#]],
);
@ -3027,13 +3028,13 @@ fn test() {
(1u8, *"foo").test(); // not Sized
}"#,
expect![[r#"
22..26 'self': &Self
22..26 'self': &'? Self
79..194 '{ ...ized }': ()
85..88 '1u8': u8
85..95 '1u8.test()': bool
101..116 '(*"foo").test()': {unknown}
102..108 '*"foo"': str
103..108 '"foo"': &str
103..108 '"foo"': &'static str
135..145 '(1u8, 1u8)': (u8, u8)
135..152 '(1u8, ...test()': bool
136..139 '1u8': u8
@ -3042,7 +3043,7 @@ fn test() {
158..178 '(1u8, ...test()': {unknown}
159..162 '1u8': u8
164..170 '*"foo"': str
165..170 '"foo"': &str
165..170 '"foo"': &'static str
"#]],
);
}
@ -3093,7 +3094,7 @@ fn foo() {
93..94 'x': Option<i32>
109..111 '{}': ()
117..124 '(&f)(s)': ()
118..120 '&f': &impl Fn(Option<i32>)
118..120 '&f': &'? impl Fn(Option<i32>)
119..120 'f': impl Fn(Option<i32>)
122..123 's': Option<i32>
"#]],
@ -3170,25 +3171,25 @@ fn foo() {
f(&s);
}"#,
expect![[r#"
154..158 'self': &Box<T>
166..205 '{ ... }': &T
176..199 'unsafe...nner }': &T
185..197 '&*self.inner': &T
154..158 'self': &'? Box<T>
166..205 '{ ... }': &'? T
176..199 'unsafe...nner }': &'? T
185..197 '&*self.inner': &'? T
186..197 '*self.inner': T
187..191 'self': &Box<T>
187..191 'self': &'? Box<T>
187..197 'self.inner': *mut T
218..324 '{ ...&s); }': ()
228..229 's': Option<i32>
232..236 'None': Option<i32>
246..247 'f': Box<dyn FnOnce(&Option<i32>)>
281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
294..308 '&mut (|ps| {})': &mut impl FnOnce(&Option<i32>)
300..307 '|ps| {}': impl FnOnce(&Option<i32>)
301..303 'ps': &Option<i32>
246..247 'f': Box<dyn FnOnce(&'? Option<i32>)>
281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>)>
294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option<i32>)
300..307 '|ps| {}': impl FnOnce(&'? Option<i32>)
301..303 'ps': &'? Option<i32>
305..307 '{}': ()
316..317 'f': Box<dyn FnOnce(&Option<i32>)>
316..317 'f': Box<dyn FnOnce(&'? Option<i32>)>
316..321 'f(&s)': ()
318..320 '&s': &Option<i32>
318..320 '&s': &'? Option<i32>
319..320 's': Option<i32>
"#]],
);
@ -3320,7 +3321,7 @@ fn f() {
}
}"#,
expect![[r#"
46..50 'self': &Self
46..50 'self': &'? Self
58..63 '{ 0 }': u8
60..61 '0': u8
115..185 '{ ... } }': ()
@ -3595,7 +3596,7 @@ fn take_u32(_: u32) {}
fn minimized() {
let v = V::default();
let p = v.get(&0);
//^ &u32
//^ &'? u32
take_u32(42 + p);
}
"#,
@ -3625,7 +3626,7 @@ fn take_u32(_: u32) {}
fn minimized() {
let v = V::default();
let p = v.get();
//^ &{unknown}
//^ &'? {unknown}
take_u32(42 + p);
}
"#,
@ -3684,11 +3685,11 @@ fn main() {
}
"#,
expect![[r#"
44..48 'self': &Self
133..137 'self': &[u8; 4]
44..48 'self': &'? Self
133..137 'self': &'? [u8; 4]
155..172 '{ ... }': usize
165..166 '2': usize
236..240 'self': &[u8; 2]
236..240 'self': &'? [u8; 2]
258..275 '{ ... }': u8
268..269 '2': u8
289..392 '{ ...g(); }': ()
@ -3732,11 +3733,11 @@ fn main() {
}
"#,
expect![[r#"
44..48 'self': &Self
151..155 'self': &[u8; L]
44..48 'self': &'? Self
151..155 'self': &'? [u8; L]
173..194 '{ ... }': [u8; L]
183..188 '*self': [u8; L]
184..188 'self': &[u8; L]
184..188 'self': &'? [u8; L]
208..260 '{ ...g(); }': ()
218..219 'v': [u8; 2]
222..230 '[0u8; 2]': [u8; 2]
@ -4056,13 +4057,13 @@ fn g(t: &(dyn Sync + T2 + T1 + Send)) {
}
"#,
expect![[r#"
68..69 't': &{unknown}
68..69 't': &'? {unknown}
101..103 '{}': ()
109..110 't': &{unknown}
109..110 't': &'? {unknown}
142..155 '{ f(t); }': ()
148..149 'f': fn f(&{unknown})
148..149 'f': fn f(&'? {unknown})
148..152 'f(t)': ()
150..151 't': &{unknown}
150..151 't': &'? {unknown}
"#]],
);
@ -4105,7 +4106,7 @@ trait Trait {
}
fn f(t: &dyn Trait<T = (), T = ()>) {}
//^&{unknown}
//^&'? {unknown}
"#,
);
}
@ -4175,27 +4176,27 @@ trait Trait {
fn f<T>(v: impl Trait) {
let a = v.get::<i32>().deref();
//^ &i32
//^ &'? i32
let a = v.get::<T>().deref();
//^ &T
//^ &'? T
}
fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
let a = v.get::<T>();
//^ &T
//^ &'a T
let a = v.get::<()>();
//^ Trait::Assoc<(), impl Trait<Assoc<T> = &T>>
//^ Trait::Assoc<(), impl Trait<Assoc<T> = &'a T>>
}
fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
let a = v.get::<i32>();
//^ &i32
//^ &'a i32
let a = v.get::<i64>();
//^ &i64
//^ &'a i64
}
fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
let a = v.get::<i32>();
//^ &i32
//^ &'a i32
let a = v.get::<i64>();
//^ &i64
//^ &'a i64
}
"#,
);
@ -4221,12 +4222,12 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
}
"#,
expect![[r#"
90..94 'self': &Self
127..128 'v': &(dyn Trait<Assoc<i32> = &i32>)
90..94 'self': &'? Self
127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32>)
164..195 '{ ...f(); }': ()
170..171 'v': &(dyn Trait<Assoc<i32> = &i32>)
170..184 'v.get::<i32>()': &i32
170..192 'v.get:...eref()': &i32
170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32>)
170..184 'v.get::<i32>()': &'? i32
170..192 'v.get:...eref()': &'? i32
"#]],
);
}
@ -4487,19 +4488,19 @@ fn derive_macro_bounds() {
let x = (&Copy).clone();
//^ Copy
let x = (&NotCopy).clone();
//^ &NotCopy
//^ &'? NotCopy
let x = (&Generic(Copy)).clone();
//^ Generic<Copy>
let x = (&Generic(NotCopy)).clone();
//^ &Generic<NotCopy>
//^ &'? Generic<NotCopy>
let x: &AssocGeneric<Copy> = &AssocGeneric(NotCopy);
let x = x.clone();
//^ &AssocGeneric<Copy>
//^ &'? AssocGeneric<Copy>
// let x: &AssocGeneric2<Copy> = &AssocGeneric2(NotCopy);
// let x = x.clone();
let x: &AssocGeneric3<Copy> = &AssocGeneric3(Generic(NotCopy));
let x = x.clone();
//^ &AssocGeneric3<Copy>
//^ &'? AssocGeneric3<Copy>
let x = (&R1(Vec())).clone();
//^ R1
let x = (&R2(R1(Vec()))).clone();
@ -4582,7 +4583,7 @@ impl B for u16 {
fn ttt() {
let inp = Y;
x::<u16>(&inp);
//^^^^ expected &X, got &Y
//^^^^ expected &'? X, got &'? Y
}
"#,
);
@ -4629,7 +4630,7 @@ fn foo() {
let mut map = SomeMap;
map["a"] = ();
map;
//^^^ SomeMap<&str>
//^^^ SomeMap<&'static str>
}
"#,
);
@ -4764,3 +4765,62 @@ fn test() {
"#,
);
}
#[test]
fn associated_type_with_impl_trait_in_tuple() {
check_no_mismatches(
r#"
pub trait Iterator {
type Item;
}
pub trait Value {}
fn bar<I: Iterator<Item = (usize, impl Value)>>() {}
fn foo() {
bar();
}
"#,
);
}
#[test]
fn associated_type_with_impl_trait_in_nested_tuple() {
check_no_mismatches(
r#"
pub trait Iterator {
type Item;
}
pub trait Value {}
fn bar<I: Iterator<Item = ((impl Value, usize), u32)>>() {}
fn foo() {
bar();
}
"#,
);
}
#[test]
fn dyn_trait_with_lifetime_in_rpit() {
check_types(
r#"
//- minicore: future
pub struct Box<T> {}
trait Trait {}
pub async fn foo_async<'a>() -> Box<dyn Trait + 'a> {
Box {}
}
fn foo() {
foo_async();
//^^^^^^^^^^^impl Future<Output = Box<dyn Trait>> + ?Sized
}
"#,
)
}

View file

@ -9,9 +9,11 @@ use hir_ty::{db::HirDatabase, diagnostics::BodyValidationDiagnostic, InferenceDi
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
pub use hir_def::VariantId;
use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId};
use hir_expand::{name::Name, HirFileId, InFile};
use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
use triomphe::Arc;
use crate::{AssocItem, Field, Local, MacroKind, Trait, Type};
@ -171,7 +173,7 @@ pub struct MacroError {
pub struct MacroExpansionParseError {
pub node: InFile<SyntaxNodePtr>,
pub precise_location: Option<TextRange>,
pub errors: Box<[SyntaxError]>,
pub errors: Arc<[SyntaxError]>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
@ -200,6 +202,7 @@ pub struct MalformedDerive {
pub struct NoSuchField {
pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
pub private: bool,
pub variant: VariantId,
}
#[derive(Debug)]
@ -525,7 +528,7 @@ impl AnyDiagnostic {
source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
};
Some(match d {
&InferenceDiagnostic::NoSuchField { field: expr, private } => {
&InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
let expr_or_pat = match expr {
ExprOrPatId::ExprId(expr) => {
source_map.field_syntax(expr).map(AstPtr::wrap_left)
@ -534,7 +537,7 @@ impl AnyDiagnostic {
source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
}
};
NoSuchField { field: expr_or_pat, private }.into()
NoSuchField { field: expr_or_pat, private, variant }.into()
}
&InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
MismatchedArgCount { call_expr: expr_syntax(call_expr)?, expected, found }.into()

View file

@ -188,28 +188,7 @@ impl HirDisplay for Struct {
StructKind::Record => {
let has_where_clause = write_where_clause(def_id, f)?;
if let Some(limit) = f.entity_limit {
let fields = self.fields(f.db);
let count = fields.len().min(limit);
f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
if count == 0 {
if fields.is_empty() {
f.write_str("{}")?;
} else {
f.write_str("{ /* … */ }")?;
}
} else {
f.write_str(" {\n")?;
for field in &fields[..count] {
f.write_str(" ")?;
field.hir_fmt(f)?;
f.write_str(",\n")?;
}
if fields.len() > count {
f.write_str(" /* … */\n")?;
}
f.write_str("}")?;
}
display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
}
}
StructKind::Unit => _ = write_where_clause(def_id, f)?,
@ -226,18 +205,10 @@ impl HirDisplay for Enum {
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
write_generic_params(def_id, f)?;
let has_where_clause = write_where_clause(def_id, f)?;
let variants = self.variants(f.db);
if !variants.is_empty() {
f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
f.write_str("{\n")?;
for variant in variants {
f.write_str(" ")?;
variant.hir_fmt(f)?;
f.write_str(",\n")?;
}
f.write_str("}")?;
let has_where_clause = write_where_clause(def_id, f)?;
if let Some(limit) = f.entity_limit {
display_variants(&self.variants(f.db), has_where_clause, limit, f)?;
}
Ok(())
@ -251,24 +222,104 @@ impl HirDisplay for Union {
write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
write_generic_params(def_id, f)?;
let has_where_clause = write_where_clause(def_id, f)?;
let fields = self.fields(f.db);
if !fields.is_empty() {
f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
f.write_str("{\n")?;
for field in self.fields(f.db) {
f.write_str(" ")?;
field.hir_fmt(f)?;
f.write_str(",\n")?;
}
f.write_str("}")?;
if let Some(limit) = f.entity_limit {
display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
}
Ok(())
}
}
fn display_fields(
fields: &[Field],
has_where_clause: bool,
limit: usize,
in_line: bool,
f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
let count = fields.len().min(limit);
let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') };
f.write_char(if !has_where_clause { ' ' } else { separator })?;
if count == 0 {
if fields.is_empty() {
f.write_str("{}")?;
} else {
f.write_str("{ /* … */ }")?;
}
} else {
f.write_char('{')?;
if !fields.is_empty() {
f.write_char(separator)?;
for field in &fields[..count] {
f.write_str(indent)?;
field.hir_fmt(f)?;
f.write_char(',')?;
f.write_char(separator)?;
}
if fields.len() > count {
f.write_str(indent)?;
f.write_str("/* … */")?;
f.write_char(separator)?;
}
}
f.write_str("}")?;
}
Ok(())
}
fn display_variants(
variants: &[Variant],
has_where_clause: bool,
limit: usize,
f: &mut HirFormatter<'_>,
) -> Result<(), HirDisplayError> {
let count = variants.len().min(limit);
f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
if count == 0 {
if variants.is_empty() {
f.write_str("{}")?;
} else {
f.write_str("{ /* … */ }")?;
}
} else {
f.write_str("{\n")?;
for variant in &variants[..count] {
f.write_str(" ")?;
write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?;
match variant.kind(f.db) {
StructKind::Tuple => {
if variant.fields(f.db).is_empty() {
f.write_str("()")?;
} else {
f.write_str("( /* … */ )")?;
}
}
StructKind::Record => {
if variant.fields(f.db).is_empty() {
f.write_str(" {}")?;
} else {
f.write_str(" { /* … */ }")?;
}
}
StructKind::Unit => {}
}
f.write_str(",\n")?;
}
if variants.len() > count {
f.write_str(" /* … */\n")?;
}
f.write_str("}")?;
}
Ok(())
}
impl HirDisplay for Field {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
@ -304,21 +355,10 @@ impl HirDisplay for Variant {
}
f.write_char(')')?;
}
VariantData::Record(fields) => {
f.write_str(" {")?;
let mut first = true;
for (_, field) in fields.iter() {
if first {
first = false;
f.write_char(' ')?;
} else {
f.write_str(", ")?;
}
// Enum variant fields must be pub.
write!(f, "{}: ", field.name.display(f.db.upcast()))?;
field.type_ref.hir_fmt(f)?;
VariantData::Record(_) => {
if let Some(limit) = f.entity_limit {
display_fields(&self.fields(f.db), false, limit, true, f)?;
}
f.write_str(" }")?;
}
}
Ok(())

View file

@ -59,7 +59,9 @@ use hir_def::{
ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId,
TypeParamId, UnionId,
};
use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind};
use hir_expand::{
attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
};
use hir_ty::{
all_super_traits, autoderef, check_orphan_rules,
consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
@ -79,7 +81,7 @@ use hir_ty::{
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
use rustc_hash::FxHashSet;
use span::Edition;
use span::{Edition, MacroCallId};
use stdx::{impl_from, never};
use syntax::{
ast::{self, HasAttrs as _, HasName},
@ -559,6 +561,12 @@ impl Module {
emit_def_diagnostic(db, acc, diag);
}
if !self.id.is_block_module() {
// These are reported by the body of block modules
let scope = &def_map[self.id.local_id].scope;
scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc));
}
for def in self.declarations(db) {
match def {
ModuleDef::Module(m) => {
@ -577,6 +585,10 @@ impl Module {
item.diagnostics(db, acc, style_lints);
}
t.all_macro_calls(db)
.iter()
.for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc));
acc.extend(def.diagnostics(db, style_lints))
}
ModuleDef::Adt(adt) => {
@ -621,6 +633,11 @@ impl Module {
// FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
continue;
}
impl_def
.all_macro_calls(db)
.iter()
.for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc));
let ast_id_map = db.ast_id_map(file_id);
for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
@ -809,6 +826,37 @@ impl Module {
}
}
fn macro_call_diagnostics(
db: &dyn HirDatabase,
macro_call_id: MacroCallId,
acc: &mut Vec<AnyDiagnostic>,
) {
let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
return;
};
let ValueResult { value: parse_errors, err } = &*e;
if let Some(err) = err {
let loc = db.lookup_intern_macro_call(macro_call_id);
let (node, precise_location, macro_name, kind) = precise_macro_call_location(&loc.kind, db);
let diag = match err {
&hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
UnresolvedProcMacro { node, precise_location, macro_name, kind, krate }.into()
}
err => MacroError { node, precise_location, message: err.to_string() }.into(),
};
acc.push(diag);
}
if !parse_errors.is_empty() {
let loc = db.lookup_intern_macro_call(macro_call_id);
let (node, precise_location, _, _) = precise_macro_call_location(&loc.kind, db);
acc.push(
MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() }
.into(),
)
}
}
fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
let id = db.macro_def(m.id);
if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) {
@ -888,16 +936,6 @@ fn emit_def_diagnostic_(
.into(),
);
}
DefDiagnosticKind::MacroError { ast, message } => {
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
acc.push(MacroError { node, precise_location, message: message.clone() }.into());
}
DefDiagnosticKind::MacroExpansionParseError { ast, errors } => {
let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
acc.push(
MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(),
);
}
DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
let node = ast.to_node(db.upcast());
// Must have a name, otherwise we wouldn't emit it.
@ -1489,6 +1527,14 @@ impl Adt {
.map(|arena| arena.1.clone())
}
pub fn as_struct(&self) -> Option<Struct> {
if let Self::Struct(v) = self {
Some(*v)
} else {
None
}
}
pub fn as_enum(&self) -> Option<Enum> {
if let Self::Enum(v) = self {
Some(*v)
@ -1636,6 +1682,10 @@ impl DefWithBody {
Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
}
source_map
.macro_calls()
.for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id.macro_call_id, acc));
for diag in source_map.diagnostics() {
acc.push(match diag {
BodyDiagnostic::InactiveCode { node, cfg, opts } => {
@ -2437,6 +2487,14 @@ impl Trait {
.filter(|(_, ty)| !count_required_only || !ty.has_default())
.count()
}
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
db.trait_data(self.id)
.macro_calls
.as_ref()
.map(|it| it.as_ref().clone().into_boxed_slice())
.unwrap_or_default()
}
}
impl HasVisibility for Trait {
@ -2505,6 +2563,15 @@ impl HasVisibility for TypeAlias {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StaticLifetime;
impl StaticLifetime {
pub fn name(self) -> Name {
known::STATIC_LIFETIME
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BuiltinType {
pub(crate) inner: hir_def::builtin_type::BuiltinType,
@ -2535,6 +2602,20 @@ impl BuiltinType {
matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
}
pub fn is_f32(&self) -> bool {
matches!(
self.inner,
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F32)
)
}
pub fn is_f64(&self) -> bool {
matches!(
self.inner,
hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F64)
)
}
pub fn is_char(&self) -> bool {
matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
}
@ -3743,6 +3824,14 @@ impl Impl {
pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool {
check_orphan_rules(db, self.id)
}
fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
db.impl_data(self.id)
.macro_calls
.as_ref()
.map(|it| it.as_ref().clone().into_boxed_slice())
.unwrap_or_default()
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@ -4495,7 +4584,8 @@ impl Type {
name: Option<&Name>,
mut callback: impl FnMut(Function) -> Option<T>,
) -> Option<T> {
let _p = tracing::span!(tracing::Level::INFO, "iterate_method_candidates").entered();
let _p =
tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered();
let mut slot = None;
self.iterate_method_candidates_dyn(

View file

@ -131,7 +131,7 @@ pub struct SemanticsImpl<'db> {
pub db: &'db dyn HirDatabase,
s2d_cache: RefCell<SourceToDefCache>,
/// Rootnode to HirFileId cache
cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
// These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens
// So we might wanna move them out into something specific for semantic highlighting
expansion_info_cache: RefCell<FxHashMap<MacroFileId, ExpansionInfo>>,
@ -294,7 +294,7 @@ impl<'db> SemanticsImpl<'db> {
SemanticsImpl {
db,
s2d_cache: Default::default(),
cache: Default::default(),
root_to_file_cache: Default::default(),
expansion_info_cache: Default::default(),
macro_call_cache: Default::default(),
}
@ -690,6 +690,7 @@ impl<'db> SemanticsImpl<'db> {
exp_info
});
// FIXME: uncached parse
// Create the source analyzer for the macro call scope
let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file()))
else {
@ -722,7 +723,7 @@ impl<'db> SemanticsImpl<'db> {
mut token: SyntaxToken,
f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
) {
let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros").entered();
let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered();
let (sa, span, file_id) =
match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) {
Some(sa) => match sa.file_id.file_id() {
@ -1025,6 +1026,7 @@ impl<'db> SemanticsImpl<'db> {
None => {
let call_node = file_id.macro_file()?.call_node(db);
// cache the node
// FIXME: uncached parse
self.parse_or_expand(call_node.file_id);
Some(call_node)
}
@ -1370,7 +1372,7 @@ impl<'db> SemanticsImpl<'db> {
offset: Option<TextSize>,
infer_body: bool,
) -> Option<SourceAnalyzer> {
let _p = tracing::span!(tracing::Level::INFO, "Semantics::analyze_impl").entered();
let _p = tracing::span!(tracing::Level::INFO, "SemanticsImpl::analyze_impl").entered();
let node = self.find_file(node);
let container = self.with_ctx(|ctx| ctx.find_container(node))?;
@ -1397,7 +1399,7 @@ impl<'db> SemanticsImpl<'db> {
fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
assert!(root_node.parent().is_none());
let mut cache = self.cache.borrow_mut();
let mut cache = self.root_to_file_cache.borrow_mut();
let prev = cache.insert(root_node, file_id);
assert!(prev.is_none() || prev == Some(file_id))
}
@ -1407,7 +1409,7 @@ impl<'db> SemanticsImpl<'db> {
}
fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
let cache = self.cache.borrow();
let cache = self.root_to_file_cache.borrow();
cache.get(root_node).copied()
}
@ -1427,7 +1429,7 @@ impl<'db> SemanticsImpl<'db> {
known nodes: {}\n\n",
node,
root_node,
self.cache
self.root_to_file_cache
.borrow()
.keys()
.map(|it| format!("{it:?}"))

View file

@ -118,10 +118,10 @@ pub(super) struct SourceToDefCtx<'a, 'b> {
impl SourceToDefCtx<'_, '_> {
pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def").entered();
let _p = tracing::span!(tracing::Level::INFO, "SourceToDefCtx::file_to_def").entered();
let mut mods = SmallVec::new();
for &crate_id in self.db.relevant_crates(file).iter() {
// FIXME: inner items
// Note: `mod` declarations in block modules cannot be supported here
let crate_def_map = self.db.crate_def_map(crate_id);
mods.extend(
crate_def_map
@ -129,6 +129,9 @@ impl SourceToDefCtx<'_, '_> {
.map(|local_id| crate_def_map.module_id(local_id)),
)
}
if mods.is_empty() {
// FIXME: detached file
}
mods
}

View file

@ -28,7 +28,7 @@ use hir_expand::{
mod_path::path,
name,
name::{AsName, Name},
HirFileId, InFile, MacroFileId, MacroFileIdExt,
HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt,
};
use hir_ty::{
diagnostics::{
@ -118,7 +118,7 @@ impl SourceAnalyzer {
fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
let src = match expr {
ast::Expr::MacroExpr(expr) => {
self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?
self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
}
_ => InFile::new(self.file_id, expr.clone()),
};
@ -145,20 +145,20 @@ impl SourceAnalyzer {
&self,
db: &dyn HirDatabase,
expr: InFile<ast::MacroCall>,
) -> Option<InFile<ast::Expr>> {
) -> Option<InMacroFile<ast::Expr>> {
let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
let expanded = db.parse_or_expand(macro_file);
let expanded = db.parse_macro_expansion(macro_file).value.0.syntax_node();
let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
match stmts.expr()? {
ast::Expr::MacroExpr(mac) => {
self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
self.expand_expr(db, InFile::new(macro_file.into(), mac.macro_call()?))?
}
expr => InFile::new(macro_file, expr),
expr => InMacroFile::new(macro_file, expr),
}
} else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
self.expand_expr(db, InFile::new(macro_file, call))?
self.expand_expr(db, InFile::new(macro_file.into(), call))?
} else {
InFile::new(macro_file, ast::Expr::cast(expanded)?)
InMacroFile::new(macro_file, ast::Expr::cast(expanded)?)
};
Some(res)

View file

@ -127,6 +127,13 @@ impl LookupTable {
self.types_wishlist.insert(ty.clone());
}
// Collapse suggestions if there are many
if let Some(res) = &res {
if res.len() > self.many_threshold {
return Some(vec![Expr::Many(ty.clone())]);
}
}
res
}
@ -158,6 +165,13 @@ impl LookupTable {
self.types_wishlist.insert(ty.clone());
}
// Collapse suggestions if there are many
if let Some(res) = &res {
if res.len() > self.many_threshold {
return Some(vec![Expr::Many(ty.clone())]);
}
}
res
}
@ -255,13 +269,13 @@ pub struct TermSearchConfig {
pub enable_borrowcheck: bool,
/// Indicate when to squash multiple trees to `Many` as there are too many to keep track
pub many_alternatives_threshold: usize,
/// Depth of the search eg. number of cycles to run
pub depth: usize,
/// Fuel for term search in "units of work"
pub fuel: u64,
}
impl Default for TermSearchConfig {
fn default() -> Self {
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 }
Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
}
}
@ -280,8 +294,7 @@ impl Default for TermSearchConfig {
/// transformation tactics. For example functions take as from set of types (arguments) to some
/// type (return type). Other transformations include methods on type, type constructors and
/// projections to struct fields (field access).
/// 3. Once we manage to find path to type we are interested in we continue for single round to see
/// if we can find more paths that take us to the `goal` type.
/// 3. If we run out of fuel (term search takes too long) we stop iterating.
/// 4. Return all the paths (type trees) that take us to the `goal` type.
///
/// Note that there are usually more ways we can get to the `goal` type but some are discarded to
@ -297,21 +310,31 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
});
let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone());
let fuel = std::cell::Cell::new(ctx.config.fuel);
let should_continue = &|| {
let remaining = fuel.get();
fuel.set(remaining.saturating_sub(1));
if remaining == 0 {
tracing::debug!("fuel exhausted");
}
remaining > 0
};
// Try trivial tactic first, also populates lookup table
let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
// Use well known types tactic before iterations as it does not depend on other tactics
solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
for _ in 0..ctx.config.depth {
while should_continue() {
lookup.new_round();
solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup));
solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup));
solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
// Discard not interesting `ScopeDef`s for speedup
for def in lookup.exhausted_scopedefs() {

View file

@ -211,13 +211,13 @@ impl Expr {
}
}
Expr::Method { func, target, params, .. } => {
if target.contains_many_in_illegal_pos() {
if self.contains_many_in_illegal_pos(db) {
return Ok(many_formatter(&target.ty(db)));
}
let func_name = func.name(db).display(db.upcast()).to_string();
let self_param = func.self_param(db).unwrap();
let target = target.gen_source_code(
let target_str = target.gen_source_code(
sema_scope,
many_formatter,
prefer_no_std,
@ -236,9 +236,12 @@ impl Expr {
Some(trait_) => {
let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
let target = match self_param.access(db) {
crate::Access::Shared => format!("&{target}"),
crate::Access::Exclusive => format!("&mut {target}"),
crate::Access::Owned => target,
crate::Access::Shared if !target.is_many() => format!("&{target_str}"),
crate::Access::Exclusive if !target.is_many() => {
format!("&mut {target_str}")
}
crate::Access::Owned => target_str,
_ => many_formatter(&target.ty(db)),
};
let res = match args.is_empty() {
true => format!("{trait_name}::{func_name}({target})",),
@ -246,7 +249,7 @@ impl Expr {
};
Ok(res)
}
None => Ok(format!("{target}.{func_name}({args})")),
None => Ok(format!("{target_str}.{func_name}({args})")),
}
}
Expr::Variant { variant, generics, params } => {
@ -381,7 +384,7 @@ impl Expr {
Ok(res)
}
Expr::Field { expr, field } => {
if expr.contains_many_in_illegal_pos() {
if expr.contains_many_in_illegal_pos(db) {
return Ok(many_formatter(&expr.ty(db)));
}
@ -395,7 +398,7 @@ impl Expr {
Ok(format!("{strukt}.{field}"))
}
Expr::Reference(expr) => {
if expr.contains_many_in_illegal_pos() {
if expr.contains_many_in_illegal_pos(db) {
return Ok(many_formatter(&expr.ty(db)));
}
@ -466,10 +469,15 @@ impl Expr {
/// macro!().bar()
/// &macro!()
/// ```
fn contains_many_in_illegal_pos(&self) -> bool {
fn contains_many_in_illegal_pos(&self, db: &dyn HirDatabase) -> bool {
match self {
Expr::Method { target, .. } => target.contains_many_in_illegal_pos(),
Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(),
Expr::Method { target, func, .. } => {
match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) {
Some(_) => false,
None => target.is_many(),
}
}
Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(db),
Expr::Reference(target) => target.is_many(),
Expr::Many(_) => true,
_ => false,

View file

@ -4,6 +4,7 @@
//! * `ctx` - Context for the term search
//! * `defs` - Set of items in scope at term search target location
//! * `lookup` - Lookup table for types
//! * `should_continue` - Function that indicates when to stop iterating
//! And they return iterator that yields type trees that unify with the `goal` type.
use std::iter;
@ -97,16 +98,19 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
/// * `ctx` - Context for the term search
/// * `defs` - Set of items in scope at term search target location
/// * `lookup` - Lookup table for types
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn type_constructor<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
fn variant_helper(
db: &dyn HirDatabase,
lookup: &mut LookupTable,
should_continue: &dyn std::ops::Fn() -> bool,
parent_enum: Enum,
variant: Variant,
config: &TermSearchConfig,
@ -152,6 +156,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
generic_params
.filter(|_| should_continue())
.filter_map(move |generics| {
// Insert default type params
let mut g = generics.into_iter();
@ -194,8 +199,14 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
defs.iter()
.filter_map(move |def| match def {
ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
let variant_exprs =
variant_helper(db, lookup, it.parent_enum(db), *it, &ctx.config);
let variant_exprs = variant_helper(
db,
lookup,
should_continue,
it.parent_enum(db),
*it,
&ctx.config,
);
if variant_exprs.is_empty() {
return None;
}
@ -213,7 +224,9 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
let exprs: Vec<(Type, Vec<Expr>)> = enum_
.variants(db)
.into_iter()
.flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.config))
.flat_map(|it| {
variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
})
.collect();
if exprs.is_empty() {
@ -271,6 +284,7 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
.chain((non_default_type_params_len == 0).then_some(Vec::new()));
let exprs = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
@ -345,10 +359,12 @@ pub(super) fn type_constructor<'a, DB: HirDatabase>(
/// * `ctx` - Context for the term search
/// * `defs` - Set of items in scope at term search target location
/// * `lookup` - Lookup table for types
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn free_function<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
@ -390,6 +406,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
.permutations(non_default_type_params_len);
let exprs: Vec<_> = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
@ -474,10 +491,12 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
/// * `ctx` - Context for the term search
/// * `defs` - Set of items in scope at term search target location
/// * `lookup` - Lookup table for types
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn impl_method<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
_defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
@ -554,6 +573,7 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
.permutations(non_default_fn_type_params_len);
let exprs: Vec<_> = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
@ -645,10 +665,12 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
/// * `ctx` - Context for the term search
/// * `defs` - Set of items in scope at term search target location
/// * `lookup` - Lookup table for types
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn struct_projection<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
_defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
@ -656,6 +678,7 @@ pub(super) fn struct_projection<'a, DB: HirDatabase>(
.new_types(NewTypesKey::StructProjection)
.into_iter()
.map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup")))
.filter(|_| should_continue())
.flat_map(move |(ty, targets)| {
ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| {
if !field.is_visible_from(db, module) {
@ -716,10 +739,12 @@ pub(super) fn famous_types<'a, DB: HirDatabase>(
/// * `ctx` - Context for the term search
/// * `defs` - Set of items in scope at term search target location
/// * `lookup` - Lookup table for types
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn impl_static_method<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
_defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
@ -728,6 +753,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
.clone()
.into_iter()
.chain(iter::once(ctx.goal.clone()))
.filter(|_| should_continue())
.flat_map(|ty| {
Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
})
@ -801,6 +827,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
.permutations(non_default_fn_type_params_len);
let exprs: Vec<_> = generic_params
.filter(|_| should_continue())
.filter_map(|generics| {
// Insert default type params
let mut g = generics.into_iter();
@ -884,10 +911,12 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
/// * `ctx` - Context for the term search
/// * `defs` - Set of items in scope at term search target location
/// * `lookup` - Lookup table for types
/// * `should_continue` - Function that indicates when to stop iterating
pub(super) fn make_tuple<'a, DB: HirDatabase>(
ctx: &'a TermSearchCtx<'a, DB>,
_defs: &'a FxHashSet<ScopeDef>,
lookup: &'a mut LookupTable,
should_continue: &'a dyn std::ops::Fn() -> bool,
) -> impl Iterator<Item = Expr> + 'a {
let db = ctx.sema.db;
let module = ctx.scope.module();
@ -896,6 +925,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
.types_wishlist()
.clone()
.into_iter()
.filter(|_| should_continue())
.filter(|ty| ty.is_tuple())
.filter_map(move |ty| {
// Double check to not contain unknown
@ -915,6 +945,7 @@ pub(super) fn make_tuple<'a, DB: HirDatabase>(
let exprs: Vec<Expr> = param_exprs
.into_iter()
.multi_cartesian_product()
.filter(|_| should_continue())
.map(|params| {
let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
let tuple_ty = Type::new_tuple(module.krate().into(), &tys);

View file

@ -16,4 +16,5 @@ pub struct AssistConfig {
pub prefer_no_std: bool,
pub prefer_prelude: bool,
pub assist_emit_must_use: bool,
pub term_search_fuel: u64,
}

View file

@ -8,8 +8,7 @@ use ide_db::{
};
use syntax::{
ast::{self, make, AstNode, Expr::BinExpr, HasArgList},
ted::{self, Position},
SyntaxKind,
ted, SyntaxKind, T,
};
use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
@ -62,7 +61,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
let demorganed = bin_expr.clone_subtree().clone_for_update();
ted::replace(demorganed.op_token()?, ast::make::token(inv_token));
let mut exprs = VecDeque::from(vec![
let mut exprs = VecDeque::from([
(bin_expr.lhs()?, demorganed.lhs()?),
(bin_expr.rhs()?, demorganed.rhs()?),
]);
@ -93,58 +92,38 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
}
}
let dm_lhs = demorganed.lhs()?;
acc.add_group(
&GroupLabel("Apply De Morgan's law".to_owned()),
AssistId("apply_demorgan", AssistKind::RefactorRewrite),
"Apply De Morgan's law",
op_range,
|edit| {
let demorganed = ast::Expr::BinExpr(demorganed);
let paren_expr = bin_expr.syntax().parent().and_then(ast::ParenExpr::cast);
let neg_expr = paren_expr
.clone()
.and_then(|paren_expr| paren_expr.syntax().parent())
.and_then(ast::PrefixExpr::cast)
.and_then(|prefix_expr| {
if prefix_expr.op_kind()? == ast::UnaryOp::Not {
Some(prefix_expr)
} else {
None
}
});
.filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not)))
.map(ast::Expr::PrefixExpr);
if let Some(paren_expr) = paren_expr {
if let Some(neg_expr) = neg_expr {
cov_mark::hit!(demorgan_double_negation);
edit.replace_ast(ast::Expr::PrefixExpr(neg_expr), demorganed.into());
let parent = neg_expr.syntax().parent();
if parent.is_some_and(|parent| demorganed.needs_parens_in(parent)) {
cov_mark::hit!(demorgan_keep_parens_for_op_precedence2);
edit.replace_ast(neg_expr, make::expr_paren(demorganed));
} else {
edit.replace_ast(neg_expr, demorganed);
};
} else {
cov_mark::hit!(demorgan_double_parens);
ted::insert_all_raw(
Position::before(dm_lhs.syntax()),
vec![
syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)),
syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)),
],
);
ted::append_child_raw(
demorganed.syntax(),
syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::R_PAREN)),
);
edit.replace_ast(ast::Expr::ParenExpr(paren_expr), demorganed.into());
edit.replace_ast(paren_expr.into(), add_bang_paren(demorganed));
}
} else {
ted::insert_all_raw(
Position::before(dm_lhs.syntax()),
vec![
syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)),
syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)),
],
);
ted::append_child_raw(demorganed.syntax(), ast::make::token(SyntaxKind::R_PAREN));
edit.replace_ast(bin_expr, demorganed);
edit.replace_ast(bin_expr.into(), add_bang_paren(demorganed));
}
},
)
@ -271,6 +250,11 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) {
}
}
/// Add bang and parentheses to the expression.
fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
make::expr_prefix(T![!], make::expr_paren(expr))
}
#[cfg(test)]
mod tests {
use super::*;
@ -349,16 +333,14 @@ fn f() { !(S <= S || S < S) }
check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
}
// FIXME : This needs to go.
// // https://github.com/rust-lang/rust-analyzer/issues/10963
// #[test]
// fn demorgan_doesnt_hang() {
// check_assist(
// apply_demorgan,
// "fn f() { 1 || 3 &&$0 4 || 5 }",
// "fn f() { !(!1 || !3 || !4) || 5 }",
// )
// }
#[test]
fn demorgan_doesnt_hang() {
check_assist(
apply_demorgan,
"fn f() { 1 || 3 &&$0 4 || 5 }",
"fn f() { 1 || !(!3 || !4) || 5 }",
)
}
#[test]
fn demorgan_keep_pars_for_op_precedence() {
@ -375,6 +357,21 @@ fn f() { !(S <= S || S < S) }
);
}
#[test]
fn demorgan_keep_pars_for_op_precedence2() {
cov_mark::check!(demorgan_keep_parens_for_op_precedence2);
check_assist(
apply_demorgan,
"fn f() { (a && !(b &&$0 c); }",
"fn f() { (a && (!b || !c); }",
);
}
#[test]
fn demorgan_keep_pars_for_op_precedence3() {
check_assist(apply_demorgan, "fn f() { (a || !(b &&$0 c); }", "fn f() { (a || !b || !c; }");
}
#[test]
fn demorgan_removes_pars_in_eq_precedence() {
check_assist(
@ -384,6 +381,11 @@ fn f() { !(S <= S || S < S) }
)
}
#[test]
fn demorgan_removes_pars_for_op_precedence2() {
check_assist(apply_demorgan, "fn f() { (a || !(b ||$0 c); }", "fn f() { (a || !b && !c; }");
}
#[test]
fn demorgan_iterator_any_all_reverse() {
check_assist(

View file

@ -85,7 +85,7 @@ fn edit_struct_def(
strukt: &Either<ast::Struct, ast::Variant>,
record_fields: ast::RecordFieldList,
) {
// Note that we don't need to consider macro files in this function because this this is
// Note that we don't need to consider macro files in this function because this is
// currently not triggered for struct definitions inside macro calls.
let tuple_fields = record_fields
.fields()

View file

@ -5623,7 +5623,7 @@ fn func<T: Debug>(i: Struct<'_, T>) {
fun_name(i);
}
fn $0fun_name(i: Struct<'_, T>) {
fn $0fun_name(i: Struct<T>) {
foo(i);
}
"#,

View file

@ -1,6 +1,6 @@
use hir::{
Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics, Type,
TypeInfo,
Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics,
StructKind, Type, TypeInfo,
};
use ide_db::{
base_db::FileId,
@ -15,8 +15,8 @@ use itertools::Itertools;
use stdx::to_lower_snake_case;
use syntax::{
ast::{
self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, CallExpr, HasArgList,
HasGenericParams, HasModuleItem, HasTypeBounds,
self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr,
HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds,
},
ted, SyntaxKind, SyntaxNode, TextRange, T,
};
@ -66,7 +66,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
}
let fn_name = &*name_ref.text();
let TargetInfo { target_module, adt_name, target, file } =
let TargetInfo { target_module, adt_info, target, file } =
fn_target_info(ctx, path, &call, fn_name)?;
if let Some(m) = target_module {
@ -75,15 +75,16 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
}
}
let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
let function_builder =
FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target, &adt_info)?;
let text_range = call.syntax().text_range();
let label = format!("Generate {} function", function_builder.fn_name);
add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label)
add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_info, label)
}
struct TargetInfo {
target_module: Option<Module>,
adt_name: Option<hir::Name>,
adt_info: Option<AdtInfo>,
target: GeneratedFunctionTarget,
file: FileId,
}
@ -91,11 +92,11 @@ struct TargetInfo {
impl TargetInfo {
fn new(
target_module: Option<Module>,
adt_name: Option<hir::Name>,
adt_info: Option<AdtInfo>,
target: GeneratedFunctionTarget,
file: FileId,
) -> Self {
Self { target_module, adt_name, target, file }
Self { target_module, adt_info, target, file }
}
}
@ -157,9 +158,9 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
target,
)?;
let text_range = call.syntax().text_range();
let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
let adt_info = AdtInfo::new(adt, impl_.is_some());
let label = format!("Generate {} method", function_builder.fn_name);
add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label)
add_func_to_accumulator(acc, ctx, text_range, function_builder, file, Some(adt_info), label)
}
fn add_func_to_accumulator(
@ -168,7 +169,7 @@ fn add_func_to_accumulator(
text_range: TextRange,
function_builder: FunctionBuilder,
file: FileId,
adt_name: Option<hir::Name>,
adt_info: Option<AdtInfo>,
label: String,
) -> Option<()> {
acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |edit| {
@ -177,8 +178,14 @@ fn add_func_to_accumulator(
let target = function_builder.target.clone();
let func = function_builder.render(ctx.config.snippet_cap, edit);
if let Some(name) = adt_name {
let name = make::ty_path(make::ext::ident_path(&format!("{}", name.display(ctx.db()))));
if let Some(adt) =
adt_info
.and_then(|adt_info| if adt_info.impl_exists { None } else { Some(adt_info.adt) })
{
let name = make::ty_path(make::ext::ident_path(&format!(
"{}",
adt.name(ctx.db()).display(ctx.db())
)));
// FIXME: adt may have generic params.
let impl_ = make::impl_(None, None, name, None, None).clone_for_update();
@ -210,6 +217,7 @@ struct FunctionBuilder {
generic_param_list: Option<ast::GenericParamList>,
where_clause: Option<ast::WhereClause>,
params: ast::ParamList,
fn_body: BlockExpr,
ret_type: Option<ast::RetType>,
should_focus_return_type: bool,
visibility: Visibility,
@ -225,6 +233,7 @@ impl FunctionBuilder {
fn_name: &str,
target_module: Option<Module>,
target: GeneratedFunctionTarget,
adt_info: &Option<AdtInfo>,
) -> Option<Self> {
let target_module =
target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
@ -243,9 +252,27 @@ impl FunctionBuilder {
let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
let is_async = await_expr.is_some();
let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
let (ret_type, should_focus_return_type) =
make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params);
let ret_type;
let should_focus_return_type;
let fn_body;
// If generated function has the name "new" and is an associated function, we generate fn body
// as a constructor and assume a "Self" return type.
if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) {
ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self"))));
should_focus_return_type = false;
fn_body = body;
} else {
let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
(ret_type, should_focus_return_type) = make_return_type(
ctx,
&expr_for_ret_ty,
target_module,
&mut necessary_generic_params,
);
let placeholder_expr = make::ext::expr_todo();
fn_body = make::block_expr(vec![], Some(placeholder_expr));
};
let (generic_param_list, where_clause) =
fn_generic_params(ctx, necessary_generic_params, &target)?;
@ -256,6 +283,7 @@ impl FunctionBuilder {
generic_param_list,
where_clause,
params,
fn_body,
ret_type,
should_focus_return_type,
visibility,
@ -294,12 +322,16 @@ impl FunctionBuilder {
let (generic_param_list, where_clause) =
fn_generic_params(ctx, necessary_generic_params, &target)?;
let placeholder_expr = make::ext::expr_todo();
let fn_body = make::block_expr(vec![], Some(placeholder_expr));
Some(Self {
target,
fn_name,
generic_param_list,
where_clause,
params,
fn_body,
ret_type,
should_focus_return_type,
visibility,
@ -308,8 +340,6 @@ impl FunctionBuilder {
}
fn render(self, cap: Option<SnippetCap>, edit: &mut SourceChangeBuilder) -> ast::Fn {
let placeholder_expr = make::ext::expr_todo();
let fn_body = make::block_expr(vec![], Some(placeholder_expr));
let visibility = match self.visibility {
Visibility::None => None,
Visibility::Crate => Some(make::visibility_pub_crate()),
@ -321,7 +351,7 @@ impl FunctionBuilder {
self.generic_param_list,
self.where_clause,
self.params,
fn_body,
self.fn_body,
self.ret_type,
self.is_async,
false, // FIXME : const and unsafe are not handled yet.
@ -391,6 +421,53 @@ fn make_return_type(
(ret_type, should_focus_return_type)
}
fn make_fn_body_as_new_function(
ctx: &AssistContext<'_>,
fn_name: &str,
adt_info: &Option<AdtInfo>,
) -> Option<ast::BlockExpr> {
if fn_name != "new" {
return None;
};
let adt_info = adt_info.as_ref()?;
let path_self = make::ext::ident_path("Self");
let placeholder_expr = make::ext::expr_todo();
let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() {
match strukt.kind(ctx.db()) {
StructKind::Record => {
let fields = strukt
.fields(ctx.db())
.iter()
.map(|field| {
make::record_expr_field(
make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))),
Some(placeholder_expr.clone()),
)
})
.collect::<Vec<_>>();
make::record_expr(path_self, make::record_expr_field_list(fields)).into()
}
StructKind::Tuple => {
let args = strukt
.fields(ctx.db())
.iter()
.map(|_| placeholder_expr.clone())
.collect::<Vec<_>>();
make::expr_call(make::expr_path(path_self), make::arg_list(args))
}
StructKind::Unit => make::expr_path(path_self),
}
} else {
placeholder_expr
};
let fn_body = make::block_expr(vec![], Some(tail_expr));
Some(fn_body)
}
fn get_fn_target_info(
ctx: &AssistContext<'_>,
target_module: Option<Module>,
@ -443,8 +520,8 @@ fn assoc_fn_target_info(
}
let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
let target = get_method_target(ctx, &impl_, &adt)?;
let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
Some(TargetInfo::new(target_module, adt_name, target, file))
let adt_info = AdtInfo::new(adt, impl_.is_some());
Some(TargetInfo::new(target_module, Some(adt_info), target, file))
}
#[derive(Clone)]
@ -560,6 +637,17 @@ impl GeneratedFunctionTarget {
}
}
struct AdtInfo {
adt: hir::Adt,
impl_exists: bool,
}
impl AdtInfo {
fn new(adt: Adt, impl_exists: bool) -> Self {
Self { adt, impl_exists }
}
}
/// Computes parameter list for the generated function.
fn fn_args(
ctx: &AssistContext<'_>,
@ -2758,18 +2846,18 @@ fn main() {
r"
enum Foo {}
fn main() {
Foo::new$0();
Foo::bar$0();
}
",
r"
enum Foo {}
impl Foo {
fn new() ${0:-> _} {
fn bar() ${0:-> _} {
todo!()
}
}
fn main() {
Foo::new();
Foo::bar();
}
",
)
@ -2849,4 +2937,152 @@ fn main() {
",
);
}
#[test]
fn new_function_assume_self_type() {
check_assist(
generate_function,
r"
pub struct Foo {
field_1: usize,
field_2: String,
}
fn main() {
let foo = Foo::new$0();
}
",
r"
pub struct Foo {
field_1: usize,
field_2: String,
}
impl Foo {
fn new() -> Self {
${0:Self { field_1: todo!(), field_2: todo!() }}
}
}
fn main() {
let foo = Foo::new();
}
",
)
}
#[test]
fn new_function_assume_self_type_for_tuple_struct() {
check_assist(
generate_function,
r"
pub struct Foo (usize, String);
fn main() {
let foo = Foo::new$0();
}
",
r"
pub struct Foo (usize, String);
impl Foo {
fn new() -> Self {
${0:Self(todo!(), todo!())}
}
}
fn main() {
let foo = Foo::new();
}
",
)
}
#[test]
fn new_function_assume_self_type_for_unit_struct() {
check_assist(
generate_function,
r"
pub struct Foo;
fn main() {
let foo = Foo::new$0();
}
",
r"
pub struct Foo;
impl Foo {
fn new() -> Self {
${0:Self}
}
}
fn main() {
let foo = Foo::new();
}
",
)
}
#[test]
fn new_function_assume_self_type_for_enum() {
check_assist(
generate_function,
r"
pub enum Foo {}
fn main() {
let foo = Foo::new$0();
}
",
r"
pub enum Foo {}
impl Foo {
fn new() -> Self {
${0:todo!()}
}
}
fn main() {
let foo = Foo::new();
}
",
)
}
#[test]
fn new_function_assume_self_type_with_args() {
check_assist(
generate_function,
r#"
pub struct Foo {
field_1: usize,
field_2: String,
}
struct Baz;
fn baz() -> Baz { Baz }
fn main() {
let foo = Foo::new$0(baz(), baz(), "foo", "bar");
}
"#,
r#"
pub struct Foo {
field_1: usize,
field_2: String,
}
impl Foo {
fn new(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) -> Self {
${0:Self { field_1: todo!(), field_2: todo!() }}
}
}
struct Baz;
fn baz() -> Baz { Baz }
fn main() {
let foo = Foo::new(baz(), baz(), "foo", "bar");
}
"#,
)
}
}

View file

@ -1,6 +1,7 @@
use std::iter;
use ast::edit::IndentLevel;
use hir::HasAttrs;
use ide_db::base_db::AnchoredPathBuf;
use itertools::Itertools;
use stdx::format_to;
@ -50,9 +51,17 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|builder| {
let path = {
let mut buf = String::from("./");
match parent_module.name(ctx.db()) {
Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
format_to!(buf, "{}/", name.display(ctx.db()))
let db = ctx.db();
match parent_module.name(db) {
Some(name)
if !parent_module.is_mod_rs(db)
&& parent_module
.attrs(db)
.by_key("path")
.string_value_unescape()
.is_none() =>
{
format_to!(buf, "{}/", name.display(db))
}
_ => (),
}
@ -107,6 +116,72 @@ mod tests {
use super::*;
#[test]
fn extract_with_specified_path_attr() {
check_assist(
move_module_to_file,
r#"
//- /main.rs
#[path="parser/__mod.rs"]
mod parser;
//- /parser/__mod.rs
fn test() {}
mod $0expr {
struct A {}
}
"#,
r#"
//- /parser/__mod.rs
fn test() {}
mod expr;
//- /parser/expr.rs
struct A {}
"#,
);
check_assist(
move_module_to_file,
r#"
//- /main.rs
#[path="parser/a/__mod.rs"]
mod parser;
//- /parser/a/__mod.rs
fn test() {}
mod $0expr {
struct A {}
}
"#,
r#"
//- /parser/a/__mod.rs
fn test() {}
mod expr;
//- /parser/a/expr.rs
struct A {}
"#,
);
check_assist(
move_module_to_file,
r#"
//- /main.rs
#[path="a.rs"]
mod parser;
//- /a.rs
fn test() {}
mod $0expr {
struct A {}
}
"#,
r#"
//- /a.rs
fn test() {}
mod expr;
//- /expr.rs
struct A {}
"#,
);
}
#[test]
fn extract_from_root() {
check_assist(

View file

@ -25,7 +25,7 @@ pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
if token.is_raw() {
return None;
}
let value = token.value()?;
let value = token.value().ok()?;
let target = token.syntax().text_range();
acc.add(
AssistId("make_raw_string", AssistKind::RefactorRewrite),
@ -64,7 +64,7 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
if !token.is_raw() {
return None;
}
let value = token.value()?;
let value = token.value().ok()?;
let target = token.syntax().text_range();
acc.add(
AssistId("make_usual_string", AssistKind::RefactorRewrite),
@ -398,12 +398,12 @@ string"###;
}
#[test]
fn remove_hash_doesnt_work() {
fn remove_hash_does_not_work() {
check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#);
}
#[test]
fn remove_hash_no_hash_doesnt_work() {
fn remove_hash_no_hash_does_not_work() {
check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#);
}

View file

@ -77,7 +77,7 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
ast::AssocItem::MacroCall(_) => None,
};
name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX)
})
.collect();

View file

@ -25,7 +25,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
// ```
pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
let value = token.value()?;
let value = token.value().ok()?;
let target = token.syntax().text_range();
if value.chars().take(2).count() != 1 {

View file

@ -1,5 +1,5 @@
//! Term search assist
use hir::term_search::TermSearchCtx;
use hir::term_search::{TermSearchConfig, TermSearchCtx};
use ide_db::{
assists::{AssistId, AssistKind, GroupLabel},
famous_defs::FamousDefs,
@ -34,7 +34,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
sema: &ctx.sema,
scope: &scope,
goal: target_ty,
config: Default::default(),
config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() },
};
let paths = hir::term_search::term_search(&term_search_ctx);

View file

@ -31,6 +31,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
prefer_no_std: false,
prefer_prelude: true,
assist_emit_must_use: false,
term_search_fuel: 400,
};
pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@ -46,6 +47,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
prefer_no_std: false,
prefer_prelude: true,
assist_emit_must_use: false,
term_search_fuel: 400,
};
pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@ -61,6 +63,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
prefer_no_std: false,
prefer_prelude: true,
assist_emit_must_use: false,
term_search_fuel: 400,
};
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {

View file

@ -353,7 +353,7 @@ pub(crate) fn complete_expr(acc: &mut Completions, ctx: &CompletionContext<'_>)
config: hir::term_search::TermSearchConfig {
enable_borrowcheck: false,
many_alternatives_threshold: 1,
depth: 6,
fuel: 200,
},
};
let exprs = hir::term_search::term_search(&term_search_ctx);

View file

@ -296,7 +296,7 @@ fn import_on_the_fly_pat_(
position: SyntaxNode,
potential_import_name: String,
) -> Option<()> {
let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat", ?potential_import_name)
let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat_", ?potential_import_name)
.entered();
ImportScope::find_insert_use_container(&position, &ctx.sema)?;

View file

@ -15,6 +15,7 @@ pub struct CompletionConfig {
pub enable_self_on_the_fly: bool,
pub enable_private_editable: bool,
pub enable_term_search: bool,
pub term_search_fuel: u64,
pub full_function_signatures: bool,
pub callable: Option<CallableSnippets>,
pub snippet_cap: Option<SnippetCap>,

View file

@ -466,7 +466,7 @@ impl CompletionContext<'_> {
cov_mark::hit!(completes_if_lifetime_without_idents);
TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
}
IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(),
IDENT | LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
_ if kind.is_keyword() => self.original_token.text_range(),
_ => TextRange::empty(self.position.offset),
}

View file

@ -368,7 +368,7 @@ fn render_resolution_pat(
import_to_add: Option<LocatedImport>,
resolution: ScopeDef,
) -> Builder {
let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
let _p = tracing::span!(tracing::Level::INFO, "render_resolution_pat").entered();
use hir::ModuleDef::*;
if let ScopeDef::ModuleDef(Macro(mac)) = resolution {
@ -386,7 +386,7 @@ fn render_resolution_path(
import_to_add: Option<LocatedImport>,
resolution: ScopeDef,
) -> Builder {
let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
let _p = tracing::span!(tracing::Level::INFO, "render_resolution_path").entered();
use hir::ModuleDef::*;
match resolution {
@ -494,7 +494,7 @@ fn render_resolution_simple_(
import_to_add: Option<LocatedImport>,
resolution: ScopeDef,
) -> Builder {
let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
let _p = tracing::span!(tracing::Level::INFO, "render_resolution_simple_").entered();
let db = ctx.db();
let ctx = ctx.import_to_add(import_to_add);
@ -1730,6 +1730,51 @@ fn foo(a: A) { B { bar: a.$0 }; }
)
}
#[test]
fn tuple_field_detail() {
check(
r#"
struct S(i32);
fn f() -> i32 {
let s = S(0);
s.0$0
}
"#,
SymbolKind::Field,
expect![[r#"
[
CompletionItem {
label: "0",
source_range: 56..57,
delete: 56..57,
insert: "0",
kind: SymbolKind(
Field,
),
detail: "i32",
relevance: CompletionRelevance {
exact_name_match: false,
type_match: Some(
Exact,
),
is_local: false,
is_item_from_trait: false,
is_item_from_notable_trait: false,
is_name_already_imported: false,
requires_import: false,
is_op_method: false,
is_private_editable: false,
postfix_match: None,
is_definite: false,
function: None,
},
},
]
"#]],
);
}
#[test]
fn record_field_and_call_relevances() {
check_relevance(
@ -1808,8 +1853,7 @@ fn f() { A { bar: b$0 }; }
fn baz() [type]
ex baz() [type]
ex bar() [type]
ex A { bar: baz() }.bar [type]
ex A { bar: bar() }.bar [type]
ex A { bar: ... }.bar [type]
st A []
fn f() []
"#]],
@ -1947,8 +1991,8 @@ fn main() {
}
"#,
expect![[r#"
ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
lc m [local]
lc t [local]
lc &t [type+local]
@ -1997,8 +2041,8 @@ fn main() {
}
"#,
expect![[r#"
ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
lc m [local]
lc t [local]
lc &mut t [type+local]

View file

@ -27,7 +27,7 @@ pub(crate) fn render_variant_lit(
variant: hir::Variant,
path: Option<hir::ModPath>,
) -> Option<Builder> {
let _p = tracing::span!(tracing::Level::INFO, "render_enum_variant").entered();
let _p = tracing::span!(tracing::Level::INFO, "render_variant_lit").entered();
let db = ctx.db();
let name = local_name.unwrap_or_else(|| variant.name(db));

View file

@ -27,7 +27,7 @@ pub(crate) fn render_macro_pat(
name: hir::Name,
macro_: hir::Macro,
) -> Builder {
let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered();
let _p = tracing::span!(tracing::Level::INFO, "render_macro_pat").entered();
render(ctx, false, false, false, name, macro_)
}

View file

@ -80,6 +80,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
},
snippets: Vec::new(),
limit: None,
term_search_fuel: 200,
};
pub(crate) fn completion_list(ra_fixture: &str) -> String {

View file

@ -19,7 +19,7 @@ struct Foo<'lt, T, const C: usize> where $0 {}
en Enum Enum
ma makro!() macro_rules! makro
md module
st Foo<> Foo<'{error}, {unknown}, _>
st Foo<> Foo<{unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit
@ -92,7 +92,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
en Enum Enum
ma makro!() macro_rules! makro
md module
st Foo<> Foo<'{error}, {unknown}, _>
st Foo<> Foo<{unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit

View file

@ -20,8 +20,8 @@ struct Foo<'lt, T, const C: usize> {
en Enum Enum
ma makro!() macro_rules! makro
md module
sp Self Foo<'{error}, {unknown}, _>
st Foo<> Foo<'{error}, {unknown}, _>
sp Self Foo<{unknown}, _>
st Foo<> Foo<{unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit
@ -45,8 +45,8 @@ struct Foo<'lt, T, const C: usize>(f$0);
en Enum Enum
ma makro!() macro_rules! makro
md module
sp Self Foo<'{error}, {unknown}, _>
st Foo<> Foo<'{error}, {unknown}, _>
sp Self Foo<{unknown}, _>
st Foo<> Foo<{unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit

View file

@ -11,8 +11,8 @@ use hir::{
Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module,
ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField,
TypeAlias, Variant, VariantDef, Visibility,
ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
};
use stdx::{format_to, impl_from};
use syntax::{
@ -39,12 +39,13 @@ pub enum Definition {
Trait(Trait),
TraitAlias(TraitAlias),
TypeAlias(TypeAlias),
BuiltinType(BuiltinType),
SelfType(Impl),
GenericParam(GenericParam),
Local(Local),
Label(Label),
DeriveHelper(DeriveHelper),
BuiltinType(BuiltinType),
BuiltinLifetime(StaticLifetime),
BuiltinAttr(BuiltinAttr),
ToolModule(ToolModule),
ExternCrateDecl(ExternCrateDecl),
@ -83,6 +84,7 @@ impl Definition {
Definition::DeriveHelper(it) => it.derive().module(db),
Definition::BuiltinAttr(_)
| Definition::BuiltinType(_)
| Definition::BuiltinLifetime(_)
| Definition::TupleField(_)
| Definition::ToolModule(_) => return None,
};
@ -112,6 +114,7 @@ impl Definition {
Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
Definition::Macro(_) => return None,
Definition::BuiltinAttr(_)
| Definition::BuiltinLifetime(_)
| Definition::ToolModule(_)
| Definition::SelfType(_)
| Definition::Local(_)
@ -141,6 +144,7 @@ impl Definition {
Definition::Local(it) => it.name(db),
Definition::GenericParam(it) => it.name(db),
Definition::Label(it) => it.name(db),
Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME,
Definition::BuiltinAttr(_) => return None, // FIXME
Definition::ToolModule(_) => return None, // FIXME
Definition::DeriveHelper(it) => it.name(db),
@ -174,6 +178,7 @@ impl Definition {
doc_owner.docs(fd.0.db)
})
}
Definition::BuiltinLifetime(StaticLifetime) => None,
Definition::Local(_) => None,
Definition::SelfType(impl_def) => {
impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
@ -228,6 +233,7 @@ impl Definition {
Definition::TraitAlias(it) => it.display(db).to_string(),
Definition::TypeAlias(it) => it.display(db).to_string(),
Definition::BuiltinType(it) => it.name().display(db).to_string(),
Definition::BuiltinLifetime(it) => it.name().display(db).to_string(),
Definition::Local(it) => {
let ty = it.ty(db);
let ty_display = ty.display_truncated(db, None);
@ -693,6 +699,9 @@ impl NameRefClass {
) -> Option<NameRefClass> {
let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime)
.entered();
if lifetime.text() == "'static" {
return Some(NameRefClass::Definition(Definition::BuiltinLifetime(StaticLifetime)));
}
let parent = lifetime.syntax().parent()?;
match parent.kind() {
SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {

View file

@ -209,8 +209,7 @@ impl ImportAssets {
prefer_no_std: bool,
prefer_prelude: bool,
) -> impl Iterator<Item = LocatedImport> {
let _p =
tracing::span!(tracing::Level::INFO, "import_assets::search_for_imports").entered();
let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_imports").entered();
self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude)
}
@ -221,7 +220,7 @@ impl ImportAssets {
prefer_no_std: bool,
prefer_prelude: bool,
) -> impl Iterator<Item = LocatedImport> {
let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for_relative_paths")
let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_relative_paths")
.entered();
self.search_for(sema, None, prefer_no_std, prefer_prelude)
}
@ -263,7 +262,7 @@ impl ImportAssets {
prefer_no_std: bool,
prefer_prelude: bool,
) -> impl Iterator<Item = LocatedImport> {
let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for").entered();
let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for").entered();
let scope = match sema.scope(&self.candidate_node) {
Some(it) => it,
@ -308,7 +307,7 @@ impl ImportAssets {
}
fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet<ScopeDef> {
let _p = tracing::span!(tracing::Level::INFO, "import_assets::scope_definitions").entered();
let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::scope_definitions").entered();
let mut scope_definitions = FxHashSet::default();
if let Some(scope) = sema.scope(&self.candidate_node) {
scope.process_all_names(&mut |_, scope_def| {
@ -327,7 +326,7 @@ fn path_applicable_imports(
scope_filter: impl Fn(ItemInNs) -> bool + Copy,
) -> FxHashSet<LocatedImport> {
let _p =
tracing::span!(tracing::Level::INFO, "import_assets::path_applicable_imports").entered();
tracing::span!(tracing::Level::INFO, "ImportAssets::path_applicable_imports").entered();
match &path_candidate.qualifier {
None => {
@ -374,7 +373,7 @@ fn import_for_item(
original_item: ItemInNs,
scope_filter: impl Fn(ItemInNs) -> bool,
) -> Option<LocatedImport> {
let _p = tracing::span!(tracing::Level::INFO, "import_assets::import_for_item").entered();
let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::import_for_item").entered();
let [first_segment, ..] = unresolved_qualifier else { return None };
let item_as_assoc = item_as_assoc(db, original_item);
@ -508,8 +507,7 @@ fn trait_applicable_items(
mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
scope_filter: impl Fn(hir::Trait) -> bool,
) -> FxHashSet<LocatedImport> {
let _p =
tracing::span!(tracing::Level::INFO, "import_assets::trait_applicable_items").entered();
let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::trait_applicable_items").entered();
let db = sema.db;

View file

@ -194,7 +194,7 @@ fn insert_use_with_alias_option(
cfg: &InsertUseConfig,
alias: Option<ast::Rename>,
) {
let _p = tracing::span!(tracing::Level::INFO, "insert_use").entered();
let _p = tracing::span!(tracing::Level::INFO, "insert_use_with_alias_option").entered();
let mut mb = match cfg.granularity {
ImportGranularity::Crate => Some(MergeBehavior::Crate),
ImportGranularity::Module => Some(MergeBehavior::Module),

View file

@ -1,6 +1,6 @@
//! rust-analyzer is lazy and doesn't compute anything unless asked. This
//! sometimes is counter productive when, for example, the first goto definition
//! request takes longer to compute. This modules implemented prepopulation of
//! request takes longer to compute. This module implements prepopulation of
//! various caches, it's not really advanced at the moment.
mod topologic_sort;
@ -32,7 +32,7 @@ pub fn parallel_prime_caches(
num_worker_threads: u8,
cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync),
) {
let _p = tracing::span!(tracing::Level::INFO, "prime_caches").entered();
let _p = tracing::span!(tracing::Level::INFO, "parallel_prime_caches").entered();
let graph = db.crate_graph();
let mut crates_to_prime = {

View file

@ -196,11 +196,12 @@ impl Definition {
.and_then(syn_ctx_is_root)
}
}
Definition::BuiltinType(_) => return None,
Definition::SelfType(_) => return None,
Definition::BuiltinAttr(_) => return None,
Definition::ToolModule(_) => return None,
Definition::TupleField(_) => return None,
Definition::BuiltinType(_)
| Definition::BuiltinLifetime(_)
| Definition::BuiltinAttr(_)
| Definition::SelfType(_)
| Definition::ToolModule(_)
| Definition::TupleField(_) => return None,
// FIXME: This should be doable in theory
Definition::DeriveHelper(_) => return None,
};

View file

@ -1,7 +1,7 @@
//! Implementation of find-usages functionality.
//!
//! It is based on the standard ide trick: first, we run a fast text search to
//! get a super-set of matches. Then, we we confirm each match using precise
//! get a super-set of matches. Then, we confirm each match using precise
//! name resolution.
use std::mem;

View file

@ -301,8 +301,8 @@ impl SymbolIndex {
}
fn range_to_map_value(start: usize, end: usize) -> u64 {
debug_assert![start <= (std::u32::MAX as usize)];
debug_assert![end <= (std::u32::MAX as usize)];
debug_assert![start <= (u32::MAX as usize)];
debug_assert![end <= (u32::MAX as usize)];
((start as u64) << 32) | end as u64
}

View file

@ -7,7 +7,7 @@ use ide_db::{
helpers::mod_path_to_ast,
imports::insert_use::{insert_use, ImportScope},
source_change::SourceChangeBuilder,
RootDatabase,
FxHashMap, RootDatabase,
};
use itertools::Itertools;
use stdx::{format_to, never};
@ -22,15 +22,22 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity};
#[derive(Default)]
struct State {
result: String,
struct_counts: usize,
has_serialize: bool,
has_deserialize: bool,
names: FxHashMap<String, usize>,
}
impl State {
fn generate_new_name(&mut self) -> ast::Name {
self.struct_counts += 1;
make::name(&format!("Struct{}", self.struct_counts))
fn generate_new_name(&mut self, name: &str) -> ast::Name {
let name = stdx::to_camel_case(name);
let count = if let Some(count) = self.names.get_mut(&name) {
*count += 1;
*count
} else {
self.names.insert(name.clone(), 1);
1
};
make::name(&format!("{}{}", name, count))
}
fn serde_derive(&self) -> String {
@ -52,15 +59,21 @@ impl State {
}
}
fn build_struct(&mut self, value: &serde_json::Map<String, serde_json::Value>) -> ast::Type {
let name = self.generate_new_name();
fn build_struct(
&mut self,
name: &str,
value: &serde_json::Map<String, serde_json::Value>,
) -> ast::Type {
let name = self.generate_new_name(name);
let ty = make::ty(&name.to_string());
let strukt = make::struct_(
None,
name,
None,
make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map(
|(name, value)| make::record_field(None, make::name(name), self.type_of(value)),
|(name, value)| {
make::record_field(None, make::name(name), self.type_of(name, value))
},
))
.into(),
);
@ -68,7 +81,7 @@ impl State {
ty
}
fn type_of(&mut self, value: &serde_json::Value) -> ast::Type {
fn type_of(&mut self, name: &str, value: &serde_json::Value) -> ast::Type {
match value {
serde_json::Value::Null => make::ty_unit(),
serde_json::Value::Bool(_) => make::ty("bool"),
@ -76,12 +89,12 @@ impl State {
serde_json::Value::String(_) => make::ty("String"),
serde_json::Value::Array(it) => {
let ty = match it.iter().next() {
Some(x) => self.type_of(x),
Some(x) => self.type_of(name, x),
None => make::ty_placeholder(),
};
make::ty(&format!("Vec<{ty}>"))
}
serde_json::Value::Object(x) => self.build_struct(x),
serde_json::Value::Object(x) => self.build_struct(name, x),
}
}
}
@ -113,7 +126,7 @@ pub(crate) fn json_in_items(
let serialize_resolved = scope_resolve("::serde::Serialize");
state.has_deserialize = deserialize_resolved.is_some();
state.has_serialize = serialize_resolved.is_some();
state.build_struct(&it);
state.build_struct("Root", &it);
edit.insert(range.start(), state.result);
acc.push(
Diagnostic::new(
@ -218,7 +231,7 @@ mod tests {
}
#[derive(Serialize)]
struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
struct Root1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
"#,
);
@ -237,9 +250,44 @@ mod tests {
}
"#,
r#"
struct Struct3{ }
struct Struct2{ kind: String, value: Struct3 }
struct Struct1{ bar: Struct2, foo: String }
struct Value1{ }
struct Bar1{ kind: String, value: Value1 }
struct Root1{ bar: Bar1, foo: String }
"#,
);
}
#[test]
fn naming() {
check_fix(
r#"
{$0
"user": {
"address": {
"street": "Main St",
"house": 3
},
"email": "example@example.com"
},
"another_user": {
"user": {
"address": {
"street": "Main St",
"house": 3
},
"email": "example@example.com"
}
}
}
"#,
r#"
struct Address1{ house: i64, street: String }
struct User1{ address: Address1, email: String }
struct AnotherUser1{ user: User1 }
struct Address2{ house: i64, street: String }
struct User2{ address: Address2, email: String }
struct Root1{ another_user: AnotherUser1, user: User2 }
"#,
);
@ -276,9 +324,9 @@ mod tests {
use serde::Deserialize;
#[derive(Serialize, Deserialize)]
struct Struct2{ x: i64, y: i64 }
struct OfObject1{ x: i64, y: i64 }
#[derive(Serialize, Deserialize)]
struct Struct1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<Struct2>, of_string: Vec<String> }
struct Root1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<OfObject1>, of_string: Vec<String> }
"#,
);

View file

@ -1,5 +1,5 @@
use either::Either;
use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics};
use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId};
use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase};
use syntax::{
ast::{self, edit::IndentLevel, make},
@ -25,7 +25,10 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
} else {
Diagnostic::new_with_syntax_node_ptr(
ctx,
DiagnosticCode::RustcHardError("E0559"),
match d.variant {
VariantId::EnumVariantId(_) => DiagnosticCode::RustcHardError("E0559"),
_ => DiagnosticCode::RustcHardError("E0560"),
},
"no such field",
node,
)

Some files were not shown because too many files have changed in this diff Show more