Merge from rustc

This commit is contained in:
Ralf Jung 2024-08-14 07:43:52 +02:00
commit 2016e149f5
213 changed files with 3973 additions and 2614 deletions

View file

@ -30,7 +30,6 @@ jobs:
run: | run: |
git config --global user.email "runner@gha.local" git config --global user.email "runner@gha.local"
git config --global user.name "GitHub Action" git config --global user.name "GitHub Action"
# Remove r-a crates from the workspaces so we don't auto-publish them as well # Only publish the crates under lib/
sed -i 's/ "crates\/\*"//' ./Cargo.toml sed -i 's|^members = .*$|members = ["lib/*"]|' Cargo.toml
sed -i 's/ "xtask\/"//' ./Cargo.toml
cargo workspaces publish --yes --exact --from-git --no-git-commit --allow-dirty cargo workspaces publish --yes --exact --from-git --no-git-commit --allow-dirty

370
Cargo.lock generated
View file

@ -52,16 +52,16 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.72" version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc", "cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object 0.35.0", "object 0.36.3",
"rustc-demangle", "rustc-demangle",
] ]
@ -92,9 +92,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.5.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@ -136,9 +136,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.98" version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292"
[[package]] [[package]]
name = "cfg" name = "cfg"
@ -148,10 +148,10 @@ dependencies = [
"derive_arbitrary", "derive_arbitrary",
"expect-test", "expect-test",
"intern", "intern",
"mbe",
"oorandom", "oorandom",
"rustc-hash", "rustc-hash",
"syntax", "syntax",
"syntax-bridge",
"tt", "tt",
] ]
@ -185,7 +185,7 @@ version = "0.98.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093" checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.6.0",
"chalk-derive", "chalk-derive",
] ]
@ -226,9 +226,9 @@ checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
[[package]] [[package]]
name = "cov-mark" name = "cov-mark"
version = "2.0.0-pre.1" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" checksum = "0570650661aa447e7335f1d5e4f499d8e58796e617bedc9267d971e51c8b49d4"
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
@ -366,9 +366,9 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
[[package]] [[package]]
name = "either" name = "either"
version = "1.12.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "ena" name = "ena"
@ -397,14 +397,14 @@ dependencies = [
[[package]] [[package]]
name = "filetime" name = "filetime"
version = "0.2.23" version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall 0.4.1", "libredox",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -415,31 +415,14 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.30" version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "flycheck"
version = "0.0.0"
dependencies = [
"cargo_metadata",
"crossbeam-channel",
"paths",
"process-wrap",
"project-model",
"rustc-hash",
"serde",
"serde_json",
"stdx",
"toolchain",
"tracing",
]
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.2.1" version = "1.2.1"
@ -529,7 +512,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"base-db", "base-db",
"bitflags 2.5.0", "bitflags 2.6.0",
"cfg", "cfg",
"cov-mark", "cov-mark",
"dashmap", "dashmap",
@ -554,6 +537,7 @@ dependencies = [
"span", "span",
"stdx", "stdx",
"syntax", "syntax",
"syntax-bridge",
"test-fixture", "test-fixture",
"test-utils", "test-utils",
"tracing", "tracing",
@ -582,6 +566,7 @@ dependencies = [
"span", "span",
"stdx", "stdx",
"syntax", "syntax",
"syntax-bridge",
"tracing", "tracing",
"triomphe", "triomphe",
"tt", "tt",
@ -593,7 +578,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"base-db", "base-db",
"bitflags 2.5.0", "bitflags 2.6.0",
"chalk-derive", "chalk-derive",
"chalk-ir", "chalk-ir",
"chalk-recursive", "chalk-recursive",
@ -722,7 +707,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"base-db", "base-db",
"bitflags 2.5.0", "bitflags 2.6.0",
"cov-mark", "cov-mark",
"crossbeam-channel", "crossbeam-channel",
"either", "either",
@ -803,9 +788,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.2.6" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@ -895,9 +880,9 @@ checksum = "3752f229dcc5a481d60f385fa479ff46818033d881d2d801aa27dffcfb5e8306"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
@ -907,19 +892,19 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.8.3" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets 0.52.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
name = "libmimalloc-sys" name = "libmimalloc-sys"
version = "0.1.38" version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7bb23d733dfcc8af652a78b7bf232f0e967710d044732185e561e47c0336b6" checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -931,8 +916,9 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.6.0",
"libc", "libc",
"redox_syscall",
] ]
[[package]] [[package]]
@ -996,9 +982,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.21" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]] [[package]]
name = "lsp-server" name = "lsp-server"
@ -1056,6 +1042,7 @@ dependencies = [
"span", "span",
"stdx", "stdx",
"syntax", "syntax",
"syntax-bridge",
"test-utils", "test-utils",
"tracing", "tracing",
"tt", "tt",
@ -1063,9 +1050,9 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.2" version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "memmap2" name = "memmap2"
@ -1087,18 +1074,18 @@ dependencies = [
[[package]] [[package]]
name = "mimalloc" name = "mimalloc"
version = "0.1.42" version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9186d86b79b52f4a77af65604b51225e8db1d6ee7e3f41aec1e40829c71a176" checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633"
dependencies = [ dependencies = [
"libmimalloc-sys", "libmimalloc-sys",
] ]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [ dependencies = [
"adler", "adler",
] ]
@ -1130,7 +1117,7 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.6.0",
"cfg-if", "cfg-if",
"cfg_aliases", "cfg_aliases",
"libc", "libc",
@ -1148,7 +1135,7 @@ version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.6.0",
"crossbeam-channel", "crossbeam-channel",
"filetime", "filetime",
"fsevent-sys", "fsevent-sys",
@ -1163,11 +1150,11 @@ dependencies = [
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.50.0" version = "0.50.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
dependencies = [ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -1197,9 +1184,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.35.0" version = "0.36.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -1212,9 +1199,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "oorandom" name = "oorandom"
version = "11.1.3" version = "11.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
[[package]] [[package]]
name = "option-ext" name = "option-ext"
@ -1240,9 +1227,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"redox_syscall 0.5.1", "redox_syscall",
"smallvec", "smallvec",
"windows-targets 0.52.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -1268,6 +1255,7 @@ name = "paths"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"camino", "camino",
"serde",
] ]
[[package]] [[package]]
@ -1319,9 +1307,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "proc-macro-api" name = "proc-macro-api"
@ -1330,14 +1321,12 @@ dependencies = [
"base-db", "base-db",
"indexmap", "indexmap",
"intern", "intern",
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"paths", "paths",
"rustc-hash", "rustc-hash",
"serde", "serde",
"serde_json", "serde_json",
"span", "span",
"stdx", "stdx",
"text-size",
"tracing", "tracing",
"tt", "tt",
] ]
@ -1350,7 +1339,6 @@ dependencies = [
"expect-test", "expect-test",
"intern", "intern",
"libloading", "libloading",
"mbe",
"memmap2", "memmap2",
"object 0.33.0", "object 0.33.0",
"paths", "paths",
@ -1360,6 +1348,7 @@ dependencies = [
"snap", "snap",
"span", "span",
"stdx", "stdx",
"syntax-bridge",
"tt", "tt",
] ]
@ -1380,9 +1369,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.85" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -1460,7 +1449,7 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.6.0",
"memchr", "memchr",
"unicase", "unicase",
] ]
@ -1485,20 +1474,20 @@ dependencies = [
[[package]] [[package]]
name = "ra-ap-rustc_abi" name = "ra-ap-rustc_abi"
version = "0.53.0" version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46" checksum = "b011c39d409940a890414e3a7b239762ac16d88029ad71b050a8374831b93790"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.6.0",
"ra-ap-rustc_index", "ra-ap-rustc_index",
"tracing", "tracing",
] ]
[[package]] [[package]]
name = "ra-ap-rustc_index" name = "ra-ap-rustc_index"
version = "0.53.0" version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9" checksum = "9027acdee649b0b27eb10b7db5be833efee3362d394935c5eed8f0745a9d43ce"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"ra-ap-rustc_index_macros", "ra-ap-rustc_index_macros",
@ -1507,21 +1496,20 @@ dependencies = [
[[package]] [[package]]
name = "ra-ap-rustc_index_macros" name = "ra-ap-rustc_index_macros"
version = "0.53.0" version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82f3d6dcb30a66905388e14756b8f2216131d9f8004922c07f13335840e058d1" checksum = "540b86dc0384141ac8e825fc2874cd44bffd4277d99d8ec63ee416f1a98d5997"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
"synstructure",
] ]
[[package]] [[package]]
name = "ra-ap-rustc_lexer" name = "ra-ap-rustc_lexer"
version = "0.53.0" version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbd8a2b0bdcba9892cbce0b25f6c953d31b0febc1f3420fc692884fce5a23ad8" checksum = "3bdf98bb457b47b9ae4aeebf867d0ca440c86925e0b6381658c4a02589748c9d"
dependencies = [ dependencies = [
"unicode-properties", "unicode-properties",
"unicode-xid", "unicode-xid",
@ -1529,9 +1517,9 @@ dependencies = [
[[package]] [[package]]
name = "ra-ap-rustc_parse_format" name = "ra-ap-rustc_parse_format"
version = "0.53.0" version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135" checksum = "e8fe3556ab6311bb775220563a300e2bf62ec56404521fe0c511a583937683d5"
dependencies = [ dependencies = [
"ra-ap-rustc_index", "ra-ap-rustc_index",
"ra-ap-rustc_lexer", "ra-ap-rustc_lexer",
@ -1539,9 +1527,9 @@ dependencies = [
[[package]] [[package]]
name = "ra-ap-rustc_pattern_analysis" name = "ra-ap-rustc_pattern_analysis"
version = "0.53.0" version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34768e1faf88c31f2e9ad57b48318a52b507dafac0cddbf01b5d63bfc0b0a365" checksum = "1709080fdeb5db630e1c2644026c2962aaa32416cd92f0190c04b0c21e114b91"
dependencies = [ dependencies = [
"ra-ap-rustc_index", "ra-ap-rustc_index",
"rustc-hash", "rustc-hash",
@ -1602,20 +1590,11 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.4.1" version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.6.0",
]
[[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]] [[package]]
@ -1648,12 +1627,12 @@ version = "0.0.0"
dependencies = [ dependencies = [
"always-assert", "always-assert",
"anyhow", "anyhow",
"cargo_metadata",
"cfg", "cfg",
"crossbeam-channel", "crossbeam-channel",
"dirs", "dirs",
"dissimilar", "dissimilar",
"expect-test", "expect-test",
"flycheck",
"hir", "hir",
"hir-def", "hir-def",
"hir-ty", "hir-ty",
@ -1665,7 +1644,6 @@ dependencies = [
"load-cargo", "load-cargo",
"lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lsp-types", "lsp-types",
"mbe",
"memchr", "memchr",
"mimalloc", "mimalloc",
"nohash-hasher", "nohash-hasher",
@ -1675,6 +1653,7 @@ dependencies = [
"parser", "parser",
"paths", "paths",
"proc-macro-api", "proc-macro-api",
"process-wrap",
"profile", "profile",
"project-model", "project-model",
"rayon", "rayon",
@ -1685,6 +1664,7 @@ dependencies = [
"serde_json", "serde_json",
"stdx", "stdx",
"syntax", "syntax",
"syntax-bridge",
"test-fixture", "test-fixture",
"test-utils", "test-utils",
"tikv-jemallocator", "tikv-jemallocator",
@ -1716,9 +1696,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustc_apfloat" name = "rustc_apfloat"
version = "0.2.0+llvm-462a31f5a5ab" version = "0.2.1+llvm-462a31f5a5ab"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "465187772033a5ee566f69fe008df03628fce549a0899aae76f0a0c2e34696be" checksum = "886d94c63c812a8037c4faca2607453a0fa4cf82f734665266876b022244543f"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"smallvec", "smallvec",
@ -1801,18 +1781,18 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.203" version = "1.0.206"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.203" version = "1.0.206"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1821,12 +1801,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.117" version = "1.0.124"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itoa", "itoa",
"memchr",
"ryu", "ryu",
"serde", "serde",
] ]
@ -1844,9 +1825,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "0.6.6" version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -1923,9 +1904,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.66" version = "2.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1967,6 +1948,21 @@ dependencies = [
"triomphe", "triomphe",
] ]
[[package]]
name = "syntax-bridge"
version = "0.0.0"
dependencies = [
"intern",
"parser",
"rustc-hash",
"span",
"stdx",
"syntax",
"test-utils",
"tracing",
"tt",
]
[[package]] [[package]]
name = "test-fixture" name = "test-fixture"
version = "0.0.0" version = "0.0.0"
@ -1987,6 +1983,7 @@ name = "test-utils"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"dissimilar", "dissimilar",
"paths",
"profile", "profile",
"rustc-hash", "rustc-hash",
"stdx", "stdx",
@ -2010,18 +2007,18 @@ checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.61" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.61" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2090,9 +2087,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.6.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
dependencies = [ dependencies = [
"tinyvec_macros", "tinyvec_macros",
] ]
@ -2105,9 +2102,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.8.14" version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [ dependencies = [
"serde", "serde",
"serde_spanned", "serde_spanned",
@ -2117,18 +2114,18 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.6.6" version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.22.14" version = "0.22.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"serde", "serde",
@ -2214,9 +2211,9 @@ dependencies = [
[[package]] [[package]]
name = "triomphe" name = "triomphe"
version = "0.1.12" version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b2cb4fbb9995eeb36ac86fadf24031ccd58f99d6b4b2d7b911db70bddb80d90" checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369"
dependencies = [ dependencies = [
"serde", "serde",
"stable_deref_trait", "stable_deref_trait",
@ -2289,9 +2286,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]] [[package]]
name = "url" name = "url"
version = "2.5.0" version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna",
@ -2307,14 +2304,15 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "vfs" name = "vfs"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"crossbeam-channel",
"fst", "fst",
"indexmap", "indexmap",
"nohash-hasher", "nohash-hasher",
@ -2331,6 +2329,8 @@ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"notify", "notify",
"paths", "paths",
"rayon",
"rustc-hash",
"stdx", "stdx",
"tracing", "tracing",
"vfs", "vfs",
@ -2355,11 +2355,11 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.8" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -2369,7 +2369,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
dependencies = [ dependencies = [
"windows-core", "windows-core",
"windows-targets 0.52.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -2381,7 +2381,7 @@ dependencies = [
"windows-implement", "windows-implement",
"windows-interface", "windows-interface",
"windows-result", "windows-result",
"windows-targets 0.52.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -2408,11 +2408,11 @@ dependencies = [
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [ dependencies = [
"windows-targets 0.52.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -2430,7 +2430,16 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets 0.52.5", "windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
] ]
[[package]] [[package]]
@ -2450,18 +2459,18 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.52.5", "windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.5", "windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.5", "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm", "windows_i686_gnullvm",
"windows_i686_msvc 0.52.5", "windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.5", "windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.5", "windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.5", "windows_x86_64_msvc 0.52.6",
] ]
[[package]] [[package]]
@ -2472,9 +2481,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
@ -2484,9 +2493,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
@ -2496,15 +2505,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]] [[package]]
name = "windows_i686_gnullvm" name = "windows_i686_gnullvm"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
@ -2514,9 +2523,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
@ -2526,9 +2535,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
@ -2538,9 +2547,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
@ -2550,15 +2559,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.5" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.6.11" version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c52728401e1dc672a56e81e593e912aa54c78f40246869f78359a2bf24d29d" checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -2618,6 +2627,27 @@ dependencies = [
"zip", "zip",
] ]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "zip" name = "zip"
version = "0.6.6" version = "0.6.6"

View file

@ -4,10 +4,11 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
rust-version = "1.78" rust-version = "1.80"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"] authors = ["rust-analyzer team"]
repository = "https://github.com/rust-lang/rust-analyzer"
[profile.dev] [profile.dev]
debug = 1 debug = 1
@ -51,7 +52,6 @@ debug = 2
# local crates # local crates
base-db = { path = "./crates/base-db", version = "0.0.0" } base-db = { path = "./crates/base-db", version = "0.0.0" }
cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] } cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] }
flycheck = { path = "./crates/flycheck", version = "0.0.0" }
hir = { path = "./crates/hir", version = "0.0.0" } hir = { path = "./crates/hir", version = "0.0.0" }
hir-def = { path = "./crates/hir-def", version = "0.0.0" } hir-def = { path = "./crates/hir-def", version = "0.0.0" }
hir-expand = { path = "./crates/hir-expand", version = "0.0.0" } hir-expand = { path = "./crates/hir-expand", version = "0.0.0" }
@ -77,17 +77,18 @@ salsa = { path = "./crates/salsa", version = "0.0.0" }
span = { path = "./crates/span", version = "0.0.0" } span = { path = "./crates/span", version = "0.0.0" }
stdx = { path = "./crates/stdx", version = "0.0.0" } stdx = { path = "./crates/stdx", version = "0.0.0" }
syntax = { path = "./crates/syntax", version = "0.0.0" } syntax = { path = "./crates/syntax", version = "0.0.0" }
syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
text-edit = { path = "./crates/text-edit", version = "0.0.0" } text-edit = { path = "./crates/text-edit", version = "0.0.0" }
toolchain = { path = "./crates/toolchain", version = "0.0.0" } toolchain = { path = "./crates/toolchain", version = "0.0.0" }
tt = { path = "./crates/tt", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" }
vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
vfs = { path = "./crates/vfs", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" }
ra-ap-rustc_lexer = { version = "0.53.0", default-features = false } ra-ap-rustc_lexer = { version = "0.63.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false } ra-ap-rustc_parse_format = { version = "0.63.0", default-features = false }
ra-ap-rustc_index = { version = "0.53.0", default-features = false } ra-ap-rustc_index = { version = "0.63.0", default-features = false }
ra-ap-rustc_abi = { version = "0.53.0", default-features = false } ra-ap-rustc_abi = { version = "0.63.0", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.53.0", default-features = false } ra-ap-rustc_pattern_analysis = { version = "0.63.0", default-features = false }
# local crates that aren't published to crates.io. These should not have versions. # local crates that aren't published to crates.io. These should not have versions.
test-fixture = { path = "./crates/test-fixture" } test-fixture = { path = "./crates/test-fixture" }
@ -124,11 +125,11 @@ memmap2 = "0.5.4"
nohash-hasher = "0.2.0" nohash-hasher = "0.2.0"
oorandom = "11.1.3" oorandom = "11.1.3"
object = { version = "0.33.0", default-features = false, features = [ object = { version = "0.33.0", default-features = false, features = [
"std", "std",
"read_core", "read_core",
"elf", "elf",
"macho", "macho",
"pe", "pe",
] } ] }
process-wrap = { version = "8.0.2", features = ["std"] } process-wrap = { version = "8.0.2", features = ["std"] }
pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark-to-cmark = "10.0.4"
@ -158,7 +159,6 @@ url = "2.3.1"
xshell = "0.2.5" xshell = "0.2.5"
# We need to freeze the version of the crate, as the raw-api feature is considered unstable # We need to freeze the version of the crate, as the raw-api feature is considered unstable
dashmap = { version = "=5.5.3", features = ["raw-api"] } dashmap = { version = "=5.5.3", features = ["raw-api"] }

View file

@ -1,7 +1,8 @@
[package] [package]
name = "base-db" name = "base-db"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Basic database traits for rust-analyzer. The concrete DB is defined by `ide` (aka `ra_ap_ide`)."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View file

@ -7,7 +7,7 @@ use salsa::Durability;
use triomphe::Arc; use triomphe::Arc;
use vfs::FileId; use vfs::FileId;
use crate::{CrateGraph, SourceDatabaseExt, SourceDatabaseExt2, SourceRoot, SourceRootId}; use crate::{CrateGraph, SourceDatabaseFileInputExt, SourceRoot, SourceRootDatabase, SourceRootId};
/// Encapsulate a bunch of raw `.set` calls on the database. /// Encapsulate a bunch of raw `.set` calls on the database.
#[derive(Default)] #[derive(Default)]
@ -50,7 +50,7 @@ impl FileChange {
self.crate_graph = Some(graph); self.crate_graph = Some(graph);
} }
pub fn apply(self, db: &mut dyn SourceDatabaseExt) { pub fn apply(self, db: &mut dyn SourceRootDatabase) {
let _p = tracing::info_span!("FileChange::apply").entered(); let _p = tracing::info_span!("FileChange::apply").entered();
if let Some(roots) = self.roots { if let Some(roots) = self.roots {
for (idx, root) in roots.into_iter().enumerate() { for (idx, root) in roots.into_iter().enumerate() {

View file

@ -690,6 +690,14 @@ impl Env {
pub fn extend_from_other(&mut self, other: &Env) { pub fn extend_from_other(&mut self, other: &Env) {
self.entries.extend(other.entries.iter().map(|(x, y)| (x.to_owned(), y.to_owned()))); self.entries.extend(other.entries.iter().map(|(x, y)| (x.to_owned(), y.to_owned())));
} }
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn insert(&mut self, k: impl Into<String>, v: impl Into<String>) -> Option<String> {
self.entries.insert(k.into(), v.into())
}
} }
impl From<Env> for Vec<(String, String)> { impl From<Env> for Vec<(String, String)> {
@ -700,6 +708,15 @@ impl From<Env> for Vec<(String, String)> {
} }
} }
impl<'a> IntoIterator for &'a Env {
type Item = (&'a String, &'a String);
type IntoIter = std::collections::hash_map::Iter<'a, String, String>;
fn into_iter(self) -> Self::IntoIter {
self.entries.iter()
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct CyclicDependenciesError { pub struct CyclicDependenciesError {
path: Vec<(CrateId, Option<CrateDisplayName>)>, path: Vec<(CrateId, Option<CrateDisplayName>)>,

View file

@ -1,5 +1,5 @@
//! base_db defines basic database traits. The concrete DB is defined by ide. //! base_db defines basic database traits. The concrete DB is defined by ide.
// FIXME: Rename this crate, base db is non descriptive
mod change; mod change;
mod input; mod input;
@ -47,8 +47,6 @@ pub const DEFAULT_PARSE_LRU_CAP: u16 = 128;
pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024; pub const DEFAULT_BORROWCK_LRU_CAP: u16 = 2024;
pub trait FileLoader { pub trait FileLoader {
/// Text of the file.
fn file_text(&self, file_id: FileId) -> Arc<str>;
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>; fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
/// Crates whose root's source root is the same as the source root of `file_id` /// 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]>; fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>;
@ -58,6 +56,13 @@ pub trait FileLoader {
/// model. Everything else in rust-analyzer is derived from these queries. /// model. Everything else in rust-analyzer is derived from these queries.
#[salsa::query_group(SourceDatabaseStorage)] #[salsa::query_group(SourceDatabaseStorage)]
pub trait SourceDatabase: FileLoader + std::fmt::Debug { pub trait SourceDatabase: FileLoader + std::fmt::Debug {
#[salsa::input]
fn compressed_file_text(&self, file_id: FileId) -> Arc<[u8]>;
/// Text of the file.
#[salsa::lru]
fn file_text(&self, file_id: FileId) -> Arc<str>;
/// Parses the file into the syntax tree. /// Parses the file into the syntax tree.
#[salsa::lru] #[salsa::lru]
fn parse(&self, file_id: EditionedFileId) -> Parse<ast::SourceFile>; fn parse(&self, file_id: EditionedFileId) -> Parse<ast::SourceFile>;
@ -99,16 +104,18 @@ fn parse_errors(db: &dyn SourceDatabase, file_id: EditionedFileId) -> Option<Arc
} }
} }
fn file_text(db: &dyn SourceDatabase, file_id: FileId) -> Arc<str> {
let bytes = db.compressed_file_text(file_id);
let bytes =
lz4_flex::decompress_size_prepended(&bytes).expect("lz4 decompression should not fail");
let text = std::str::from_utf8(&bytes).expect("file contents should be valid UTF-8");
Arc::from(text)
}
/// We don't want to give HIR knowledge of source roots, hence we extract these /// We don't want to give HIR knowledge of source roots, hence we extract these
/// methods into a separate DB. /// methods into a separate DB.
#[salsa::query_group(SourceDatabaseExtStorage)] #[salsa::query_group(SourceRootDatabaseStorage)]
pub trait SourceDatabaseExt: SourceDatabase { pub trait SourceRootDatabase: SourceDatabase {
#[salsa::input]
fn compressed_file_text(&self, file_id: FileId) -> Arc<[u8]>;
#[salsa::lru]
fn file_text(&self, file_id: FileId) -> Arc<str>;
/// Path to a file, relative to the root of its source root. /// Path to a file, relative to the root of its source root.
/// Source root of the file. /// Source root of the file.
#[salsa::input] #[salsa::input]
@ -121,15 +128,7 @@ pub trait SourceDatabaseExt: SourceDatabase {
fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
} }
fn file_text(db: &dyn SourceDatabaseExt, file_id: FileId) -> Arc<str> { pub trait SourceDatabaseFileInputExt {
let bytes = db.compressed_file_text(file_id);
let bytes =
lz4_flex::decompress_size_prepended(&bytes).expect("lz4 decompression should not fail");
let text = std::str::from_utf8(&bytes).expect("file contents should be valid UTF-8");
Arc::from(text)
}
pub trait SourceDatabaseExt2 {
fn set_file_text(&mut self, file_id: FileId, text: &str) { fn set_file_text(&mut self, file_id: FileId, text: &str) {
self.set_file_text_with_durability(file_id, text, Durability::LOW); self.set_file_text_with_durability(file_id, text, Durability::LOW);
} }
@ -142,7 +141,7 @@ pub trait SourceDatabaseExt2 {
); );
} }
impl<Db: ?Sized + SourceDatabaseExt> SourceDatabaseExt2 for Db { impl<Db: ?Sized + SourceRootDatabase> SourceDatabaseFileInputExt for Db {
fn set_file_text_with_durability( fn set_file_text_with_durability(
&mut self, &mut self,
file_id: FileId, file_id: FileId,
@ -159,7 +158,7 @@ impl<Db: ?Sized + SourceDatabaseExt> SourceDatabaseExt2 for Db {
} }
} }
fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<[CrateId]> { fn source_root_crates(db: &dyn SourceRootDatabase, id: SourceRootId) -> Arc<[CrateId]> {
let graph = db.crate_graph(); let graph = db.crate_graph();
let mut crates = graph let mut crates = graph
.iter() .iter()
@ -173,13 +172,12 @@ fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<[Crat
crates.into_iter().collect() crates.into_iter().collect()
} }
/// Silly workaround for cyclic deps between the traits // FIXME: Would be nice to get rid of this somehow
/// Silly workaround for cyclic deps due to the SourceRootDatabase and SourceDatabase split
/// regarding FileLoader
pub struct FileLoaderDelegate<T>(pub T); pub struct FileLoaderDelegate<T>(pub T);
impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { impl<T: SourceRootDatabase> FileLoader for FileLoaderDelegate<&'_ T> {
fn file_text(&self, file_id: FileId) -> Arc<str> {
SourceDatabaseExt::file_text(self.0, file_id)
}
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
// FIXME: this *somehow* should be platform agnostic... // FIXME: this *somehow* should be platform agnostic...
let source_root = self.0.file_source_root(path.anchor); let source_root = self.0.file_source_root(path.anchor);

View file

@ -1,7 +1,8 @@
[package] [package]
name = "cfg" name = "cfg"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Conditional compiling options, `cfg` attribute parser and evaluator for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
@ -28,7 +29,7 @@ arbitrary = "1.3.2"
derive_arbitrary = "1.3.2" derive_arbitrary = "1.3.2"
# local deps # local deps
mbe.workspace = true syntax-bridge.workspace = true
syntax.workspace = true syntax.workspace = true
[lints] [lints]

View file

@ -108,6 +108,14 @@ impl<'a> IntoIterator for &'a CfgOptions {
} }
} }
impl FromIterator<CfgAtom> for CfgOptions {
fn from_iter<T: IntoIterator<Item = CfgAtom>>(iter: T) -> Self {
let mut options = CfgOptions::default();
options.extend(iter);
options
}
}
#[derive(Default, Clone, Debug, PartialEq, Eq)] #[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct CfgDiff { pub struct CfgDiff {
// Invariants: No duplicates, no atom that's both in `enable` and `disable`. // Invariants: No duplicates, no atom that's both in `enable` and `disable`.

View file

@ -1,8 +1,11 @@
use arbitrary::{Arbitrary, Unstructured}; use arbitrary::{Arbitrary, Unstructured};
use expect_test::{expect, Expect}; use expect_test::{expect, Expect};
use intern::Symbol; use intern::Symbol;
use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
use syntax::{ast, AstNode, Edition}; use syntax::{ast, AstNode, Edition};
use syntax_bridge::{
dummy_test_span_utils::{DummyTestSpanMap, DUMMY},
syntax_node_to_token_tree, DocCommentDesugarMode,
};
use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr}; use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr};

View file

@ -1,30 +0,0 @@
[package]
name = "flycheck"
version = "0.0.0"
description = "TBD"
authors.workspace = true
edition.workspace = true
license.workspace = true
rust-version.workspace = true
[lib]
doctest = false
[dependencies]
cargo_metadata.workspace = true
crossbeam-channel.workspace = true
tracing.workspace = true
rustc-hash.workspace = true
serde_json.workspace = true
serde.workspace = true
process-wrap.workspace = true
# local deps
paths.workspace = true
stdx.workspace = true
toolchain.workspace = true
project-model.workspace = true
[lints]
workspace = true

View file

@ -1,7 +1,8 @@
[package] [package]
name = "hir-def" name = "hir-def"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "RPC Api for the `proc-macro-srv` crate of rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
@ -52,7 +53,7 @@ expect-test.workspace = true
# local deps # local deps
test-utils.workspace = true test-utils.workspace = true
test-fixture.workspace = true test-fixture.workspace = true
syntax-bridge.workspace = true
[features] [features]
in-rust-tree = ["hir-expand/in-rust-tree"] in-rust-tree = ["hir-expand/in-rust-tree"]

View file

@ -657,9 +657,9 @@ mod tests {
use triomphe::Arc; use triomphe::Arc;
use hir_expand::span_map::{RealSpanMap, SpanMap}; use hir_expand::span_map::{RealSpanMap, SpanMap};
use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode};
use span::FileId; use span::FileId;
use syntax::{ast, AstNode, TextRange}; use syntax::{ast, AstNode, TextRange};
use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode};
use crate::attr::{DocAtom, DocExpr}; use crate::attr::{DocAtom, DocExpr};

View file

@ -118,6 +118,7 @@ pub enum BodyDiagnostic {
MacroError { node: InFile<AstPtr<ast::MacroCall>>, err: ExpandError }, MacroError { node: InFile<AstPtr<ast::MacroCall>>, err: ExpandError },
UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath }, UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath },
UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
AwaitOutsideOfAsync { node: InFile<AstPtr<ast::AwaitExpr>>, location: String },
UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name }, UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
} }
@ -157,7 +158,7 @@ impl Body {
}), }),
) )
}); });
is_async_fn = data.has_async_kw(); is_async_fn = data.is_async();
src.map(|it| it.body().map(ast::Expr::from)) src.map(|it| it.body().map(ast::Expr::from))
} }
DefWithBodyId::ConstId(c) => { DefWithBodyId::ConstId(c) => {

View file

@ -72,6 +72,7 @@ pub(super) fn lower(
is_lowering_coroutine: false, is_lowering_coroutine: false,
label_ribs: Vec::new(), label_ribs: Vec::new(),
current_binding_owner: None, current_binding_owner: None,
awaitable_context: None,
} }
.collect(params, body, is_async_fn) .collect(params, body, is_async_fn)
} }
@ -100,6 +101,8 @@ struct ExprCollector<'a> {
// resolution // resolution
label_ribs: Vec<LabelRib>, label_ribs: Vec<LabelRib>,
current_binding_owner: Option<ExprId>, current_binding_owner: Option<ExprId>,
awaitable_context: Option<Awaitable>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -135,6 +138,11 @@ impl RibKind {
} }
} }
enum Awaitable {
Yes,
No(&'static str),
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct BindingList { struct BindingList {
map: FxHashMap<Name, BindingId>, map: FxHashMap<Name, BindingId>,
@ -180,6 +188,18 @@ impl ExprCollector<'_> {
body: Option<ast::Expr>, body: Option<ast::Expr>,
is_async_fn: bool, is_async_fn: bool,
) -> (Body, BodySourceMap) { ) -> (Body, BodySourceMap) {
self.awaitable_context.replace(if is_async_fn {
Awaitable::Yes
} else {
match self.owner {
DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),
DefWithBodyId::StaticId(..) => Awaitable::No("static"),
DefWithBodyId::ConstId(..) | DefWithBodyId::InTypeConstId(..) => {
Awaitable::No("constant")
}
DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),
}
});
if let Some((param_list, mut attr_enabled)) = param_list { if let Some((param_list, mut attr_enabled)) = param_list {
let mut params = vec![]; let mut params = vec![];
if let Some(self_param) = if let Some(self_param) =
@ -280,31 +300,40 @@ impl ExprCollector<'_> {
} }
Some(ast::BlockModifier::Async(_)) => { Some(ast::BlockModifier::Async(_)) => {
self.with_label_rib(RibKind::Closure, |this| { self.with_label_rib(RibKind::Closure, |this| {
this.collect_block_(e, |id, statements, tail| Expr::Async { this.with_awaitable_block(Awaitable::Yes, |this| {
id, this.collect_block_(e, |id, statements, tail| Expr::Async {
statements, id,
tail, statements,
tail,
})
}) })
}) })
} }
Some(ast::BlockModifier::Const(_)) => { Some(ast::BlockModifier::Const(_)) => {
self.with_label_rib(RibKind::Constant, |this| { self.with_label_rib(RibKind::Constant, |this| {
let (result_expr_id, prev_binding_owner) = this.with_awaitable_block(Awaitable::No("constant block"), |this| {
this.initialize_binding_owner(syntax_ptr); let (result_expr_id, prev_binding_owner) =
let inner_expr = this.collect_block(e); this.initialize_binding_owner(syntax_ptr);
let it = this.db.intern_anonymous_const(ConstBlockLoc { let inner_expr = this.collect_block(e);
parent: this.owner, let it = this.db.intern_anonymous_const(ConstBlockLoc {
root: inner_expr, parent: this.owner,
}); root: inner_expr,
this.body.exprs[result_expr_id] = Expr::Const(it); });
this.current_binding_owner = prev_binding_owner; this.body.exprs[result_expr_id] = Expr::Const(it);
result_expr_id this.current_binding_owner = prev_binding_owner;
result_expr_id
})
}) })
} }
// FIXME // FIXME
Some(ast::BlockModifier::AsyncGen(_)) | Some(ast::BlockModifier::Gen(_)) | None => { Some(ast::BlockModifier::AsyncGen(_)) => {
self.collect_block(e) self.with_awaitable_block(Awaitable::Yes, |this| this.collect_block(e))
} }
Some(ast::BlockModifier::Gen(_)) => self
.with_awaitable_block(Awaitable::No("non-async gen block"), |this| {
this.collect_block(e)
}),
None => self.collect_block(e),
}, },
ast::Expr::LoopExpr(e) => { ast::Expr::LoopExpr(e) => {
let label = e.label().map(|label| self.collect_label(label)); let label = e.label().map(|label| self.collect_label(label));
@ -469,6 +498,12 @@ impl ExprCollector<'_> {
} }
ast::Expr::AwaitExpr(e) => { ast::Expr::AwaitExpr(e) => {
let expr = self.collect_expr_opt(e.expr()); let expr = self.collect_expr_opt(e.expr());
if let Awaitable::No(location) = self.is_lowering_awaitable_block() {
self.source_map.diagnostics.push(BodyDiagnostic::AwaitOutsideOfAsync {
node: InFile::new(self.expander.current_file_id(), AstPtr::new(&e)),
location: location.to_string(),
});
}
self.alloc_expr(Expr::Await { expr }, syntax_ptr) self.alloc_expr(Expr::Await { expr }, syntax_ptr)
} }
ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e), ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
@ -527,7 +562,13 @@ impl ExprCollector<'_> {
let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine); let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
let prev_try_block_label = this.current_try_block_label.take(); let prev_try_block_label = this.current_try_block_label.take();
let body = this.collect_expr_opt(e.body()); let awaitable = if e.async_token().is_some() {
Awaitable::Yes
} else {
Awaitable::No("non-async closure")
};
let body =
this.with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
let closure_kind = if this.is_lowering_coroutine { let closure_kind = if this.is_lowering_coroutine {
let movability = if e.static_token().is_some() { let movability = if e.static_token().is_some() {
@ -2082,6 +2123,21 @@ impl ExprCollector<'_> {
fn alloc_label_desugared(&mut self, label: Label) -> LabelId { fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
self.body.labels.alloc(label) self.body.labels.alloc(label)
} }
fn is_lowering_awaitable_block(&self) -> &Awaitable {
self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown"))
}
fn with_awaitable_block<T>(
&mut self,
awaitable: Awaitable,
f: impl FnOnce(&mut Self) -> T,
) -> T {
let orig = self.awaitable_context.replace(awaitable);
let res = f(self);
self.awaitable_context = orig;
res
}
} }
fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool { fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {

View file

@ -94,6 +94,12 @@ impl FunctionData {
.filter(|it| !it.is_empty()) .filter(|it| !it.is_empty())
.map(Box::new); .map(Box::new);
let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists(); let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists();
if flags.contains(FnFlags::HAS_UNSAFE_KW)
&& !crate_graph[krate].edition.at_least_2024()
&& attrs.by_key(&sym::rustc_deprecated_safe_2024).exists()
{
flags.remove(FnFlags::HAS_UNSAFE_KW);
}
Arc::new(FunctionData { Arc::new(FunctionData {
name: func.name.clone(), name: func.name.clone(),
@ -126,19 +132,19 @@ impl FunctionData {
self.flags.contains(FnFlags::HAS_SELF_PARAM) self.flags.contains(FnFlags::HAS_SELF_PARAM)
} }
pub fn has_default_kw(&self) -> bool { pub fn is_default(&self) -> bool {
self.flags.contains(FnFlags::HAS_DEFAULT_KW) self.flags.contains(FnFlags::HAS_DEFAULT_KW)
} }
pub fn has_const_kw(&self) -> bool { pub fn is_const(&self) -> bool {
self.flags.contains(FnFlags::HAS_CONST_KW) self.flags.contains(FnFlags::HAS_CONST_KW)
} }
pub fn has_async_kw(&self) -> bool { pub fn is_async(&self) -> bool {
self.flags.contains(FnFlags::HAS_ASYNC_KW) self.flags.contains(FnFlags::HAS_ASYNC_KW)
} }
pub fn has_unsafe_kw(&self) -> bool { pub fn is_unsafe(&self) -> bool {
self.flags.contains(FnFlags::HAS_UNSAFE_KW) self.flags.contains(FnFlags::HAS_UNSAFE_KW)
} }

View file

@ -160,7 +160,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn const_data(&self, konst: ConstId) -> Arc<ConstData>; fn const_data(&self, konst: ConstId) -> Arc<ConstData>;
#[salsa::invoke(StaticData::static_data_query)] #[salsa::invoke(StaticData::static_data_query)]
fn static_data(&self, konst: StaticId) -> Arc<StaticData>; fn static_data(&self, statik: StaticId) -> Arc<StaticData>;
#[salsa::invoke(Macro2Data::macro2_data_query)] #[salsa::invoke(Macro2Data::macro2_data_query)]
fn macro2_data(&self, makro: Macro2Id) -> Arc<Macro2Data>; fn macro2_data(&self, makro: Macro2Id) -> Arc<Macro2Data>;
@ -240,14 +240,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool; fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
fn include_macro_invoc(&self, crate_id: CrateId) -> Vec<(MacroCallId, EditionedFileId)>; fn include_macro_invoc(&self, crate_id: CrateId) -> Arc<[(MacroCallId, EditionedFileId)]>;
} }
// return: macro call id and include file id // return: macro call id and include file id
fn include_macro_invoc( fn include_macro_invoc(
db: &dyn DefDatabase, db: &dyn DefDatabase,
krate: CrateId, krate: CrateId,
) -> Vec<(MacroCallId, EditionedFileId)> { ) -> Arc<[(MacroCallId, EditionedFileId)]> {
db.crate_def_map(krate) db.crate_def_map(krate)
.modules .modules
.values() .values()

View file

@ -50,13 +50,13 @@ pub fn find_path(
prefix: prefix_kind, prefix: prefix_kind,
cfg, cfg,
ignore_local_imports, ignore_local_imports,
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
from, from,
from_def_map: &from.def_map(db), from_def_map: &from.def_map(db),
fuel: Cell::new(FIND_PATH_FUEL), fuel: Cell::new(FIND_PATH_FUEL),
}, },
item, item,
MAX_PATH_LEN, MAX_PATH_LEN,
db.crate_graph()[item_module.krate()].origin.is_lang(),
) )
} }
@ -98,20 +98,16 @@ struct FindPathCtx<'db> {
prefix: PrefixKind, prefix: PrefixKind,
cfg: ImportPathConfig, cfg: ImportPathConfig,
ignore_local_imports: bool, ignore_local_imports: bool,
is_std_item: bool,
from: ModuleId, from: ModuleId,
from_def_map: &'db DefMap, from_def_map: &'db DefMap,
fuel: Cell<usize>, fuel: Cell<usize>,
} }
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
fn find_path_inner( fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
ctx: &FindPathCtx<'_>,
item: ItemInNs,
max_len: usize,
is_std_item: bool,
) -> Option<ModPath> {
// - if the item is a module, jump straight to module search // - if the item is a module, jump straight to module search
if !is_std_item { if !ctx.is_std_item {
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len) return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len)
.map(|choice| choice.path); .map(|choice| choice.path);
@ -138,12 +134,9 @@ fn find_path_inner(
if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
// - if the item is an enum variant, refer to it via the enum // - if the item is an enum variant, refer to it via the enum
if let Some(mut path) = find_path_inner( if let Some(mut path) =
ctx, find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len)
ItemInNs::Types(variant.lookup(ctx.db).parent.into()), {
max_len,
is_std_item,
) {
path.push_segment(ctx.db.enum_variant_data(variant).name.clone()); path.push_segment(ctx.db.enum_variant_data(variant).name.clone());
return Some(path); return Some(path);
} }
@ -152,16 +145,6 @@ fn find_path_inner(
// variant somewhere // variant somewhere
} }
if is_std_item {
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
// the sysroot libraries directly.
// We do need to fallback as the item in question could be re-exported by another crate
// while not being a transitive dependency of the current crate.
if let Some(choice) = find_in_sysroot(ctx, &mut FxHashSet::default(), item, max_len) {
return Some(choice.path);
}
}
let mut best_choice = None; let mut best_choice = None;
calculate_best_path(ctx, &mut FxHashSet::default(), item, max_len, &mut best_choice); calculate_best_path(ctx, &mut FxHashSet::default(), item, max_len, &mut best_choice);
best_choice.map(|choice| choice.path) best_choice.map(|choice| choice.path)
@ -366,6 +349,12 @@ fn calculate_best_path(
// Item was defined in the same crate that wants to import it. It cannot be found in any // Item was defined in the same crate that wants to import it. It cannot be found in any
// dependency in this case. // dependency in this case.
calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice) calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice)
} else if ctx.is_std_item {
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
// the sysroot libraries directly.
// We do need to fallback as the item in question could be re-exported by another crate
// while not being a transitive dependency of the current crate.
find_in_sysroot(ctx, visited_modules, item, max_len, best_choice)
} else { } else {
// Item was defined in some upstream crate. This means that it must be exported from one, // Item was defined in some upstream crate. This means that it must be exported from one,
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
@ -382,10 +371,10 @@ fn find_in_sysroot(
visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>, visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
item: ItemInNs, item: ItemInNs,
max_len: usize, max_len: usize,
) -> Option<Choice> { best_choice: &mut Option<Choice>,
) {
let crate_graph = ctx.db.crate_graph(); let crate_graph = ctx.db.crate_graph();
let dependencies = &crate_graph[ctx.from.krate].dependencies; let dependencies = &crate_graph[ctx.from.krate].dependencies;
let mut best_choice = None;
let mut search = |lang, best_choice: &mut _| { let mut search = |lang, best_choice: &mut _| {
if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| { if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| {
match crate_graph[dep.crate_id].origin { match crate_graph[dep.crate_id].origin {
@ -397,29 +386,31 @@ fn find_in_sysroot(
} }
}; };
if ctx.cfg.prefer_no_std { if ctx.cfg.prefer_no_std {
search(LangCrateOrigin::Core, &mut best_choice); search(LangCrateOrigin::Core, best_choice);
if matches!(best_choice, Some(Choice { stability: Stable, .. })) { if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
return best_choice; return;
} }
search(LangCrateOrigin::Std, &mut best_choice); search(LangCrateOrigin::Std, best_choice);
if matches!(best_choice, Some(Choice { stability: Stable, .. })) { if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
return best_choice; return;
} }
} else { } else {
search(LangCrateOrigin::Std, &mut best_choice); search(LangCrateOrigin::Std, best_choice);
if matches!(best_choice, Some(Choice { stability: Stable, .. })) { if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
return best_choice; return;
} }
search(LangCrateOrigin::Core, &mut best_choice); search(LangCrateOrigin::Core, best_choice);
if matches!(best_choice, Some(Choice { stability: Stable, .. })) { if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
return best_choice; return;
} }
} }
let mut best_choice = None; dependencies
dependencies.iter().filter(|it| it.is_sysroot()).for_each(|dep| { .iter()
find_in_dep(ctx, visited_modules, item, max_len, &mut best_choice, dep.crate_id); .filter(|it| it.is_sysroot())
}); .chain(dependencies.iter().filter(|it| !it.is_sysroot()))
best_choice .for_each(|dep| {
find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id);
});
} }
fn find_in_dep( fn find_in_dep(
@ -491,6 +482,7 @@ fn calculate_best_path_local(
); );
} }
#[derive(Debug)]
struct Choice { struct Choice {
path: ModPath, path: ModPath,
/// The length in characters of the path /// The length in characters of the path
@ -676,6 +668,7 @@ mod tests {
path: &str, path: &str,
prefer_prelude: bool, prefer_prelude: bool,
prefer_absolute: bool, prefer_absolute: bool,
prefer_no_std: bool,
expect: Expect, expect: Expect,
) { ) {
let (db, pos) = TestDB::with_position(ra_fixture); let (db, pos) = TestDB::with_position(ra_fixture);
@ -717,7 +710,7 @@ mod tests {
module, module,
prefix, prefix,
ignore_local_imports, ignore_local_imports,
ImportPathConfig { prefer_no_std: false, prefer_prelude, prefer_absolute }, ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute },
); );
format_to!( format_to!(
res, res,
@ -732,15 +725,19 @@ mod tests {
} }
fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) { fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, false, false, expect); check_found_path_(ra_fixture, path, false, false, false, expect);
} }
fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) { fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, true, false, expect); check_found_path_(ra_fixture, path, true, false, false, expect);
} }
fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) { fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, false, true, expect); check_found_path_(ra_fixture, path, false, true, false, expect);
}
fn check_found_path_prefer_no_std(ra_fixture: &str, path: &str, expect: Expect) {
check_found_path_(ra_fixture, path, false, false, true, expect);
} }
#[test] #[test]
@ -1361,9 +1358,66 @@ pub mod sync {
"#]], "#]],
); );
} }
#[test]
fn prefer_core_paths_over_std_for_mod_reexport() {
check_found_path_prefer_no_std(
r#"
//- /main.rs crate:main deps:core,std
$0
//- /stdlib.rs crate:std deps:core
pub use core::pin;
//- /corelib.rs crate:core
pub mod pin {
pub struct Pin;
}
"#,
"std::pin::Pin",
expect![[r#"
Plain (imports ): core::pin::Pin
Plain (imports ): core::pin::Pin
ByCrate(imports ): core::pin::Pin
ByCrate(imports ): core::pin::Pin
BySelf (imports ): core::pin::Pin
BySelf (imports ): core::pin::Pin
"#]],
);
}
#[test] #[test]
fn prefer_core_paths_over_std() { fn prefer_core_paths_over_std() {
check_found_path_prefer_no_std(
r#"
//- /main.rs crate:main deps:core,std
$0
//- /std.rs crate:std deps:core
pub mod fmt {
pub use core::fmt::Error;
}
//- /zzz.rs crate:core
pub mod fmt {
pub struct Error;
}
"#,
"core::fmt::Error",
expect![[r#"
Plain (imports ): core::fmt::Error
Plain (imports ): core::fmt::Error
ByCrate(imports ): core::fmt::Error
ByCrate(imports ): core::fmt::Error
BySelf (imports ): core::fmt::Error
BySelf (imports ): core::fmt::Error
"#]],
);
check_found_path( check_found_path(
r#" r#"
//- /main.rs crate:main deps:core,std //- /main.rs crate:main deps:core,std
@ -1878,10 +1932,9 @@ pub mod ops {
#[test] #[test]
fn respect_unstable_modules() { fn respect_unstable_modules() {
check_found_path( check_found_path_prefer_no_std(
r#" r#"
//- /main.rs crate:main deps:std,core //- /main.rs crate:main deps:std,core
#![no_std]
extern crate std; extern crate std;
$0 $0
//- /longer.rs crate:std deps:core //- /longer.rs crate:std deps:core

View file

@ -105,7 +105,7 @@ use crate::{
type FxIndexMap<K, V> = type FxIndexMap<K, V> =
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>; indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
/// A wrapper around two booleans, [`ImportPathConfig::prefer_no_std`] and [`ImportPathConfig::prefer_prelude`]. /// A wrapper around three booleans
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
pub struct ImportPathConfig { pub struct ImportPathConfig {
/// If true, prefer to unconditionally use imports of the `core` and `alloc` crate /// If true, prefer to unconditionally use imports of the `core` and `alloc` crate

View file

@ -1201,7 +1201,6 @@ macro_rules! m {
#[test] #[test]
fn test_meta_doc_comments() { fn test_meta_doc_comments() {
cov_mark::check!(test_meta_doc_comments);
check( check(
r#" r#"
macro_rules! m { macro_rules! m {

View file

@ -317,9 +317,9 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
_: Span, _: Span,
_: Span, _: Span,
) -> Result<Subtree, ProcMacroExpansionError> { ) -> Result<Subtree, ProcMacroExpansionError> {
let (parse, _) = ::mbe::token_tree_to_syntax_node( let (parse, _) = syntax_bridge::token_tree_to_syntax_node(
subtree, subtree,
::mbe::TopEntryPoint::MacroItems, syntax_bridge::TopEntryPoint::MacroItems,
span::Edition::CURRENT, span::Edition::CURRENT,
); );
if parse.errors().is_empty() { if parse.errors().is_empty() {

View file

@ -56,7 +56,6 @@ use crate::{
}; };
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
static EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128);
static FIXED_POINT_LIMIT: Limit = Limit::new(8192); static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap { pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap {
@ -1440,7 +1439,14 @@ impl DefCollector<'_> {
depth: usize, depth: usize,
container: ItemContainerId, container: ItemContainerId,
) { ) {
if EXPANSION_DEPTH_LIMIT.check(depth).is_err() { let recursion_limit = self.def_map.recursion_limit() as usize;
let recursion_limit = Limit::new(if cfg!(test) {
// Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
std::cmp::min(32, recursion_limit)
} else {
recursion_limit
});
if recursion_limit.check(depth).is_err() {
cov_mark::hit!(macro_expansion_overflow); cov_mark::hit!(macro_expansion_overflow);
tracing::warn!("macro expansion is too deep"); tracing::warn!("macro expansion is too deep");
return; return;
@ -2003,7 +2009,7 @@ impl ModCollector<'_, '_> {
Err(cfg) => { Err(cfg) => {
self.emit_unconfigured_diagnostic( self.emit_unconfigured_diagnostic(
self.tree_id, self.tree_id,
AttrOwner::TopLevel, AttrOwner::ModItem(module_id.into()),
&cfg, &cfg,
); );
} }

View file

@ -1,4 +1,4 @@
use base_db::{SourceDatabase, SourceDatabaseExt2 as _}; use base_db::{SourceDatabase, SourceDatabaseFileInputExt as _};
use test_fixture::WithFixture; use test_fixture::WithFixture;
use crate::{db::DefDatabase, nameres::tests::TestDB, AdtId, ModuleDefId}; use crate::{db::DefDatabase, nameres::tests::TestDB, AdtId, ModuleDefId};

View file

@ -194,6 +194,11 @@ pub(super) fn lower_generic_args(
match generic_arg { match generic_arg {
ast::GenericArg::TypeArg(type_arg) => { ast::GenericArg::TypeArg(type_arg) => {
let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty()); let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
type_ref.walk(&mut |tr| {
if let TypeRef::ImplTrait(bounds) = tr {
lower_ctx.update_impl_traits_bounds(bounds.clone());
}
});
args.push(GenericArg::Type(type_ref)); args.push(GenericArg::Type(type_ref));
} }
ast::GenericArg::AssocTypeArg(assoc_type_arg) => { ast::GenericArg::AssocTypeArg(assoc_type_arg) => {

View file

@ -19,7 +19,7 @@ use crate::{
}; };
#[salsa::database( #[salsa::database(
base_db::SourceDatabaseExtStorage, base_db::SourceRootDatabaseStorage,
base_db::SourceDatabaseStorage, base_db::SourceDatabaseStorage,
hir_expand::db::ExpandDatabaseStorage, hir_expand::db::ExpandDatabaseStorage,
crate::db::InternDatabaseStorage, crate::db::InternDatabaseStorage,
@ -69,9 +69,6 @@ impl fmt::Debug for TestDB {
impl panic::RefUnwindSafe for TestDB {} impl panic::RefUnwindSafe for TestDB {}
impl FileLoader for TestDB { impl FileLoader for TestDB {
fn file_text(&self, file_id: FileId) -> Arc<str> {
FileLoaderDelegate(self).file_text(file_id)
}
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
FileLoaderDelegate(self).resolve_path(path) FileLoaderDelegate(self).resolve_path(path)
} }

View file

@ -1,7 +1,8 @@
[package] [package]
name = "hir-expand" name = "hir-expand"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Macro expansion for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
@ -33,6 +34,7 @@ mbe.workspace = true
limit.workspace = true limit.workspace = true
span.workspace = true span.workspace = true
parser.workspace = true parser.workspace = true
syntax-bridge.workspace = true
[dev-dependencies] [dev-dependencies]
expect-test = "1.4.0" expect-test = "1.4.0"

View file

@ -6,14 +6,12 @@ use cfg::CfgExpr;
use either::Either; use either::Either;
use intern::{sym, Interned, Symbol}; use intern::{sym, Interned, Symbol};
use mbe::{ use mbe::{DelimiterKind, Punct};
desugar_doc_comment_text, syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode,
Punct,
};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use span::{Span, SyntaxContextId}; use span::{Span, SyntaxContextId};
use syntax::unescape; use syntax::unescape;
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxNode}; use syntax::{ast, match_ast, AstNode, AstToken, SyntaxNode};
use syntax_bridge::{desugar_doc_comment_text, syntax_node_to_token_tree, DocCommentDesugarMode};
use triomphe::ThinArc; use triomphe::ThinArc;
use crate::name::Name; use crate::name::Name;

View file

@ -2,10 +2,10 @@
use intern::sym; use intern::sym;
use itertools::izip; use itertools::izip;
use mbe::DocCommentDesugarMode;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use span::{MacroCallId, Span}; use span::{MacroCallId, Span};
use stdx::never; use stdx::never;
use syntax_bridge::DocCommentDesugarMode;
use tracing::debug; use tracing::debug;
use crate::{ use crate::{
@ -209,9 +209,9 @@ struct BasicAdtInfo {
} }
fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandError> { fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandError> {
let (parsed, tm) = &mbe::token_tree_to_syntax_node( let (parsed, tm) = &syntax_bridge::token_tree_to_syntax_node(
tt, tt,
mbe::TopEntryPoint::MacroItems, syntax_bridge::TopEntryPoint::MacroItems,
parser::Edition::CURRENT_FIXME, parser::Edition::CURRENT_FIXME,
); );
let macro_items = ast::MacroItems::cast(parsed.syntax_node()) let macro_items = ast::MacroItems::cast(parsed.syntax_node())
@ -268,7 +268,7 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
match this { match this {
Some(it) => { Some(it) => {
param_type_set.insert(it.as_name()); param_type_set.insert(it.as_name());
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
it.syntax(), it.syntax(),
tm, tm,
call_site, call_site,
@ -282,7 +282,7 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
}; };
let bounds = match &param { let bounds = match &param {
ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| { ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| {
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
it.syntax(), it.syntax(),
tm, tm,
call_site, call_site,
@ -295,7 +295,7 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
let ty = param let ty = param
.ty() .ty()
.map(|ty| { .map(|ty| {
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
ty.syntax(), ty.syntax(),
tm, tm,
call_site, call_site,
@ -316,7 +316,7 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
let where_clause = if let Some(w) = where_clause { let where_clause = if let Some(w) = where_clause {
w.predicates() w.predicates()
.map(|it| { .map(|it| {
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
it.syntax(), it.syntax(),
tm, tm,
call_site, call_site,
@ -353,7 +353,7 @@ fn parse_adt(tt: &tt::Subtree, call_site: Span) -> Result<BasicAdtInfo, ExpandEr
param_type_set.contains(&name).then_some(p) param_type_set.contains(&name).then_some(p)
}) })
.map(|it| { .map(|it| {
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
it.syntax(), it.syntax(),
tm, tm,
call_site, call_site,

View file

@ -4,13 +4,14 @@ use base_db::AnchoredPath;
use cfg::CfgExpr; use cfg::CfgExpr;
use either::Either; use either::Either;
use intern::{sym, Symbol}; use intern::{sym, Symbol};
use mbe::{parse_exprs_with_sep, parse_to_token_tree, DelimiterKind}; use mbe::{expect_fragment, DelimiterKind};
use span::{Edition, EditionedFileId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use span::{Edition, EditionedFileId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
use stdx::format_to; use stdx::format_to;
use syntax::{ use syntax::{
format_smolstr, format_smolstr,
unescape::{unescape_byte, unescape_char, unescape_unicode, Mode}, unescape::{unescape_byte, unescape_char, unescape_unicode, Mode},
}; };
use syntax_bridge::parse_to_token_tree;
use crate::{ use crate::{
builtin::quote::{dollar_crate, quote}, builtin::quote::{dollar_crate, quote},
@ -228,20 +229,22 @@ fn assert_expand(
span: Span, span: Span,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let call_site_span = span_with_call_site_ctxt(db, span, id); let call_site_span = span_with_call_site_ctxt(db, span, id);
let args = parse_exprs_with_sep(tt, ',', call_site_span, Edition::CURRENT_FIXME);
let mut iter = ::tt::iter::TtIter::new(tt);
let cond = expect_fragment(
&mut iter,
parser::PrefixEntryPoint::Expr,
db.crate_graph()[id.lookup(db).krate].edition,
tt::DelimSpan { open: tt.delimiter.open, close: tt.delimiter.close },
);
_ = iter.expect_char(',');
let rest = iter.as_slice();
let dollar_crate = dollar_crate(span); let dollar_crate = dollar_crate(span);
let expanded = match &*args { let expanded = match cond.value {
[cond, panic_args @ ..] => { Some(cond) => {
let comma = tt::Subtree { let panic_args = rest.iter().cloned();
delimiter: tt::Delimiter::invisible_spanned(call_site_span),
token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
char: ',',
spacing: tt::Spacing::Alone,
span: call_site_span,
}))]),
};
let cond = cond.clone();
let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
let mac = if use_panic_2021(db, span) { let mac = if use_panic_2021(db, span) {
quote! {call_site_span => #dollar_crate::panic::panic_2021!(##panic_args) } quote! {call_site_span => #dollar_crate::panic::panic_2021!(##panic_args) }
} else { } else {
@ -253,10 +256,13 @@ fn assert_expand(
} }
}} }}
} }
[] => quote! {call_site_span =>{}}, None => quote! {call_site_span =>{}},
}; };
ExpandResult::ok(expanded) match cond.err {
Some(err) => ExpandResult::new(expanded, err.into()),
None => ExpandResult::ok(expanded),
}
} }
fn file_expand( fn file_expand(

View file

@ -1,7 +1,7 @@
//! Defines a unit of change that can applied to the database to get the next //! Defines a unit of change that can applied to the database to get the next
//! state. Changes are transactional. //! state. Changes are transactional.
use base_db::{ use base_db::{
salsa::Durability, CrateGraph, CrateId, FileChange, SourceDatabaseExt, SourceRoot, salsa::Durability, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootDatabase,
TargetLayoutLoadResult, Version, TargetLayoutLoadResult, Version,
}; };
use la_arena::RawIdx; use la_arena::RawIdx;
@ -23,7 +23,7 @@ impl ChangeWithProcMacros {
Self::default() Self::default()
} }
pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) { pub fn apply(self, db: &mut (impl ExpandDatabase + SourceRootDatabase)) {
self.source_change.apply(db); self.source_change.apply(db);
if let Some(proc_macros) = self.proc_macros { if let Some(proc_macros) = self.proc_macros {
db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);

View file

@ -3,10 +3,11 @@
use base_db::{salsa, CrateId, SourceDatabase}; use base_db::{salsa, CrateId, SourceDatabase};
use either::Either; use either::Either;
use limit::Limit; use limit::Limit;
use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, MatchedArmIndex}; use mbe::MatchedArmIndex;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use span::{AstIdMap, EditionedFileId, Span, SyntaxContextData, SyntaxContextId}; use span::{AstIdMap, EditionedFileId, Span, SyntaxContextData, SyntaxContextId};
use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T}; use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode};
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
@ -165,7 +166,7 @@ pub fn expand_speculative(
// Build the subtree and token mapping for the speculative args // Build the subtree and token mapping for the speculative args
let (mut tt, undo_info) = match loc.kind { let (mut tt, undo_info) = match loc.kind {
MacroCallKind::FnLike { .. } => ( MacroCallKind::FnLike { .. } => (
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
speculative_args, speculative_args,
span_map, span_map,
span, span,
@ -178,7 +179,7 @@ pub fn expand_speculative(
SyntaxFixupUndoInfo::NONE, SyntaxFixupUndoInfo::NONE,
), ),
MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => ( MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
speculative_args, speculative_args,
span_map, span_map,
span, span,
@ -213,7 +214,7 @@ pub fn expand_speculative(
fixups.remove.extend(censor_cfg); fixups.remove.extend(censor_cfg);
( (
mbe::syntax_node_to_token_tree_modified( syntax_bridge::syntax_node_to_token_tree_modified(
speculative_args, speculative_args,
span_map, span_map,
fixups.append, fixups.append,
@ -459,7 +460,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
return dummy_tt(kind); return dummy_tt(kind);
} }
let mut tt = mbe::syntax_node_to_token_tree( let mut tt = syntax_bridge::syntax_node_to_token_tree(
tt.syntax(), tt.syntax(),
map.as_ref(), map.as_ref(),
span, span,
@ -515,7 +516,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
fixups.remove.extend(censor_cfg); fixups.remove.extend(censor_cfg);
( (
mbe::syntax_node_to_token_tree_modified( syntax_bridge::syntax_node_to_token_tree_modified(
syntax, syntax,
map, map,
fixups.append, fixups.append,
@ -720,13 +721,13 @@ fn token_tree_to_syntax_node(
edition: parser::Edition, edition: parser::Edition,
) -> (Parse<SyntaxNode>, ExpansionSpanMap) { ) -> (Parse<SyntaxNode>, ExpansionSpanMap) {
let entry_point = match expand_to { let entry_point = match expand_to {
ExpandTo::Statements => mbe::TopEntryPoint::MacroStmts, ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts,
ExpandTo::Items => mbe::TopEntryPoint::MacroItems, ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems,
ExpandTo::Pattern => mbe::TopEntryPoint::Pattern, ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern,
ExpandTo::Type => mbe::TopEntryPoint::Type, ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
ExpandTo::Expr => mbe::TopEntryPoint::Expr, ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
}; };
mbe::token_tree_to_syntax_node(tt, entry_point, edition) syntax_bridge::token_tree_to_syntax_node(tt, entry_point, edition)
} }
fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<()>> { fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<()>> {

View file

@ -2,10 +2,10 @@
use base_db::CrateId; use base_db::CrateId;
use intern::sym; use intern::sym;
use mbe::DocCommentDesugarMode;
use span::{Edition, MacroCallId, Span, SyntaxContextId}; use span::{Edition, MacroCallId, Span, SyntaxContextId};
use stdx::TupleExt; use stdx::TupleExt;
use syntax::{ast, AstNode}; use syntax::{ast, AstNode};
use syntax_bridge::DocCommentDesugarMode;
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
@ -112,7 +112,7 @@ impl DeclarativeMacroExpander {
ast::Macro::MacroRules(macro_rules) => ( ast::Macro::MacroRules(macro_rules) => (
match macro_rules.token_tree() { match macro_rules.token_tree() {
Some(arg) => { Some(arg) => {
let tt = mbe::syntax_node_to_token_tree( let tt = syntax_bridge::syntax_node_to_token_tree(
arg.syntax(), arg.syntax(),
map.as_ref(), map.as_ref(),
map.span_for_range( map.span_for_range(
@ -135,14 +135,14 @@ impl DeclarativeMacroExpander {
let span = let span =
map.span_for_range(macro_def.macro_token().unwrap().text_range()); map.span_for_range(macro_def.macro_token().unwrap().text_range());
let args = macro_def.args().map(|args| { let args = macro_def.args().map(|args| {
mbe::syntax_node_to_token_tree( syntax_bridge::syntax_node_to_token_tree(
args.syntax(), args.syntax(),
map.as_ref(), map.as_ref(),
span, span,
DocCommentDesugarMode::Mbe, DocCommentDesugarMode::Mbe,
) )
}); });
let body = mbe::syntax_node_to_token_tree( let body = syntax_bridge::syntax_node_to_token_tree(
body.syntax(), body.syntax(),
map.as_ref(), map.as_ref(),
span, span,

View file

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

View file

@ -2,7 +2,6 @@
//! fix up syntax errors in the code we're passing to them. //! fix up syntax errors in the code we're passing to them.
use intern::sym; use intern::sym;
use mbe::DocCommentDesugarMode;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::SmallVec; use smallvec::SmallVec;
use span::{ use span::{
@ -14,6 +13,7 @@ use syntax::{
ast::{self, AstNode, HasLoopBody}, ast::{self, AstNode, HasLoopBody},
match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, TextSize, match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, TextSize,
}; };
use syntax_bridge::DocCommentDesugarMode;
use triomphe::Arc; use triomphe::Arc;
use tt::Spacing; use tt::Spacing;
@ -76,7 +76,8 @@ pub(crate) fn fixup_syntax(
if can_handle_error(&node) && has_error_to_handle(&node) { if can_handle_error(&node) && has_error_to_handle(&node) {
remove.insert(node.clone().into()); remove.insert(node.clone().into());
// the node contains an error node, we have to completely replace it by something valid // 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, mode); let original_tree =
syntax_bridge::syntax_node_to_token_tree(&node, span_map, call_site, mode);
let idx = original.len() as u32; let idx = original.len() as u32;
original.push(original_tree); original.push(original_tree);
let span = span_map.span_for_range(node_range); let span = span_map.span_for_range(node_range);
@ -434,9 +435,9 @@ fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use expect_test::{expect, Expect}; use expect_test::{expect, Expect};
use mbe::DocCommentDesugarMode;
use span::{Edition, EditionedFileId, FileId}; use span::{Edition, EditionedFileId, FileId};
use syntax::TextRange; use syntax::TextRange;
use syntax_bridge::DocCommentDesugarMode;
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
@ -483,7 +484,7 @@ mod tests {
span_map.span_for_range(TextRange::empty(0.into())), span_map.span_for_range(TextRange::empty(0.into())),
DocCommentDesugarMode::Mbe, DocCommentDesugarMode::Mbe,
); );
let mut tt = mbe::syntax_node_to_token_tree_modified( let mut tt = syntax_bridge::syntax_node_to_token_tree_modified(
&parsed.syntax_node(), &parsed.syntax_node(),
span_map.as_ref(), span_map.as_ref(),
fixups.append, fixups.append,
@ -498,9 +499,9 @@ mod tests {
expect.assert_eq(&actual); expect.assert_eq(&actual);
// the fixed-up tree should be syntactically valid // the fixed-up tree should be syntactically valid
let (parse, _) = mbe::token_tree_to_syntax_node( let (parse, _) = syntax_bridge::token_tree_to_syntax_node(
&tt, &tt,
::mbe::TopEntryPoint::MacroItems, syntax_bridge::TopEntryPoint::MacroItems,
parser::Edition::CURRENT, parser::Edition::CURRENT,
); );
assert!( assert!(
@ -513,7 +514,7 @@ mod tests {
// the fixed-up + reversed version should be equivalent to the original input // the fixed-up + reversed version should be equivalent to the original input
// modulo token IDs and `Punct`s' spacing. // modulo token IDs and `Punct`s' spacing.
let original_as_tt = mbe::syntax_node_to_token_tree( let original_as_tt = syntax_bridge::syntax_node_to_token_tree(
&parsed.syntax_node(), &parsed.syntax_node(),
span_map.as_ref(), span_map.as_ref(),
span_map.span_for_range(TextRange::empty(0.into())), span_map.span_for_range(TextRange::empty(0.into())),

View file

@ -176,7 +176,12 @@ impl ExpandErrorKind {
&ExpandErrorKind::MissingProcMacroExpander(def_crate) => { &ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
match db.proc_macros().get_error_for_crate(def_crate) { match db.proc_macros().get_error_for_crate(def_crate) {
Some((e, hard_err)) => (e.to_owned(), hard_err), Some((e, hard_err)) => (e.to_owned(), hard_err),
None => ("missing expander".to_owned(), true), None => (
format!(
"internal error: proc-macro map is missing error entry for crate {def_crate:?}"
),
true,
),
} }
} }
ExpandErrorKind::MacroDefinition => { ExpandErrorKind::MacroDefinition => {

View file

@ -28,13 +28,13 @@ pub enum SpanMapRef<'a> {
RealSpanMap(&'a RealSpanMap), RealSpanMap(&'a RealSpanMap),
} }
impl mbe::SpanMapper<Span> for SpanMap { impl syntax_bridge::SpanMapper<Span> for SpanMap {
fn span_for(&self, range: TextRange) -> Span { fn span_for(&self, range: TextRange) -> Span {
self.span_for_range(range) self.span_for_range(range)
} }
} }
impl mbe::SpanMapper<Span> for SpanMapRef<'_> { impl syntax_bridge::SpanMapper<Span> for SpanMapRef<'_> {
fn span_for(&self, range: TextRange) -> Span { fn span_for(&self, range: TextRange) -> Span {
self.span_for_range(range) self.span_for_range(range)
} }

View file

@ -1,7 +1,8 @@
[package] [package]
name = "hir-ty" name = "hir-ty"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "The type system for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View file

@ -275,7 +275,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
}; };
chalk_ir::Binders::new(binders, bound) chalk_ir::Binders::new(binders, bound)
} }
crate::ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = self let datas = self
.db .db
.type_alias_impl_traits(alias) .type_alias_impl_traits(alias)

View file

@ -276,7 +276,7 @@ impl TyExt for Ty {
data.substitute(Interner, &subst).into_value_and_skipped_binders().0 data.substitute(Interner, &subst).into_value_and_skipped_binders().0
}) })
} }
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { ImplTraitId::TypeAliasImplTrait(alias, idx) => {
db.type_alias_impl_traits(alias).map(|it| { db.type_alias_impl_traits(alias).map(|it| {
let data = let data =
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
@ -295,7 +295,7 @@ impl TyExt for Ty {
data.substitute(Interner, &opaque_ty.substitution) data.substitute(Interner, &opaque_ty.substitution)
}) })
} }
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { ImplTraitId::TypeAliasImplTrait(alias, idx) => {
db.type_alias_impl_traits(alias).map(|it| { db.type_alias_impl_traits(alias).map(|it| {
let data = let data =
(*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone()); (*it).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());

View file

@ -4,20 +4,25 @@
use std::fmt; use std::fmt;
use chalk_solve::rust_ir::AdtKind;
use either::Either; use either::Either;
use hir_def::lang_item::LangItem; use hir_def::{
use hir_def::{resolver::HasResolver, AdtId, AssocItemId, DefWithBodyId, HasModule}; lang_item::LangItem,
use hir_def::{ItemContainerId, Lookup}; resolver::{HasResolver, ValueNs},
AdtId, AssocItemId, DefWithBodyId, HasModule, ItemContainerId, Lookup,
};
use intern::sym; use intern::sym;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use rustc_pattern_analysis::constructor::Constructor; use rustc_pattern_analysis::constructor::Constructor;
use syntax::{ast, AstNode}; use syntax::{
ast::{self, UnaryOp},
AstNode,
};
use tracing::debug; use tracing::debug;
use triomphe::Arc; use triomphe::Arc;
use typed_arena::Arena; use typed_arena::Arena;
use crate::Interner;
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
diagnostics::match_check::{ diagnostics::match_check::{
@ -25,7 +30,7 @@ use crate::{
pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat}, pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat},
}, },
display::HirDisplay, display::HirDisplay,
InferenceResult, Ty, TyExt, Adjust, InferenceResult, Interner, Ty, TyExt, TyKind,
}; };
pub(crate) use hir_def::{ pub(crate) use hir_def::{
@ -117,7 +122,7 @@ impl ExprValidator {
Expr::If { .. } => { Expr::If { .. } => {
self.check_for_unnecessary_else(id, expr, db); self.check_for_unnecessary_else(id, expr, db);
} }
Expr::Block { .. } => { Expr::Block { .. } | Expr::Async { .. } | Expr::Unsafe { .. } => {
self.validate_block(db, expr); self.validate_block(db, expr);
} }
_ => {} _ => {}
@ -236,7 +241,12 @@ impl ExprValidator {
return; return;
} }
let report = match cx.compute_match_usefulness(m_arms.as_slice(), scrut_ty.clone()) { let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr, db));
let report = match cx.compute_match_usefulness(
m_arms.as_slice(),
scrut_ty.clone(),
known_valid_scrutinee,
) {
Ok(report) => report, Ok(report) => report,
Err(()) => return, Err(()) => return,
}; };
@ -253,8 +263,52 @@ impl ExprValidator {
} }
} }
// [rustc's `is_known_valid_scrutinee`](https://github.com/rust-lang/rust/blob/c9bd03cb724e13cca96ad320733046cbdb16fbbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L288)
//
// While the above function in rustc uses thir exprs, r-a doesn't have them.
// So, the logic here is getting same result as "hir lowering + match with lowered thir"
// with "hir only"
fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId, db: &dyn HirDatabase) -> bool {
if self
.infer
.expr_adjustments
.get(&scrutinee_expr)
.is_some_and(|adjusts| adjusts.iter().any(|a| matches!(a.kind, Adjust::Deref(..))))
{
return false;
}
match &self.body[scrutinee_expr] {
Expr::UnaryOp { op: UnaryOp::Deref, .. } => false,
Expr::Path(path) => {
let value_or_partial = self
.owner
.resolver(db.upcast())
.resolve_path_in_value_ns_fully(db.upcast(), path);
value_or_partial.map_or(true, |v| !matches!(v, ValueNs::StaticId(_)))
}
Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind(Interner) {
TyKind::Adt(adt, ..)
if db.adt_datum(self.owner.krate(db.upcast()), *adt).kind == AdtKind::Union =>
{
false
}
_ => self.is_known_valid_scrutinee(*expr, db),
},
Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base, db),
Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr, db),
Expr::Missing => false,
_ => true,
}
}
fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) { fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
let Expr::Block { statements, .. } = expr else { return }; let (Expr::Block { statements, .. }
| Expr::Async { statements, .. }
| Expr::Unsafe { statements, .. }) = expr
else {
return;
};
let pattern_arena = Arena::new(); let pattern_arena = Arena::new();
let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db); let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db);
for stmt in &**statements { for stmt in &**statements {
@ -280,7 +334,7 @@ impl ExprValidator {
has_guard: false, has_guard: false,
arm_data: (), arm_data: (),
}; };
let report = match cx.compute_match_usefulness(&[match_arm], ty.clone()) { let report = match cx.compute_match_usefulness(&[match_arm], ty.clone(), None) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
debug!(?e, "match usefulness error"); debug!(?e, "match usefulness error");

View file

@ -69,22 +69,20 @@ pub(crate) struct MatchCheckCtx<'db> {
body: DefWithBodyId, body: DefWithBodyId,
pub(crate) db: &'db dyn HirDatabase, pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool, exhaustive_patterns: bool,
min_exhaustive_patterns: bool,
} }
impl<'db> MatchCheckCtx<'db> { impl<'db> MatchCheckCtx<'db> {
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self { pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
let def_map = db.crate_def_map(module.krate()); let def_map = db.crate_def_map(module.krate());
let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
let min_exhaustive_patterns = Self { module, body, db, exhaustive_patterns }
def_map.is_unstable_feature_enabled(&sym::min_exhaustive_patterns);
Self { module, body, db, exhaustive_patterns, min_exhaustive_patterns }
} }
pub(crate) fn compute_match_usefulness( pub(crate) fn compute_match_usefulness(
&self, &self,
arms: &[MatchArm<'db>], arms: &[MatchArm<'db>],
scrut_ty: Ty, scrut_ty: Ty,
known_valid_scrutinee: Option<bool>,
) -> Result<UsefulnessReport<'db, Self>, ()> { ) -> Result<UsefulnessReport<'db, Self>, ()> {
if scrut_ty.contains_unknown() { if scrut_ty.contains_unknown() {
return Err(()); return Err(());
@ -95,8 +93,7 @@ impl<'db> MatchCheckCtx<'db> {
} }
} }
// FIXME: Determine place validity correctly. For now, err on the safe side. let place_validity = PlaceValidity::from_bool(known_valid_scrutinee.unwrap_or(true));
let place_validity = PlaceValidity::MaybeInvalid;
// Measured to take ~100ms on modern hardware. // Measured to take ~100ms on modern hardware.
let complexity_limit = Some(500000); let complexity_limit = Some(500000);
compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit) compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
@ -307,7 +304,8 @@ impl<'db> MatchCheckCtx<'db> {
&Str(void) => match void {}, &Str(void) => match void {},
Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
Never => PatKind::Never, Never => PatKind::Never,
Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => { Missing | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..)
| Or => {
never!("can't convert to pattern: {:?}", pat.ctor()); never!("can't convert to pattern: {:?}", pat.ctor());
PatKind::Wild PatKind::Wild
} }
@ -327,9 +325,6 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
fn is_exhaustive_patterns_feature_on(&self) -> bool { fn is_exhaustive_patterns_feature_on(&self) -> bool {
self.exhaustive_patterns self.exhaustive_patterns
} }
fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
self.min_exhaustive_patterns
}
fn ctor_arity( fn ctor_arity(
&self, &self,
@ -356,8 +351,9 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
}, },
Ref => 1, Ref => 1,
Slice(..) => unimplemented!(), Slice(..) => unimplemented!(),
Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
| Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited
| Hidden | Missing | Wildcard => 0,
Or => { Or => {
never!("The `Or` constructor doesn't have a fixed arity"); never!("The `Or` constructor doesn't have a fixed arity");
0 0
@ -419,8 +415,9 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
} }
}, },
Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..)
| Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => { | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited
| Hidden | Missing | Wildcard => {
smallvec![] smallvec![]
} }
Or => { Or => {

View file

@ -17,7 +17,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
let mut res = Vec::new(); let mut res = Vec::new();
let is_unsafe = match def { let is_unsafe = match def {
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(), DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
DefWithBodyId::StaticId(_) DefWithBodyId::StaticId(_)
| DefWithBodyId::ConstId(_) | DefWithBodyId::ConstId(_)
| DefWithBodyId::VariantId(_) | DefWithBodyId::VariantId(_)

View file

@ -1022,16 +1022,16 @@ impl HirDisplay for Ty {
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if parameters.len() - impl_ > 0 { if parameters.len() - impl_ > 0 {
// `parameters` are in the order of fn's params (including impl traits), fn's lifetimes // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
let without_impl = self_param as usize + type_ + const_ + lifetime;
// parent's params (those from enclosing impl or trait, if any). // parent's params (those from enclosing impl or trait, if any).
let (fn_params, other) = let (fn_params, parent_params) = parameters.split_at(without_impl + impl_);
parameters.split_at(self_param as usize + type_ + const_ + lifetime);
let (_impl, parent_params) = other.split_at(impl_);
debug_assert_eq!(parent_params.len(), parent_len); debug_assert_eq!(parent_params.len(), parent_len);
let parent_params = let parent_params =
generic_args_sans_defaults(f, Some(generic_def_id), parent_params); generic_args_sans_defaults(f, Some(generic_def_id), parent_params);
let fn_params = let fn_params =
generic_args_sans_defaults(f, Some(generic_def_id), fn_params); &generic_args_sans_defaults(f, Some(generic_def_id), fn_params)
[0..without_impl];
write!(f, "<")?; write!(f, "<")?;
hir_fmt_generic_arguments(f, parent_params, None)?; hir_fmt_generic_arguments(f, parent_params, None)?;
@ -1069,6 +1069,7 @@ impl HirDisplay for Ty {
module_id, module_id,
PrefixKind::Plain, PrefixKind::Plain,
false, false,
// FIXME: no_std Cfg?
ImportPathConfig { ImportPathConfig {
prefer_no_std: false, prefer_no_std: false,
prefer_prelude: true, prefer_prelude: true,
@ -1151,11 +1152,10 @@ impl HirDisplay for Ty {
)?; )?;
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
} }
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data"); db.type_alias_impl_traits(alias).expect("impl trait id without data");
let data = let data = (*datas).as_ref().map(|it| it.impl_traits[idx].bounds.clone());
(*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
let bounds = data.substitute(Interner, &parameters); let bounds = data.substitute(Interner, &parameters);
let krate = alias.krate(db.upcast()); let krate = alias.krate(db.upcast());
write_bounds_like_dyn_trait_with_prefix( write_bounds_like_dyn_trait_with_prefix(
@ -1338,7 +1338,7 @@ impl HirDisplay for Ty {
SizedByDefault::Sized { anchor: krate }, SizedByDefault::Sized { anchor: krate },
)?; )?;
} }
ImplTraitId::AssociatedTypeImplTrait(alias, idx) => { ImplTraitId::TypeAliasImplTrait(alias, idx) => {
let datas = let datas =
db.type_alias_impl_traits(alias).expect("impl trait id without data"); db.type_alias_impl_traits(alias).expect("impl trait id without data");
let data = let data =

View file

@ -36,15 +36,14 @@ use hir_def::{
body::Body, body::Body,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData}, data::{ConstData, StaticData},
hir::LabelId, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, PatId},
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
layout::Integer, layout::Integer,
path::{ModPath, Path}, path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::{LifetimeRef, TypeRef}, type_ref::{LifetimeRef, TypeRef},
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId, AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
TupleFieldId, TupleId, TypeAliasId, VariantId, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use indexmap::IndexSet; use indexmap::IndexSet;
@ -785,14 +784,19 @@ impl<'a> InferenceContext<'a> {
fn collect_const(&mut self, data: &ConstData) { fn collect_const(&mut self, data: &ConstData) {
let return_ty = self.make_ty(&data.type_ref); let return_ty = self.make_ty(&data.type_ref);
// Constants might be associated items that define ATPITs. // Constants might be defining usage sites of TAITs.
self.insert_atpit_coercion_table(iter::once(&return_ty)); self.make_tait_coercion_table(iter::once(&return_ty));
self.return_ty = return_ty; self.return_ty = return_ty;
} }
fn collect_static(&mut self, data: &StaticData) { fn collect_static(&mut self, data: &StaticData) {
self.return_ty = self.make_ty(&data.type_ref); let return_ty = self.make_ty(&data.type_ref);
// Statics might be defining usage sites of TAITs.
self.make_tait_coercion_table(iter::once(&return_ty));
self.return_ty = return_ty;
} }
fn collect_fn(&mut self, func: FunctionId) { fn collect_fn(&mut self, func: FunctionId) {
@ -857,11 +861,11 @@ impl<'a> InferenceContext<'a> {
self.return_ty = self.normalize_associated_types_in(return_ty); self.return_ty = self.normalize_associated_types_in(return_ty);
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone())); self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
// Functions might be associated items that define ATPITs. // Functions might be defining usage sites of TAITs.
// To define an ATPITs, that ATPIT must appear in the function's signatures. // To define an TAITs, that TAIT must appear in the function's signatures.
// So, it suffices to check for params and return types. // So, it suffices to check for params and return types.
params_and_ret_tys.push(self.return_ty.clone()); params_and_ret_tys.push(self.return_ty.clone());
self.insert_atpit_coercion_table(params_and_ret_tys.iter()); self.make_tait_coercion_table(params_and_ret_tys.iter());
} }
fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T
@ -880,7 +884,7 @@ impl<'a> InferenceContext<'a> {
ImplTraitId::ReturnTypeImplTrait(def, idx) => { ImplTraitId::ReturnTypeImplTrait(def, idx) => {
(self.db.return_type_impl_traits(def), idx) (self.db.return_type_impl_traits(def), idx)
} }
ImplTraitId::AssociatedTypeImplTrait(def, idx) => { ImplTraitId::TypeAliasImplTrait(def, idx) => {
(self.db.type_alias_impl_traits(def), idx) (self.db.type_alias_impl_traits(def), idx)
} }
_ => unreachable!(), _ => unreachable!(),
@ -909,23 +913,25 @@ impl<'a> InferenceContext<'a> {
} }
/// The coercion of a non-inference var into an opaque type should fail, /// The coercion of a non-inference var into an opaque type should fail,
/// but not in the defining sites of the ATPITs. /// but not in the defining sites of the TAITs.
/// In such cases, we insert an proxy inference var for each ATPIT, /// In such cases, we insert an proxy inference var for each TAIT,
/// and coerce into it instead of ATPIT itself. /// and coerce into it instead of TAIT itself.
/// ///
/// The inference var stretagy is effective because; /// The inference var stretagy is effective because;
/// ///
/// - It can still unify types that coerced into ATPIT /// - It can still unify types that coerced into TAITs
/// - We are pushing `impl Trait` bounds into it /// - We are pushing `impl Trait` bounds into it
/// ///
/// This function inserts a map that maps the opaque type to that proxy inference var. /// This function inserts a map that maps the opaque type to that proxy inference var.
fn insert_atpit_coercion_table<'b>(&mut self, tys: impl Iterator<Item = &'b Ty>) { fn make_tait_coercion_table<'b>(&mut self, tait_candidates: impl Iterator<Item = &'b Ty>) {
struct OpaqueTyCollector<'a, 'b> { struct TypeAliasImplTraitCollector<'a, 'b> {
db: &'b dyn HirDatabase,
table: &'b mut InferenceTable<'a>, table: &'b mut InferenceTable<'a>,
opaque_tys: FxHashMap<OpaqueTyId, Ty>, assocs: FxHashMap<OpaqueTyId, (ImplId, Ty)>,
non_assocs: FxHashMap<OpaqueTyId, Ty>,
} }
impl<'a, 'b> TypeVisitor<Interner> for OpaqueTyCollector<'a, 'b> { impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> {
type BreakTy = (); type BreakTy = ();
fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> { fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
@ -944,59 +950,105 @@ impl<'a> InferenceContext<'a> {
let ty = self.table.resolve_ty_shallow(ty); let ty = self.table.resolve_ty_shallow(ty);
if let TyKind::OpaqueType(id, _) = ty.kind(Interner) { if let TyKind::OpaqueType(id, _) = ty.kind(Interner) {
self.opaque_tys.insert(*id, ty.clone()); if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
self.db.lookup_intern_impl_trait_id((*id).into())
{
let loc = self.db.lookup_intern_type_alias(alias_id);
match loc.container {
ItemContainerId::ImplId(impl_id) => {
self.assocs.insert(*id, (impl_id, ty.clone()));
}
ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => {
self.non_assocs.insert(*id, ty.clone());
}
_ => {}
}
}
} }
ty.super_visit_with(self, outer_binder) ty.super_visit_with(self, outer_binder)
} }
} }
// Early return if this is not happening inside the impl block let mut collector = TypeAliasImplTraitCollector {
let impl_id = if let Some(impl_id) = self.resolver.impl_def() { db: self.db,
impl_id table: &mut self.table,
} else { assocs: FxHashMap::default(),
return; non_assocs: FxHashMap::default(),
}; };
for ty in tait_candidates {
let assoc_tys: FxHashSet<_> = self
.db
.impl_data(impl_id)
.items
.iter()
.filter_map(|item| match item {
AssocItemId::TypeAliasId(alias) => Some(*alias),
_ => None,
})
.collect();
if assoc_tys.is_empty() {
return;
}
let mut collector =
OpaqueTyCollector { table: &mut self.table, opaque_tys: FxHashMap::default() };
for ty in tys {
ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST); ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
} }
let atpit_coercion_table: FxHashMap<_, _> = collector
.opaque_tys
.into_iter()
.filter_map(|(opaque_ty_id, ty)| {
if let ImplTraitId::AssociatedTypeImplTrait(alias_id, _) =
self.db.lookup_intern_impl_trait_id(opaque_ty_id.into())
{
if assoc_tys.contains(&alias_id) {
let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id);
let ty = self.insert_inference_vars_for_impl_trait(ty, alias_placeholders);
return Some((opaque_ty_id, ty));
}
}
None // Non-assoc TAITs can be define-used everywhere as long as they are
// in function signatures or const types, etc
let mut taits = collector.non_assocs;
// assoc TAITs(ATPITs) can be only define-used inside their impl block.
// They cannot be define-used in inner items like in the following;
//
// ```
// impl Trait for Struct {
// type Assoc = impl Default;
//
// fn assoc_fn() -> Self::Assoc {
// let foo: Self::Assoc = true; // Allowed here
//
// fn inner() -> Self::Assoc {
// false // Not allowed here
// }
//
// foo
// }
// }
// ```
let impl_id = match self.owner {
DefWithBodyId::FunctionId(it) => {
let loc = self.db.lookup_intern_function(it);
if let ItemContainerId::ImplId(impl_id) = loc.container {
Some(impl_id)
} else {
None
}
}
DefWithBodyId::ConstId(it) => {
let loc = self.db.lookup_intern_const(it);
if let ItemContainerId::ImplId(impl_id) = loc.container {
Some(impl_id)
} else {
None
}
}
_ => None,
};
if let Some(impl_id) = impl_id {
taits.extend(collector.assocs.into_iter().filter_map(|(id, (impl_, ty))| {
if impl_ == impl_id {
Some((id, ty))
} else {
None
}
}));
}
let tait_coercion_table: FxHashMap<_, _> = taits
.into_iter()
.filter_map(|(id, ty)| {
if let ImplTraitId::TypeAliasImplTrait(alias_id, _) =
self.db.lookup_intern_impl_trait_id(id.into())
{
let subst = TyBuilder::placeholder_subst(self.db, alias_id);
let ty = self.insert_inference_vars_for_impl_trait(ty, subst);
Some((id, ty))
} else {
None
}
}) })
.collect(); .collect();
if !atpit_coercion_table.is_empty() { if !tait_coercion_table.is_empty() {
self.table.atpit_coercion_table = Some(atpit_coercion_table); self.table.tait_coercion_table = Some(tait_coercion_table);
} }
} }

View file

@ -276,16 +276,16 @@ impl InferenceTable<'_> {
return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]); return success(simple(Adjust::NeverToAny)(to_ty.clone()), to_ty.clone(), vec![]);
} }
// If we are coercing into an ATPIT, coerce into its proxy inference var, instead. // If we are coercing into a TAIT, coerce into its proxy inference var, instead.
let mut to_ty = to_ty; let mut to_ty = to_ty;
let _to; let _to;
if let Some(atpit_table) = &self.atpit_coercion_table { if let Some(tait_table) = &self.tait_coercion_table {
if let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) { if let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) {
if !matches!( if !matches!(
from_ty.kind(Interner), from_ty.kind(Interner),
TyKind::InferenceVar(..) | TyKind::OpaqueType(..) TyKind::InferenceVar(..) | TyKind::OpaqueType(..)
) { ) {
if let Some(ty) = atpit_table.get(opaque_ty_id) { if let Some(ty) = tait_table.get(opaque_ty_id) {
_to = ty.clone(); _to = ty.clone();
to_ty = &_to; to_ty = &_to;
} }

View file

@ -1759,13 +1759,14 @@ impl InferenceContext<'_> {
skip_indices: &[u32], skip_indices: &[u32],
is_varargs: bool, is_varargs: bool,
) { ) {
if args.len() != param_tys.len() + skip_indices.len() && !is_varargs { let arg_count_mismatch = args.len() != param_tys.len() + skip_indices.len() && !is_varargs;
if arg_count_mismatch {
self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount { self.push_diagnostic(InferenceDiagnostic::MismatchedArgCount {
call_expr: expr, call_expr: expr,
expected: param_tys.len() + skip_indices.len(), expected: param_tys.len() + skip_indices.len(),
found: args.len(), found: args.len(),
}); });
} };
// Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 -- // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
// We do this in a pretty awful way: first we type-check any arguments // We do this in a pretty awful way: first we type-check any arguments
@ -1819,7 +1820,7 @@ impl InferenceContext<'_> {
// The function signature may contain some unknown types, so we need to insert // The function signature may contain some unknown types, so we need to insert
// type vars here to avoid type mismatch false positive. // type vars here to avoid type mismatch false positive.
let coercion_target = self.insert_type_vars(coercion_target); let coercion_target = self.insert_type_vars(coercion_target);
if self.coerce(Some(arg), &ty, &coercion_target).is_err() { if self.coerce(Some(arg), &ty, &coercion_target).is_err() && !arg_count_mismatch {
self.result.type_mismatches.insert( self.result.type_mismatches.insert(
arg.into(), arg.into(),
TypeMismatch { expected: coercion_target, actual: ty.clone() }, TypeMismatch { expected: coercion_target, actual: ty.clone() },

View file

@ -224,7 +224,7 @@ type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
pub(crate) struct InferenceTable<'a> { pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>, pub(crate) trait_env: Arc<TraitEnvironment>,
pub(crate) atpit_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>, pub(crate) tait_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
var_unification_table: ChalkInferenceTable, var_unification_table: ChalkInferenceTable,
type_variable_table: SmallVec<[TypeVariableFlags; 16]>, type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
@ -244,7 +244,7 @@ impl<'a> InferenceTable<'a> {
InferenceTable { InferenceTable {
db, db,
trait_env, trait_env,
atpit_coercion_table: None, tait_coercion_table: None,
var_unification_table: ChalkInferenceTable::new(), var_unification_table: ChalkInferenceTable::new(),
type_variable_table: SmallVec::new(), type_variable_table: SmallVec::new(),
pending_obligations: Vec::new(), pending_obligations: Vec::new(),

View file

@ -391,7 +391,7 @@ pub fn layout_of_ty_query(
let infer = db.infer(func.into()); let infer = db.infer(func.into());
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env); return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env);
} }
crate::ImplTraitId::AssociatedTypeImplTrait(..) => { crate::ImplTraitId::TypeAliasImplTrait(..) => {
return Err(LayoutError::NotImplemented); return Err(LayoutError::NotImplemented);
} }
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {

View file

@ -595,7 +595,7 @@ impl TypeFoldable<Interner> for CallableSig {
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ImplTraitId { pub enum ImplTraitId {
ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx), ReturnTypeImplTrait(hir_def::FunctionId, ImplTraitIdx),
AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx), TypeAliasImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
} }
impl InternValueTrivial for ImplTraitId {} impl InternValueTrivial for ImplTraitId {}

View file

@ -341,7 +341,7 @@ impl<'a> TyLoweringContext<'a> {
let impl_trait_id = origin.either( let impl_trait_id = origin.either(
|f| ImplTraitId::ReturnTypeImplTrait(f, idx), |f| ImplTraitId::ReturnTypeImplTrait(f, idx),
|a| ImplTraitId::AssociatedTypeImplTrait(a, idx), |a| ImplTraitId::TypeAliasImplTrait(a, idx),
); );
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
let generics = let generics =
@ -1857,7 +1857,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
params, params,
ret, ret,
data.is_varargs(), data.is_varargs(),
if data.has_unsafe_kw() { Safety::Unsafe } else { Safety::Safe }, if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
); );
make_binders(db, &generics, sig) make_binders(db, &generics, sig)
@ -2131,7 +2131,6 @@ pub(crate) fn type_alias_impl_traits(
if let Some(type_ref) = &data.type_ref { if let Some(type_ref) = &data.type_ref {
let _ty = ctx.lower_ty(type_ref); let _ty = ctx.lower_ty(type_ref);
} }
let generics = generics(db.upcast(), def.into());
let type_alias_impl_traits = ImplTraits { let type_alias_impl_traits = ImplTraits {
impl_traits: match ctx.impl_trait_mode { impl_traits: match ctx.impl_trait_mode {
ImplTraitLoweringState::Opaque(x) => x.into_inner(), ImplTraitLoweringState::Opaque(x) => x.into_inner(),
@ -2141,6 +2140,7 @@ pub(crate) fn type_alias_impl_traits(
if type_alias_impl_traits.impl_traits.is_empty() { if type_alias_impl_traits.impl_traits.is_empty() {
None None
} else { } else {
let generics = generics(db.upcast(), def.into());
Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits))) Some(Arc::new(make_binders(db, &generics, type_alias_impl_traits)))
} }
} }

View file

@ -82,8 +82,8 @@ impl FallibleTypeFolder<Interner> for Filler<'_> {
}; };
filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder) filler.try_fold_ty(infer.type_of_rpit[idx].clone(), outer_binder)
} }
crate::ImplTraitId::AssociatedTypeImplTrait(..) => { crate::ImplTraitId::TypeAliasImplTrait(..) => {
not_supported!("associated type impl trait"); not_supported!("type alias impl trait");
} }
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => { crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
not_supported!("async block impl trait"); not_supported!("async block impl trait");

View file

@ -15,7 +15,7 @@ use test_utils::extract_annotations;
use triomphe::Arc; use triomphe::Arc;
#[salsa::database( #[salsa::database(
base_db::SourceDatabaseExtStorage, base_db::SourceRootDatabaseStorage,
base_db::SourceDatabaseStorage, base_db::SourceDatabaseStorage,
hir_expand::db::ExpandDatabaseStorage, hir_expand::db::ExpandDatabaseStorage,
hir_def::db::InternDatabaseStorage, hir_def::db::InternDatabaseStorage,
@ -75,9 +75,6 @@ impl salsa::ParallelDatabase for TestDB {
impl panic::RefUnwindSafe for TestDB {} impl panic::RefUnwindSafe for TestDB {}
impl FileLoader for TestDB { impl FileLoader for TestDB {
fn file_text(&self, file_id: FileId) -> Arc<str> {
FileLoaderDelegate(self).file_text(file_id)
}
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
FileLoaderDelegate(self).resolve_path(path) FileLoaderDelegate(self).resolve_path(path)
} }

View file

@ -9,10 +9,11 @@ mod patterns;
mod regression; mod regression;
mod simple; mod simple;
mod traits; mod traits;
mod type_alias_impl_traits;
use std::env; use std::env;
use base_db::SourceDatabaseExt2 as _; use base_db::SourceDatabaseFileInputExt as _;
use expect_test::Expect; use expect_test::Expect;
use hir_def::{ use hir_def::{
body::{Body, BodySourceMap, SyntheticSyntax}, body::{Body, BodySourceMap, SyntheticSyntax},

View file

@ -1,4 +1,4 @@
use base_db::SourceDatabaseExt2 as _; use base_db::SourceDatabaseFileInputExt as _;
use test_fixture::WithFixture; use test_fixture::WithFixture;
use crate::{db::HirDatabase, test_db::TestDB}; use crate::{db::HirDatabase, test_db::TestDB};

View file

@ -2122,3 +2122,22 @@ fn test() {
"#, "#,
) )
} }
#[test]
fn issue_17191() {
check_types(
r#"
trait A {
type Item;
}
trait B<T> {}
fn foo<T: B<impl A>>() {}
fn test() {
let f = foo;
//^ fn foo<{unknown}>()
}"#,
);
}

View file

@ -4691,119 +4691,6 @@ fn f<T: Send, U>() {
); );
} }
#[test]
fn associated_type_impl_trait() {
check_types(
r#"
trait Foo {}
struct S1;
impl Foo for S1 {}
trait Bar {
type Item;
fn bar(&self) -> Self::Item;
}
struct S2;
impl Bar for S2 {
type Item = impl Foo;
fn bar(&self) -> Self::Item {
S1
}
}
fn test() {
let x = S2.bar();
//^ impl Foo + ?Sized
}
"#,
);
}
#[test]
fn associated_type_impl_traits_complex() {
check_types(
r#"
struct Unary<T>(T);
struct Binary<T, U>(T, U);
trait Foo {}
struct S1;
impl Foo for S1 {}
trait Bar {
type Item;
fn bar(&self) -> Unary<Self::Item>;
}
struct S2;
impl Bar for S2 {
type Item = Unary<impl Foo>;
fn bar(&self) -> Unary<<Self as Bar>::Item> {
Unary(Unary(S1))
}
}
trait Baz {
type Target1;
type Target2;
fn baz(&self) -> Binary<Self::Target1, Self::Target2>;
}
struct S3;
impl Baz for S3 {
type Target1 = impl Foo;
type Target2 = Unary<impl Bar>;
fn baz(&self) -> Binary<Self::Target1, Self::Target2> {
Binary(S1, Unary(S2))
}
}
fn test() {
let x = S3.baz();
//^ Binary<impl Foo + ?Sized, Unary<impl Bar + ?Sized>>
let y = x.1.0.bar();
//^ Unary<Bar::Item<impl Bar + ?Sized>>
}
"#,
);
}
#[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] #[test]
fn dyn_trait_with_lifetime_in_rpit() { fn dyn_trait_with_lifetime_in_rpit() {
check_types( check_types(

View file

@ -0,0 +1,161 @@
use expect_test::expect;
use super::{check_infer_with_mismatches, check_no_mismatches, check_types};
#[test]
fn associated_type_impl_trait() {
check_types(
r#"
trait Foo {}
struct S1;
impl Foo for S1 {}
trait Bar {
type Item;
fn bar(&self) -> Self::Item;
}
struct S2;
impl Bar for S2 {
type Item = impl Foo;
fn bar(&self) -> Self::Item {
S1
}
}
fn test() {
let x = S2.bar();
//^ impl Foo + ?Sized
}
"#,
);
}
#[test]
fn associated_type_impl_traits_complex() {
check_types(
r#"
struct Unary<T>(T);
struct Binary<T, U>(T, U);
trait Foo {}
struct S1;
impl Foo for S1 {}
trait Bar {
type Item;
fn bar(&self) -> Unary<Self::Item>;
}
struct S2;
impl Bar for S2 {
type Item = Unary<impl Foo>;
fn bar(&self) -> Unary<<Self as Bar>::Item> {
Unary(Unary(S1))
}
}
trait Baz {
type Target1;
type Target2;
fn baz(&self) -> Binary<Self::Target1, Self::Target2>;
}
struct S3;
impl Baz for S3 {
type Target1 = impl Foo;
type Target2 = Unary<impl Bar>;
fn baz(&self) -> Binary<Self::Target1, Self::Target2> {
Binary(S1, Unary(S2))
}
}
fn test() {
let x = S3.baz();
//^ Binary<impl Foo + ?Sized, Unary<impl Bar + ?Sized>>
let y = x.1.0.bar();
//^ Unary<Bar::Item<impl Bar + ?Sized>>
}
"#,
);
}
#[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 type_alias_impl_trait_simple() {
check_no_mismatches(
r#"
trait Trait {}
struct Struct;
impl Trait for Struct {}
type AliasTy = impl Trait;
static ALIAS: AliasTy = {
let res: AliasTy = Struct;
res
};
"#,
);
check_infer_with_mismatches(
r#"
trait Trait {}
struct Struct;
impl Trait for Struct {}
type AliasTy = impl Trait;
static ALIAS: i32 = {
// TATIs cannot be define-used if not in signature or type annotations
let _a: AliasTy = Struct;
5
};
"#,
expect![[r#"
106..220 '{ ... 5 }': i32
191..193 '_a': impl Trait + ?Sized
205..211 'Struct': Struct
217..218 '5': i32
205..211: expected impl Trait + ?Sized, got Struct
"#]],
)
}

View file

@ -253,12 +253,7 @@ impl<'a> ClosureSubst<'a> {
pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
let data = db.function_data(func); let data = db.function_data(func);
if data.has_unsafe_kw() { if data.is_unsafe() {
// Functions that are `#[rustc_deprecated_safe_2024]` are safe to call before 2024.
if db.attrs(func.into()).by_key(&sym::rustc_deprecated_safe_2024).exists() {
// FIXME: Properly check the caller span and mark it as unsafe after 2024.
return false;
}
return true; return true;
} }

View file

@ -1,7 +1,8 @@
[package] [package]
name = "hir" name = "hir"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "A high-level object-oriented access to Rust code for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View file

@ -48,6 +48,7 @@ macro_rules! diagnostics {
// ] // ]
diagnostics![ diagnostics![
AwaitOutsideOfAsync,
BreakOutsideOfLoop, BreakOutsideOfLoop,
ExpectedFunction, ExpectedFunction,
InactiveCode, InactiveCode,
@ -135,6 +136,12 @@ pub struct UnreachableLabel {
pub name: Name, pub name: Name,
} }
#[derive(Debug)]
pub struct AwaitOutsideOfAsync {
pub node: InFile<AstPtr<ast::AwaitExpr>>,
pub location: String,
}
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct UndeclaredLabel { pub struct UndeclaredLabel {
pub node: InFile<AstPtr<ast::Lifetime>>, pub node: InFile<AstPtr<ast::Lifetime>>,

View file

@ -69,13 +69,13 @@ impl HirDisplay for Function {
write_visibility(module_id, self.visibility(db), f)?; write_visibility(module_id, self.visibility(db), f)?;
if data.has_default_kw() { if data.is_default() {
f.write_str("default ")?; f.write_str("default ")?;
} }
if data.has_const_kw() { if data.is_const() {
f.write_str("const ")?; f.write_str("const ")?;
} }
if data.has_async_kw() { if data.is_async() {
f.write_str("async ")?; f.write_str("async ")?;
} }
if self.is_unsafe_to_call(db) { if self.is_unsafe_to_call(db) {
@ -125,7 +125,7 @@ impl HirDisplay for Function {
// `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns. // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
// Use ugly pattern match to strip the Future trait. // Use ugly pattern match to strip the Future trait.
// Better way? // Better way?
let ret_type = if !data.has_async_kw() { let ret_type = if !data.is_async() {
&data.ret_type &data.ret_type
} else { } else {
match &*data.ret_type { match &*data.ret_type {

View file

@ -1,4 +1,4 @@
//! HIR (previously known as descriptors) provides a high-level object oriented //! HIR (previously known as descriptors) provides a high-level object-oriented
//! access to Rust code. //! access to Rust code.
//! //!
//! The principal difference between HIR and syntax trees is that HIR is bound //! The principal difference between HIR and syntax trees is that HIR is bound
@ -1828,6 +1828,9 @@ impl DefWithBody {
is_bang: true, is_bang: true,
} }
.into(), .into(),
BodyDiagnostic::AwaitOutsideOfAsync { node, location } => {
AwaitOutsideOfAsync { node: *node, location: location.clone() }.into()
}
BodyDiagnostic::UnreachableLabel { node, name } => { BodyDiagnostic::UnreachableLabel { node, name } => {
UnreachableLabel { node: *node, name: name.clone() }.into() UnreachableLabel { node: *node, name: name.clone() }.into()
} }
@ -2186,11 +2189,11 @@ impl Function {
} }
pub fn is_const(self, db: &dyn HirDatabase) -> bool { pub fn is_const(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).has_const_kw() db.function_data(self.id).is_const()
} }
pub fn is_async(self, db: &dyn HirDatabase) -> bool { pub fn is_async(self, db: &dyn HirDatabase) -> bool {
db.function_data(self.id).has_async_kw() db.function_data(self.id).is_async()
} }
/// Does this function have `#[test]` attribute? /// Does this function have `#[test]` attribute?

View file

@ -28,7 +28,7 @@ use hir_expand::{
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use span::{EditionedFileId, FileId, Span, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use span::{EditionedFileId, FileId};
use stdx::TupleExt; use stdx::TupleExt;
use syntax::{ use syntax::{
algo::skip_trivia_token, algo::skip_trivia_token,
@ -757,81 +757,9 @@ impl<'db> SemanticsImpl<'db> {
res res
} }
// return:
// SourceAnalyzer(file_id that original call include!)
// macro file id
// token in include! macro mapped from token in params
// span for the mapped token
fn is_from_include_file(
&self,
token: SyntaxToken,
) -> Option<(SourceAnalyzer, HirFileId, SyntaxToken, Span)> {
let parent = token.parent()?;
let file_id = self.find_file(&parent).file_id.file_id()?;
// iterate related crates and find all include! invocations that include_file_id matches
for (invoc, _) in self
.db
.relevant_crates(file_id.file_id())
.iter()
.flat_map(|krate| self.db.include_macro_invoc(*krate))
.filter(|&(_, include_file_id)| include_file_id == file_id)
{
let macro_file = invoc.as_macro_file();
let expansion_info = {
self.with_ctx(|ctx| {
ctx.cache
.expansion_info_cache
.entry(macro_file)
.or_insert_with(|| {
let exp_info = macro_file.expansion_info(self.db.upcast());
let InMacroFile { file_id, value } = exp_info.expanded();
if let InFile { file_id, value: Some(value) } = exp_info.arg() {
self.cache(value.ancestors().last().unwrap(), file_id);
}
self.cache(value, file_id.into());
exp_info
})
.clone()
})
};
// FIXME: uncached parse
// Create the source analyzer for the macro call scope
let Some(sa) = expansion_info
.arg()
.value
.and_then(|it| self.analyze_no_infer(&it.ancestors().last().unwrap()))
else {
continue;
};
// get mapped token in the include! macro file
let span = span::Span {
range: token.text_range(),
anchor: span::SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
ctx: SyntaxContextId::ROOT,
};
let Some(InMacroFile { file_id, value: mut mapped_tokens }) =
expansion_info.map_range_down_exact(span)
else {
continue;
};
// if we find one, then return
if let Some(t) = mapped_tokens.next() {
return Some((sa, file_id.into(), t, span));
}
}
None
}
fn descend_into_macros_impl( fn descend_into_macros_impl(
&self, &self,
mut token: SyntaxToken, token: SyntaxToken,
f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>, f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
) { ) {
let _p = tracing::info_span!("descend_into_macros_impl").entered(); let _p = tracing::info_span!("descend_into_macros_impl").entered();
@ -848,17 +776,7 @@ impl<'db> SemanticsImpl<'db> {
return; return;
} }
}, },
None => { None => return,
// if we cannot find a source analyzer for this token, then we try to find out
// whether this file is an included file and treat that as the include input
let Some((it, macro_file_id, mapped_token, s)) =
self.is_from_include_file(token)
else {
return;
};
token = mapped_token;
(it, s, macro_file_id)
}
}; };
let mut m_cache = self.macro_call_cache.borrow_mut(); let mut m_cache = self.macro_call_cache.borrow_mut();

View file

@ -94,8 +94,9 @@ use hir_def::{
}, },
hir::{BindingId, LabelId}, hir::{BindingId, LabelId},
AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, AdtId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId,
FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, FieldId, FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, Lookup, MacroId,
StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, VariantId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId,
VariantId,
}; };
use hir_expand::{ use hir_expand::{
attrs::AttrId, name::AsName, ExpansionInfo, HirFileId, HirFileIdExt, MacroCallId, attrs::AttrId, name::AsName, ExpansionInfo, HirFileId, HirFileIdExt, MacroCallId,
@ -131,11 +132,30 @@ impl SourceToDefCtx<'_, '_> {
for &crate_id in self.db.relevant_crates(file).iter() { for &crate_id in self.db.relevant_crates(file).iter() {
// Note: `mod` declarations in block modules cannot be supported here // Note: `mod` declarations in block modules cannot be supported here
let crate_def_map = self.db.crate_def_map(crate_id); let crate_def_map = self.db.crate_def_map(crate_id);
mods.extend( let n_mods = mods.len();
let modules = |file| {
crate_def_map crate_def_map
.modules_for_file(file) .modules_for_file(file)
.map(|local_id| crate_def_map.module_id(local_id)), .map(|local_id| crate_def_map.module_id(local_id))
) };
mods.extend(modules(file));
if mods.len() == n_mods {
mods.extend(
self.db
.include_macro_invoc(crate_id)
.iter()
.filter(|&&(_, file_id)| file_id == file)
.flat_map(|(call, _)| {
modules(
call.lookup(self.db.upcast())
.kind
.file_id()
.original_file(self.db.upcast())
.file_id(),
)
}),
);
}
} }
if mods.is_empty() { if mods.is_empty() {
// FIXME: detached file // FIXME: detached file

View file

@ -1,7 +1,8 @@
[package] [package]
name = "ide-assists" name = "ide-assists"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Code assists for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View file

@ -2280,4 +2280,29 @@ impl b::LocalTrait for B {
"#, "#,
) )
} }
#[test]
fn impl_with_type_param_with_former_param_as_default() {
check_assist(
add_missing_impl_members,
r#"
pub trait Test<'a, T, U = T> {
fn test(item: &'a T) -> U;
}
impl<'a> Test<'a, i32> for bool {
$0
}
"#,
r#"
pub trait Test<'a, T, U = T> {
fn test(item: &'a T) -> U;
}
impl<'a> Test<'a, i32> for bool {
fn test(item: &'a i32) -> i32 {
${0:todo!()}
}
}
"#,
);
}
} }

View file

@ -43,7 +43,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
acc.add( acc.add(
AssistId("bind_unused_param", AssistKind::QuickFix), AssistId("bind_unused_param", AssistKind::QuickFix),
&format!("Bind as `let _ = {ident_pat};`"), format!("Bind as `let _ = {ident_pat};`"),
param.syntax().text_range(), param.syntax().text_range(),
|builder| { |builder| {
let line_index = ctx.db().line_index(ctx.file_id().into()); let line_index = ctx.db().line_index(ctx.file_id().into());

View file

@ -2,7 +2,7 @@ use either::Either;
use ide_db::defs::{Definition, NameRefClass}; use ide_db::defs::{Definition, NameRefClass};
use syntax::{ use syntax::{
ast::{self, AstNode, HasGenericParams, HasVisibility}, ast::{self, AstNode, HasGenericParams, HasVisibility},
match_ast, SyntaxNode, match_ast, SyntaxKind, SyntaxNode,
}; };
use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists}; use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
@ -100,7 +100,9 @@ fn edit_struct_def(
ast::make::tokens::single_newline().text(), ast::make::tokens::single_newline().text(),
); );
edit.insert(tuple_fields_text_range.start(), w.syntax().text()); edit.insert(tuple_fields_text_range.start(), w.syntax().text());
edit.insert(tuple_fields_text_range.start(), ","); if !w.syntax().last_token().is_some_and(|t| t.kind() == SyntaxKind::COMMA) {
edit.insert(tuple_fields_text_range.start(), ",");
}
edit.insert( edit.insert(
tuple_fields_text_range.start(), tuple_fields_text_range.start(),
ast::make::tokens::single_newline().text(), ast::make::tokens::single_newline().text(),
@ -879,6 +881,29 @@ use crate::{A::Variant, Inner};
fn f() { fn f() {
let a = Variant { field1: Inner }; let a = Variant { field1: Inner };
} }
"#,
);
}
#[test]
fn where_clause_with_trailing_comma() {
check_assist(
convert_tuple_struct_to_named_struct,
r#"
trait Foo {}
struct Bar$0<T>(pub T)
where
T: Foo,;
"#,
r#"
trait Foo {}
struct Bar<T>
where
T: Foo,
{ pub field1: T }
"#, "#,
); );
} }

View file

@ -3,7 +3,7 @@ mod generated;
use expect_test::expect; use expect_test::expect;
use hir::{FileRange, Semantics}; use hir::{FileRange, Semantics};
use ide_db::{ use ide_db::{
base_db::SourceDatabaseExt, base_db::{SourceDatabase, SourceRootDatabase},
imports::insert_use::{ImportGranularity, InsertUseConfig}, imports::insert_use::{ImportGranularity, InsertUseConfig},
source_change::FileSystemEdit, source_change::FileSystemEdit,
EditionedFileId, RootDatabase, SnippetCap, EditionedFileId, RootDatabase, SnippetCap,

View file

@ -1,7 +1,8 @@
[package] [package]
name = "ide-completion" name = "ide-completion"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Utilities for generating completions of user input for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View file

@ -24,7 +24,7 @@ pub(crate) mod vis;
use std::iter; use std::iter;
use hir::{sym, HasAttrs, ImportPathConfig, Name, ScopeDef, Variant}; use hir::{sym, HasAttrs, Name, ScopeDef, Variant};
use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind}; use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind};
use syntax::{ast, SmolStr, ToSmolStr}; use syntax::{ast, SmolStr, ToSmolStr};
@ -645,11 +645,7 @@ fn enum_variants_with_paths(
if let Some(path) = ctx.module.find_path( if let Some(path) = ctx.module.find_path(
ctx.db, ctx.db,
hir::ModuleDef::from(variant), hir::ModuleDef::from(variant),
ImportPathConfig { ctx.config.import_path_config(),
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
) { ) {
// Variants with trivial paths are already added by the existing completion logic, // Variants with trivial paths are already added by the existing completion logic,
// so we should avoid adding these twice // so we should avoid adding these twice

View file

@ -1,6 +1,6 @@
//! Completion of names from the current scope in expression position. //! Completion of names from the current scope in expression position.
use hir::{sym, ImportPathConfig, Name, ScopeDef}; use hir::{sym, Name, ScopeDef};
use syntax::ast; use syntax::ast;
use crate::{ use crate::{
@ -174,11 +174,7 @@ pub(crate) fn complete_expr_path(
.find_path( .find_path(
ctx.db, ctx.db,
hir::ModuleDef::from(strukt), hir::ModuleDef::from(strukt),
ImportPathConfig { ctx.config.import_path_config(),
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
) )
.filter(|it| it.len() > 1); .filter(|it| it.len() > 1);
@ -200,11 +196,7 @@ pub(crate) fn complete_expr_path(
.find_path( .find_path(
ctx.db, ctx.db,
hir::ModuleDef::from(un), hir::ModuleDef::from(un),
ImportPathConfig { ctx.config.import_path_config(),
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
},
) )
.filter(|it| it.len() > 1); .filter(|it| it.len() > 1);

View file

@ -1,5 +1,5 @@
//! See [`import_on_the_fly`]. //! See [`import_on_the_fly`].
use hir::{ImportPathConfig, ItemInNs, ModuleDef}; use hir::{ItemInNs, ModuleDef};
use ide_db::imports::{ use ide_db::imports::{
import_assets::{ImportAssets, LocatedImport}, import_assets::{ImportAssets, LocatedImport},
insert_use::ImportScope, insert_use::ImportScope,
@ -256,11 +256,7 @@ fn import_on_the_fly(
}; };
let user_input_lowercased = potential_import_name.to_lowercase(); let user_input_lowercased = potential_import_name.to_lowercase();
let import_cfg = ImportPathConfig { let import_cfg = ctx.config.import_path_config();
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
import_assets import_assets
.search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind) .search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind)
@ -306,12 +302,7 @@ fn import_on_the_fly_pat_(
ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)), ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
}; };
let user_input_lowercased = potential_import_name.to_lowercase(); let user_input_lowercased = potential_import_name.to_lowercase();
let cfg = ctx.config.import_path_config();
let cfg = ImportPathConfig {
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
import_assets import_assets
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind) .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@ -353,11 +344,7 @@ fn import_on_the_fly_method(
let user_input_lowercased = potential_import_name.to_lowercase(); let user_input_lowercased = potential_import_name.to_lowercase();
let cfg = ImportPathConfig { let cfg = ctx.config.import_path_config();
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
import_assets import_assets
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind) .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)

View file

@ -4,7 +4,7 @@ use std::iter;
use hir::{HirFileIdExt, Module}; use hir::{HirFileIdExt, Module};
use ide_db::{ use ide_db::{
base_db::{SourceDatabaseExt, VfsPath}, base_db::{SourceRootDatabase, VfsPath},
FxHashSet, RootDatabase, SymbolKind, FxHashSet, RootDatabase, SymbolKind,
}; };
use stdx::IsNoneOr; use stdx::IsNoneOr;

View file

@ -2,7 +2,7 @@
mod format_like; mod format_like;
use hir::{ImportPathConfig, ItemInNs}; use hir::ItemInNs;
use ide_db::{ use ide_db::{
documentation::{Documentation, HasDocs}, documentation::{Documentation, HasDocs},
imports::insert_use::ImportScope, imports::insert_use::ImportScope,
@ -60,11 +60,7 @@ pub(crate) fn complete_postfix(
None => return, None => return,
}; };
let cfg = ImportPathConfig { let cfg = ctx.config.import_path_config();
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() { if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) { if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {

View file

@ -4,6 +4,7 @@
//! module, and we use to statically check that we only produce snippet //! module, and we use to statically check that we only produce snippet
//! completions if we are allowed to. //! completions if we are allowed to.
use hir::ImportPathConfig;
use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap}; use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
use crate::snippet::Snippet; use crate::snippet::Snippet;
@ -45,4 +46,12 @@ impl CompletionConfig {
.iter() .iter()
.flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip))) .flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip)))
} }
pub fn import_path_config(&self) -> ImportPathConfig {
ImportPathConfig {
prefer_no_std: self.prefer_no_std,
prefer_prelude: self.prefer_prelude,
prefer_absolute: self.prefer_absolute,
}
}
} }

View file

@ -10,7 +10,6 @@ mod snippet;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use hir::ImportPathConfig;
use ide_db::{ use ide_db::{
helpers::mod_path_to_ast, helpers::mod_path_to_ast,
imports::{ imports::{
@ -249,11 +248,7 @@ pub fn resolve_completion_edits(
let new_ast = scope.clone_for_update(); let new_ast = scope.clone_for_update();
let mut import_insert = TextEdit::builder(); let mut import_insert = TextEdit::builder();
let cfg = ImportPathConfig { let cfg = config.import_path_config();
prefer_no_std: config.prefer_no_std,
prefer_prelude: config.prefer_prelude,
prefer_absolute: config.prefer_absolute,
};
imports.into_iter().for_each(|(full_import_path, imported_name)| { imports.into_iter().for_each(|(full_import_path, imported_name)| {
let items_with_name = items_locator::items_with_name( let items_with_name = items_locator::items_with_name(

View file

@ -10,7 +10,7 @@ pub(crate) mod type_alias;
pub(crate) mod union_literal; pub(crate) mod union_literal;
pub(crate) mod variant; pub(crate) mod variant;
use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ImportPathConfig, ModuleDef, ScopeDef, Type}; use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type};
use ide_db::{ use ide_db::{
documentation::{Documentation, HasDocs}, documentation::{Documentation, HasDocs},
helpers::item_name, helpers::item_name,
@ -294,11 +294,7 @@ pub(crate) fn render_expr(
.unwrap_or_else(|| String::from("...")) .unwrap_or_else(|| String::from("..."))
}; };
let cfg = ImportPathConfig { let cfg = ctx.config.import_path_config();
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg).ok()?; let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg).ok()?;

View file

@ -100,7 +100,6 @@
// } // }
// ---- // ----
use hir::ImportPathConfig;
use ide_db::imports::import_assets::LocatedImport; use ide_db::imports::import_assets::LocatedImport;
use itertools::Itertools; use itertools::Itertools;
use syntax::{ast, AstNode, GreenNode, SyntaxNode}; use syntax::{ast, AstNode, GreenNode, SyntaxNode};
@ -169,11 +168,7 @@ impl Snippet {
} }
fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> { fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
let import_cfg = ImportPathConfig { let import_cfg = ctx.config.import_path_config();
prefer_no_std: ctx.config.prefer_no_std,
prefer_prelude: ctx.config.prefer_prelude,
prefer_absolute: ctx.config.prefer_absolute,
};
let resolve = |import: &GreenNode| { let resolve = |import: &GreenNode| {
let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?; let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;

View file

@ -23,10 +23,10 @@ mod type_pos;
mod use_tree; mod use_tree;
mod visibility; mod visibility;
use base_db::SourceDatabase;
use expect_test::Expect; use expect_test::Expect;
use hir::PrefixKind; use hir::PrefixKind;
use ide_db::{ use ide_db::{
base_db::FileLoader,
imports::insert_use::{ImportGranularity, InsertUseConfig}, imports::insert_use::{ImportGranularity, InsertUseConfig},
FilePosition, RootDatabase, SnippetCap, FilePosition, RootDatabase, SnippetCap,
}; };

View file

@ -1,7 +1,8 @@
[package] [package]
name = "ide-db" name = "ide-db"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Core data structure representing IDE state for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
@ -13,7 +14,7 @@ doctest = false
[dependencies] [dependencies]
cov-mark = "2.0.0-pre.1" cov-mark = "2.0.0-pre.1"
crossbeam-channel = "0.5.5" crossbeam-channel.workspace = true
tracing.workspace = true tracing.workspace = true
rayon.workspace = true rayon.workspace = true
fst = { version = "0.4.7", default-features = false } fst = { version = "0.4.7", default-features = false }

View file

@ -2,7 +2,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use base_db::SourceDatabaseExt; use base_db::SourceRootDatabase;
use hir::{Crate, DescendPreference, ItemInNs, ModuleDef, Name, Semantics}; use hir::{Crate, DescendPreference, ItemInNs, ModuleDef, Name, Semantics};
use span::FileId; use span::FileId;
use syntax::{ use syntax::{

View file

@ -1,4 +1,4 @@
//! This crate defines the core datastructure representing IDE state -- `RootDatabase`. //! This crate defines the core data structure representing IDE state -- `RootDatabase`.
//! //!
//! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
@ -74,7 +74,7 @@ pub type FilePosition = FilePositionWrapper<FileId>;
pub type FileRange = FileRangeWrapper<FileId>; pub type FileRange = FileRangeWrapper<FileId>;
#[salsa::database( #[salsa::database(
base_db::SourceDatabaseExtStorage, base_db::SourceRootDatabaseStorage,
base_db::SourceDatabaseStorage, base_db::SourceDatabaseStorage,
hir::db::ExpandDatabaseStorage, hir::db::ExpandDatabaseStorage,
hir::db::DefDatabaseStorage, hir::db::DefDatabaseStorage,
@ -125,9 +125,6 @@ impl Upcast<dyn HirDatabase> for RootDatabase {
} }
impl FileLoader for RootDatabase { impl FileLoader for RootDatabase {
fn file_text(&self, file_id: FileId) -> Arc<str> {
FileLoaderDelegate(self).file_text(file_id)
}
fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> { fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
FileLoaderDelegate(self).resolve_path(path) FileLoaderDelegate(self).resolve_path(path)
} }

View file

@ -7,7 +7,7 @@ use itertools::Itertools;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use syntax::{ use syntax::{
ast::{self, make, AstNode, HasGenericArgs}, ast::{self, make, AstNode, HasGenericArgs},
ted, SyntaxNode, ted, NodeOrToken, SyntaxNode,
}; };
#[derive(Default)] #[derive(Default)]
@ -328,10 +328,26 @@ impl Ctx<'_> {
let qualified = make::path_from_segments(std::iter::once(segment), false); let qualified = make::path_from_segments(std::iter::once(segment), false);
ted::replace(path.syntax(), qualified.clone_for_update().syntax()); ted::replace(path.syntax(), qualified.clone_for_update().syntax());
} else if let Some(path_ty) = ast::PathType::cast(parent) { } else if let Some(path_ty) = ast::PathType::cast(parent) {
ted::replace( let old = path_ty.syntax();
path_ty.syntax(),
subst.clone_subtree().clone_for_update().syntax(), if old.parent().is_some() {
); ted::replace(old, subst.clone_subtree().clone_for_update().syntax());
} else {
// Some `path_ty` has no parent, especially ones made for default value
// of type parameters.
// In this case, `ted` cannot replace `path_ty` with `subst` directly.
// So, just replace its children as long as the `subst` is the same type.
let new = subst.clone_subtree().clone_for_update();
if !matches!(new, ast::Type::PathType(..)) {
return None;
}
let start = path_ty.syntax().first_child().map(NodeOrToken::Node)?;
let end = path_ty.syntax().last_child().map(NodeOrToken::Node)?;
ted::replace_all(
start..=end,
new.syntax().children().map(NodeOrToken::Node).collect::<Vec<_>>(),
);
}
} else { } else {
ted::replace( ted::replace(
path.syntax(), path.syntax(),

View file

@ -11,7 +11,7 @@ use hir::db::DefDatabase;
use crate::{ use crate::{
base_db::{ base_db::{
salsa::{Database, ParallelDatabase, Snapshot}, salsa::{Database, ParallelDatabase, Snapshot},
Cancelled, CrateId, SourceDatabase, SourceDatabaseExt, Cancelled, CrateId, SourceDatabase, SourceRootDatabase,
}, },
FxIndexMap, RootDatabase, FxIndexMap, RootDatabase,
}; };

View file

@ -6,7 +6,7 @@
use std::mem; use std::mem;
use base_db::{salsa::Database, SourceDatabase, SourceDatabaseExt}; use base_db::{salsa::Database, SourceDatabase, SourceRootDatabase};
use hir::{ use hir::{
sym, AsAssocItem, DefWithBody, DescendPreference, FileRange, HasAttrs, HasSource, HirFileIdExt, sym, AsAssocItem, DefWithBody, DescendPreference, FileRange, HasAttrs, HasSource, HirFileIdExt,
InFile, InRealFile, ModuleSource, PathResolution, Semantics, Visibility, InFile, InRealFile, ModuleSource, PathResolution, Semantics, Visibility,
@ -663,9 +663,16 @@ impl<'a> FindUsages<'a> {
name_ref: &ast::NameRef, name_ref: &ast::NameRef,
sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool,
) -> bool { ) -> bool {
// See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845
let ty_eq = |ty: hir::Type| match (ty.as_adt(), self_ty.as_adt()) {
(Some(ty), Some(self_ty)) => ty == self_ty,
(None, None) => ty == *self_ty,
_ => false,
};
match NameRefClass::classify(self.sema, name_ref) { match NameRefClass::classify(self.sema, name_ref) {
Some(NameRefClass::Definition(Definition::SelfType(impl_))) Some(NameRefClass::Definition(Definition::SelfType(impl_)))
if impl_.self_ty(self.sema.db).as_adt() == self_ty.as_adt() => if ty_eq(impl_.self_ty(self.sema.db)) =>
{ {
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
let reference = FileReference { let reference = FileReference {

View file

@ -29,7 +29,7 @@ use std::{
use base_db::{ use base_db::{
salsa::{self, ParallelDatabase}, salsa::{self, ParallelDatabase},
SourceDatabaseExt, SourceRootId, Upcast, SourceRootDatabase, SourceRootId, Upcast,
}; };
use fst::{raw::IndexedValue, Automaton, Streamer}; use fst::{raw::IndexedValue, Automaton, Streamer};
use hir::{ use hir::{
@ -100,7 +100,7 @@ impl Query {
} }
#[salsa::query_group(SymbolsDatabaseStorage)] #[salsa::query_group(SymbolsDatabaseStorage)]
pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatabase> { pub trait SymbolsDatabase: HirDatabase + SourceRootDatabase + Upcast<dyn HirDatabase> {
/// The symbol index for a given module. These modules should only be in source roots that /// The symbol index for a given module. These modules should only be in source roots that
/// are inside local_roots. /// are inside local_roots.
fn module_symbols(&self, module: Module) -> Arc<SymbolIndex>; fn module_symbols(&self, module: Module) -> Arc<SymbolIndex>;

View file

@ -1,7 +1,8 @@
[package] [package]
name = "ide-diagnostics" name = "ide-diagnostics"
version = "0.0.0" version = "0.0.0"
description = "TBD" repository.workspace = true
description = "Diagnostics rendering and fixits for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View file

@ -0,0 +1,101 @@
use crate::{adjusted_display_range, Diagnostic, DiagnosticsContext};
// Diagnostic: await-outside-of-async
//
// This diagnostic is triggered if the `await` keyword is used outside of an async function or block
pub(crate) fn await_outside_of_async(
ctx: &DiagnosticsContext<'_>,
d: &hir::AwaitOutsideOfAsync,
) -> Diagnostic {
let display_range =
adjusted_display_range(ctx, d.node, &|node| Some(node.await_token()?.text_range()));
Diagnostic::new(
crate::DiagnosticCode::RustcHardError("E0728"),
format!("`await` is used inside {}, which is not an `async` context", d.location),
display_range,
)
}
#[cfg(test)]
mod tests {
use crate::tests::check_diagnostics;
#[test]
fn await_inside_non_async_fn() {
check_diagnostics(
r#"
async fn foo() {}
fn bar() {
foo().await;
//^^^^^ error: `await` is used inside non-async function, which is not an `async` context
}
"#,
);
}
#[test]
fn await_inside_async_fn() {
check_diagnostics(
r#"
async fn foo() {}
async fn bar() {
foo().await;
}
"#,
);
}
#[test]
fn await_inside_closure() {
check_diagnostics(
r#"
async fn foo() {}
async fn bar() {
let _a = || { foo().await };
//^^^^^ error: `await` is used inside non-async closure, which is not an `async` context
}
"#,
);
}
#[test]
fn await_inside_async_block() {
check_diagnostics(
r#"
async fn foo() {}
fn bar() {
let _a = async { foo().await };
}
"#,
);
}
#[test]
fn await_in_complex_context() {
check_diagnostics(
r#"
async fn foo() {}
fn bar() {
async fn baz() {
let a = foo().await;
}
let x = || {
let y = async {
baz().await;
let z = || {
baz().await;
//^^^^^ error: `await` is used inside non-async closure, which is not an `async` context
};
};
};
}
"#,
);
}
}

View file

@ -42,7 +42,10 @@ mod tests {
use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig};
pub(crate) fn check(ra_fixture: &str) { pub(crate) fn check(ra_fixture: &str) {
let config = DiagnosticsConfig::test_sample(); let config = DiagnosticsConfig {
disabled: std::iter::once("unlinked-file".to_owned()).collect(),
..DiagnosticsConfig::test_sample()
};
check_diagnostics_with_config(config, ra_fixture) check_diagnostics_with_config(config, ra_fixture)
} }
@ -168,6 +171,27 @@ union FooBar {
#[cfg(a)] baz: u32, #[cfg(a)] baz: u32,
//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled //^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
} }
"#,
);
}
#[test]
fn modules() {
check(
r#"
//- /main.rs
#[cfg(outline)] mod outline;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: outline is disabled
mod outline_inner;
//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: outline_inner is disabled
#[cfg(inline)] mod inline {}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: inline is disabled
//- /outline_inner.rs
#![cfg(outline_inner)]
//- /outline.rs
"#, "#,
); );
} }

View file

@ -273,11 +273,7 @@ fn f() {
#[test] #[test]
fn include_does_not_break_diagnostics() { fn include_does_not_break_diagnostics() {
let mut config = DiagnosticsConfig::test_sample(); check_diagnostics(
config.disabled.insert("inactive-code".to_owned());
config.disabled.insert("unlinked-file".to_owned());
check_diagnostics_with_config(
config,
r#" r#"
//- minicore: include //- minicore: include
//- /lib.rs crate:lib //- /lib.rs crate:lib

View file

@ -472,4 +472,18 @@ fn f(
"#, "#,
) )
} }
#[test]
fn no_type_mismatches_when_arg_count_mismatch() {
check_diagnostics(
r#"
fn foo((): (), (): ()) {
foo(1, 2, 3);
// ^^ error: expected 2 arguments, found 3
foo(1);
// ^ error: expected 2 arguments, found 1
}
"#,
);
}
} }

View file

@ -1032,6 +1032,44 @@ fn f() {
check_diagnostics_no_bails(&code); check_diagnostics_no_bails(&code);
} }
#[test]
fn min_exhaustive() {
check_diagnostics(
r#"
//- minicore: result
fn test(x: Result<i32, !>) {
match x {
Ok(_y) => {}
}
}
"#,
);
check_diagnostics(
r#"
//- minicore: result
fn test(ptr: *const Result<i32, !>) {
unsafe {
match *ptr {
//^^^^ error: missing match arm: `Err(!)` not covered
Ok(_x) => {}
}
}
}
"#,
);
check_diagnostics(
r#"
//- minicore: result
fn test(x: Result<i32, &'static !>) {
match x {
//^ error: missing match arm: `Err(_)` not covered
Ok(_y) => {}
}
}
"#,
);
}
mod rust_unstable { mod rust_unstable {
use super::*; use super::*;

View file

@ -483,6 +483,30 @@ unsafe fn foo() -> u8 {
fn main() { fn main() {
let x = format!("foo: {}", foo$0()); let x = format!("foo: {}", foo$0());
}
"#,
)
}
#[test]
fn rustc_deprecated_safe_2024() {
check_diagnostics(
r#"
//- /ed2021.rs crate:ed2021 edition:2021
#[rustc_deprecated_safe_2024]
unsafe fn safe() -> u8 {
0
}
//- /ed2024.rs crate:ed2024 edition:2024
#[rustc_deprecated_safe_2024]
unsafe fn not_safe() -> u8 {
0
}
//- /main.rs crate:main deps:ed2021,ed2024
fn main() {
ed2021::safe();
ed2024::not_safe();
//^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block
} }
"#, "#,
) )

View file

@ -41,6 +41,67 @@ fn main() {
fn main() { fn main() {
let Some(_) | None = Some(5); let Some(_) | None = Some(5);
} }
"#,
);
}
#[test]
fn option_nonexhaustive_inside_blocks() {
check_diagnostics(
r#"
//- minicore: option
fn main() {
'_a: {
let None = Some(5);
//^^^^ error: non-exhaustive pattern: `Some(_)` not covered
}
}
"#,
);
check_diagnostics(
r#"
//- minicore: future, option
fn main() {
let _ = async {
let None = Some(5);
//^^^^ error: non-exhaustive pattern: `Some(_)` not covered
};
}
"#,
);
check_diagnostics(
r#"
//- minicore: option
fn main() {
unsafe {
let None = Some(5);
//^^^^ error: non-exhaustive pattern: `Some(_)` not covered
}
}
"#,
);
}
#[test]
fn min_exhaustive() {
check_diagnostics(
r#"
//- minicore: result
fn test(x: Result<i32, !>) {
let Ok(_y) = x;
}
"#,
);
check_diagnostics(
r#"
//- minicore: result
fn test(x: Result<i32, &'static !>) {
let Ok(_y) = x;
//^^^^^^ error: non-exhaustive pattern: `Err(_)` not covered
}
"#, "#,
); );
} }

View file

@ -2,8 +2,12 @@ use either::Either;
use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type}; use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{ use syntax::{
ast::{self, BlockExpr, ExprStmt}, ast::{
AstNode, AstPtr, self,
edit::{AstNodeEdit, IndentLevel},
BlockExpr, Expr, ExprStmt,
},
AstNode, AstPtr, TextSize,
}; };
use text_edit::TextEdit; use text_edit::TextEdit;
@ -119,6 +123,38 @@ fn add_missing_ok_or_some(
return None; return None;
} }
if d.actual.is_unit() {
if let Expr::BlockExpr(block) = &expr {
if block.tail_expr().is_none() {
let mut builder = TextEdit::builder();
let block_indent = block.indent_level();
if block.statements().count() == 0 {
// Empty block
let indent = block_indent + 1;
builder.insert(
block.syntax().text_range().start() + TextSize::from(1),
format!("\n{indent}{variant_name}(())\n{block_indent}"),
);
} else {
let indent = IndentLevel::from(1);
builder.insert(
block.syntax().text_range().end() - TextSize::from(1),
format!("{indent}{variant_name}(())\n{block_indent}"),
);
}
let source_change = SourceChange::from_text_edit(
expr_ptr.file_id.original_file(ctx.sema.db),
builder.finish(),
);
let name = format!("Insert {variant_name}(()) as the tail of this block");
acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
}
return Some(());
}
}
let mut builder = TextEdit::builder(); let mut builder = TextEdit::builder();
builder.insert(expr.syntax().text_range().start(), format!("{variant_name}(")); builder.insert(expr.syntax().text_range().start(), format!("{variant_name}("));
builder.insert(expr.syntax().text_range().end(), ")".to_owned()); builder.insert(expr.syntax().text_range().end(), ")".to_owned());
@ -533,6 +569,36 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
); );
} }
#[test]
fn test_wrapped_unit_as_block_tail_expr() {
check_fix(
r#"
//- minicore: result
fn foo() -> Result<(), ()> {
foo();
}$0
"#,
r#"
fn foo() -> Result<(), ()> {
foo();
Ok(())
}
"#,
);
check_fix(
r#"
//- minicore: result
fn foo() -> Result<(), ()> {}$0
"#,
r#"
fn foo() -> Result<(), ()> {
Ok(())
}
"#,
);
}
#[test] #[test]
fn test_in_const_and_static() { fn test_in_const_and_static() {
check_fix( check_fix(

View file

@ -4,7 +4,7 @@ use std::iter;
use hir::{db::DefDatabase, DefMap, InFile, ModuleSource}; use hir::{db::DefDatabase, DefMap, InFile, ModuleSource};
use ide_db::{ use ide_db::{
base_db::{FileLoader, SourceDatabaseExt}, base_db::{FileLoader, SourceDatabase, SourceRootDatabase},
source_change::SourceChange, source_change::SourceChange,
FileId, FileRange, LineIndexDatabase, FileId, FileRange, LineIndexDatabase,
}; };
@ -47,7 +47,7 @@ pub(crate) fn unlinked_file(
// //
// Only show this diagnostic on the first three characters of // Only show this diagnostic on the first three characters of
// the file, to avoid overwhelming the user during startup. // the file, to avoid overwhelming the user during startup.
range = FileLoader::file_text(ctx.sema.db, file_id) range = SourceDatabase::file_text(ctx.sema.db, file_id)
.char_indices() .char_indices()
.take(3) .take(3)
.last() .last()
@ -499,6 +499,18 @@ $0
mod bar { mod bar {
mod foo; mod foo;
} }
"#,
);
}
#[test]
fn include_macro_works() {
check_diagnostics(
r#"
//- minicore: include
//- /main.rs
include!("bar/foo/mod.rs");
//- /bar/foo/mod.rs
"#, "#,
); );
} }

View file

@ -24,6 +24,7 @@
//! don't yet have a great pattern for how to do them properly. //! don't yet have a great pattern for how to do them properly.
mod handlers { mod handlers {
pub(crate) mod await_outside_of_async;
pub(crate) mod break_outside_of_loop; pub(crate) mod break_outside_of_loop;
pub(crate) mod expected_function; pub(crate) mod expected_function;
pub(crate) mod inactive_code; pub(crate) mod inactive_code;
@ -96,6 +97,7 @@ use syntax::{
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum DiagnosticCode { pub enum DiagnosticCode {
RustcHardError(&'static str), RustcHardError(&'static str),
SyntaxError,
RustcLint(&'static str), RustcLint(&'static str),
Clippy(&'static str), Clippy(&'static str),
Ra(&'static str, Severity), Ra(&'static str, Severity),
@ -107,6 +109,9 @@ impl DiagnosticCode {
DiagnosticCode::RustcHardError(e) => { DiagnosticCode::RustcHardError(e) => {
format!("https://doc.rust-lang.org/stable/error_codes/{e}.html") format!("https://doc.rust-lang.org/stable/error_codes/{e}.html")
} }
DiagnosticCode::SyntaxError => {
String::from("https://doc.rust-lang.org/stable/reference/")
}
DiagnosticCode::RustcLint(e) => { DiagnosticCode::RustcLint(e) => {
format!("https://doc.rust-lang.org/rustc/?search={e}") format!("https://doc.rust-lang.org/rustc/?search={e}")
} }
@ -125,6 +130,7 @@ impl DiagnosticCode {
| DiagnosticCode::RustcLint(r) | DiagnosticCode::RustcLint(r)
| DiagnosticCode::Clippy(r) | DiagnosticCode::Clippy(r)
| DiagnosticCode::Ra(r, _) => r, | DiagnosticCode::Ra(r, _) => r,
DiagnosticCode::SyntaxError => "syntax-error",
} }
} }
} }
@ -154,7 +160,7 @@ impl Diagnostic {
message, message,
range: range.into(), range: range.into(),
severity: match code { severity: match code {
DiagnosticCode::RustcHardError(_) => Severity::Error, DiagnosticCode::RustcHardError(_) | DiagnosticCode::SyntaxError => Severity::Error,
// FIXME: Rustc lints are not always warning, but the ones that are currently implemented are all warnings. // FIXME: Rustc lints are not always warning, but the ones that are currently implemented are all warnings.
DiagnosticCode::RustcLint(_) => Severity::Warning, DiagnosticCode::RustcLint(_) => Severity::Warning,
// FIXME: We can make this configurable, and if the user uses `cargo clippy` on flycheck, we can // FIXME: We can make this configurable, and if the user uses `cargo clippy` on flycheck, we can
@ -297,31 +303,54 @@ impl DiagnosticsContext<'_> {
} }
} }
/// Request diagnostics for the given [`FileId`]. The produced diagnostics may point to other files /// Request parser level diagnostics for the given [`FileId`].
pub fn syntax_diagnostics(
db: &RootDatabase,
config: &DiagnosticsConfig,
file_id: FileId,
) -> Vec<Diagnostic> {
let _p = tracing::info_span!("syntax_diagnostics").entered();
if config.disabled.contains("syntax-error") {
return Vec::new();
}
let sema = Semantics::new(db);
let file_id = sema
.attach_first_edition(file_id)
.unwrap_or_else(|| EditionedFileId::current_edition(file_id));
// [#3434] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
db.parse_errors(file_id)
.as_deref()
.into_iter()
.flatten()
.take(128)
.map(|err| {
Diagnostic::new(
DiagnosticCode::SyntaxError,
format!("Syntax Error: {err}"),
FileRange { file_id: file_id.into(), range: err.range() },
)
})
.collect()
}
/// Request semantic diagnostics for the given [`FileId`]. The produced diagnostics may point to other files
/// due to macros. /// due to macros.
pub fn diagnostics( pub fn semantic_diagnostics(
db: &RootDatabase, db: &RootDatabase,
config: &DiagnosticsConfig, config: &DiagnosticsConfig,
resolve: &AssistResolveStrategy, resolve: &AssistResolveStrategy,
file_id: FileId, file_id: FileId,
) -> Vec<Diagnostic> { ) -> Vec<Diagnostic> {
let _p = tracing::info_span!("diagnostics").entered(); let _p = tracing::info_span!("semantic_diagnostics").entered();
let sema = Semantics::new(db); let sema = Semantics::new(db);
let file_id = sema let file_id = sema
.attach_first_edition(file_id) .attach_first_edition(file_id)
.unwrap_or_else(|| EditionedFileId::current_edition(file_id)); .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
let mut res = Vec::new(); let mut res = Vec::new();
// [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| {
Diagnostic::new(
DiagnosticCode::RustcHardError("syntax-error"),
format!("Syntax Error: {err}"),
FileRange { file_id: file_id.into(), range: err.range() },
)
}));
let parse_errors = res.len();
let parse = sema.parse(file_id); let parse = sema.parse(file_id);
// FIXME: This iterates the entire file which is a rather expensive operation. // FIXME: This iterates the entire file which is a rather expensive operation.
@ -341,13 +370,17 @@ pub fn diagnostics(
match module { match module {
// A bunch of parse errors in a file indicate some bigger structural parse changes in the // A bunch of parse errors in a file indicate some bigger structural parse changes in the
// file, so we skip semantic diagnostics so we can show these faster. // file, so we skip semantic diagnostics so we can show these faster.
Some(m) if parse_errors < 16 => m.diagnostics(db, &mut diags, config.style_lints), Some(m) => {
Some(_) => (), if !db.parse_errors(file_id).as_deref().is_some_and(|es| es.len() >= 16) {
m.diagnostics(db, &mut diags, config.style_lints);
}
}
None => handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id.file_id()), None => handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id.file_id()),
} }
for diag in diags { for diag in diags {
let d = match diag { let d = match diag {
AnyDiagnostic::AwaitOutsideOfAsync(d) => handlers::await_outside_of_async::await_outside_of_async(&ctx, &d),
AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d), AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
Some(it) => it, Some(it) => it,
@ -363,7 +396,7 @@ pub fn diagnostics(
res.extend(d.errors.iter().take(16).map(|err| { res.extend(d.errors.iter().take(16).map(|err| {
{ {
Diagnostic::new( Diagnostic::new(
DiagnosticCode::RustcHardError("syntax-error"), DiagnosticCode::SyntaxError,
format!("Syntax Error in Expansion: {err}"), format!("Syntax Error in Expansion: {err}"),
ctx.resolve_precise_location(&d.node.clone(), d.precise_location), ctx.resolve_precise_location(&d.node.clone(), d.precise_location),
) )
@ -464,6 +497,19 @@ pub fn diagnostics(
res res
} }
/// Request both syntax and semantic diagnostics for the given [`FileId`].
pub fn full_diagnostics(
db: &RootDatabase,
config: &DiagnosticsConfig,
resolve: &AssistResolveStrategy,
file_id: FileId,
) -> Vec<Diagnostic> {
let mut res = syntax_diagnostics(db, config, file_id);
let sema = semantic_diagnostics(db, config, resolve, file_id);
res.extend(sema);
res
}
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros // `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
static RUSTC_LINT_GROUPS_DICT: Lazy<FxHashMap<&str, Vec<&str>>> = static RUSTC_LINT_GROUPS_DICT: Lazy<FxHashMap<&str, Vec<&str>>> =

View file

@ -1,7 +1,7 @@
#![allow(clippy::print_stderr)] #![allow(clippy::print_stderr)]
use ide_db::{ use ide_db::{
assists::AssistResolveStrategy, base_db::SourceDatabaseExt, LineIndexDatabase, RootDatabase, assists::AssistResolveStrategy, base_db::SourceDatabase, LineIndexDatabase, RootDatabase,
}; };
use itertools::Itertools; use itertools::Itertools;
use stdx::trim_indent; use stdx::trim_indent;
@ -59,10 +59,14 @@ fn check_nth_fix_with_config(
let after = trim_indent(ra_fixture_after); let after = trim_indent(ra_fixture_after);
let (db, file_position) = RootDatabase::with_position(ra_fixture_before); let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
let diagnostic = let diagnostic = super::full_diagnostics(
super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_position.file_id.into()) &db,
.pop() &config,
.expect("no diagnostics"); &AssistResolveStrategy::All,
file_position.file_id.into(),
)
.pop()
.expect("no diagnostics");
let fix = &diagnostic let fix = &diagnostic
.fixes .fixes
.unwrap_or_else(|| panic!("{:?} diagnostic misses fixes", diagnostic.code))[nth]; .unwrap_or_else(|| panic!("{:?} diagnostic misses fixes", diagnostic.code))[nth];
@ -102,37 +106,39 @@ pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
let (db, file_position) = RootDatabase::with_position(ra_fixture_before); let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
let mut conf = DiagnosticsConfig::test_sample(); let mut conf = DiagnosticsConfig::test_sample();
conf.expr_fill_default = ExprFillDefaultMode::Default; conf.expr_fill_default = ExprFillDefaultMode::Default;
let fix = let fix = super::full_diagnostics(
super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id.into()) &db,
.into_iter() &conf,
.find(|d| { &AssistResolveStrategy::All,
d.fixes file_position.file_id.into(),
.as_ref() )
.and_then(|fixes| { .into_iter()
fixes.iter().find(|fix| { .find(|d| {
if !fix.target.contains_inclusive(file_position.offset) { d.fixes
return false; .as_ref()
} .and_then(|fixes| {
let actual = { fixes.iter().find(|fix| {
let source_change = fix.source_change.as_ref().unwrap(); if !fix.target.contains_inclusive(file_position.offset) {
let file_id = return false;
*source_change.source_file_edits.keys().next().unwrap(); }
let mut actual = db.file_text(file_id).to_string(); let actual = {
let source_change = fix.source_change.as_ref().unwrap();
let file_id = *source_change.source_file_edits.keys().next().unwrap();
let mut actual = db.file_text(file_id).to_string();
for (edit, snippet_edit) in source_change.source_file_edits.values() for (edit, snippet_edit) in source_change.source_file_edits.values() {
{ edit.apply(&mut actual);
edit.apply(&mut actual); if let Some(snippet_edit) = snippet_edit {
if let Some(snippet_edit) = snippet_edit { snippet_edit.apply(&mut actual);
snippet_edit.apply(&mut actual); }
} }
} actual
actual };
}; after == actual
after == actual })
}) })
}) .is_some()
.is_some() });
});
assert!(fix.is_some(), "no diagnostic with desired fix"); assert!(fix.is_some(), "no diagnostic with desired fix");
} }
@ -144,38 +150,40 @@ pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &s
let mut conf = DiagnosticsConfig::test_sample(); let mut conf = DiagnosticsConfig::test_sample();
conf.expr_fill_default = ExprFillDefaultMode::Default; conf.expr_fill_default = ExprFillDefaultMode::Default;
let mut n_fixes = 0; let mut n_fixes = 0;
let fix = let fix = super::full_diagnostics(
super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id.into()) &db,
.into_iter() &conf,
.find(|d| { &AssistResolveStrategy::All,
d.fixes file_position.file_id.into(),
.as_ref() )
.and_then(|fixes| { .into_iter()
n_fixes += fixes.len(); .find(|d| {
fixes.iter().find(|fix| { d.fixes
if !fix.target.contains_inclusive(file_position.offset) { .as_ref()
return false; .and_then(|fixes| {
} n_fixes += fixes.len();
let actual = { fixes.iter().find(|fix| {
let source_change = fix.source_change.as_ref().unwrap(); if !fix.target.contains_inclusive(file_position.offset) {
let file_id = return false;
*source_change.source_file_edits.keys().next().unwrap(); }
let mut actual = db.file_text(file_id).to_string(); let actual = {
let source_change = fix.source_change.as_ref().unwrap();
let file_id = *source_change.source_file_edits.keys().next().unwrap();
let mut actual = db.file_text(file_id).to_string();
for (edit, snippet_edit) in source_change.source_file_edits.values() for (edit, snippet_edit) in source_change.source_file_edits.values() {
{ edit.apply(&mut actual);
edit.apply(&mut actual); if let Some(snippet_edit) = snippet_edit {
if let Some(snippet_edit) = snippet_edit { snippet_edit.apply(&mut actual);
snippet_edit.apply(&mut actual); }
} }
} actual
actual };
}; after == actual
after == actual })
}) })
}) .is_some()
.is_some() });
});
assert!(fix.is_some(), "no diagnostic with desired fix"); assert!(fix.is_some(), "no diagnostic with desired fix");
assert!(n_fixes == 1, "Too many fixes suggested"); assert!(n_fixes == 1, "Too many fixes suggested");
} }
@ -183,7 +191,7 @@ pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &s
/// Checks that there's a diagnostic *without* fix at `$0`. /// Checks that there's a diagnostic *without* fix at `$0`.
pub(crate) fn check_no_fix(ra_fixture: &str) { pub(crate) fn check_no_fix(ra_fixture: &str) {
let (db, file_position) = RootDatabase::with_position(ra_fixture); let (db, file_position) = RootDatabase::with_position(ra_fixture);
let diagnostic = super::diagnostics( let diagnostic = super::full_diagnostics(
&db, &db,
&DiagnosticsConfig::test_sample(), &DiagnosticsConfig::test_sample(),
&AssistResolveStrategy::All, &AssistResolveStrategy::All,
@ -215,7 +223,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur
.iter() .iter()
.copied() .copied()
.flat_map(|file_id| { .flat_map(|file_id| {
super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id.into()) super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id.into())
.into_iter() .into_iter()
.map(|d| { .map(|d| {
let mut annotation = String::new(); let mut annotation = String::new();
@ -243,6 +251,12 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur
let mut actual = annotations.remove(&file_id).unwrap_or_default(); let mut actual = annotations.remove(&file_id).unwrap_or_default();
let expected = extract_annotations(&db.file_text(file_id)); let expected = extract_annotations(&db.file_text(file_id));
actual.sort_by_key(|(range, _)| range.start()); actual.sort_by_key(|(range, _)| range.start());
// FIXME: We should panic on duplicates instead, but includes currently cause us to report
// diagnostics twice for the calling module when both files are queried.
actual.dedup();
// actual.iter().duplicates().for_each(|(range, msg)| {
// panic!("duplicate diagnostic at {:?}: {msg:?}", line_index.line_col(range.start()))
// });
if expected.is_empty() { if expected.is_empty() {
// makes minicore smoke test debuggable // makes minicore smoke test debuggable
for (e, _) in &actual { for (e, _) in &actual {
@ -277,10 +291,10 @@ fn test_disabled_diagnostics() {
let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#);
let file_id = file_id.into(); let file_id = file_id.into();
let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id); let diagnostics = super::full_diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
assert!(diagnostics.is_empty()); assert!(diagnostics.is_empty());
let diagnostics = super::diagnostics( let diagnostics = super::full_diagnostics(
&db, &db,
&DiagnosticsConfig::test_sample(), &DiagnosticsConfig::test_sample(),
&AssistResolveStrategy::All, &AssistResolveStrategy::All,

View file

@ -1,8 +1,8 @@
[package] [package]
name = "ide-ssr" name = "ide-ssr"
version = "0.0.0" version = "0.0.0"
description = "Structural search and replace of Rust code" repository.workspace = true
repository = "https://github.com/rust-lang/rust-analyzer" description = "Structural search and replace of Rust code for rust-analyzer."
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

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