diff options
| author | Ralf Jung <post@ralfj.de> | 2023-11-30 11:02:40 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2023-11-30 11:02:40 +0100 |
| commit | 7a661d048ca63c58fe45399ac813f347fa754294 (patch) | |
| tree | 6ea6290c08709fe4102bdf4dc88f8849cb69f647 /src | |
| parent | 76ec47782ad310262598c21b618225d718cefbea (diff) | |
| parent | 2d476222e8458aa873e6760aac189b5e9d0a9930 (diff) | |
Merge from rustc
Diffstat (limited to 'src')
81 files changed, 1311 insertions, 461 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5a84e37f8cf..4691fb3ad6f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1083,6 +1083,11 @@ def bootstrap(args): include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile) include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults') include_path = os.path.join(include_dir, include_file) + + if not os.path.exists(include_path): + raise Exception("Unrecognized config profile '{}'. Check src/bootstrap/defaults" + " for available options.".format(profile)) + # HACK: This works because `self.get_toml()` returns the first match it finds for a # specific key, so appending our defaults at the end allows the user to override them with open(include_path) as included_toml: diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index f710c01ca33..7c119b0273b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -15,6 +15,7 @@ use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; use std::process::Command; +use std::sync::OnceLock; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; @@ -105,13 +106,16 @@ pub fn prebuilt_llvm_config( let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir }; - let smart_stamp_hash = generate_smart_stamp_hash( - &builder.config.src.join("src/llvm-project"), - &builder.in_tree_llvm_info.sha().unwrap_or_default(), - ); + static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); + let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { + generate_smart_stamp_hash( + &builder.config.src.join("src/llvm-project"), + &builder.in_tree_llvm_info.sha().unwrap_or_default(), + ) + }); let stamp = out_dir.join("llvm-finished-building"); - let stamp = HashStamp::new(stamp, Some(&smart_stamp_hash)); + let stamp = HashStamp::new(stamp, Some(smart_stamp_hash)); if stamp.is_done() { if stamp.hash.is_none() { @@ -565,11 +569,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { - if major >= 15 { + if major >= 16 { return; } } - panic!("\n\nbad LLVM version: {version}, need >=15.0\n\n") + panic!("\n\nbad LLVM version: {version}, need >=16.0\n\n") } fn configure_cmake( diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ec859d30c82..77a4f2c4cb2 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -999,6 +999,7 @@ impl Step for RustdocGUI { let run = run.suite_path("tests/rustdoc-gui"); run.lazy_default_condition(Box::new(move || { builder.config.nodejs.is_some() + && builder.doc_tests != DocTests::Only && builder .config .npm @@ -1158,7 +1159,8 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/tidy") + let default = run.builder.doc_tests != DocTests::Only; + run.path("src/tools/tidy").default_condition(default) } fn make_run(run: RunConfig<'_>) { @@ -1560,6 +1562,10 @@ impl Step for Compiletest { /// compiletest `mode` and `suite` arguments. For example `mode` can be /// "run-pass" or `suite` can be something like `debuginfo`. fn run(self, builder: &Builder<'_>) { + if builder.doc_tests == DocTests::Only { + return; + } + if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() { eprintln!("\ ERROR: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail @@ -1821,6 +1827,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--json"); + if builder.config.rust_debug_assertions_std { + cmd.arg("--with-debug-assertions"); + }; + let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled() { @@ -2323,6 +2333,8 @@ impl Step for CrateLibrustc { } fn run(self, builder: &Builder<'_>) { + builder.ensure(compile::Std::new(self.compiler, self.target)); + builder.ensure(Crate { compiler: self.compiler, target: self.target, diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile deleted file mode 100644 index cefdcad7643..00000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -FROM ubuntu:22.04 - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - gcc-multilib \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python3.11 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-15-tools \ - llvm-15-dev \ - libedit-dev \ - libssl-dev \ - pkg-config \ - zlib1g-dev \ - xz-utils \ - nodejs \ - mingw-w64 \ - libgccjit-12-dev \ - && rm -rf /var/lib/apt/lists/* - -# Install powershell (universal package) so we can test x.ps1 on Linux -RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ - dpkg -i powershell.deb && \ - rm -f powershell.deb - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# Make `libgccjit.so` accessible to the linker. -RUN ln -s /usr/lib/gcc/x86_64-linux-gnu/12/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so - -# We are disabling CI LLVM since this builder is intentionally using a host -# LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 - -# This is not the latest LLVM version, so some components required by tests may -# be missing. -ENV IS_NOT_LATEST_LLVM 1 - -# Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-15 \ - --enable-llvm-link-shared \ - $USE_NEW_MANGLING \ - --set rust.thin-lto-import-instr-limit=10 - -COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ - -ENV SCRIPT /tmp/script.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile index c177e7387fc..4757c3e7329 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile @@ -49,6 +49,6 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ +COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ ENV SCRIPT /tmp/script.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh index 2eb751ca376..2eb751ca376 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index 76846f1fed7..dc5a04d4e06 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -45,6 +45,6 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ +COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ ENV SCRIPT /tmp/script.sh diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index da29ffb8e5f..5b9c90273a3 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -334,7 +334,7 @@ jobs: - name: mingw-check-tidy <<: *job-linux-4c - - name: x86_64-gnu-llvm-15 + - name: x86_64-gnu-llvm-16 env: ENABLE_GCC_CODEGEN: "1" <<: *job-linux-16c @@ -486,11 +486,6 @@ jobs: RUST_BACKTRACE: 1 <<: *job-linux-8c - - name: x86_64-gnu-llvm-15 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - name: x86_64-gnu-nopt <<: *job-linux-4c diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 9f0662783a4..2a741fa3d02 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -121,10 +121,8 @@ export build_env=' env $build_env \ ./x.py build \ - --target aarch64-unknown-nto-qnx710 \ - --target x86_64-pc-nto-qnx710 \ - --target x86_64-unknown-linux-gnu \ - rustc library/core library/alloc + --target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ + rustc library/core library/alloc library/std ``` ## Running the Rust test suite diff --git a/src/doc/unstable-book/src/compiler-flags/function-return.md b/src/doc/unstable-book/src/compiler-flags/function-return.md new file mode 100644 index 00000000000..d044a6f68aa --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/function-return.md @@ -0,0 +1,25 @@ +# `function-return` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116853. + +------------------------ + +Option `-Zfunction-return` controls how function returns are converted. + +It is equivalent to [Clang]'s and [GCC]'s `-mfunction-return`. The Linux kernel +uses it for RETHUNK builds. For details, see [LLVM commit 2240d72f15f3] ("[X86] +initial -mfunction-return=thunk-extern support") which introduces the feature. + +Supported values for this option are: + + - `keep`: do not convert function returns. + - `thunk-extern`: convert function returns (`ret`) to jumps (`jmp`) + to an external symbol called `__x86_return_thunk`. + +Like in Clang, GCC's values `thunk` and `thunk-inline` are not supported. + +Only x86 and non-large code models are supported. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mfunction-return +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mfunction-return +[LLVM commit 2240d72f15f3]: https://github.com/llvm/llvm-project/commit/2240d72f15f3b7b9d9fb65450f9bf635fd310f6f diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dc9098d3ade..fe1f43835ef 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1821,11 +1821,8 @@ fn maybe_expand_private_type_alias<'tcx>( } _ => None, }); - if let Some(ct) = const_ { - args.insert( - param.def_id.to_def_id(), - SubstParam::Constant(clean_const(ct, cx)), - ); + if let Some(_) = const_ { + args.insert(param.def_id.to_def_id(), SubstParam::Constant); } // FIXME(const_generics_defaults) indices.consts += 1; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f079d01bd84..7a5cf803137 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2546,7 +2546,7 @@ pub(crate) enum TypeBindingKind { pub(crate) enum SubstParam { Type(Type), Lifetime(Lifetime), - Constant(Constant), + Constant, } impl SubstParam { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c22ad43e049..82f4a38384d 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { debug!("trying to get a name from pattern: {p:?}"); Symbol::intern(&match p.kind { - PatKind::Wild | PatKind::Struct(..) => return kw::Underscore, + // FIXME(never_patterns): does this make sense? + PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore, PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Or(pats) => { diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index e607a16ad54..0056fb48530 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -9,21 +9,6 @@ pub(crate) use renderer::{run_format, FormatRenderer}; use crate::clean::{self, ItemId}; use crate::html::render::Context; -/// Specifies whether rendering directly implemented trait items or ones from a certain Deref -/// impl. -pub(crate) enum AssocItemRender<'a> { - All, - DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, -} - -/// For different handling of associated items from the Deref target of a type rather than the type -/// itself. -#[derive(Copy, Clone, PartialEq)] -pub(crate) enum RenderMode { - Normal, - ForDeref { mut_: bool }, -} - /// Metadata about implementations for a type or trait. #[derive(Clone, Debug)] pub(crate) struct Impl { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 06bfd4652d6..bed8f6ffef5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1305,7 +1305,7 @@ impl clean::Impl { primitive_link_fragment( f, PrimitiveType::Tuple, - format_args!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), + format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx, )?; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ff5c761208b..348d546c236 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -66,7 +66,7 @@ use crate::clean::{self, ItemId, RenderedLink, SelfTy}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::{AssocItemRender, Impl, RenderMode}; +use crate::formats::Impl; use crate::html::escape::Escape; use crate::html::format::{ display_fn, href, join_with_double_colon, print_abi_with_space, print_constness_with_space, @@ -89,6 +89,21 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { }) } +/// Specifies whether rendering directly implemented trait items or ones from a certain Deref +/// impl. +pub(crate) enum AssocItemRender<'a> { + All, + DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, +} + +/// For different handling of associated items from the Deref target of a type rather than the type +/// itself. +#[derive(Copy, Clone, PartialEq)] +pub(crate) enum RenderMode { + Normal, + ForDeref { mut_: bool }, +} + // Helper structs for rendering items/sidebars and carrying along contextual // information diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 14387e0d45d..2dac943f695 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -22,12 +22,13 @@ use super::{ item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw, - render_stability_since_raw_with_extra, AssocItemLink, Context, ImplRenderingParameters, + render_stability_since_raw_with_extra, AssocItemLink, AssocItemRender, Context, + ImplRenderingParameters, RenderMode, }; use crate::clean; use crate::config::ModuleSorting; use crate::formats::item_type::ItemType; -use crate::formats::{AssocItemRender, Impl, RenderMode}; +use crate::formats::Impl; use crate::html::escape::Escape; use crate::html::format::{ display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index d2c7c578c08..b04776e91dc 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -15,14 +15,14 @@ use rustc_span::Symbol; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use super::{collect_paths_for_type, ensure_trailing_slash, Context}; +use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode}; use crate::clean::{Crate, Item, ItemId, ItemKind}; use crate::config::{EmitType, RenderOptions}; use crate::docfs::PathError; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::{Impl, RenderMode}; +use crate::formats::Impl; use crate::html::format::Buffer; use crate::html::render::{AssocItemLink, ImplRenderingParameters}; use crate::html::{layout, static_files}; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 7cc0f2e8f1e..d613997cd7f 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1318,8 +1318,7 @@ function preLoadCss(cssUrl) { const infos = [ `For a full list of all search features, take a look <a \ -href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ -#the-search-interface">here</a>.`, +href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.html">here</a>.`, "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \ restrict the search to a given item kind.", "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \ diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 9b13310ca596020a737aaa47daa4ed9ff8898a2 +Subproject 26333c732095d207aa05932ce863d850fb30938 diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 575fead5bf3..630df9a84f5 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -46,7 +46,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { pats.iter().all(unary_pattern) } match &pat.kind { - PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => { false }, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 70892ce608f..2ab04682f1d 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; +use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -144,7 +144,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { let eq_span = lhs.span.between(rhs.span); if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { - let op = UnOp::to_string(op); + let op = op.as_str(); let eqop_span = lhs.span.between(sub_rhs.span); if eq_snippet.ends_with('=') { span_lint_and_note( @@ -177,11 +177,11 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { && let unop_operand_span = rhs.span.until(un_rhs.span) && let Some(binop_snippet) = snippet_opt(cx, binop_span) && let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span) - && let binop_str = BinOpKind::to_string(&binop.node) + && let binop_str = binop.node.as_str() // no space after BinOp operator and space after UnOp operator && binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ') { - let unop_str = UnOp::to_string(op); + let unop_str = op.as_str(); let eqop_span = lhs.span.between(un_rhs.span); span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 745be671b86..cbf478620ec 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -150,6 +150,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { #[derive(Clone, Copy)] enum NormalizedPat<'a> { Wild, + Never, Struct(Option<DefId>, &'a [(Symbol, Self)]), Tuple(Option<DefId>, &'a [Self]), Or(&'a [Self]), @@ -229,6 +230,7 @@ impl<'a> NormalizedPat<'a> { PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => { Self::from_pat(cx, arena, pat) }, + PatKind::Never => Self::Never, PatKind::Struct(ref path, fields, _) => { let fields = arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat)))); @@ -333,6 +335,7 @@ impl<'a> NormalizedPat<'a> { fn has_overlapping_values(&self, other: &Self) -> bool { match (*self, *other) { (Self::Wild, _) | (_, Self::Wild) => true, + (Self::Never, Self::Never) => true, (Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => { pats.iter().any(|pat| pat.has_overlapping_values(other)) }, diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index b638e83997a..52cec437378 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -78,7 +78,7 @@ impl EarlyLintPass for Precedence { let sugg = format!( "({}) {} ({})", snippet_with_applicability(cx, left.span, "..", &mut applicability), - op.to_string(), + op.as_str(), snippet_with_applicability(cx, right.span, "..", &mut applicability) ); span_sugg(expr, sugg, applicability); @@ -87,7 +87,7 @@ impl EarlyLintPass for Precedence { let sugg = format!( "({}) {} {}", snippet_with_applicability(cx, left.span, "..", &mut applicability), - op.to_string(), + op.as_str(), snippet_with_applicability(cx, right.span, "..", &mut applicability) ); span_sugg(expr, sugg, applicability); @@ -96,7 +96,7 @@ impl EarlyLintPass for Precedence { let sugg = format!( "{} {} ({})", snippet_with_applicability(cx, left.span, "..", &mut applicability), - op.to_string(), + op.as_str(), snippet_with_applicability(cx, right.span, "..", &mut applicability) ); span_sugg(expr, sugg, applicability); diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 92de7917871..b332309a552 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -298,7 +298,7 @@ fn replace_left_sugg( ) -> String { format!( "{left_suggestion} {} {}", - binop.op.to_string(), + binop.op.as_str(), snippet_with_applicability(cx, binop.right.span, "..", applicability), ) } @@ -312,7 +312,7 @@ fn replace_right_sugg( format!( "{} {} {right_suggestion}", snippet_with_applicability(cx, binop.left.span, "..", applicability), - binop.op.to_string(), + binop.op.as_str(), ) } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 8ff088a208f..952c0dc72b1 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e8842ce10f8..e83c04eda20 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -629,6 +629,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match pat.value.kind { PatKind::Wild => kind!("Wild"), + PatKind::Never => kind!("Never"), PatKind::Binding(ann, _, name, sub) => { bind!(self, name); opt_bind!(self, sub); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 8031e6faa74..34ec83709ff 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1017,6 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, + PatKind::Never => {}, PatKind::Wild => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 172b063df31..fd37713fc60 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1707,6 +1707,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild => false, + PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Lit(..) | PatKind::Range(..) => true, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index db79dd78801..f143163152e 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -382,7 +382,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::GreaterEqual => { format!( "{lhs} {} {rhs}", - op.to_ast_binop().expect("Those are AST ops").to_string() + op.to_ast_binop().expect("Those are AST ops").as_str() ) }, AssocOp::Assign => format!("{lhs} = {rhs}"), diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index e7d2e1aab3a..e85f6319936 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -242,6 +242,9 @@ pub struct Config { /// Run ignored tests pub run_ignored: bool, + /// Whether to run tests with `ignore-debug` header + pub with_debug_assertions: bool, + /// Only run tests that match these filters pub filters: Vec<String>, diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 3a1b9dff3a6..e2a04b7e558 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -190,8 +190,8 @@ pub(super) fn parse_cfg_name_directive<'a>( } condition! { name: "debug", - condition: cfg!(debug_assertions), - message: "when building with debug assertions", + condition: config.with_debug_assertions, + message: "when running tests with `ignore-debug` header", } condition! { name: config.debugger.as_ref().map(|d| d.to_str()), diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index bb09c03ef5b..5a80b9121f0 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -81,6 +81,7 @@ pub fn parse_config(args: Vec<String>) -> Config { ) .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") + .optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header") .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") .optflag("", "exact", "filters match exactly") .optopt( @@ -203,6 +204,7 @@ pub fn parse_config(args: Vec<String>) -> Config { let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); + let with_debug_assertions = matches.opt_present("with-debug-assertions"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); let has_tidy = if mode == Mode::Rustdoc { Command::new("tidy") @@ -238,6 +240,7 @@ pub fn parse_config(args: Vec<String>) -> Config { suite: matches.opt_str("suite").unwrap(), debugger: None, run_ignored, + with_debug_assertions, filters: matches.free.clone(), skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index ba40a1b3c32..be30627cf0c 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -66,11 +66,6 @@ pub trait FileDescriptor: std::fmt::Debug + Any { fn is_tty(&self, _communicate_allowed: bool) -> bool { false } - - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - None - } } impl dyn FileDescriptor { @@ -150,12 +145,6 @@ impl FileDescriptor for FileHandle { Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - use std::os::unix::io::AsRawFd; - Some(self.file.as_raw_fd()) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.file.is_terminal() } @@ -183,11 +172,6 @@ impl FileDescriptor for io::Stdin { Ok(Box::new(io::stdin())) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - Some(libc::STDIN_FILENO) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -220,11 +204,6 @@ impl FileDescriptor for io::Stdout { Ok(Box::new(io::stdout())) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - Some(libc::STDOUT_FILENO) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -250,11 +229,6 @@ impl FileDescriptor for io::Stderr { Ok(Box::new(io::stderr())) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - Some(libc::STDERR_FILENO) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } diff --git a/src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs new file mode 100644 index 00000000000..98f9cc96fd0 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs @@ -0,0 +1,27 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; +use std::ptr; + +#[repr(C)] +struct S(u8, u16); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let s: S; + let sptr; + let sptr2; + let _val; + { + sptr = ptr::addr_of_mut!(s); + sptr2 = sptr as *mut [u8; 4]; + *sptr2 = [0; 4]; + *sptr = S(0, 0); // should reset the padding + _val = *sptr2; // should hence be UB + //~^ERROR: encountered uninitialized memory + Return() + } + } +} diff --git a/src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr new file mode 100644 index 00000000000..5f3d9bde1f2 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + --> $DIR/uninit-after-aggregate-assign.rs:LL:CC + | +LL | _val = *sptr2; // should hence be UB + | ^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/uninit-after-aggregate-assign.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 701e36d74a6..5a8d971c3d4 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", ] @@ -290,6 +290,16 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -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", @@ -752,16 +759,6 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" @@ -791,15 +788,6 @@ dependencies = [ ] [[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" dependencies = [ @@ -811,15 +799,6 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" @@ -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", @@ -1101,6 +1081,17 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1176,37 +1167,12 @@ 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" 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", @@ -1604,6 +1563,35 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -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", ] @@ -1632,35 +1620,6 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -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]] @@ -1800,17 +1759,6 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" @@ -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]] @@ -2113,12 +2061,6 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -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 171c113a950..5ad88f65188 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 3f5ccb621c7..3da555a47ac 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 65db5c0fc7d..e4f78321e21 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<ReleaseChannel>, } +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<CrateId, CrateId> = 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<CrateId> 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 c5c4afa30f7..40cfab88afd 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 0aeb0b05052..8bbe5e2a8c2 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<Item = &'a CfgAtom> + '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 460a908b6db..4c1b8f306c5 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<MacroSubNs>, ) -> 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 f2d2451511f..bbcb76a43ff 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 0a68a9f3b58..ac39bdf5bf5 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<T: HasInterner<Interner = Interner>> Canonicalized<T> { - pub(super) fn apply_solution( + pub(crate) fn apply_solution( &self, ctx: &mut InferenceTable<'_>, solution: Canonical<Substitution>, 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 c8a85b4a9ff..04005311b67 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 87c93283361..732643566a2 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::<Goal>(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 48dd9540329..003ae60e8e5 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 @@ -2598,6 +2598,34 @@ fn test<T: Trait>() { } #[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<F> { + foo: F, +} +impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> { + fn foobar(&self) -> u8 { + self.foo.deref().bar() + } +} +"#, + ) +} + +#[test] fn dyn_trait_through_chalk() { check_types( r#" diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index bdc11aa3561..1bfbf7212bf 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 b7d57f02be5..f864ee50c81 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<ast::Attr> { - 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 0bf1782a489..0876246e90b 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 `<i32 as std::ops::Add>` - 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 c5bbb7f8d75..5bcc867fe18 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<Unknown>) { "#]], ); } + + #[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<F> { + foo: F, +} + +impl<F> Foo<F> { + fn new(foo: F) -> Foo<F> { + Foo { foo } + } +} + +impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> { + 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<F> { + foo: F, +} + +impl<F> Foo<F> { + fn new(foo: F) -> Foo<F> { + Foo { foo } + } +} + +impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> { + 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 ed74ef7b667..99b895eed4d 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<SmolStr>, + /// 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 dfe8fe7e2f7..00a9081985b 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 9db8e972dd4..f28afacc586 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<CompletionItem>) -> 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 40d0b6fdd4b..51923797ac9 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 @@ -36,6 +36,19 @@ 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( r#" 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 3d89599c583..9b2ff070c74 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 46a0464e9e6..a7f5ae92a4c 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 80897f7478c..931eba11576 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::<Vec<_>>(), 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 7815b9dda77..98f3063bb98 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 e0209ca15a5..9333570354a 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 00000000000..b0fb5845cef --- /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 00000000000..b5d1e16e62e --- /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 727d39a3077..e98f016ca7d 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 727d39a3077..e98f016ca7d 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 89728babd82..7ecd53572e2 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 b7bf6cb2774..581a6afc148 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 aca91570f7c..fb366fd5cc4 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<lsp_ext::SnippetWorkspaceEdit> { let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = 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 d5991429899..5cd02f78404 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 56b5fcef3c2..45adbf5c573 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 ba36fb0b044..cd7ec305936 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 18d5ddd4d0a..9fc19a7d074 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 265c63f3e2d..c43f2b964fd 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 96e888402ba..c27a446b380 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 00000000000..09d64efc048 --- /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<T>( + 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 8d00813b0d7..be1573913ff 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 affab60a227..b190c0af73d 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<dyn Error + Sync + Send>> { + /// 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<C>( + &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<C>( + &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<dyn Error + Sync + Send>> { + /// 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<C>( + &self, + server_capabilities: serde_json::Value, + running: C, + ) -> Result<serde_json::Value, ProtocolError> + 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<bool, ProtocolError> { if !req.is_shutdown() { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index fa941e6146a..60e0e007b1d 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1933,7 +1933,7 @@ fn rewrite_unary_op( shape: Shape, ) -> Option<String> { // For some reason, an UnOp is not spanned like BinOp! - rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape) + rewrite_unary_prefix(context, op.as_str(), expr, shape) } pub(crate) enum RhsAssignKind<'ast> { diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs index 07c05193739..bfc2ffed383 100644 --- a/src/tools/rustfmt/src/pairs.rs +++ b/src/tools/rustfmt/src/pairs.rs @@ -339,7 +339,7 @@ impl FlattenPair for ast::Expr { if let Some(pop) = stack.pop() { match pop.kind { ast::ExprKind::Binary(op, _, ref rhs) => { - separators.push(op.node.to_string()); + separators.push(op.node.as_str()); node = rhs; } _ => unreachable!(), diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 33f3b4b8a21..8504999b8ff 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -40,7 +40,9 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { fn is_short_pattern_inner(pat: &ast::Pat) -> bool { match pat.kind { - ast::PatKind::Rest | ast::PatKind::Wild | ast::PatKind::Lit(_) => true, + ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => { + true + } ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -193,6 +195,7 @@ impl Rewrite for Pat { None } } + PatKind::Never => None, PatKind::Range(ref lhs, ref rhs, ref end_kind) => { let infix = match end_kind.node { RangeEnd::Included(RangeSyntax::DotDotDot) => "...", diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f36893bfb94..1f8edd7937b 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 |
