diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 701e36d74a657..5a8d971c3d4f8 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -72,8 +72,8 @@ dependencies = [ "cfg", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "profile", + "rust-analyzer-salsa", "rustc-hash", - "salsa", "stdx", "syntax", "test-utils", @@ -160,32 +160,32 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0322d5289ceba3217a03c9af72aa403d87542822b753daa1da32e4b992a4e80" +checksum = "329427f28cd2bddaacd47c4dcd3d7082d315c61fb164394c690fe98c1b6ee9d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "synstructure", ] [[package]] name = "chalk-ir" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0946cbc6d9136980a24a2dddf1888b5f0aa978dda300a3aa470b55b777b6bf3c" +checksum = "9e1e1659238bd598d0f7dbc5034cf1ff46010a3d6827704c9ed443c8359cb484" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "chalk-derive", "lazy_static", ] [[package]] name = "chalk-recursive" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd93fedbeeadc0cd4d0eb73bd061b621af99f5324a6a518264c8ef5e526e0ec" +checksum = "b3e0bff0ba1bed11407384fcec0353aeb6888901e63cb47d04505ec47adad847" dependencies = [ "chalk-derive", "chalk-ir", @@ -196,15 +196,15 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a254cff72303c58c82df421cfe9465606372b81588923fcf179922b7eaad9a53" +checksum = "eb9c46d501cf83732a91056c0c846ae7a16d6b3c67a6a6bb5e9cc0a2e91563b6" dependencies = [ "chalk-derive", "chalk-ir", "ena", - "indexmap 2.1.0", - "itertools 0.10.5", + "indexmap", + "itertools", "petgraph", "rustc-hash", "tracing", @@ -216,7 +216,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916" dependencies = [ - "nix", + "nix 0.26.2", "winapi", ] @@ -289,6 +289,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ctrlc" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +dependencies = [ + "nix 0.27.1", + "windows-sys 0.48.0", +] + [[package]] name = "dashmap" version = "5.4.0" @@ -299,7 +309,7 @@ dependencies = [ "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.6", + "parking_lot_core", ] [[package]] @@ -310,7 +320,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -450,12 +460,9 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -477,7 +484,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "rustc-hash", @@ -504,9 +511,9 @@ dependencies = [ "fst", "hashbrown 0.12.3", "hir-expand", - "indexmap 2.1.0", + "indexmap", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -534,7 +541,7 @@ dependencies = [ "expect-test", "hashbrown 0.12.3", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -566,7 +573,7 @@ dependencies = [ "hir-def", "hir-expand", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "nohash-hasher", @@ -613,7 +620,7 @@ dependencies = [ "ide-db", "ide-diagnostics", "ide-ssr", - "itertools 0.12.0", + "itertools", "nohash-hasher", "oorandom", "profile", @@ -639,7 +646,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "profile", "smallvec", "sourcegen", @@ -658,7 +665,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "smallvec", @@ -679,8 +686,8 @@ dependencies = [ "expect-test", "fst", "hir", - "indexmap 2.1.0", - "itertools 0.12.0", + "indexmap", + "itertools", "limit", "line-index 0.1.0-pre.1", "memchr", @@ -711,7 +718,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "serde_json", @@ -730,7 +737,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "nohash-hasher", "parser", "stdx", @@ -750,16 +757,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.1.0" @@ -790,15 +787,6 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "intern" version = "0.0.0" @@ -809,15 +797,6 @@ dependencies = [ "triomphe", ] -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.0" @@ -931,7 +910,7 @@ dependencies = [ "crossbeam-channel", "ide", "ide-db", - "itertools 0.12.0", + "itertools", "proc-macro-api", "project-model", "tracing", @@ -961,6 +940,7 @@ name = "lsp-server" version = "0.7.4" dependencies = [ "crossbeam-channel", + "ctrlc", "log", "lsp-types", "serde", @@ -1100,6 +1080,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -1174,17 +1165,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -1192,21 +1172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.6", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -1276,7 +1242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap", ] [[package]] @@ -1371,7 +1337,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", "profile", @@ -1436,50 +1402,43 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2ea80a299f04a896000ce17b76f3aa1d2fe59f347fbc99c4b8970316ef5a0d" +checksum = "b5f38444d48da534b3bb612713fce9b0aeeffb2e0dfa242764f55482acc5b52d" dependencies = [ "bitflags 1.3.2", - "ra-ap-rustc_index 0.19.0", + "ra-ap-rustc_index", "tracing", ] [[package]] name = "ra-ap-rustc_index" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643ca3609870b1778d9cd1f2a8e4ccb4af0f48f3637cc257a09494d087bd93dc" -dependencies = [ - "arrayvec", - "smallvec", -] - -[[package]] -name = "ra-ap-rustc_index" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556489ef652e5eb6cdad6078fff08507badac80bfc1f79085c85a6d8b77ab5c" +checksum = "69fb5da07e1a39222d9c311203123c3b6a86420fa06dc695aa1661b0aecf8d16" dependencies = [ "arrayvec", + "ra-ap-rustc_index_macros", "smallvec", ] [[package]] -name = "ra-ap-rustc_lexer" -version = "0.14.0" +name = "ra-ap-rustc_index_macros" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ffd24f9ba4f1d25ff27ca1469b8d22a3bdfb12cf644fc8bfcb63121fa5da6b" +checksum = "3d69f9f6af58124f2da0cb8b0c3d8494e0d883a5fe0c6732258bde81ac5a87cc" dependencies = [ - "unicode-properties", - "unicode-xid", + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] name = "ra-ap-rustc_lexer" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e573bf707e01fe2841dbdedeed42012004274db0edc0314e6e3e58a40598fc" +checksum = "9d5e8650195795c4023d8321846466994a975bc457cb8a91c0b3b17a5fc8ba40" dependencies = [ "unicode-properties", "unicode-xid", @@ -1487,12 +1446,12 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.14.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207b5ac1a21d4926695e03b605ffb9f63d4968e0488e9197c04c512c37303aa7" +checksum = "0a6b325ee1ec90e4dbd4394913adf4ef32e4fcf2b311ec9563a0fa50cd549af6" dependencies = [ - "ra-ap-rustc_index 0.14.0", - "ra-ap-rustc_lexer 0.14.0", + "ra-ap-rustc_index", + "ra-ap-rustc_lexer", ] [[package]] @@ -1563,7 +1522,7 @@ dependencies = [ "ide", "ide-db", "ide-ssr", - "itertools 0.12.0", + "itertools", "load-cargo", "lsp-server 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", @@ -1573,8 +1532,8 @@ dependencies = [ "nohash-hasher", "num_cpus", "oorandom", - "parking_lot 0.12.1", - "parking_lot_core 0.9.6", + "parking_lot", + "parking_lot_core", "parser", "proc-macro-api", "profile", @@ -1603,6 +1562,35 @@ dependencies = [ "xshell", ] +[[package]] +name = "rust-analyzer-salsa" +version = "0.17.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca92b657d614d076800aa7bf5d5ba33564e71fa7f16cd79eacdfe301a50ab1c" +dependencies = [ + "crossbeam-utils", + "indexmap", + "lock_api", + "log", + "oorandom", + "parking_lot", + "rust-analyzer-salsa-macros", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "rust-analyzer-salsa-macros" +version = "0.17.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b190359266d293f2ee13eaa502a766dc8b77b63fbaa5d460d24fd0210675ceef" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1614,8 +1602,8 @@ name = "rustc-dependencies" version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", - "ra-ap-rustc_index 0.19.0", - "ra-ap-rustc_lexer 0.19.0", + "ra-ap-rustc_index", + "ra-ap-rustc_lexer", "ra-ap-rustc_parse_format", ] @@ -1631,35 +1619,6 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" -[[package]] -name = "salsa" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a" -dependencies = [ - "crossbeam-utils", - "indexmap 1.9.3", - "lock_api", - "log", - "oorandom", - "parking_lot 0.11.2", - "rustc-hash", - "salsa-macros", - "smallvec", -] - -[[package]] -name = "salsa-macros" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "same-file" version = "1.0.6" @@ -1701,22 +1660,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1725,7 +1684,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", "ryu", "serde", @@ -1739,7 +1698,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1798,17 +1757,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.39" @@ -1828,7 +1776,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "unicode-xid", ] @@ -1839,8 +1787,8 @@ dependencies = [ "cov-mark", "either", "expect-test", - "indexmap 2.1.0", - "itertools 0.12.0", + "indexmap", + "itertools", "once_cell", "parser", "proc-macro2", @@ -1874,7 +1822,7 @@ dependencies = [ name = "text-edit" version = "0.0.0" dependencies = [ - "itertools 0.12.0", + "itertools", "text-size", ] @@ -1901,7 +1849,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2002,7 +1950,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2112,12 +2060,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0" -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -2153,7 +2095,7 @@ name = "vfs" version = "0.0.0" dependencies = [ "fst", - "indexmap 2.1.0", + "indexmap", "nohash-hasher", "paths", "rustc-hash", diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 171c113a950d0..5ad88f65188e0 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -salsa = "0.17.0-pre.2" +rust-analyzer-salsa = "0.17.0-pre.3" rustc-hash = "1.1.0" triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs index 3f5ccb621c767..3da555a47acb2 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs @@ -13,9 +13,9 @@ use vfs::{file_set::FileSet, VfsPath}; use crate::{ input::{CrateName, CrateOrigin, LangCrateOrigin}, - Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel, - SourceDatabaseExt, SourceRoot, SourceRootId, + Change, CrateDisplayName, CrateGraph, CrateId, Dependency, DependencyKind, Edition, Env, + FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, + ProcMacros, ReleaseChannel, SourceDatabaseExt, SourceRoot, SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -237,7 +237,12 @@ impl ChangeFixture { crate_graph .add_dep( from_id, - Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude), + Dependency::with_prelude( + CrateName::new(&to).unwrap(), + to_id, + prelude, + DependencyKind::Normal, + ), ) .unwrap(); } @@ -275,7 +280,14 @@ impl ChangeFixture { for krate in all_crates { crate_graph - .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate)) + .add_dep( + krate, + Dependency::new( + CrateName::new("core").unwrap(), + core_crate, + DependencyKind::Normal, + ), + ) .unwrap(); } } @@ -317,7 +329,11 @@ impl ChangeFixture { crate_graph .add_dep( krate, - Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate), + Dependency::new( + CrateName::new("proc_macros").unwrap(), + proc_macros_crate, + DependencyKind::Normal, + ), ) .unwrap(); } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 65db5c0fc7d31..e4f78321e215a 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -155,6 +155,10 @@ impl CrateOrigin { pub fn is_local(&self) -> bool { matches!(self, CrateOrigin::Local { .. }) } + + pub fn is_lib(&self) -> bool { + matches!(self, CrateOrigin::Library { .. }) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -324,6 +328,62 @@ pub struct CrateData { pub channel: Option, } +impl CrateData { + /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value. + pub fn eq_ignoring_origin_and_deps(&self, other: &CrateData, ignore_dev_deps: bool) -> bool { + // This method has some obscure bits. These are mostly there to be compliant with + // some patches. References to the patches are given. + if self.root_file_id != other.root_file_id { + return false; + } + + if self.display_name != other.display_name { + return false; + } + + if self.is_proc_macro != other.is_proc_macro { + return false; + } + + if self.edition != other.edition { + return false; + } + + if self.version != other.version { + return false; + } + + let mut opts = self.cfg_options.difference(&other.cfg_options); + if let Some(it) = opts.next() { + // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. + // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 + if it.to_string() != "rust_analyzer" { + return false; + } + + if let Some(_) = opts.next() { + return false; + } + } + + if self.env != other.env { + return false; + } + + let slf_deps = self.dependencies.iter(); + let other_deps = other.dependencies.iter(); + + if ignore_dev_deps { + return slf_deps + .clone() + .filter(|it| it.kind != DependencyKind::Dev) + .eq(other_deps.clone().filter(|it| it.kind != DependencyKind::Dev)); + } + + slf_deps.eq(other_deps) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Edition { Edition2015, @@ -351,26 +411,43 @@ impl Env { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum DependencyKind { + Normal, + Dev, + Build, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, pub name: CrateName, + kind: DependencyKind, prelude: bool, } impl Dependency { - pub fn new(name: CrateName, crate_id: CrateId) -> Self { - Self { name, crate_id, prelude: true } + pub fn new(name: CrateName, crate_id: CrateId, kind: DependencyKind) -> Self { + Self { name, crate_id, prelude: true, kind } } - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self { - Self { name, crate_id, prelude } + pub fn with_prelude( + name: CrateName, + crate_id: CrateId, + prelude: bool, + kind: DependencyKind, + ) -> Self { + Self { name, crate_id, prelude, kind } } /// Whether this dependency is to be added to the depending crate's extern prelude. pub fn is_prelude(&self) -> bool { self.prelude } + + pub fn kind(&self) -> DependencyKind { + self.kind + } } impl CrateGraph { @@ -574,23 +651,46 @@ impl CrateGraph { pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap = FxHashMap::default(); - for topo in topo { let crate_data = &mut other.arena[topo]; + crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); crate_data.dependencies.sort_by_key(|dep| dep.crate_id); - - let res = self.arena.iter().find_map( - |(id, data)| { - if data == crate_data { - Some(id) - } else { - None + let res = self.arena.iter().find_map(|(id, data)| { + match (&data.origin, &crate_data.origin) { + (a, b) if a == b => { + if data.eq_ignoring_origin_and_deps(&crate_data, false) { + return Some((id, false)); + } + } + (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. }) + | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => { + // If the origins differ, check if the two crates are equal without + // considering the dev dependencies, if they are, they most likely are in + // different loaded workspaces which may cause issues. We keep the local + // version and discard the library one as the local version may have + // dev-dependencies that we want to keep resolving. See #15656 for more + // information. + if data.eq_ignoring_origin_and_deps(&crate_data, true) { + return Some((id, if a.is_local() { false } else { true })); + } } - }, - ); - if let Some(res) = res { + (_, _) => return None, + } + + None + }); + + if let Some((res, should_update_lib_to_local)) = res { id_map.insert(topo, res); + if should_update_lib_to_local { + assert!(self.arena[res].origin.is_lib()); + assert!(crate_data.origin.is_local()); + self.arena[res].origin = crate_data.origin.clone(); + + // Move local's dev dependencies into the newly-local-formerly-lib crate. + self.arena[res].dependencies = crate_data.dependencies.clone(); + } } else { let id = self.arena.alloc(crate_data.clone()); id_map.insert(topo, id); @@ -636,9 +736,11 @@ impl CrateGraph { match (cfg_if, std) { (Some(cfg_if), Some(std)) => { self.arena[cfg_if].dependencies.clear(); - self.arena[std] - .dependencies - .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); + self.arena[std].dependencies.push(Dependency::new( + CrateName::new("cfg_if").unwrap(), + cfg_if, + DependencyKind::Normal, + )); true } _ => false, @@ -658,6 +760,8 @@ impl ops::Index for CrateGraph { } impl CrateData { + /// Add a dependency to `self` without checking if the dependency + // is existent among `self.dependencies`. fn add_dep(&mut self, dep: Dependency) { self.dependencies.push(dep) } @@ -759,7 +863,7 @@ impl fmt::Display for CyclicDependenciesError { #[cfg(test)] mod tests { - use crate::CrateOrigin; + use crate::{CrateOrigin, DependencyKind}; use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; @@ -806,13 +910,22 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1)) + .add_dep( + crate3, + Dependency::new(CrateName::new("crate1").unwrap(), crate1, DependencyKind::Normal) + ) .is_err()); } @@ -846,10 +959,16 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_err()); } @@ -896,10 +1015,16 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal) + ) .is_ok()); } @@ -935,12 +1060,20 @@ mod tests { assert!(graph .add_dep( crate1, - Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2) + Dependency::new( + CrateName::normalize_dashes("crate-name-with-dashes"), + crate2, + DependencyKind::Normal + ) ) .is_ok()); assert_eq!( graph[crate1].dependencies, - vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2)] + vec![Dependency::new( + CrateName::new("crate_name_with_dashes").unwrap(), + crate2, + DependencyKind::Normal + )] ); } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index c5c4afa30f792..40cfab88afdbe 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -12,6 +12,7 @@ use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; use triomphe::Arc; +pub use crate::input::DependencyKind; pub use crate::{ change::Change, input::{ diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 0aeb0b0505248..8bbe5e2a8c29b 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -58,6 +58,13 @@ impl CfgOptions { self.enabled.insert(CfgAtom::KeyValue { key, value }); } + pub fn difference<'a>( + &'a self, + other: &'a CfgOptions, + ) -> impl Iterator + 'a { + self.enabled.difference(&other.enabled) + } + pub fn apply_diff(&mut self, diff: CfgDiff) { for atom in diff.enable { self.enabled.insert(atom); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 460a908b6db2c..4c1b8f306c50f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -183,15 +183,6 @@ impl DefMap { shadow: BuiltinShadowMode, expected_macro_subns: Option, ) -> ResolvePathResult { - let graph = db.crate_graph(); - let _cx = stdx::panic_context::enter(format!( - "DefMap {:?} crate_name={:?} block={:?} path={}", - self.krate, - graph[self.krate].display_name, - self.block, - path.display(db.upcast()) - )); - let mut segments = path.segments().iter().enumerate(); let mut curr_per_ns = match path.kind { PathKind::DollarCrate(krate) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index f2d2451511f7c..bbcb76a43ffef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -23,10 +23,10 @@ oorandom = "11.1.3" tracing.workspace = true rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.94.0", default-features = false } -chalk-ir = "0.94.0" -chalk-recursive = { version = "0.94.0", default-features = false } -chalk-derive = "0.94.0" +chalk-solve = { version = "0.95.0", default-features = false } +chalk-ir = "0.95.0" +chalk-recursive = { version = "0.95.0", default-features = false } +chalk-derive = "0.95.0" la-arena.workspace = true once_cell = "1.17.0" triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 0a68a9f3b5831..ac39bdf5bf53c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -43,7 +43,7 @@ where } impl> Canonicalized { - pub(super) fn apply_solution( + pub(crate) fn apply_solution( &self, ctx: &mut InferenceTable<'_>, solution: Canonical, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index c8a85b4a9ff09..04005311b673b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1097,10 +1097,25 @@ impl<'a> TyLoweringContext<'a> { binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = &binding.type_ref { - let ty = self.lower_ty(type_ref); - let alias_eq = - AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) = + (type_ref, &self.impl_trait_mode) + { + for bound in bounds { + predicates.extend( + self.lower_type_bound( + bound, + TyKind::Alias(AliasTy::Projection(projection_ty.clone())) + .intern(Interner), + false, + ), + ); + } + } else { + let ty = self.lower_ty(type_ref); + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + } } for bound in binding.bounds.iter() { predicates.extend(self.lower_type_bound( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 87c93283361fc..732643566a2d6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -27,8 +27,9 @@ use crate::{ primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment, - Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, + AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance, + InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef, + TraitRefExt, Ty, TyBuilder, TyExt, }; /// This is used as a key for indexing impls. @@ -1478,26 +1479,52 @@ fn is_valid_fn_candidate( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. let predicates = db.generic_predicates(impl_id.into()); - let valid = predicates - .iter() - .map(|predicate| { - let (p, b) = predicate - .clone() - .substitute(Interner, &impl_subst) - // Skipping the inner binders is ok, as we don't handle quantified where - // clauses yet. - .into_value_and_skipped_binders(); - stdx::always!(b.len(Interner) == 0); - p - }) - // It's ok to get ambiguity here, as we may not have enough information to prove - // obligations. We'll check if the user is calling the selected method properly - // later anyway. - .all(|p| table.try_obligation(p.cast(Interner)).is_some()); - match valid { - true => IsValidCandidate::Yes, - false => IsValidCandidate::No, + let goals = predicates.iter().map(|p| { + let (p, b) = p + .clone() + .substitute(Interner, &impl_subst) + // Skipping the inner binders is ok, as we don't handle quantified where + // clauses yet. + .into_value_and_skipped_binders(); + stdx::always!(b.len(Interner) == 0); + + p.cast::(Interner) + }); + + for goal in goals.clone() { + let in_env = InEnvironment::new(&table.trait_env.env, goal); + let canonicalized = table.canonicalize(in_env); + let solution = table.db.trait_solve( + table.trait_env.krate, + table.trait_env.block, + canonicalized.value.clone(), + ); + + match solution { + Some(Solution::Unique(canonical_subst)) => { + canonicalized.apply_solution( + table, + Canonical { + binders: canonical_subst.binders, + value: canonical_subst.value.subst, + }, + ); + } + Some(Solution::Ambig(Guidance::Definite(substs))) => { + canonicalized.apply_solution(table, substs); + } + Some(_) => (), + None => return IsValidCandidate::No, + } } + + for goal in goals { + if table.try_obligation(goal).is_none() { + return IsValidCandidate::No; + } + } + + IsValidCandidate::Yes } else { // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in // `iterate_trait_method_candidates()`. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 48dd9540329d6..003ae60e8e517 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -2597,6 +2597,34 @@ fn test() { ); } +#[test] +fn associated_type_in_type_bound() { + check_types( + r#" +//- minicore: deref +fn fb(f: Foo<&u8>) { + f.foobar(); + //^^^^^^^^^^ u8 +} +trait Bar { + fn bar(&self) -> u8; +} +impl Bar for u8 { + fn bar(&self) -> u8 { *self } +} + +struct Foo { + foo: F, +} +impl> Foo { + fn foobar(&self) -> u8 { + self.foo.deref().bar() + } +} +"#, + ) +} + #[test] fn dyn_trait_through_chalk() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index bdc11aa3561b7..1bfbf7212bf0a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -667,21 +667,21 @@ impl Module { let items = &db.trait_data(trait_.into()).items; let required_items = items.iter().filter(|&(_, assoc)| match *assoc { AssocItemId::FunctionId(it) => !db.function_data(it).has_body(), - AssocItemId::ConstId(_) => true, + AssocItemId::ConstId(id) => Const::from(id).value(db).is_none(), AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(), }); - impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().map( + impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map( |&item| { - ( + Some(( item, match item { AssocItemId::FunctionId(it) => db.function_data(it).name.clone(), AssocItemId::ConstId(it) => { - db.const_data(it).name.as_ref().unwrap().clone() + db.const_data(it).name.as_ref()?.clone() } AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(), }, - ) + )) }, )); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs index b7d57f02be566..f864ee50c81da 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs @@ -55,7 +55,7 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio } fn has_ignore_attribute(fn_def: &ast::Fn) -> Option { - fn_def.attrs().find(|attr| attr.path().map(|it| it.syntax().text() == "ignore") == Some(true)) + fn_def.attrs().find(|attr| attr.path().is_some_and(|it| it.syntax().text() == "ignore")) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs index 0bf1782a489de..0876246e90b10 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -91,7 +91,7 @@ fn add_import( ) { if let Some(path_segment) = qualifier.segment() { // for `` - let path_type = path_segment.syntax().children().filter_map(ast::PathType::cast).last(); + let path_type = path_segment.qualifying_trait(); let import = match path_type { Some(it) => { if let Some(path) = it.path() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index c5bbb7f8d755d..5bcc867fe1810 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -1095,4 +1095,81 @@ fn test(s: S) { "#]], ); } + + #[test] + fn assoc_impl_1() { + check( + r#" +//- minicore: deref +fn main() { + let foo: Foo<&u8> = Foo::new(&42_u8); + foo.$0 +} + +trait Bar { + fn bar(&self); +} + +impl Bar for u8 { + fn bar(&self) {} +} + +struct Foo { + foo: F, +} + +impl Foo { + fn new(foo: F) -> Foo { + Foo { foo } + } +} + +impl> Foo { + fn foobar(&self) { + self.foo.deref().bar() + } +} +"#, + expect![[r#" + fd foo &u8 + me foobar() fn(&self) + "#]], + ); + } + + #[test] + fn assoc_impl_2() { + check( + r#" +//- minicore: deref +fn main() { + let foo: Foo<&u8> = Foo::new(&42_u8); + foo.$0 +} + +trait Bar { + fn bar(&self); +} + +struct Foo { + foo: F, +} + +impl Foo { + fn new(foo: F) -> Foo { + Foo { foo } + } +} + +impl> Foo { + fn foobar(&self) { + self.foo.deref().bar() + } +} +"#, + expect![[r#" + fd foo &u8 + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index ed74ef7b667bb..99b895eed4d23 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -26,6 +26,10 @@ use crate::{ pub struct CompletionItem { /// Label in the completion pop up which identifies completion. pub label: SmolStr, + /// Additional label details in the completion pop up that are + /// displayed and aligned on the right side after the label. + pub label_detail: Option, + /// Range of identifier that is being completed. /// /// It should be used primarily for UI, but we also use this to convert @@ -425,13 +429,14 @@ impl Builder { pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem { let _p = profile::span("item::Builder::build"); - let mut label = self.label; + let label = self.label; + let mut label_detail = None; let mut lookup = self.lookup.unwrap_or_else(|| label.clone()); let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); if !self.doc_aliases.is_empty() { let doc_aliases = self.doc_aliases.iter().join(", "); - label = SmolStr::from(format!("{label} (alias {doc_aliases})")); + label_detail.replace(SmolStr::from(format!(" (alias {doc_aliases})"))); let lookup_doc_aliases = self .doc_aliases .iter() @@ -454,10 +459,17 @@ impl Builder { if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one if let Some(original_path) = import_edit.original_path.as_ref() { - label = SmolStr::from(format!("{label} (use {})", original_path.display(db))); + label_detail.replace(SmolStr::from(format!( + "{} (use {})", + label_detail.as_deref().unwrap_or_default(), + original_path.display(db) + ))); } } else if let Some(trait_name) = self.trait_name { - label = SmolStr::from(format!("{label} (as {trait_name})")); + label_detail.replace(SmolStr::from(format!( + "{} (as {trait_name})", + label_detail.as_deref().unwrap_or_default(), + ))); } let text_edit = match self.text_edit { @@ -479,6 +491,7 @@ impl Builder { CompletionItem { source_range: self.source_range, label, + label_detail, text_edit, is_snippet: self.is_snippet, detail: self.detail, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index dfe8fe7e2f7f7..00a9081985b83 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -557,7 +557,11 @@ mod tests { let tag = it.kind.tag(); let relevance = display_relevance(it.relevance); - items.push(format!("{tag} {} {relevance}\n", it.label)); + items.push(format!( + "{tag} {}{} {relevance}\n", + it.label, + it.label_detail.clone().unwrap_or_default(), + )); if let Some((label, _indel, relevance)) = it.ref_match() { let relevance = display_relevance(relevance); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 9db8e972dd4ba..f28afacc586ff 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -150,16 +150,29 @@ fn render_completion_list(completions: Vec) -> String { fn monospace_width(s: &str) -> usize { s.chars().count() } - let label_width = - completions.iter().map(|it| monospace_width(&it.label)).max().unwrap_or_default().min(22); + let label_width = completions + .iter() + .map(|it| { + monospace_width(&it.label) + + monospace_width(it.label_detail.as_deref().unwrap_or_default()) + }) + .max() + .unwrap_or_default() + .min(22); completions .into_iter() .map(|it| { let tag = it.kind.tag(); let var_name = format!("{tag} {}", it.label); let mut buf = var_name; + if let Some(ref label_detail) = it.label_detail { + format_to!(buf, "{label_detail}"); + } if let Some(detail) = it.detail { - let width = label_width.saturating_sub(monospace_width(&it.label)); + let width = label_width.saturating_sub( + monospace_width(&it.label) + + monospace_width(&it.label_detail.unwrap_or_default()), + ); format_to!(buf, "{:width$} {}", "", detail, width = width); } if it.deprecated { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 40d0b6fdd4b0e..51923797ac91a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -35,6 +35,19 @@ pub(crate) fn trait_impl_missing_assoc_item( mod tests { use crate::tests::check_diagnostics; + #[test] + fn trait_with_default_value() { + check_diagnostics( + r#" +trait Marker { + const FLAG: bool = false; +} +struct Foo; +impl Marker for Foo {} + "#, + ) + } + #[test] fn simple() { check_diagnostics( diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs index 3d89599c5832e..9b2ff070c74b1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs +++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs @@ -108,7 +108,7 @@ fn try_extend_selection( let node = shallowest_node(&node); - if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) { + if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) { if let Some(range) = extend_list_item(&node) { return Some(range); } diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 46a0464e9e6ea..a7f5ae92a4cac 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -43,7 +43,7 @@ pub struct HighlightRelatedConfig { // // . if on an identifier, highlights all references to that identifier in the current file // .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope -// . if on an `async` or `await token, highlights all yield points for that async context +// . if on an `async` or `await` token, highlights all yield points for that async context // . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context // . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context // . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure. diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index 80897f7478cf9..931eba1157663 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -49,7 +49,7 @@ //! user explores them belongs to that extension (it's totally valid to change //! rust-project.json over time via configuration request!) -use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition}; +use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, DependencyKind, Edition}; use la_arena::RawIdx; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; @@ -135,6 +135,7 @@ impl ProjectJson { Dependency::new( dep_data.name, CrateId::from_raw(RawIdx::from(dep_data.krate as u32)), + DependencyKind::Normal, ) }) .collect::>(), diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 7815b9dda77f2..98f3063bb9829 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -249,3 +249,55 @@ fn crate_graph_dedup() { crate_graph.extend(regex_crate_graph, &mut regex_proc_macros); assert_eq!(crate_graph.iter().count(), 118); } + +#[test] +fn test_deduplicate_origin_dev() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + crate_graph.sort_deps(); + let (crate_graph_1, mut _proc_macros_2) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + + crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + + let mut crates_named_p2 = vec![]; + for id in crate_graph.iter() { + let krate = &crate_graph[id]; + if let Some(name) = krate.display_name.as_ref() { + if name.to_string() == "p2" { + crates_named_p2.push(krate); + } + } + } + + assert!(crates_named_p2.len() == 1); + let p2 = crates_named_p2[0]; + assert!(p2.origin.is_local()); +} + +#[test] +fn test_deduplicate_origin_dev_rev() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + crate_graph.sort_deps(); + let (crate_graph_1, mut _proc_macros_2) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + + crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + + let mut crates_named_p2 = vec![]; + for id in crate_graph.iter() { + let krate = &crate_graph[id]; + if let Some(name) = krate.display_name.as_ref() { + if name.to_string() == "p2" { + crates_named_p2.push(krate); + } + } + } + + assert!(crates_named_p2.len() == 1); + let p2 = crates_named_p2[0]; + assert!(p2.origin.is_local()); +} diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index e0209ca15a539..9333570354a0c 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -6,8 +6,8 @@ use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, use anyhow::{format_err, Context}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, + CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind, + Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -834,7 +834,7 @@ fn project_json_to_crate_graph( for dep in &krate.deps { if let Some(&to) = crates.get(&dep.crate_id) { - add_dep(crate_graph, from, dep.name.clone(), to) + add_dep(crate_graph, from, dep.name.clone(), to, dep.kind().to_owned()) } } } @@ -979,7 +979,7 @@ fn cargo_to_crate_graph( // cargo metadata does not do any normalization, // so we do it ourselves currently let name = CrateName::normalize_dashes(&name); - add_dep(crate_graph, from, name, to); + add_dep(crate_graph, from, name, to, DependencyKind::Normal); } } } @@ -999,7 +999,17 @@ fn cargo_to_crate_graph( continue; } - add_dep(crate_graph, from, name.clone(), to) + add_dep( + crate_graph, + from, + name.clone(), + to, + match dep.kind { + DepKind::Normal => DependencyKind::Normal, + DepKind::Dev => DependencyKind::Dev, + DepKind::Build => DependencyKind::Build, + }, + ) } } } @@ -1187,7 +1197,17 @@ fn handle_rustc_crates( let name = CrateName::new(&dep.name).unwrap(); if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { - add_dep(crate_graph, from, name.clone(), to); + add_dep( + crate_graph, + from, + name.clone(), + to, + match dep.kind { + DepKind::Normal => DependencyKind::Normal, + DepKind::Dev => DependencyKind::Dev, + DepKind::Build => DependencyKind::Build, + }, + ); } } } @@ -1209,7 +1229,7 @@ fn handle_rustc_crates( // `rust_analyzer` thinks that it should use the one from the `rustc_source` // instead of the one from `crates.io` if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) { - add_dep(crate_graph, *from, name.clone(), to); + add_dep(crate_graph, *from, name.clone(), to, DependencyKind::Normal); } } } @@ -1308,7 +1328,14 @@ impl SysrootPublicDeps { /// Makes `from` depend on the public sysroot crates. fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) { for (name, krate, prelude) in &self.deps { - add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude); + add_dep_with_prelude( + crate_graph, + from, + name.clone(), + *krate, + *prelude, + DependencyKind::Normal, + ); } } } @@ -1363,7 +1390,7 @@ fn sysroot_to_crate_graph( for &to in sysroot[from].deps.iter() { let name = CrateName::new(&sysroot[to].name).unwrap(); if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { - add_dep(crate_graph, from, name, to); + add_dep(crate_graph, from, name, to, DependencyKind::Normal); } } } @@ -1442,8 +1469,14 @@ fn handle_hack_cargo_workspace( .collect() } -fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { - add_dep_inner(graph, from, Dependency::new(name, to)) +fn add_dep( + graph: &mut CrateGraph, + from: CrateId, + name: CrateName, + to: CrateId, + kind: DependencyKind, +) { + add_dep_inner(graph, from, Dependency::new(name, to, kind)) } fn add_dep_with_prelude( @@ -1452,12 +1485,20 @@ fn add_dep_with_prelude( name: CrateName, to: CrateId, prelude: bool, + kind: DependencyKind, ) { - add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude)) + add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, kind)) } fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) { - add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude); + add_dep_with_prelude( + crate_graph, + from, + CrateName::new("proc_macro").unwrap(), + to, + prelude, + DependencyKind::Normal, + ); } fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json new file mode 100644 index 0000000000000..b0fb5845cef76 --- /dev/null +++ b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json @@ -0,0 +1,140 @@ +{ + "packages": [ + { + "name": "p1", + "version": "0.1.0", + "id": "p1 0.1.0 (path+file:///example_project/p1)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [ + { + "name": "p2", + "source": null, + "req": "*", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$example_project/p2" + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p1", + "src_path": "$ROOT$example_project/p1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$example_project/p1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "p2", + "version": "0.1.0", + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p2", + "src_path": "$ROOT$example_project/p2/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$example_project/p2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "p1 0.1.0 (path+file:///example_project/p1)" + ], + "workspace_default_members": [ + "p1 0.1.0 (path+file:///example_project/p1)" + ], + "resolve": { + "nodes": [ + { + "id": "p1 0.1.0 (path+file:///example_project/p1)", + "dependencies": [ + "p2 0.1.0 (path+file:///example_project/p2)" + ], + "deps": [ + { + "name": "p2", + "pkg": "p2 0.1.0 (path+file:///example_project/p2)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "p1 0.1.0 (path+file:///example_project/p1)" + }, + "target_directory": "$ROOT$example_project/p1/target", + "version": 1, + "workspace_root": "$ROOT$example_project/p1", + "metadata": null +} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json new file mode 100644 index 0000000000000..b5d1e16e62e03 --- /dev/null +++ b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json @@ -0,0 +1,66 @@ +{ + "packages": [ + { + "name": "p2", + "version": "0.1.0", + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p2", + "src_path": "$ROOT$example_project/p2/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$example_project/p2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "p2 0.1.0 (path+file:///example_project/p2)" + ], + "workspace_default_members": [ + "p2 0.1.0 (path+file:///example_project/p2)" + ], + "resolve": { + "nodes": [ + { + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "p2 0.1.0 (path+file:///example_project/p2)" + }, + "target_directory": "$ROOT$example_project/p2/target", + "version": 1, + "workspace_root": "$ROOT$example_project/p2", + "metadata": null +} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt index 727d39a3077cd..e98f016ca7df3 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -48,6 +48,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -112,6 +113,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -119,6 +121,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -183,6 +186,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -190,6 +194,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -254,6 +259,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -261,6 +267,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt index 727d39a3077cd..e98f016ca7df3 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -48,6 +48,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -112,6 +113,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -119,6 +121,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -183,6 +186,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -190,6 +194,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -254,6 +259,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -261,6 +267,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt index 89728babd82ef..7ecd53572e2f3 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -47,6 +47,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -110,6 +111,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -117,6 +119,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -180,6 +183,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -187,6 +191,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -250,6 +255,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -257,6 +263,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index b7bf6cb2774ea..581a6afc148fa 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -28,6 +28,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, ], @@ -168,6 +169,7 @@ name: CrateName( "std", ), + kind: Normal, prelude: true, }, Dependency { @@ -175,6 +177,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, ], @@ -249,6 +252,7 @@ name: CrateName( "alloc", ), + kind: Normal, prelude: true, }, Dependency { @@ -256,6 +260,7 @@ name: CrateName( "panic_unwind", ), + kind: Normal, prelude: true, }, Dependency { @@ -263,6 +268,7 @@ name: CrateName( "panic_abort", ), + kind: Normal, prelude: true, }, Dependency { @@ -270,6 +276,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, Dependency { @@ -277,6 +284,7 @@ name: CrateName( "profiler_builtins", ), + kind: Normal, prelude: true, }, Dependency { @@ -284,6 +292,7 @@ name: CrateName( "unwind", ), + kind: Normal, prelude: true, }, Dependency { @@ -291,6 +300,7 @@ name: CrateName( "std_detect", ), + kind: Normal, prelude: true, }, Dependency { @@ -298,6 +308,7 @@ name: CrateName( "test", ), + kind: Normal, prelude: true, }, ], @@ -438,6 +449,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, Dependency { @@ -445,6 +457,7 @@ name: CrateName( "alloc", ), + kind: Normal, prelude: true, }, Dependency { @@ -452,6 +465,7 @@ name: CrateName( "std", ), + kind: Normal, prelude: true, }, Dependency { @@ -459,6 +473,7 @@ name: CrateName( "test", ), + kind: Normal, prelude: false, }, Dependency { @@ -466,6 +481,7 @@ name: CrateName( "proc_macro", ), + kind: Normal, prelude: false, }, ], diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index aca91570f7c27..fb366fd5cc41f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1,7 +1,7 @@ //! Conversion of rust-analyzer specific types to lsp_types equivalents. use std::{ iter::once, - path, + mem, path, sync::atomic::{AtomicU32, Ordering}, }; @@ -301,9 +301,11 @@ fn completion_item( if config.completion_label_details_support() { lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { - detail: None, + detail: item.label_detail.as_ref().map(ToString::to_string), description: lsp_item.detail.clone(), }); + } else if let Some(label_detail) = item.label_detail { + lsp_item.label.push_str(label_detail.as_str()); } set_score(&mut lsp_item, max_relevance, item.relevance); @@ -1123,13 +1125,20 @@ pub(crate) fn snippet_text_document_ops( pub(crate) fn snippet_workspace_edit( snap: &GlobalStateSnapshot, - source_change: SourceChange, + mut source_change: SourceChange, ) -> Cancellable { let mut document_changes: Vec = Vec::new(); - for op in source_change.file_system_edits { - let ops = snippet_text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); + for op in &mut source_change.file_system_edits { + if let FileSystemEdit::CreateFile { dst, initial_contents } = op { + // replace with a placeholder to avoid cloneing the edit + let op = FileSystemEdit::CreateFile { + dst: dst.clone(), + initial_contents: mem::take(initial_contents), + }; + let ops = snippet_text_document_ops(snap, op)?; + document_changes.extend_from_slice(&ops); + } } for (file_id, (edit, snippet_edit)) in source_change.source_file_edits { let edit = snippet_text_document_edit( @@ -1141,6 +1150,12 @@ pub(crate) fn snippet_workspace_edit( )?; document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); } + for op in source_change.file_system_edits { + if !matches!(op, FileSystemEdit::CreateFile { .. }) { + let ops = snippet_text_document_ops(snap, op)?; + document_changes.extend_from_slice(&ops); + } + } let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index d59914298991c..5cd02f7840460 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -984,6 +984,11 @@ fn main() {} //- /src/old_file.rs //- /src/old_folder/mod.rs +mod nested; + +//- /src/old_folder/nested.rs +struct foo; +use crate::old_folder::nested::foo as bar; //- /src/from_mod/mod.rs @@ -1080,6 +1085,27 @@ fn main() {} "newText": "new_folder" } ] + }, + { + "textDocument": { + "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")), + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 1, + "character": 11 + }, + "end": { + "line": 1, + "character": 21 + } + }, + "newText": "new_folder" + } + ] } ] }), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs index 56b5fcef3c2f5..45adbf5c573be 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -316,7 +316,7 @@ fn check_trailing_ws(path: &Path, text: &str) { return; } for (line_number, line) in text.lines().enumerate() { - if line.chars().last().map(char::is_whitespace) == Some(true) { + if line.chars().last().is_some_and(char::is_whitespace) { panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1) } } diff --git a/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml b/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml index ba36fb0b04464..cd7ec30593656 100644 --- a/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml @@ -11,10 +11,10 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ra-ap-rustc_lexer = { version = "0.19.0" } -ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } -ra-ap-rustc_index = { version = "0.19.0", default-features = false } -ra-ap-rustc_abi = { version = "0.19.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.20.0" } +ra-ap-rustc_parse_format = { version = "0.20.0", default-features = false } +ra-ap-rustc_index = { version = "0.20.0", default-features = false } +ra-ap-rustc_abi = { version = "0.20.0", default-features = false } [features] in-rust-tree = [] diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index 18d5ddd4d0afb..9fc19a7d07450 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -174,7 +174,7 @@ $ rustup component add rust-analyzer The `rust-analyzer` binary can be installed from the repos or AUR (Arch User Repository): -- https://www.archlinux.org/packages/community/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) +- https://www.archlinux.org/packages/extra/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) - https://aur.archlinux.org/packages/rust-analyzer-git[`rust-analyzer-git`] (latest Git version) Install it with pacman, for example: diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 265c63f3e2dc8..c43f2b964fde9 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -498,6 +498,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.showRequestFailedErrorNotification": { + "markdownDescription": "Whether to show error notifications for failing requests.", + "default": true, + "type": "boolean" + }, "rust-analyzer.showDependenciesExplorer": { "markdownDescription": "Whether to show the dependencies view.", "default": true, diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index 96e888402baf2..c27a446b38043 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -10,6 +10,7 @@ import { type Config, prepareVSCodeConfig } from "./config"; import { randomUUID } from "crypto"; import { sep as pathSeparator } from "path"; import { unwrapUndefinable } from "./undefinable"; +import { RaLanguageClient } from "./lang_client"; export interface Env { [name: string]: string; @@ -363,7 +364,7 @@ export async function createClient( }, }; - const client = new lc.LanguageClient( + const client = new RaLanguageClient( "rust-analyzer", "Rust Analyzer Language Server", serverOptions, diff --git a/src/tools/rust-analyzer/editors/code/src/lang_client.ts b/src/tools/rust-analyzer/editors/code/src/lang_client.ts new file mode 100644 index 0000000000000..09d64efc048ae --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/lang_client.ts @@ -0,0 +1,26 @@ +import * as lc from "vscode-languageclient/node"; +import * as vscode from "vscode"; + +export class RaLanguageClient extends lc.LanguageClient { + override handleFailedRequest( + type: lc.MessageSignature, + token: vscode.CancellationToken | undefined, + error: any, + defaultValue: T, + showNotification?: boolean | undefined, + ): T { + const showError = vscode.workspace + .getConfiguration("rust-analyzer") + .get("showRequestFailedErrorNotification"); + if ( + !showError && + error instanceof lc.ResponseError && + error.code === lc.ErrorCodes.InternalError + ) { + // Don't show notification for internal errors, these are emitted by r-a when a request fails. + showNotification = false; + } + + return super.handleFailedRequest(type, token, error, defaultValue, showNotification); + } +} diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml index 8d00813b0d7a4..be1573913ff24 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml +++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml @@ -14,3 +14,4 @@ crossbeam-channel = "0.5.6" [dev-dependencies] lsp-types = "=0.94" +ctrlc = "3.4.1" diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs index affab60a22783..b190c0af73d73 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs @@ -17,7 +17,7 @@ use std::{ net::{TcpListener, TcpStream, ToSocketAddrs}, }; -use crossbeam_channel::{Receiver, Sender}; +use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; pub use crate::{ error::{ExtractError, ProtocolError}, @@ -113,11 +113,62 @@ impl Connection { /// } /// ``` pub fn initialize_start(&self) -> Result<(RequestId, serde_json::Value), ProtocolError> { - loop { - break match self.receiver.recv() { - Ok(Message::Request(req)) if req.is_initialize() => Ok((req.id, req.params)), + self.initialize_start_while(|| true) + } + + /// Starts the initialization process by waiting for an initialize as described in + /// [`Self::initialize_start`] as long as `running` returns + /// `true` while the return value can be changed through a sig handler such as `CTRL + C`. + /// + /// # Example + /// + /// ```rust + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// use std::sync::Arc; + /// # use std::error::Error; + /// # use lsp_types::{ClientCapabilities, InitializeParams, ServerCapabilities}; + /// # use lsp_server::{Connection, Message, Request, RequestId, Response}; + /// # fn main() -> Result<(), Box> { + /// let running = Arc::new(AtomicBool::new(true)); + /// # running.store(true, Ordering::SeqCst); + /// let r = running.clone(); + /// + /// ctrlc::set_handler(move || { + /// r.store(false, Ordering::SeqCst); + /// }).expect("Error setting Ctrl-C handler"); + /// + /// let (connection, io_threads) = Connection::stdio(); + /// + /// let res = connection.initialize_start_while(|| running.load(Ordering::SeqCst)); + /// # assert!(res.is_err()); + /// + /// # Ok(()) + /// # } + /// ``` + pub fn initialize_start_while( + &self, + running: C, + ) -> Result<(RequestId, serde_json::Value), ProtocolError> + where + C: Fn() -> bool, + { + while running() { + let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) { + Ok(msg) => msg, + Err(RecvTimeoutError::Timeout) => { + continue; + } + Err(e) => { + return Err(ProtocolError(format!( + "expected initialize request, got error: {e}" + ))) + } + }; + + match msg { + Message::Request(req) if req.is_initialize() => return Ok((req.id, req.params)), // Respond to non-initialize requests with ServerNotInitialized - Ok(Message::Request(req)) => { + Message::Request(req) => { let resp = Response::new_err( req.id.clone(), ErrorCode::ServerNotInitialized as i32, @@ -126,15 +177,18 @@ impl Connection { self.sender.send(resp.into()).unwrap(); continue; } - Ok(Message::Notification(n)) if !n.is_exit() => { + Message::Notification(n) if !n.is_exit() => { continue; } - Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))), - Err(e) => { - Err(ProtocolError(format!("expected initialize request, got error: {e}"))) + msg => { + return Err(ProtocolError(format!("expected initialize request, got {msg:?}"))); } }; } + + return Err(ProtocolError(String::from( + "Initialization has been aborted during initialization", + ))); } /// Finishes the initialization process by sending an `InitializeResult` to the client @@ -156,6 +210,51 @@ impl Connection { } } + /// Finishes the initialization process as described in [`Self::initialize_finish`] as + /// long as `running` returns `true` while the return value can be changed through a sig + /// handler such as `CTRL + C`. + pub fn initialize_finish_while( + &self, + initialize_id: RequestId, + initialize_result: serde_json::Value, + running: C, + ) -> Result<(), ProtocolError> + where + C: Fn() -> bool, + { + let resp = Response::new_ok(initialize_id, initialize_result); + self.sender.send(resp.into()).unwrap(); + + while running() { + let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) { + Ok(msg) => msg, + Err(RecvTimeoutError::Timeout) => { + continue; + } + Err(e) => { + return Err(ProtocolError(format!( + "expected initialized notification, got error: {e}", + ))); + } + }; + + match msg { + Message::Notification(n) if n.is_initialized() => { + return Ok(()); + } + msg => { + return Err(ProtocolError(format!( + r#"expected initialized notification, got: {msg:?}"# + ))); + } + } + } + + return Err(ProtocolError(String::from( + "Initialization has been aborted during initialization", + ))); + } + /// Initialize the connection. Sends the server capabilities /// to the client and returns the serialized client capabilities /// on success. If more fine-grained initialization is required use @@ -198,6 +297,58 @@ impl Connection { Ok(params) } + /// Initialize the connection as described in [`Self::initialize`] as long as `running` returns + /// `true` while the return value can be changed through a sig handler such as `CTRL + C`. + /// + /// # Example + /// + /// ```rust + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// use std::sync::Arc; + /// # use std::error::Error; + /// # use lsp_types::ServerCapabilities; + /// # use lsp_server::{Connection, Message, Request, RequestId, Response}; + /// + /// # fn main() -> Result<(), Box> { + /// let running = Arc::new(AtomicBool::new(true)); + /// # running.store(true, Ordering::SeqCst); + /// let r = running.clone(); + /// + /// ctrlc::set_handler(move || { + /// r.store(false, Ordering::SeqCst); + /// }).expect("Error setting Ctrl-C handler"); + /// + /// let (connection, io_threads) = Connection::stdio(); + /// + /// let server_capabilities = serde_json::to_value(&ServerCapabilities::default()).unwrap(); + /// let initialization_params = connection.initialize_while( + /// server_capabilities, + /// || running.load(Ordering::SeqCst) + /// ); + /// + /// # assert!(initialization_params.is_err()); + /// # Ok(()) + /// # } + /// ``` + pub fn initialize_while( + &self, + server_capabilities: serde_json::Value, + running: C, + ) -> Result + where + C: Fn() -> bool, + { + let (id, params) = self.initialize_start_while(&running)?; + + let initialize_data = serde_json::json!({ + "capabilities": server_capabilities, + }); + + self.initialize_finish_while(id, initialize_data, running)?; + + Ok(params) + } + /// If `req` is `Shutdown`, respond to it and return `true`, otherwise return `false` pub fn handle_shutdown(&self, req: &Request) -> Result { if !req.is_shutdown() { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f36893bfb94c9..1f8edd7937b49 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -129,7 +129,6 @@ const EXCEPTIONS_CARGO: ExceptionList = &[ const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ // tidy-alphabetical-start ("dissimilar", "Apache-2.0"), - ("instant", "BSD-3-Clause"), ("notify", "CC0-1.0"), ("pulldown-cmark-to-cmark", "Apache-2.0"), ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0