From d9ca835db4ead44eba68345f32e0e8226822440c Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Sun, 8 Jun 2025 18:15:33 +0000 Subject: [PATCH 001/242] Mark `slice::swap_with_slice` unstably const --- library/core/src/slice/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4f7e14408804..9ad3fd5cd339 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3927,8 +3927,9 @@ impl [T] { /// /// [`split_at_mut`]: slice::split_at_mut #[stable(feature = "swap_with_slice", since = "1.27.0")] + #[rustc_const_unstable(feature = "const_swap_with_slice", issue = "142204")] #[track_caller] - pub fn swap_with_slice(&mut self, other: &mut [T]) { + pub const fn swap_with_slice(&mut self, other: &mut [T]) { assert!(self.len() == other.len(), "destination and source slices have different lengths"); // SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was // checked to have the same length. The slices cannot overlap because From f4b77355c6849085b0a841f962abae4ced5e50ba Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 17 Jun 2025 15:02:38 +0100 Subject: [PATCH 002/242] Rename hir const arg walking functions --- compiler/rustc_ast_lowering/src/index.rs | 2 +- compiler/rustc_hir/src/intravisit.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 956cb580d103..a0a3a973fbec 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -311,7 +311,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { ); self.with_parent(const_arg.hir_id, |this| { - intravisit::walk_ambig_const_arg(this, const_arg); + intravisit::walk_const_arg(this, const_arg); }); } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 57e49625148c..c8f6978ee8be 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -380,7 +380,7 @@ pub trait Visitor<'v>: Sized { /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result { - walk_ambig_const_arg(self, c) + walk_const_arg(self, c) } #[allow(unused_variables)] @@ -525,7 +525,7 @@ pub trait VisitorExt<'v>: Visitor<'v> { /// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in /// discovery by IDes when `v.visit_const_arg` is written. fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result { - walk_const_arg(self, c) + walk_unambig_const_arg(self, c) } } impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {} @@ -1038,7 +1038,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - V::Result::output() } -pub fn walk_const_arg<'v, V: Visitor<'v>>( +pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v>, ) -> V::Result { @@ -1052,7 +1052,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( } } -pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>( +pub fn walk_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, ) -> V::Result { From c9264a1f4963182fb31c1da32d191bb3bac930ca Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 17 Jun 2025 15:03:02 +0100 Subject: [PATCH 003/242] Don't double visit `HirId`s of inferred const/types --- compiler/rustc_hir/src/intravisit.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index c8f6978ee8be..cb971bedecd2 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -980,7 +980,6 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> Some(ambig_ty) => visitor.visit_ty(ambig_ty), None => { let Ty { hir_id, span, kind: _ } = typ; - try_visit!(visitor.visit_id(*hir_id)); visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ)) } } @@ -1046,7 +1045,6 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( Some(ambig_ct) => visitor.visit_const_arg(ambig_ct), None => { let ConstArg { hir_id, kind: _ } = const_arg; - try_visit!(visitor.visit_id(*hir_id)); visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg)) } } From 2411fbaa49f8c10d0fc8bc1a41d39d0df2f73f0f Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 18 Jun 2025 15:58:00 +0100 Subject: [PATCH 004/242] Link to dev-guide docs --- compiler/rustc_hir/src/hir.rs | 32 ++++++++++++++++++++-------- compiler/rustc_hir/src/intravisit.rs | 22 +++++++++++++++---- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 556f50a85af7..bd59ad613d63 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -407,10 +407,8 @@ impl<'hir> PathSegment<'hir> { /// that are [just paths](ConstArgKind::Path) (currently just bare const params) /// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). /// -/// The `Unambig` generic parameter represents whether the position this const is from is -/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an -/// ambiguous context the parameter is instantiated with an uninhabited type making the -/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead. +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(C)] pub struct ConstArg<'hir, Unambig = ()> { @@ -429,6 +427,9 @@ impl<'hir> ConstArg<'hir, AmbigArg> { /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or /// specifically matching on [`GenericArg::Infer`] when handling generic arguments. /// + /// For an explanation of what it means for a const arg to be ambig or unambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html + /// /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer] pub fn as_unambig_ct(&self) -> &ConstArg<'hir> { // SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the @@ -444,6 +445,9 @@ impl<'hir> ConstArg<'hir> { /// /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if /// infer consts are relevant to you then care should be taken to handle them separately. + /// + /// For an explanation of what it means for a const arg to be ambig or unambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> { if let ConstArgKind::Infer(_, ()) = self.kind { return None; @@ -475,6 +479,9 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { } /// See [`ConstArg`]. +/// +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { @@ -3302,10 +3309,8 @@ pub enum AmbigArg {} #[repr(C)] /// Represents a type in the `HIR`. /// -/// The `Unambig` generic parameter represents whether the position this type is from is -/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an -/// ambiguous context the parameter is instantiated with an uninhabited type making the -/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead. +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub struct Ty<'hir, Unambig = ()> { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -3323,6 +3328,9 @@ impl<'hir> Ty<'hir, AmbigArg> { /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or /// specifically matching on [`GenericArg::Infer`] when handling generic arguments. /// + /// For an explanation of what it means for a type to be ambig or unambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html + /// /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer] pub fn as_unambig_ty(&self) -> &Ty<'hir> { // SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is @@ -3338,6 +3346,9 @@ impl<'hir> Ty<'hir> { /// /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if /// infer types are relevant to you then care should be taken to handle them separately. + /// + /// For an explanation of what it means for a type to be ambig or unambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> { if let TyKind::Infer(()) = self.kind { return None; @@ -3640,9 +3651,12 @@ pub enum InferDelegationKind { } /// The various kinds of types recognized by the compiler. -#[derive(Debug, Clone, Copy, HashStable_Generic)] +/// +/// For an explanation of the `Unambig` generic parameter see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html // SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind` are layout compatible #[repr(u8, C)] +#[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TyKind<'hir, Unambig = ()> { /// Actual type should be inherited from `DefId` signature InferDelegation(DefId, InferDelegationKind), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cb971bedecd2..95fee05a71b9 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -364,8 +364,8 @@ pub trait Visitor<'v>: Sized { /// All types are treated as ambiguous types for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// - /// See the doc comments on [`Ty`] for an explanation of what it means for a type to be - /// ambiguous. + /// For an explanation of what it means for a type to be ambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result { @@ -375,8 +375,8 @@ pub trait Visitor<'v>: Sized { /// All consts are treated as ambiguous consts for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// - /// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be - /// ambiguous. + /// For an explanation of what it means for a const arg to be ambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result { @@ -516,6 +516,9 @@ pub trait VisitorExt<'v>: Visitor<'v> { /// /// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery /// by IDes when `v.visit_ty` is written. + /// + /// For an explanation of what it means for a type to be unambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html fn visit_ty_unambig(&mut self, t: &'v Ty<'v>) -> Self::Result { walk_unambig_ty(self, t) } @@ -524,6 +527,9 @@ pub trait VisitorExt<'v>: Visitor<'v> { /// /// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in /// discovery by IDes when `v.visit_const_arg` is written. + /// + /// For an explanation of what it means for a const arg to be unambig, see the dev-guide: + /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result { walk_unambig_const_arg(self, c) } @@ -975,6 +981,8 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>( } } +/// For an explanation of what it means for a type to be unambig, see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result { match typ.try_as_ambig_ty() { Some(ambig_ty) => visitor.visit_ty(ambig_ty), @@ -985,6 +993,8 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> } } +/// For an explanation of what it means for a type to be ambig, see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result { let Ty { hir_id, span: _, kind } = typ; try_visit!(visitor.visit_id(*hir_id)); @@ -1037,6 +1047,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - V::Result::output() } +/// For an explanation of what it means for a const arg to be unambig, see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v>, @@ -1050,6 +1062,8 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( } } +/// For an explanation of what it means for a const arg to be ambig, see the dev-guide: +/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, From fa5895ea8c39cb2d8f7078ccd4e78a41aeb2eb84 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 25 Jun 2025 12:29:04 +0100 Subject: [PATCH 005/242] Reviews --- compiler/rustc_hir/src/hir.rs | 27 ++++++--------------------- compiler/rustc_hir/src/intravisit.rs | 20 -------------------- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bd59ad613d63..380120ecfe28 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -408,7 +408,7 @@ impl<'hir> PathSegment<'hir> { /// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html +/// #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(C)] pub struct ConstArg<'hir, Unambig = ()> { @@ -420,16 +420,13 @@ pub struct ConstArg<'hir, Unambig = ()> { impl<'hir> ConstArg<'hir, AmbigArg> { /// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position. /// - /// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant + /// Functions accepting unambiguous consts may expect the [`ConstArgKind::Infer`] variant /// to be used. Care should be taken to separately handle infer consts when calling this /// function as it cannot be handled by downstream code making use of the returned const. /// /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or /// specifically matching on [`GenericArg::Infer`] when handling generic arguments. /// - /// For an explanation of what it means for a const arg to be ambig or unambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html - /// /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer] pub fn as_unambig_ct(&self) -> &ConstArg<'hir> { // SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the @@ -445,9 +442,6 @@ impl<'hir> ConstArg<'hir> { /// /// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if /// infer consts are relevant to you then care should be taken to handle them separately. - /// - /// For an explanation of what it means for a const arg to be ambig or unambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> { if let ConstArgKind::Infer(_, ()) = self.kind { return None; @@ -479,9 +473,6 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { } /// See [`ConstArg`]. -/// -/// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html #[derive(Clone, Copy, Debug, HashStable_Generic)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { @@ -3305,12 +3296,12 @@ impl<'hir> AssocItemConstraintKind<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum AmbigArg {} -#[derive(Debug, Clone, Copy, HashStable_Generic)] -#[repr(C)] /// Represents a type in the `HIR`. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html +/// +#[derive(Debug, Clone, Copy, HashStable_Generic)] +#[repr(C)] pub struct Ty<'hir, Unambig = ()> { #[stable_hasher(ignore)] pub hir_id: HirId, @@ -3328,9 +3319,6 @@ impl<'hir> Ty<'hir, AmbigArg> { /// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or /// specifically matching on [`GenericArg::Infer`] when handling generic arguments. /// - /// For an explanation of what it means for a type to be ambig or unambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html - /// /// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer] pub fn as_unambig_ty(&self) -> &Ty<'hir> { // SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is @@ -3346,9 +3334,6 @@ impl<'hir> Ty<'hir> { /// /// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if /// infer types are relevant to you then care should be taken to handle them separately. - /// - /// For an explanation of what it means for a type to be ambig or unambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> { if let TyKind::Infer(()) = self.kind { return None; @@ -3653,7 +3638,7 @@ pub enum InferDelegationKind { /// The various kinds of types recognized by the compiler. /// /// For an explanation of the `Unambig` generic parameter see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html +/// // SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind` are layout compatible #[repr(u8, C)] #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 95fee05a71b9..aa96ff1eb1af 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -364,9 +364,6 @@ pub trait Visitor<'v>: Sized { /// All types are treated as ambiguous types for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// - /// For an explanation of what it means for a type to be ambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html - /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result { walk_ty(self, t) @@ -375,9 +372,6 @@ pub trait Visitor<'v>: Sized { /// All consts are treated as ambiguous consts for the purposes of hir visiting in /// order to ensure that visitors can handle infer vars without it being too error-prone. /// - /// For an explanation of what it means for a const arg to be ambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html - /// /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result { walk_const_arg(self, c) @@ -516,9 +510,6 @@ pub trait VisitorExt<'v>: Visitor<'v> { /// /// Named `visit_ty_unambig` instead of `visit_unambig_ty` to aid in discovery /// by IDes when `v.visit_ty` is written. - /// - /// For an explanation of what it means for a type to be unambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html fn visit_ty_unambig(&mut self, t: &'v Ty<'v>) -> Self::Result { walk_unambig_ty(self, t) } @@ -527,9 +518,6 @@ pub trait VisitorExt<'v>: Visitor<'v> { /// /// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in /// discovery by IDes when `v.visit_const_arg` is written. - /// - /// For an explanation of what it means for a const arg to be unambig, see the dev-guide: - /// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result { walk_unambig_const_arg(self, c) } @@ -981,8 +969,6 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>( } } -/// For an explanation of what it means for a type to be unambig, see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Result { match typ.try_as_ambig_ty() { Some(ambig_ty) => visitor.visit_ty(ambig_ty), @@ -993,8 +979,6 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> } } -/// For an explanation of what it means for a type to be ambig, see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result { let Ty { hir_id, span: _, kind } = typ; try_visit!(visitor.visit_id(*hir_id)); @@ -1047,8 +1031,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) - V::Result::output() } -/// For an explanation of what it means for a const arg to be unambig, see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v>, @@ -1062,8 +1044,6 @@ pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>( } } -/// For an explanation of what it means for a const arg to be ambig, see the dev-guide: -/// https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html pub fn walk_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, From 34ddd59e4544e77464fd6230bc354d0753987800 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Wed, 2 Jul 2025 22:09:04 -0700 Subject: [PATCH 006/242] Improve settings tree title and descriptions - All settings are now phrased in the imperative form stating what the setting does rather than talking about what it controls. (E.g.: "Show `Debug` action." instead of "Whether to show `Debug` action" - Categories are now displayed in title case - Categories are now sorted lexicographically - General category is removed (and all the settings are moved to the top level) - Language for a few descriptions is made a bit less ambiguous --- .../crates/rust-analyzer/src/config.rs | 606 +++++++++++------ .../docs/book/src/configuration_generated.md | 292 ++++---- .../rust-analyzer/editors/code/package.json | 639 ++++++++++-------- 3 files changed, 906 insertions(+), 631 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index e716d1407522..3f700862280f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -61,233 +61,312 @@ pub enum MaxSubstitutionLength { Limit(usize), } -// Defines the server-side configuration of the rust-analyzer. We generate -// *parts* of VS Code's `package.json` config from this. Run `cargo test` to -// re-generate that file. +// Defines the server-side configuration of the rust-analyzer. We generate *parts* of VS Code's +// `package.json` config from this. Run `cargo test` to re-generate that file. // -// However, editor specific config, which the server doesn't know about, should -// be specified directly in `package.json`. +// However, editor specific config, which the server doesn't know about, should be specified +// directly in `package.json`. // -// To deprecate an option by replacing it with another name use `new_name` | `old_name` so that we keep -// parsing the old name. +// To deprecate an option by replacing it with another name use `new_name` | `old_name` so that we +// keep parsing the old name. config_data! { - /// Configs that apply on a workspace-wide scope. There are 2 levels on which a global configuration can be configured + /// Configs that apply on a workspace-wide scope. There are 2 levels on which a global + /// configuration can be configured /// - /// 1. `rust-analyzer.toml` file under user's config directory (e.g ~/.config/rust-analyzer/rust-analyzer.toml) + /// 1. `rust-analyzer.toml` file under user's config directory (e.g + /// ~/.config/rust-analyzer/rust-analyzer.toml) /// 2. Client's own configurations (e.g `settings.json` on VS Code) /// - /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle. + /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen + /// by the nearest first principle. global: struct GlobalDefaultConfigData <- GlobalConfigInput -> { /// Warm up caches on project load. cachePriming_enable: bool = true, - /// How many worker threads to handle priming caches. The default `0` means to pick automatically. + + /// How many worker threads to handle priming caches. The default `0` means to pick + /// automatically. cachePriming_numThreads: NumThreads = NumThreads::Physical, /// Custom completion snippets. - completion_snippets_custom: FxIndexMap = Config::completion_snippets_default(), + completion_snippets_custom: FxIndexMap = + Config::completion_snippets_default(), - - /// These paths (file/directories) will be ignored by rust-analyzer. They are - /// relative to the workspace root, and globs are not supported. You may - /// also need to add the folders to Code's `files.watcherExclude`. + /// List of files to ignore + /// + /// These paths (file/directories) will be ignored by rust-analyzer. They are relative to + /// the workspace root, and globs are not supported. You may also need to add the folders to + /// Code's `files.watcherExclude`. files_exclude | files_excludeDirs: Vec = vec![], - - - /// Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`). + /// Highlight related return values while the cursor is on any `match`, `if`, or match arm + /// arrow (`=>`). highlightRelated_branchExitPoints_enable: bool = true, - /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. + + /// Highlight related references while the cursor is on `break`, `loop`, `while`, or `for` + /// keywords. highlightRelated_breakPoints_enable: bool = true, - /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure. + + /// Highlight all captures of a closure while the cursor is on the `|` or move keyword of a closure. highlightRelated_closureCaptures_enable: bool = true, - /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). + + /// Highlight all exit points while the cursor is on any `return`, `?`, `fn`, or return type + /// arrow (`->`). highlightRelated_exitPoints_enable: bool = true, - /// Enables highlighting of related references while the cursor is on any identifier. + + /// Highlight related references while the cursor is on any identifier. highlightRelated_references_enable: bool = true, - /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords. + + /// Highlight all break points for a loop or block context while the cursor is on any + /// `async` or `await` keywords. highlightRelated_yieldPoints_enable: bool = true, - /// Whether to show `Debug` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_debug_enable: bool = true, - /// Whether to show HoverActions in Rust files. - hover_actions_enable: bool = true, - /// Whether to show `Go to Type Definition` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_gotoTypeDef_enable: bool = true, - /// Whether to show `Implementations` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_implementations_enable: bool = true, - /// Whether to show `References` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_references_enable: bool = false, - /// Whether to show `Run` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` is set. - hover_actions_run_enable: bool = true, - /// Whether to show `Update Test` action. Only applies when - /// `#rust-analyzer.hover.actions.enable#` and `#rust-analyzer.hover.actions.run.enable#` are set. - hover_actions_updateTest_enable: bool = true, + /// Show `Debug` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_debug_enable: bool = true, - /// Whether to show documentation on hover. - hover_documentation_enable: bool = true, - /// Whether to show keyword hover popups. Only applies when + /// Show HoverActions in Rust files. + hover_actions_enable: bool = true, + + /// Show `Go to Type Definition` action. Only applies when + /// `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_gotoTypeDef_enable: bool = true, + + /// Show `Implementations` action. Only applies when `#rust-analyzer.hover.actions.enable#` + /// is set. + hover_actions_implementations_enable: bool = true, + + /// Show `References` action. Only applies when `#rust-analyzer.hover.actions.enable#` is + /// set. + hover_actions_references_enable: bool = false, + + /// Show `Run` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set. + hover_actions_run_enable: bool = true, + + /// Show `Update Test` action. Only applies when `#rust-analyzer.hover.actions.enable#` and + /// `#rust-analyzer.hover.actions.run.enable#` are set. + hover_actions_updateTest_enable: bool = true, + + /// Show documentation on hover. + hover_documentation_enable: bool = true, + + /// Show keyword hover popups. Only applies when /// `#rust-analyzer.hover.documentation.enable#` is set. - hover_documentation_keywords_enable: bool = true, - /// Whether to show drop glue information on hover. - hover_dropGlue_enable: bool = true, + hover_documentation_keywords_enable: bool = true, + + /// Show drop glue information on hover. + hover_dropGlue_enable: bool = true, + /// Use markdown syntax for links on hover. hover_links_enable: bool = true, - /// Whether to show what types are used as generic arguments in calls etc. on hover, and what is their max length to show such types, beyond it they will be shown with ellipsis. + + /// Show what types are used as generic arguments in calls etc. on hover, and limit the max + /// length to show such types, beyond which they will be shown with ellipsis. /// - /// This can take three values: `null` means "unlimited", the string `"hide"` means to not show generic substitutions at all, and a number means to limit them to X characters. + /// This can take three values: `null` means "unlimited", the string `"hide"` means to not + /// show generic substitutions at all, and a number means to limit them to X characters. /// /// The default is 20 characters. - hover_maxSubstitutionLength: Option = Some(MaxSubstitutionLength::Limit(20)), + hover_maxSubstitutionLength: Option = + Some(MaxSubstitutionLength::Limit(20)), + /// How to render the align information in a memory layout hover. - hover_memoryLayout_alignment: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), - /// Whether to show memory layout data on hover. + hover_memoryLayout_alignment: Option = + Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), + + /// Show memory layout data on hover. hover_memoryLayout_enable: bool = true, + /// How to render the niche information in a memory layout hover. hover_memoryLayout_niches: Option = Some(false), + /// How to render the offset information in a memory layout hover. - hover_memoryLayout_offset: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), + hover_memoryLayout_offset: Option = + Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), + /// How to render the padding information in a memory layout hover. hover_memoryLayout_padding: Option = None, + /// How to render the size information in a memory layout hover. - hover_memoryLayout_size: Option = Some(MemoryLayoutHoverRenderKindDef::Both), + hover_memoryLayout_size: Option = + Some(MemoryLayoutHoverRenderKindDef::Both), /// How many variants of an enum to display when hovering on. Show none if empty. hover_show_enumVariants: Option = Some(5), - /// How many fields of a struct, variant or union to display when hovering on. Show none if empty. + + /// How many fields of a struct, variant or union to display when hovering on. Show none if + /// empty. hover_show_fields: Option = Some(5), + /// How many associated items of a trait to display when hovering a trait. hover_show_traitAssocItems: Option = None, - /// Whether to show inlay type hints for binding modes. - inlayHints_bindingModeHints_enable: bool = false, - /// Whether to show inlay type hints for method chains. - inlayHints_chainingHints_enable: bool = true, - /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to. - inlayHints_closingBraceHints_enable: bool = true, + /// Show inlay type hints for binding modes. + inlayHints_bindingModeHints_enable: bool = false, + + /// Show inlay type hints for method chains. + inlayHints_chainingHints_enable: bool = true, + + /// Show inlay hints after a closing `}` to indicate what item it belongs to. + inlayHints_closingBraceHints_enable: bool = true, + /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1 /// to always show them). - inlayHints_closingBraceHints_minLines: usize = 25, - /// Whether to show inlay hints for closure captures. - inlayHints_closureCaptureHints_enable: bool = false, - /// Whether to show inlay type hints for return types of closures. - inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = ClosureReturnTypeHintsDef::Never, - /// Closure notation in type and chaining inlay hints. - inlayHints_closureStyle: ClosureStyle = ClosureStyle::ImplFn, - /// Whether to show enum variant discriminant hints. - inlayHints_discriminantHints_enable: DiscriminantHintsDef = DiscriminantHintsDef::Never, - /// Whether to show inlay hints for type adjustments. - inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = AdjustmentHintsDef::Never, - /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. - inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false, - /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). - inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = AdjustmentHintsModeDef::Prefix, - /// Whether to show const generic parameter name inlay hints. - inlayHints_genericParameterHints_const_enable: bool= true, - /// Whether to show generic lifetime parameter name inlay hints. - inlayHints_genericParameterHints_lifetime_enable: bool = false, - /// Whether to show generic type parameter name inlay hints. - inlayHints_genericParameterHints_type_enable: bool = false, - /// Whether to show implicit drop hints. - inlayHints_implicitDrops_enable: bool = false, - /// Whether to show inlay hints for the implied type parameter `Sized` bound. - inlayHints_implicitSizedBoundHints_enable: bool = false, - /// Whether to show inlay type hints for elided lifetimes in function signatures. - inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never, - /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. - inlayHints_lifetimeElisionHints_useParameterNames: bool = false, - /// Maximum length for inlay hints. Set to null to have an unlimited length. - inlayHints_maxLength: Option = Some(25), - /// Whether to show function parameter name inlay hints at the call - /// site. - inlayHints_parameterHints_enable: bool = true, - /// Whether to show exclusive range inlay hints. - inlayHints_rangeExclusiveHints_enable: bool = false, - /// Whether to show inlay hints for compiler inserted reborrows. - /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. - inlayHints_reborrowHints_enable: ReborrowHintsDef = ReborrowHintsDef::Never, - /// Whether to render leading colons for type hints, and trailing colons for parameter hints. - inlayHints_renderColons: bool = true, - /// Whether to show inlay type hints for variables. - inlayHints_typeHints_enable: bool = true, - /// Whether to hide inlay type hints for `let` statements that initialize to a closure. - /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. - inlayHints_typeHints_hideClosureInitialization: bool = false, - /// Whether to hide inlay parameter type hints for closures. - inlayHints_typeHints_hideClosureParameter:bool = false, - /// Whether to hide inlay type hints for constructors. - inlayHints_typeHints_hideNamedConstructor: bool = false, + inlayHints_closingBraceHints_minLines: usize = 25, - /// Enables the experimental support for interpreting tests. + /// Show inlay hints for closure captures. + inlayHints_closureCaptureHints_enable: bool = false, + + /// Show inlay type hints for return types of closures. + inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = + ClosureReturnTypeHintsDef::Never, + + /// Closure notation in type and chaining inlay hints. + inlayHints_closureStyle: ClosureStyle = ClosureStyle::ImplFn, + + /// Show enum variant discriminant hints. + inlayHints_discriminantHints_enable: DiscriminantHintsDef = + DiscriminantHintsDef::Never, + + /// Show inlay hints for type adjustments. + inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = + AdjustmentHintsDef::Never, + + /// Hide inlay hints for type adjustments outside of `unsafe` blocks. + inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false, + + /// Show inlay hints as postfix ops (`.*` instead of `*`, etc). + inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = + AdjustmentHintsModeDef::Prefix, + + /// Show const generic parameter name inlay hints. + inlayHints_genericParameterHints_const_enable: bool = true, + + /// Show generic lifetime parameter name inlay hints. + inlayHints_genericParameterHints_lifetime_enable: bool = false, + + /// Show generic type parameter name inlay hints. + inlayHints_genericParameterHints_type_enable: bool = false, + + /// Show implicit drop hints. + inlayHints_implicitDrops_enable: bool = false, + + /// Show inlay hints for the implied type parameter `Sized` bound. + inlayHints_implicitSizedBoundHints_enable: bool = false, + + /// Show inlay type hints for elided lifetimes in function signatures. + inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never, + + /// Prefer using parameter names as the name for elided lifetime hints if possible. + inlayHints_lifetimeElisionHints_useParameterNames: bool = false, + + /// Maximum length for inlay hints. Set to null to have an unlimited length. + inlayHints_maxLength: Option = Some(25), + + /// Show function parameter name inlay hints at the call site. + inlayHints_parameterHints_enable: bool = true, + + /// Show exclusive range inlay hints. + inlayHints_rangeExclusiveHints_enable: bool = false, + + /// Show inlay hints for compiler inserted reborrows. + /// + /// This setting is deprecated in favor of + /// #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. + inlayHints_reborrowHints_enable: ReborrowHintsDef = ReborrowHintsDef::Never, + + /// Whether to render leading colons for type hints, and trailing colons for parameter hints. + inlayHints_renderColons: bool = true, + + /// Show inlay type hints for variables. + inlayHints_typeHints_enable: bool = true, + + /// Hide inlay type hints for `let` statements that initialize to a closure. + /// + /// Only applies to closures with blocks, same as + /// `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. + inlayHints_typeHints_hideClosureInitialization: bool = false, + + /// Hide inlay parameter type hints for closures. + inlayHints_typeHints_hideClosureParameter: bool = false, + + /// Hide inlay type hints for constructors. + inlayHints_typeHints_hideNamedConstructor: bool = false, + + /// Enable the experimental support for interpreting tests. interpret_tests: bool = false, /// Join lines merges consecutive declaration and initialization of an assignment. joinLines_joinAssignments: bool = true, + /// Join lines inserts else between consecutive ifs. joinLines_joinElseIf: bool = true, + /// Join lines removes trailing commas. joinLines_removeTrailingComma: bool = true, + /// Join lines unwraps trivial blocks. joinLines_unwrapTrivialBlock: bool = true, - /// Whether to show `Debug` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_debug_enable: bool = true, - /// Whether to show CodeLens in Rust files. - lens_enable: bool = true, - /// Whether to show `Implementations` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_implementations_enable: bool = true, + /// Show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set. + lens_debug_enable: bool = true, + + /// Show CodeLens in Rust files. + lens_enable: bool = true, + + /// Show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set. + lens_implementations_enable: bool = true, + /// Where to render annotations. lens_location: AnnotationLocation = AnnotationLocation::AboveName, - /// Whether to show `References` lens for Struct, Enum, and Union. - /// Only applies when `#rust-analyzer.lens.enable#` is set. + + /// Show `References` lens for Struct, Enum, and Union. Only applies when + /// `#rust-analyzer.lens.enable#` is set. lens_references_adt_enable: bool = false, - /// Whether to show `References` lens for Enum Variants. - /// Only applies when `#rust-analyzer.lens.enable#` is set. + + /// Show `References` lens for Enum Variants. Only applies when + /// `#rust-analyzer.lens.enable#` is set. lens_references_enumVariant_enable: bool = false, - /// Whether to show `Method References` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. + + /// Show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. lens_references_method_enable: bool = false, - /// Whether to show `References` lens for Trait. - /// Only applies when `#rust-analyzer.lens.enable#` is set. + + /// Show `References` lens for Trait. Only applies when `#rust-analyzer.lens.enable#` is + /// set. lens_references_trait_enable: bool = false, - /// Whether to show `Run` lens. Only applies when - /// `#rust-analyzer.lens.enable#` is set. - lens_run_enable: bool = true, - /// Whether to show `Update Test` lens. Only applies when - /// `#rust-analyzer.lens.enable#` and `#rust-analyzer.lens.run.enable#` are set. + + /// Show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set. + lens_run_enable: bool = true, + + /// Show `Update Test` lens. Only applies when `#rust-analyzer.lens.enable#` and + /// `#rust-analyzer.lens.run.enable#` are set. lens_updateTest_enable: bool = true, - /// Disable project auto-discovery in favor of explicitly specified set - /// of projects. + /// Disable project auto-discovery in favor of explicitly specified set of projects. /// - /// Elements must be paths pointing to `Cargo.toml`, - /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON - /// objects in `rust-project.json` format. + /// Elements must be paths pointing to `Cargo.toml`, `rust-project.json`, `.rs` files (which + /// will be treated as standalone files) or JSON objects in `rust-project.json` format. linkedProjects: Vec = vec![], /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. - lru_capacity: Option = None, - /// Sets the LRU capacity of the specified queries. + lru_capacity: Option = None, + + /// The LRU capacity of the specified queries. lru_query_capacities: FxHashMap, u16> = FxHashMap::default(), - /// Whether to show `can't find Cargo.toml` error message. - notifications_cargoTomlNotFound: bool = true, + /// Show `can't find Cargo.toml` error message. + notifications_cargoTomlNotFound: bool = true, - /// How many worker threads in the main loop. The default `null` means to pick automatically. + /// The number of worker threads in the main loop. The default `null` means to pick + /// automatically. numThreads: Option = None, /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set. procMacro_attributes_enable: bool = true, + /// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`. - procMacro_enable: bool = true, + procMacro_enable: bool = true, + /// Internal config, path to proc-macro server executable. - procMacro_server: Option = None, + procMacro_server: Option = None, /// Exclude imports from find-all-references. references_excludeImports: bool = false, @@ -300,31 +379,41 @@ config_data! { /// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra /// doc links. semanticHighlighting_doc_comment_inject_enable: bool = true, - /// Whether the server is allowed to emit non-standard tokens and modifiers. + + /// Emit non-standard tokens and modifiers + /// + /// When enabled, rust-analyzer will emit tokens and modifiers that are not part of the + /// standard set of semantic tokens. semanticHighlighting_nonStandardTokens: bool = true, + /// Use semantic tokens for operators. /// /// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when /// they are tagged with modifiers. semanticHighlighting_operator_enable: bool = true, + /// Use specialized semantic tokens for operators. /// /// When enabled, rust-analyzer will emit special token types for operator tokens instead /// of the generic `operator` token type. semanticHighlighting_operator_specialization_enable: bool = false, + /// Use semantic tokens for punctuation. /// /// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when /// they are tagged with modifiers or have a special role. semanticHighlighting_punctuation_enable: bool = false, + /// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro /// calls. semanticHighlighting_punctuation_separate_macro_bang: bool = false, + /// Use specialized semantic tokens for punctuation. /// /// When enabled, rust-analyzer will emit special token types for punctuation tokens instead /// of the generic `punctuation` token type. semanticHighlighting_punctuation_specialization_enable: bool = false, + /// Use semantic tokens for strings. /// /// In some editors (e.g. vscode) semantic tokens override other highlighting grammars. @@ -333,16 +422,21 @@ config_data! { semanticHighlighting_strings_enable: bool = true, /// Show full signature of the callable. Only shows parameters if disabled. - signatureInfo_detail: SignatureDetail = SignatureDetail::Full, + signatureInfo_detail: SignatureDetail = SignatureDetail::Full, + /// Show documentation. - signatureInfo_documentation_enable: bool = true, + signatureInfo_documentation_enable: bool = true, /// Specify the characters allowed to invoke special on typing triggers. - /// - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression + /// + /// - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing + /// expression /// - typing `=` between two expressions adds `;` when in statement position - /// - typing `=` to turn an assignment into an equality comparison removes `;` when in expression position + /// - typing `=` to turn an assignment into an equality comparison removes `;` when in + /// expression position /// - typing `.` in a chain method call auto-indents - /// - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression + /// - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the + /// expression /// - typing `{` in a use item adds a closing `}` in the right place /// - typing `>` to complete a return type `->` will insert a whitespace after it /// - typing `<` in a path or type position inserts a closing `>` after the path or type. @@ -374,8 +468,8 @@ config_data! { /// /// **Warning**: This format is provisional and subject to change. /// - /// [`DiscoverWorkspaceConfig::command`] *must* return a JSON object - /// corresponding to `DiscoverProjectData::Finished`: + /// [`DiscoverWorkspaceConfig::command`] *must* return a JSON object corresponding to + /// `DiscoverProjectData::Finished`: /// /// ```norun /// #[derive(Debug, Clone, Deserialize, Serialize)] @@ -405,12 +499,11 @@ config_data! { /// } /// ``` /// - /// It is encouraged, but not required, to use the other variants on - /// `DiscoverProjectData` to provide a more polished end-user experience. + /// It is encouraged, but not required, to use the other variants on `DiscoverProjectData` + /// to provide a more polished end-user experience. /// - /// `DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`, - /// which will be substituted with the JSON-serialized form of the following - /// enum: + /// `DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`, which will be + /// substituted with the JSON-serialized form of the following enum: /// /// ```norun /// #[derive(PartialEq, Clone, Debug, Serialize)] @@ -437,11 +530,10 @@ config_data! { /// } /// ``` /// - /// `DiscoverArgument::Path` is used to find and generate a `rust-project.json`, - /// and therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to - /// to update an existing workspace. As a reference for implementors, - /// buck2's `rust-project` will likely be useful: - /// https://github.com/facebook/buck2/tree/main/integrations/rust-project. + /// `DiscoverArgument::Path` is used to find and generate a `rust-project.json`, and + /// therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to to update an + /// existing workspace. As a reference for implementors, buck2's `rust-project` will likely + /// be useful: https://github.com/facebook/buck2/tree/main/integrations/rust-project. workspace_discoverConfig: Option = None, } } @@ -449,109 +541,154 @@ config_data! { config_data! { /// Local configurations can be defined per `SourceRoot`. This almost always corresponds to a `Crate`. local: struct LocalDefaultConfigData <- LocalConfigInput -> { - /// Whether to insert #[must_use] when generating `as_` methods - /// for enum variants. - assist_emitMustUse: bool = false, + /// Insert #[must_use] when generating `as_` methods for enum variants. + assist_emitMustUse: bool = false, + /// Placeholder expression to use for missing expressions in assists. - assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo, - /// When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible. + assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo, + + /// Prefer to use `Self` over the type name when inserting a type (e.g. in "fill match arms" assist). assist_preferSelf: bool = false, - /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check. + + /// Enable borrow checking for term search code assists. If set to false, also there will be + /// more suggestions, but some of them may not borrow-check. assist_termSearch_borrowcheck: bool = true, + /// Term search fuel in "units of work" for assists (Defaults to 1800). assist_termSearch_fuel: usize = 1800, - - /// Whether to automatically add a semicolon when completing unit-returning functions. + /// Automatically add a semicolon when completing unit-returning functions. /// /// In `match` arms it completes a comma instead. completion_addSemicolonToUnit: bool = true, - /// Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future. - completion_autoAwait_enable: bool = true, - /// Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them. - completion_autoIter_enable: bool = true, - /// Toggles the additional completions that automatically add imports when completed. - /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. - completion_autoimport_enable: bool = true, + + /// Show method calls and field accesses completions with `await` prefixed to them when + /// completing on a future. + completion_autoAwait_enable: bool = true, + + /// Show method call completions with `iter()` or `into_iter()` prefixed to them when + /// completing on a type that has them. + completion_autoIter_enable: bool = true, + + /// Show completions that automatically add imports when completed. + /// + /// Note that your client must specify the `additionalTextEdits` LSP client capability to + /// truly have this feature enabled. + completion_autoimport_enable: bool = true, + /// A list of full paths to items to exclude from auto-importing completions. /// /// Traits in this list won't have their methods suggested in completions unless the trait /// is in scope. /// - /// You can either specify a string path which defaults to type "always" or use the more verbose - /// form `{ "path": "path::to::item", type: "always" }`. + /// You can either specify a string path which defaults to type "always" or use the more + /// verbose form `{ "path": "path::to::item", type: "always" }`. /// - /// For traits the type "methods" can be used to only exclude the methods but not the trait itself. + /// For traits the type "methods" can be used to only exclude the methods but not the trait + /// itself. /// /// This setting also inherits `#rust-analyzer.completion.excludeTraits#`. completion_autoimport_exclude: Vec = vec![ AutoImportExclusion::Verbose { path: "core::borrow::Borrow".to_owned(), r#type: AutoImportExclusionType::Methods }, AutoImportExclusion::Verbose { path: "core::borrow::BorrowMut".to_owned(), r#type: AutoImportExclusionType::Methods }, ], - /// Toggles the additional completions that automatically show method calls and field accesses - /// with `self` prefixed to them when inside a method. - completion_autoself_enable: bool = true, - /// Whether to add parenthesis and argument snippets when completing function. - completion_callable_snippets: CallableCompletionDef = CallableCompletionDef::FillArguments, + + /// Show method calls and field access completions with `self` prefixed to them when + /// inside a method. + completion_autoself_enable: bool = true, + + /// Add parenthesis and argument snippets when completing function. + completion_callable_snippets: CallableCompletionDef = CallableCompletionDef::FillArguments, + /// A list of full paths to traits whose methods to exclude from completion. /// - /// Methods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`. + /// Methods from these traits won't be completed, even if the trait is in scope. However, + /// they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or + /// `T where T: Trait`. /// /// Note that the trait themselves can still be completed. completion_excludeTraits: Vec = Vec::new(), - /// Whether to show full function/method signatures in completion docs. + + /// Show full function / method signatures in completion docs. completion_fullFunctionSignatures_enable: bool = false, - /// Whether to omit deprecated items from autocompletion. By default they are marked as deprecated but not hidden. + + /// Omit deprecated items from completions. By default they are marked as deprecated but not + /// hidden. completion_hideDeprecated: bool = false, + /// Maximum number of completions to return. If `None`, the limit is infinite. completion_limit: Option = None, - /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. - completion_postfix_enable: bool = true, - /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. + + /// Show postfix snippets like `dbg`, `if`, `not`, etc. + completion_postfix_enable: bool = true, + + /// Show completions of private items and fields that are defined in the current workspace + /// even if they are not visible at the current position. completion_privateEditable_enable: bool = false, - /// Whether to enable term search based snippets like `Some(foo.bar().baz())`. + + /// Enable term search based snippets like `Some(foo.bar().baz())`. completion_termSearch_enable: bool = false, + /// Term search fuel in "units of work" for autocompletion (Defaults to 1000). completion_termSearch_fuel: usize = 1000, /// List of rust-analyzer diagnostics to disable. diagnostics_disabled: FxHashSet = FxHashSet::default(), - /// Whether to show native rust-analyzer diagnostics. - diagnostics_enable: bool = true, - /// Whether to show experimental rust-analyzer diagnostics that might - /// have more false positives than usual. - diagnostics_experimental_enable: bool = false, - /// Map of prefixes to be substituted when parsing diagnostic file paths. - /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. + + /// Show native rust-analyzer diagnostics. + diagnostics_enable: bool = true, + + /// Show experimental rust-analyzer diagnostics that might have more false positives than + /// usual. + diagnostics_experimental_enable: bool = false, + + /// Map of prefixes to be substituted when parsing diagnostic file paths. This should be the + /// reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. diagnostics_remapPrefix: FxHashMap = FxHashMap::default(), - /// Whether to run additional style lints. - diagnostics_styleLints_enable: bool = false, + + /// Run additional style lints. + diagnostics_styleLints_enable: bool = false, + /// List of warnings that should be displayed with hint severity. /// - /// The warnings will be indicated by faded text or three dots in code - /// and will not show up in the `Problems Panel`. + /// The warnings will be indicated by faded text or three dots in code and will not show up + /// in the `Problems Panel`. diagnostics_warningsAsHint: Vec = vec![], + /// List of warnings that should be displayed with info severity. /// - /// The warnings will be indicated by a blue squiggly underline in code - /// and a blue icon in the `Problems Panel`. + /// The warnings will be indicated by a blue squiggly underline in code and a blue icon in + /// the `Problems Panel`. diagnostics_warningsAsInfo: Vec = vec![], - /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. - imports_granularity_enforce: bool = false, + /// Enforce the import granularity setting for all files. If set to false rust-analyzer will + /// try to keep import styles consistent per file. + imports_granularity_enforce: bool = false, + /// How imports should be grouped into use statements. - imports_granularity_group: ImportGranularityDef = ImportGranularityDef::Crate, - /// Group inserted imports by the [following order](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are separated by newlines. - imports_group_enable: bool = true, - /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. - imports_merge_glob: bool = true, + imports_granularity_group: ImportGranularityDef = ImportGranularityDef::Crate, + + /// Group inserted imports by the [following + /// order](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are + /// separated by newlines. + imports_group_enable: bool = true, + + /// Allow import insertion to merge new imports into single path glob imports like `use + /// std::fmt::*;`. + imports_merge_glob: bool = true, + /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate. imports_preferNoStd | imports_prefer_no_std: bool = false, - /// Whether to prefer import paths containing a `prelude` module. - imports_preferPrelude: bool = false, + + /// Prefer import paths containing a `prelude` module. + imports_preferPrelude: bool = false, + /// The path structure for newly inserted paths to use. - imports_prefix: ImportPrefixDef = ImportPrefixDef::ByCrate, - /// Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;". + imports_prefix: ImportPrefixDef = ImportPrefixDef::ByCrate, + + /// Prefix external (including std, core) crate imports with `::`. + /// + /// E.g. `use ::std::io::Read;`. imports_prefixExternPrelude: bool = false, } } @@ -3203,8 +3340,10 @@ fn schema(fields: &[SchemaField]) -> serde_json::Value { .iter() .map(|(field, ty, doc, default)| { let name = field.replace('_', "."); - let category = - name.find('.').map(|end| String::from(&name[..end])).unwrap_or("general".into()); + let category = name + .split_once(".") + .map(|(category, _name)| to_title_case(category)) + .unwrap_or("rust-analyzer".into()); let name = format!("rust-analyzer.{name}"); let props = field_props(field, ty, doc, default); serde_json::json!({ @@ -3218,6 +3357,29 @@ fn schema(fields: &[SchemaField]) -> serde_json::Value { map.into() } +/// Translate a field name to a title case string suitable for use in the category names on the +/// vscode settings page. +/// +/// First letter of word should be uppercase, if an uppercase letter is encountered, add a space +/// before it e.g. "fooBar" -> "Foo Bar", "fooBarBaz" -> "Foo Bar Baz", "foo" -> "Foo" +/// +/// This likely should be in stdx (or just use heck instead), but it doesn't handle any edge cases +/// and is intentionally simple. +fn to_title_case(s: &str) -> String { + let mut result = String::with_capacity(s.len()); + let mut chars = s.chars(); + if let Some(first) = chars.next() { + result.push(first.to_ascii_uppercase()); + for c in chars { + if c.is_uppercase() { + result.push(' '); + } + result.push(c); + } + } + result +} + fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value { let doc = doc_comment_to_string(doc); let doc = doc.trim_end_matches('\n'); diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index ebac26e1d60a..05299f1d017e 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -2,8 +2,7 @@ Default: `false` -Whether to insert #[must_use] when generating `as_` methods -for enum variants. +Insert #[must_use] when generating `as_` methods for enum variants. ## rust-analyzer.assist.expressionFillDefault {#assist.expressionFillDefault} @@ -17,14 +16,15 @@ Placeholder expression to use for missing expressions in assists. Default: `false` -When inserting a type (e.g. in "fill match arms" assist), prefer to use `Self` over the type name where possible. +Prefer to use `Self` over the type name when inserting a type (e.g. in "fill match arms" assist). ## rust-analyzer.assist.termSearch.borrowcheck {#assist.termSearch.borrowcheck} Default: `true` -Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check. +Enable borrow checking for term search code assists. If set to false, also there will be +more suggestions, but some of them may not borrow-check. ## rust-analyzer.assist.termSearch.fuel {#assist.termSearch.fuel} @@ -45,7 +45,8 @@ Warm up caches on project load. Default: `"physical"` -How many worker threads to handle priming caches. The default `0` means to pick automatically. +How many worker threads to handle priming caches. The default `0` means to pick +automatically. ## rust-analyzer.cargo.allTargets {#cargo.allTargets} @@ -358,7 +359,7 @@ check will be performed. Default: `true` -Whether to automatically add a semicolon when completing unit-returning functions. +Automatically add a semicolon when completing unit-returning functions. In `match` arms it completes a comma instead. @@ -367,22 +368,26 @@ In `match` arms it completes a comma instead. Default: `true` -Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future. +Show method calls and field accesses completions with `await` prefixed to them when +completing on a future. ## rust-analyzer.completion.autoIter.enable {#completion.autoIter.enable} Default: `true` -Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them. +Show method call completions with `iter()` or `into_iter()` prefixed to them when +completing on a type that has them. ## rust-analyzer.completion.autoimport.enable {#completion.autoimport.enable} Default: `true` -Toggles the additional completions that automatically add imports when completed. -Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. +Show completions that automatically add imports when completed. + +Note that your client must specify the `additionalTextEdits` LSP client capability to +truly have this feature enabled. ## rust-analyzer.completion.autoimport.exclude {#completion.autoimport.exclude} @@ -406,10 +411,11 @@ A list of full paths to items to exclude from auto-importing completions. Traits in this list won't have their methods suggested in completions unless the trait is in scope. -You can either specify a string path which defaults to type "always" or use the more verbose -form `{ "path": "path::to::item", type: "always" }`. +You can either specify a string path which defaults to type "always" or use the more +verbose form `{ "path": "path::to::item", type: "always" }`. -For traits the type "methods" can be used to only exclude the methods but not the trait itself. +For traits the type "methods" can be used to only exclude the methods but not the trait +itself. This setting also inherits `#rust-analyzer.completion.excludeTraits#`. @@ -418,15 +424,15 @@ This setting also inherits `#rust-analyzer.completion.excludeTraits#`. Default: `true` -Toggles the additional completions that automatically show method calls and field accesses -with `self` prefixed to them when inside a method. +Show method calls and field access completions with `self` prefixed to them when +inside a method. ## rust-analyzer.completion.callable.snippets {#completion.callable.snippets} Default: `"fill_arguments"` -Whether to add parenthesis and argument snippets when completing function. +Add parenthesis and argument snippets when completing function. ## rust-analyzer.completion.excludeTraits {#completion.excludeTraits} @@ -435,7 +441,9 @@ Default: `[]` A list of full paths to traits whose methods to exclude from completion. -Methods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`. +Methods from these traits won't be completed, even if the trait is in scope. However, +they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or +`T where T: Trait`. Note that the trait themselves can still be completed. @@ -444,14 +452,15 @@ Note that the trait themselves can still be completed. Default: `false` -Whether to show full function/method signatures in completion docs. +Show full function / method signatures in completion docs. ## rust-analyzer.completion.hideDeprecated {#completion.hideDeprecated} Default: `false` -Whether to omit deprecated items from autocompletion. By default they are marked as deprecated but not hidden. +Omit deprecated items from completions. By default they are marked as deprecated but not +hidden. ## rust-analyzer.completion.limit {#completion.limit} @@ -465,14 +474,15 @@ Maximum number of completions to return. If `None`, the limit is infinite. Default: `true` -Whether to show postfix snippets like `dbg`, `if`, `not`, etc. +Show postfix snippets like `dbg`, `if`, `not`, etc. ## rust-analyzer.completion.privateEditable.enable {#completion.privateEditable.enable} Default: `false` -Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. +Show completions of private items and fields that are defined in the current workspace +even if they are not visible at the current position. ## rust-analyzer.completion.snippets.custom {#completion.snippets.custom} @@ -529,7 +539,7 @@ Custom completion snippets. Default: `false` -Whether to enable term search based snippets like `Some(foo.bar().baz())`. +Enable term search based snippets like `Some(foo.bar().baz())`. ## rust-analyzer.completion.termSearch.fuel {#completion.termSearch.fuel} @@ -550,30 +560,30 @@ List of rust-analyzer diagnostics to disable. Default: `true` -Whether to show native rust-analyzer diagnostics. +Show native rust-analyzer diagnostics. ## rust-analyzer.diagnostics.experimental.enable {#diagnostics.experimental.enable} Default: `false` -Whether to show experimental rust-analyzer diagnostics that might -have more false positives than usual. +Show experimental rust-analyzer diagnostics that might have more false positives than +usual. ## rust-analyzer.diagnostics.remapPrefix {#diagnostics.remapPrefix} Default: `{}` -Map of prefixes to be substituted when parsing diagnostic file paths. -This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. +Map of prefixes to be substituted when parsing diagnostic file paths. This should be the +reverse mapping of what is passed to `rustc` as `--remap-path-prefix`. ## rust-analyzer.diagnostics.styleLints.enable {#diagnostics.styleLints.enable} Default: `false` -Whether to run additional style lints. +Run additional style lints. ## rust-analyzer.diagnostics.warningsAsHint {#diagnostics.warningsAsHint} @@ -582,8 +592,8 @@ Default: `[]` List of warnings that should be displayed with hint severity. -The warnings will be indicated by faded text or three dots in code -and will not show up in the `Problems Panel`. +The warnings will be indicated by faded text or three dots in code and will not show up +in the `Problems Panel`. ## rust-analyzer.diagnostics.warningsAsInfo {#diagnostics.warningsAsInfo} @@ -592,17 +602,19 @@ Default: `[]` List of warnings that should be displayed with info severity. -The warnings will be indicated by a blue squiggly underline in code -and a blue icon in the `Problems Panel`. +The warnings will be indicated by a blue squiggly underline in code and a blue icon in +the `Problems Panel`. ## rust-analyzer.files.exclude {#files.exclude} Default: `[]` -These paths (file/directories) will be ignored by rust-analyzer. They are -relative to the workspace root, and globs are not supported. You may -also need to add the folders to Code's `files.watcherExclude`. +List of files to ignore + +These paths (file/directories) will be ignored by rust-analyzer. They are relative to +the workspace root, and globs are not supported. You may also need to add the folders to +Code's `files.watcherExclude`. ## rust-analyzer.files.watcher {#files.watcher} @@ -616,64 +628,67 @@ Controls file watching implementation. Default: `true` -Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`). +Highlight related return values while the cursor is on any `match`, `if`, or match arm +arrow (`=>`). ## rust-analyzer.highlightRelated.breakPoints.enable {#highlightRelated.breakPoints.enable} Default: `true` -Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. +Highlight related references while the cursor is on `break`, `loop`, `while`, or `for` +keywords. ## rust-analyzer.highlightRelated.closureCaptures.enable {#highlightRelated.closureCaptures.enable} Default: `true` -Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure. +Highlight all captures of a closure while the cursor is on the `|` or move keyword of a closure. ## rust-analyzer.highlightRelated.exitPoints.enable {#highlightRelated.exitPoints.enable} Default: `true` -Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). +Highlight all exit points while the cursor is on any `return`, `?`, `fn`, or return type +arrow (`->`). ## rust-analyzer.highlightRelated.references.enable {#highlightRelated.references.enable} Default: `true` -Enables highlighting of related references while the cursor is on any identifier. +Highlight related references while the cursor is on any identifier. ## rust-analyzer.highlightRelated.yieldPoints.enable {#highlightRelated.yieldPoints.enable} Default: `true` -Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords. +Highlight all break points for a loop or block context while the cursor is on any +`async` or `await` keywords. ## rust-analyzer.hover.actions.debug.enable {#hover.actions.debug.enable} Default: `true` -Whether to show `Debug` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. +Show `Debug` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set. ## rust-analyzer.hover.actions.enable {#hover.actions.enable} Default: `true` -Whether to show HoverActions in Rust files. +Show HoverActions in Rust files. ## rust-analyzer.hover.actions.gotoTypeDef.enable {#hover.actions.gotoTypeDef.enable} Default: `true` -Whether to show `Go to Type Definition` action. Only applies when +Show `Go to Type Definition` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set. @@ -681,46 +696,45 @@ Whether to show `Go to Type Definition` action. Only applies when Default: `true` -Whether to show `Implementations` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. +Show `Implementations` action. Only applies when `#rust-analyzer.hover.actions.enable#` +is set. ## rust-analyzer.hover.actions.references.enable {#hover.actions.references.enable} Default: `false` -Whether to show `References` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. +Show `References` action. Only applies when `#rust-analyzer.hover.actions.enable#` is +set. ## rust-analyzer.hover.actions.run.enable {#hover.actions.run.enable} Default: `true` -Whether to show `Run` action. Only applies when -`#rust-analyzer.hover.actions.enable#` is set. +Show `Run` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set. ## rust-analyzer.hover.actions.updateTest.enable {#hover.actions.updateTest.enable} Default: `true` -Whether to show `Update Test` action. Only applies when -`#rust-analyzer.hover.actions.enable#` and `#rust-analyzer.hover.actions.run.enable#` are set. +Show `Update Test` action. Only applies when `#rust-analyzer.hover.actions.enable#` and +`#rust-analyzer.hover.actions.run.enable#` are set. ## rust-analyzer.hover.documentation.enable {#hover.documentation.enable} Default: `true` -Whether to show documentation on hover. +Show documentation on hover. ## rust-analyzer.hover.documentation.keywords.enable {#hover.documentation.keywords.enable} Default: `true` -Whether to show keyword hover popups. Only applies when +Show keyword hover popups. Only applies when `#rust-analyzer.hover.documentation.enable#` is set. @@ -728,7 +742,7 @@ Whether to show keyword hover popups. Only applies when Default: `true` -Whether to show drop glue information on hover. +Show drop glue information on hover. ## rust-analyzer.hover.links.enable {#hover.links.enable} @@ -742,9 +756,11 @@ Use markdown syntax for links on hover. Default: `20` -Whether to show what types are used as generic arguments in calls etc. on hover, and what is their max length to show such types, beyond it they will be shown with ellipsis. +Show what types are used as generic arguments in calls etc. on hover, and limit the max +length to show such types, beyond which they will be shown with ellipsis. -This can take three values: `null` means "unlimited", the string `"hide"` means to not show generic substitutions at all, and a number means to limit them to X characters. +This can take three values: `null` means "unlimited", the string `"hide"` means to not +show generic substitutions at all, and a number means to limit them to X characters. The default is 20 characters. @@ -760,7 +776,7 @@ How to render the align information in a memory layout hover. Default: `true` -Whether to show memory layout data on hover. +Show memory layout data on hover. ## rust-analyzer.hover.memoryLayout.niches {#hover.memoryLayout.niches} @@ -802,7 +818,8 @@ How many variants of an enum to display when hovering on. Show none if empty. Default: `5` -How many fields of a struct, variant or union to display when hovering on. Show none if empty. +How many fields of a struct, variant or union to display when hovering on. Show none if +empty. ## rust-analyzer.hover.show.traitAssocItems {#hover.show.traitAssocItems} @@ -816,7 +833,8 @@ How many associated items of a trait to display when hovering a trait. Default: `false` -Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. +Enforce the import granularity setting for all files. If set to false rust-analyzer will +try to keep import styles consistent per file. ## rust-analyzer.imports.granularity.group {#imports.granularity.group} @@ -830,14 +848,17 @@ How imports should be grouped into use statements. Default: `true` -Group inserted imports by the [following order](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are separated by newlines. +Group inserted imports by the [following +order](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are +separated by newlines. ## rust-analyzer.imports.merge.glob {#imports.merge.glob} Default: `true` -Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. +Allow import insertion to merge new imports into single path glob imports like `use +std::fmt::*;`. ## rust-analyzer.imports.preferNoStd {#imports.preferNoStd} @@ -851,7 +872,7 @@ Prefer to unconditionally use imports of the core and alloc crate, over the std Default: `false` -Whether to prefer import paths containing a `prelude` module. +Prefer import paths containing a `prelude` module. ## rust-analyzer.imports.prefix {#imports.prefix} @@ -865,28 +886,30 @@ The path structure for newly inserted paths to use. Default: `false` -Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;". +Prefix external (including std, core) crate imports with `::`. + +E.g. `use ::std::io::Read;`. ## rust-analyzer.inlayHints.bindingModeHints.enable {#inlayHints.bindingModeHints.enable} Default: `false` -Whether to show inlay type hints for binding modes. +Show inlay type hints for binding modes. ## rust-analyzer.inlayHints.chainingHints.enable {#inlayHints.chainingHints.enable} Default: `true` -Whether to show inlay type hints for method chains. +Show inlay type hints for method chains. ## rust-analyzer.inlayHints.closingBraceHints.enable {#inlayHints.closingBraceHints.enable} Default: `true` -Whether to show inlay hints after a closing `}` to indicate what item it belongs to. +Show inlay hints after a closing `}` to indicate what item it belongs to. ## rust-analyzer.inlayHints.closingBraceHints.minLines {#inlayHints.closingBraceHints.minLines} @@ -901,14 +924,14 @@ to always show them). Default: `false` -Whether to show inlay hints for closure captures. +Show inlay hints for closure captures. ## rust-analyzer.inlayHints.closureReturnTypeHints.enable {#inlayHints.closureReturnTypeHints.enable} Default: `"never"` -Whether to show inlay type hints for return types of closures. +Show inlay type hints for return types of closures. ## rust-analyzer.inlayHints.closureStyle {#inlayHints.closureStyle} @@ -922,77 +945,77 @@ Closure notation in type and chaining inlay hints. Default: `"never"` -Whether to show enum variant discriminant hints. +Show enum variant discriminant hints. ## rust-analyzer.inlayHints.expressionAdjustmentHints.enable {#inlayHints.expressionAdjustmentHints.enable} Default: `"never"` -Whether to show inlay hints for type adjustments. +Show inlay hints for type adjustments. ## rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe {#inlayHints.expressionAdjustmentHints.hideOutsideUnsafe} Default: `false` -Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. +Hide inlay hints for type adjustments outside of `unsafe` blocks. ## rust-analyzer.inlayHints.expressionAdjustmentHints.mode {#inlayHints.expressionAdjustmentHints.mode} Default: `"prefix"` -Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). +Show inlay hints as postfix ops (`.*` instead of `*`, etc). ## rust-analyzer.inlayHints.genericParameterHints.const.enable {#inlayHints.genericParameterHints.const.enable} Default: `true` -Whether to show const generic parameter name inlay hints. +Show const generic parameter name inlay hints. ## rust-analyzer.inlayHints.genericParameterHints.lifetime.enable {#inlayHints.genericParameterHints.lifetime.enable} Default: `false` -Whether to show generic lifetime parameter name inlay hints. +Show generic lifetime parameter name inlay hints. ## rust-analyzer.inlayHints.genericParameterHints.type.enable {#inlayHints.genericParameterHints.type.enable} Default: `false` -Whether to show generic type parameter name inlay hints. +Show generic type parameter name inlay hints. ## rust-analyzer.inlayHints.implicitDrops.enable {#inlayHints.implicitDrops.enable} Default: `false` -Whether to show implicit drop hints. +Show implicit drop hints. ## rust-analyzer.inlayHints.implicitSizedBoundHints.enable {#inlayHints.implicitSizedBoundHints.enable} Default: `false` -Whether to show inlay hints for the implied type parameter `Sized` bound. +Show inlay hints for the implied type parameter `Sized` bound. ## rust-analyzer.inlayHints.lifetimeElisionHints.enable {#inlayHints.lifetimeElisionHints.enable} Default: `"never"` -Whether to show inlay type hints for elided lifetimes in function signatures. +Show inlay type hints for elided lifetimes in function signatures. ## rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames {#inlayHints.lifetimeElisionHints.useParameterNames} Default: `false` -Whether to prefer using parameter names as the name for elided lifetime hints if possible. +Prefer using parameter names as the name for elided lifetime hints if possible. ## rust-analyzer.inlayHints.maxLength {#inlayHints.maxLength} @@ -1006,23 +1029,24 @@ Maximum length for inlay hints. Set to null to have an unlimited length. Default: `true` -Whether to show function parameter name inlay hints at the call -site. +Show function parameter name inlay hints at the call site. ## rust-analyzer.inlayHints.rangeExclusiveHints.enable {#inlayHints.rangeExclusiveHints.enable} Default: `false` -Whether to show exclusive range inlay hints. +Show exclusive range inlay hints. ## rust-analyzer.inlayHints.reborrowHints.enable {#inlayHints.reborrowHints.enable} Default: `"never"` -Whether to show inlay hints for compiler inserted reborrows. -This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. +Show inlay hints for compiler inserted reborrows. + +This setting is deprecated in favor of +#rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. ## rust-analyzer.inlayHints.renderColons {#inlayHints.renderColons} @@ -1036,36 +1060,38 @@ Whether to render leading colons for type hints, and trailing colons for paramet Default: `true` -Whether to show inlay type hints for variables. +Show inlay type hints for variables. ## rust-analyzer.inlayHints.typeHints.hideClosureInitialization {#inlayHints.typeHints.hideClosureInitialization} Default: `false` -Whether to hide inlay type hints for `let` statements that initialize to a closure. -Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. +Hide inlay type hints for `let` statements that initialize to a closure. + +Only applies to closures with blocks, same as +`#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. ## rust-analyzer.inlayHints.typeHints.hideClosureParameter {#inlayHints.typeHints.hideClosureParameter} Default: `false` -Whether to hide inlay parameter type hints for closures. +Hide inlay parameter type hints for closures. ## rust-analyzer.inlayHints.typeHints.hideNamedConstructor {#inlayHints.typeHints.hideNamedConstructor} Default: `false` -Whether to hide inlay type hints for constructors. +Hide inlay type hints for constructors. ## rust-analyzer.interpret.tests {#interpret.tests} Default: `false` -Enables the experimental support for interpreting tests. +Enable the experimental support for interpreting tests. ## rust-analyzer.joinLines.joinAssignments {#joinLines.joinAssignments} @@ -1100,23 +1126,21 @@ Join lines unwraps trivial blocks. Default: `true` -Whether to show `Debug` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. +Show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set. ## rust-analyzer.lens.enable {#lens.enable} Default: `true` -Whether to show CodeLens in Rust files. +Show CodeLens in Rust files. ## rust-analyzer.lens.implementations.enable {#lens.implementations.enable} Default: `true` -Whether to show `Implementations` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. +Show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set. ## rust-analyzer.lens.location {#lens.location} @@ -1130,60 +1154,56 @@ Where to render annotations. Default: `false` -Whether to show `References` lens for Struct, Enum, and Union. -Only applies when `#rust-analyzer.lens.enable#` is set. +Show `References` lens for Struct, Enum, and Union. Only applies when +`#rust-analyzer.lens.enable#` is set. ## rust-analyzer.lens.references.enumVariant.enable {#lens.references.enumVariant.enable} Default: `false` -Whether to show `References` lens for Enum Variants. -Only applies when `#rust-analyzer.lens.enable#` is set. +Show `References` lens for Enum Variants. Only applies when +`#rust-analyzer.lens.enable#` is set. ## rust-analyzer.lens.references.method.enable {#lens.references.method.enable} Default: `false` -Whether to show `Method References` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. +Show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set. ## rust-analyzer.lens.references.trait.enable {#lens.references.trait.enable} Default: `false` -Whether to show `References` lens for Trait. -Only applies when `#rust-analyzer.lens.enable#` is set. +Show `References` lens for Trait. Only applies when `#rust-analyzer.lens.enable#` is +set. ## rust-analyzer.lens.run.enable {#lens.run.enable} Default: `true` -Whether to show `Run` lens. Only applies when -`#rust-analyzer.lens.enable#` is set. +Show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set. ## rust-analyzer.lens.updateTest.enable {#lens.updateTest.enable} Default: `true` -Whether to show `Update Test` lens. Only applies when -`#rust-analyzer.lens.enable#` and `#rust-analyzer.lens.run.enable#` are set. +Show `Update Test` lens. Only applies when `#rust-analyzer.lens.enable#` and +`#rust-analyzer.lens.run.enable#` are set. ## rust-analyzer.linkedProjects {#linkedProjects} Default: `[]` -Disable project auto-discovery in favor of explicitly specified set -of projects. +Disable project auto-discovery in favor of explicitly specified set of projects. -Elements must be paths pointing to `Cargo.toml`, -`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON -objects in `rust-project.json` format. +Elements must be paths pointing to `Cargo.toml`, `rust-project.json`, `.rs` files (which +will be treated as standalone files) or JSON objects in `rust-project.json` format. ## rust-analyzer.lru.capacity {#lru.capacity} @@ -1197,21 +1217,22 @@ Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. Default: `{}` -Sets the LRU capacity of the specified queries. +The LRU capacity of the specified queries. ## rust-analyzer.notifications.cargoTomlNotFound {#notifications.cargoTomlNotFound} Default: `true` -Whether to show `can't find Cargo.toml` error message. +Show `can't find Cargo.toml` error message. ## rust-analyzer.numThreads {#numThreads} Default: `null` -How many worker threads in the main loop. The default `null` means to pick automatically. +The number of worker threads in the main loop. The default `null` means to pick +automatically. ## rust-analyzer.procMacro.attributes.enable {#procMacro.attributes.enable} @@ -1346,7 +1367,10 @@ doc links. Default: `true` -Whether the server is allowed to emit non-standard tokens and modifiers. +Emit non-standard tokens and modifiers + +When enabled, rust-analyzer will emit tokens and modifiers that are not part of the +standard set of semantic tokens. ## rust-analyzer.semanticHighlighting.operator.enable {#semanticHighlighting.operator.enable} @@ -1427,11 +1451,15 @@ Show documentation. Default: `"=."` Specify the characters allowed to invoke special on typing triggers. -- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression + +- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing + expression - typing `=` between two expressions adds `;` when in statement position -- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position +- typing `=` to turn an assignment into an equality comparison removes `;` when in + expression position - typing `.` in a chain method call auto-indents -- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression +- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the + expression - typing `{` in a use item adds a closing `}` in the right place - typing `>` to complete a return type `->` will insert a whitespace after it - typing `<` in a path or type position inserts a closing `>` after the path or type. @@ -1475,8 +1503,8 @@ Below is an example of a valid configuration: **Warning**: This format is provisional and subject to change. -[`DiscoverWorkspaceConfig::command`] *must* return a JSON object -corresponding to `DiscoverProjectData::Finished`: +[`DiscoverWorkspaceConfig::command`] *must* return a JSON object corresponding to +`DiscoverProjectData::Finished`: ```norun #[derive(Debug, Clone, Deserialize, Serialize)] @@ -1506,12 +1534,11 @@ As JSON, `DiscoverProjectData::Finished` is: } ``` -It is encouraged, but not required, to use the other variants on -`DiscoverProjectData` to provide a more polished end-user experience. +It is encouraged, but not required, to use the other variants on `DiscoverProjectData` +to provide a more polished end-user experience. -`DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`, -which will be substituted with the JSON-serialized form of the following -enum: +`DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`, which will be +substituted with the JSON-serialized form of the following enum: ```norun #[derive(PartialEq, Clone, Debug, Serialize)] @@ -1538,11 +1565,10 @@ Similarly, the JSON representation of `DiscoverArgument::Buildfile` is: } ``` -`DiscoverArgument::Path` is used to find and generate a `rust-project.json`, -and therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to -to update an existing workspace. As a reference for implementors, -buck2's `rust-project` will likely be useful: -https://github.com/facebook/buck2/tree/main/integrations/rust-project. +`DiscoverArgument::Path` is used to find and generate a `rust-project.json`, and +therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to to update an +existing workspace. As a reference for implementors, buck2's `rust-project` will likely +be useful: https://github.com/facebook/buck2/tree/main/integrations/rust-project. ## rust-analyzer.workspace.symbol.search.excludeImports {#workspace.symbol.search.excludeImports} diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 3cb4c21ee1fb..8953a30dacb2 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -354,35 +354,122 @@ ], "configuration": [ { - "title": "general", + "title": "Rust Analyzer" + }, + { + "title": "Assist" + }, + { + "title": "Cache Priming" + }, + { + "title": "Cargo" + }, + { + "title": "Cfg" + }, + { + "title": "Check" + }, + { + "title": "Completion" + }, + { + "title": "Debug" + }, + { + "title": "Diagnostics" + }, + { + "title": "Files" + }, + { + "title": "Highlight Related" + }, + { + "title": "Hover" + }, + { + "title": "Imports" + }, + { + "title": "Inlay Hints" + }, + { + "title": "Interpret" + }, + { + "title": "Join Lines" + }, + { + "title": "Lens" + }, + { + "title": "Lru" + }, + { + "title": "Notifications" + }, + { + "title": "Proc Macro" + }, + { + "title": "References" + }, + { + "title": "Runnables" + }, + { + "title": "Rustc" + }, + { + "title": "Rustfmt" + }, + { + "title": "Semantic Highlighting" + }, + { + "title": "Signature Info" + }, + { + "title": "Typing" + }, + { + "title": "Vfs" + }, + { + "title": "Workspace" + }, + { + "title": "rust-analyzer", "properties": { "rust-analyzer.restartServerOnConfigChange": { - "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.", + "description": "Restart the server automatically when settings that require a restart are changed.", "default": false, "type": "boolean" }, "rust-analyzer.showUnlinkedFileNotification": { - "markdownDescription": "Whether to show a notification for unlinked files asking the user to add the corresponding Cargo.toml to the linked projects setting.", + "description": "Show a notification for unlinked files, prompting the user to add the corresponding Cargo.toml to the linked projects setting.", "default": true, "type": "boolean" }, "rust-analyzer.showRequestFailedErrorNotification": { - "markdownDescription": "Whether to show error notifications for failing requests.", + "description": "Show error notifications when requests fail.", "default": true, "type": "boolean" }, "rust-analyzer.showDependenciesExplorer": { - "markdownDescription": "Whether to show the dependencies view.", + "description": "Show Rust Dependencies in the Explorer view.", "default": true, "type": "boolean" }, "rust-analyzer.showSyntaxTree": { - "markdownDescription": "Whether to show the syntax tree view.", + "description": "Show Syntax Tree in the Explorer view.", "default": false, "type": "boolean" }, "rust-analyzer.testExplorer": { - "markdownDescription": "Whether to show the test explorer.", + "description": "Show the Test Explorer view.", "default": false, "type": "boolean" }, @@ -394,7 +481,7 @@ } }, { - "title": "runnables", + "title": "Runnables", "properties": { "rust-analyzer.runnables.extraEnv": { "anyOf": [ @@ -452,7 +539,7 @@ } }, { - "title": "statusBar", + "title": "Status Bar", "properties": { "rust-analyzer.statusBar.clickAction": { "type": "string", @@ -524,7 +611,7 @@ } }, { - "title": "server", + "title": "Server", "properties": { "rust-analyzer.server.path": { "type": [ @@ -553,7 +640,7 @@ } }, { - "title": "trace", + "title": "Trace", "properties": { "rust-analyzer.trace.server": { "type": "string", @@ -580,7 +667,7 @@ } }, { - "title": "debug", + "title": "Debug", "properties": { "rust-analyzer.debug.engine": { "type": "string", @@ -625,7 +712,7 @@ } }, { - "title": "typing", + "title": "Typing", "properties": { "rust-analyzer.typing.continueCommentsOnNewline": { "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.", @@ -635,7 +722,7 @@ } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.previewRustcOutput": { "markdownDescription": "Whether to show the main part of the rendered rustc output of a diagnostic message.", @@ -653,17 +740,17 @@ "title": "$generated-start" }, { - "title": "assist", + "title": "Assist", "properties": { "rust-analyzer.assist.emitMustUse": { - "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.", + "markdownDescription": "Insert #[must_use] when generating `as_` methods for enum variants.", "default": false, "type": "boolean" } } }, { - "title": "assist", + "title": "Assist", "properties": { "rust-analyzer.assist.expressionFillDefault": { "markdownDescription": "Placeholder expression to use for missing expressions in assists.", @@ -681,27 +768,27 @@ } }, { - "title": "assist", + "title": "Assist", "properties": { "rust-analyzer.assist.preferSelf": { - "markdownDescription": "When inserting a type (e.g. in \"fill match arms\" assist), prefer to use `Self` over the type name where possible.", + "markdownDescription": "Prefer to use `Self` over the type name when inserting a type (e.g. in \"fill match arms\" assist).", "default": false, "type": "boolean" } } }, { - "title": "assist", + "title": "Assist", "properties": { "rust-analyzer.assist.termSearch.borrowcheck": { - "markdownDescription": "Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.", + "markdownDescription": "Enable borrow checking for term search code assists. If set to false, also there will be\nmore suggestions, but some of them may not borrow-check.", "default": true, "type": "boolean" } } }, { - "title": "assist", + "title": "Assist", "properties": { "rust-analyzer.assist.termSearch.fuel": { "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 1800).", @@ -712,7 +799,7 @@ } }, { - "title": "cachePriming", + "title": "Cache Priming", "properties": { "rust-analyzer.cachePriming.enable": { "markdownDescription": "Warm up caches on project load.", @@ -722,10 +809,10 @@ } }, { - "title": "cachePriming", + "title": "Cache Priming", "properties": { "rust-analyzer.cachePriming.numThreads": { - "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.", + "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick\nautomatically.", "default": "physical", "anyOf": [ { @@ -749,7 +836,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.allTargets": { "markdownDescription": "Pass `--all-targets` to cargo invocation.", @@ -759,7 +846,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.autoreload": { "markdownDescription": "Automatically refresh project info via `cargo metadata` on\n`Cargo.toml` or `.cargo/config.toml` changes.", @@ -769,7 +856,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.buildScripts.enable": { "markdownDescription": "Run build scripts (`build.rs`) for more precise code analysis.", @@ -779,7 +866,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.buildScripts.invocationStrategy": { "markdownDescription": "Specifies the invocation strategy to use when running the build scripts command.\nIf `per_workspace` is set, the command will be executed for each Rust workspace with the\nworkspace as the working directory.\nIf `once` is set, the command will be executed once with the opened project as the\nworking directory.\nThis config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`\nis set.", @@ -797,7 +884,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.buildScripts.overrideCommand": { "markdownDescription": "Override the command rust-analyzer uses to run build scripts and\nbuild procedural macros. The command is required to output json\nand should therefore include `--message-format=json` or a similar\noption.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#`.\n\nBy default, a cargo invocation will be constructed for the configured\ntargets and features, with the following base command line:\n\n```bash\ncargo check --quiet --workspace --message-format=json --all-targets --keep-going\n```\n.", @@ -813,7 +900,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.buildScripts.rebuildOnSave": { "markdownDescription": "Rerun proc-macros building/build-scripts running when proc-macro\nor build-script sources change and are saved.", @@ -823,7 +910,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.buildScripts.useRustcWrapper": { "markdownDescription": "Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to\navoid checking unnecessary things.", @@ -833,7 +920,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.cfgs": { "markdownDescription": "List of cfg options to enable with the given values.\n\nTo enable a name without a value, use `\"key\"`.\nTo enable a name with a value, use `\"key=value\"`.\nTo disable, prefix the entry with a `!`.", @@ -849,7 +936,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.extraArgs": { "markdownDescription": "Extra arguments that are passed to every cargo invocation.", @@ -862,7 +949,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.extraEnv": { "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.", @@ -872,7 +959,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.features": { "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.", @@ -898,7 +985,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.noDefaultFeatures": { "markdownDescription": "Whether to pass `--no-default-features` to cargo.", @@ -908,7 +995,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.noDeps": { "markdownDescription": "Whether to skip fetching dependencies. If set to \"true\", the analysis is performed\nentirely offline, and Cargo metadata for dependencies is not fetched.", @@ -918,7 +1005,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.sysroot": { "markdownDescription": "Relative path to the sysroot, or \"discover\" to try to automatically find it via\n\"rustc --print sysroot\".\n\nUnsetting this disables sysroot loading.\n\nThis option does not take effect until rust-analyzer is restarted.", @@ -931,7 +1018,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.sysrootSrc": { "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.", @@ -944,7 +1031,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.target": { "markdownDescription": "Compilation target override (target tuple).", @@ -957,7 +1044,7 @@ } }, { - "title": "cargo", + "title": "Cargo", "properties": { "rust-analyzer.cargo.targetDir": { "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` and initial build-script and proc-macro\nbuilding from locking the `Cargo.lock` at the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.", @@ -977,7 +1064,7 @@ } }, { - "title": "cfg", + "title": "Cfg", "properties": { "rust-analyzer.cfg.setTest": { "markdownDescription": "Set `cfg(test)` for local crates. Defaults to true.", @@ -987,7 +1074,7 @@ } }, { - "title": "general", + "title": "rust-analyzer", "properties": { "rust-analyzer.checkOnSave": { "markdownDescription": "Run the check command for diagnostics on save.", @@ -997,7 +1084,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.allTargets": { "markdownDescription": "Check all targets and tests (`--all-targets`). Defaults to\n`#rust-analyzer.cargo.allTargets#`.", @@ -1010,7 +1097,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.command": { "markdownDescription": "Cargo command to use for `cargo check`.", @@ -1020,7 +1107,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.extraArgs": { "markdownDescription": "Extra arguments for `cargo check`.", @@ -1033,7 +1120,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.extraEnv": { "markdownDescription": "Extra environment variables that will be set when running `cargo check`.\nExtends `#rust-analyzer.cargo.extraEnv#`.", @@ -1043,7 +1130,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.features": { "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.", @@ -1072,7 +1159,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.ignore": { "markdownDescription": "List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore.\n\nFor example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,...", @@ -1086,7 +1173,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.invocationStrategy": { "markdownDescription": "Specifies the invocation strategy to use when running the check command.\nIf `per_workspace` is set, the command will be executed for each workspace.\nIf `once` is set, the command will be executed once.\nThis config only has an effect when `#rust-analyzer.check.overrideCommand#`\nis set.", @@ -1104,7 +1191,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.noDefaultFeatures": { "markdownDescription": "Whether to pass `--no-default-features` to Cargo. Defaults to\n`#rust-analyzer.cargo.noDefaultFeatures#`.", @@ -1117,7 +1204,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.overrideCommand": { "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the future.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", @@ -1133,7 +1220,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.targets": { "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", @@ -1156,7 +1243,7 @@ } }, { - "title": "check", + "title": "Check", "properties": { "rust-analyzer.check.workspace": { "markdownDescription": "Whether `--workspace` should be passed to `cargo check`.\nIf false, `-p ` will be passed instead if applicable. In case it is not, no\ncheck will be performed.", @@ -1166,50 +1253,50 @@ } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.addSemicolonToUnit": { - "markdownDescription": "Whether to automatically add a semicolon when completing unit-returning functions.\n\nIn `match` arms it completes a comma instead.", + "markdownDescription": "Automatically add a semicolon when completing unit-returning functions.\n\nIn `match` arms it completes a comma instead.", "default": true, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.autoAwait.enable": { - "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.", + "markdownDescription": "Show method calls and field accesses completions with `await` prefixed to them when\ncompleting on a future.", "default": true, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.autoIter.enable": { - "markdownDescription": "Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.", + "markdownDescription": "Show method call completions with `iter()` or `into_iter()` prefixed to them when\ncompleting on a type that has them.", "default": true, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.autoimport.enable": { - "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", + "markdownDescription": "Show completions that automatically add imports when completed.\n\nNote that your client must specify the `additionalTextEdits` LSP client capability to\ntruly have this feature enabled.", "default": true, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.autoimport.exclude": { - "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more verbose\nform `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait itself.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", + "markdownDescription": "A list of full paths to items to exclude from auto-importing completions.\n\nTraits in this list won't have their methods suggested in completions unless the trait\nis in scope.\n\nYou can either specify a string path which defaults to type \"always\" or use the more\nverbose form `{ \"path\": \"path::to::item\", type: \"always\" }`.\n\nFor traits the type \"methods\" can be used to only exclude the methods but not the trait\nitself.\n\nThis setting also inherits `#rust-analyzer.completion.excludeTraits#`.", "default": [ { "path": "core::borrow::Borrow", @@ -1251,20 +1338,20 @@ } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.autoself.enable": { - "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.", + "markdownDescription": "Show method calls and field access completions with `self` prefixed to them when\ninside a method.", "default": true, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.callable.snippets": { - "markdownDescription": "Whether to add parenthesis and argument snippets when completing function.", + "markdownDescription": "Add parenthesis and argument snippets when completing function.", "default": "fill_arguments", "type": "string", "enum": [ @@ -1281,10 +1368,10 @@ } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.excludeTraits": { - "markdownDescription": "A list of full paths to traits whose methods to exclude from completion.\n\nMethods from these traits won't be completed, even if the trait is in scope. However, they will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or `T where T: Trait`.\n\nNote that the trait themselves can still be completed.", + "markdownDescription": "A list of full paths to traits whose methods to exclude from completion.\n\nMethods from these traits won't be completed, even if the trait is in scope. However,\nthey will still be suggested on expressions whose type is `dyn Trait`, `impl Trait` or\n`T where T: Trait`.\n\nNote that the trait themselves can still be completed.", "default": [], "type": "array", "items": { @@ -1294,27 +1381,27 @@ } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.fullFunctionSignatures.enable": { - "markdownDescription": "Whether to show full function/method signatures in completion docs.", + "markdownDescription": "Show full function / method signatures in completion docs.", "default": false, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.hideDeprecated": { - "markdownDescription": "Whether to omit deprecated items from autocompletion. By default they are marked as deprecated but not hidden.", + "markdownDescription": "Omit deprecated items from completions. By default they are marked as deprecated but not\nhidden.", "default": false, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.limit": { "markdownDescription": "Maximum number of completions to return. If `None`, the limit is infinite.", @@ -1328,27 +1415,27 @@ } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.postfix.enable": { - "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.", + "markdownDescription": "Show postfix snippets like `dbg`, `if`, `not`, etc.", "default": true, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.privateEditable.enable": { - "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.", + "markdownDescription": "Show completions of private items and fields that are defined in the current workspace\neven if they are not visible at the current position.", "default": false, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.snippets.custom": { "markdownDescription": "Custom completion snippets.", @@ -1398,17 +1485,17 @@ } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.termSearch.enable": { - "markdownDescription": "Whether to enable term search based snippets like `Some(foo.bar().baz())`.", + "markdownDescription": "Enable term search based snippets like `Some(foo.bar().baz())`.", "default": false, "type": "boolean" } } }, { - "title": "completion", + "title": "Completion", "properties": { "rust-analyzer.completion.termSearch.fuel": { "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 1000).", @@ -1419,7 +1506,7 @@ } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.disabled": { "markdownDescription": "List of rust-analyzer diagnostics to disable.", @@ -1433,50 +1520,50 @@ } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.enable": { - "markdownDescription": "Whether to show native rust-analyzer diagnostics.", + "markdownDescription": "Show native rust-analyzer diagnostics.", "default": true, "type": "boolean" } } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.experimental.enable": { - "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might\nhave more false positives than usual.", + "markdownDescription": "Show experimental rust-analyzer diagnostics that might have more false positives than\nusual.", "default": false, "type": "boolean" } } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.remapPrefix": { - "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths.\nThis should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.", + "markdownDescription": "Map of prefixes to be substituted when parsing diagnostic file paths. This should be the\nreverse mapping of what is passed to `rustc` as `--remap-path-prefix`.", "default": {}, "type": "object" } } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.styleLints.enable": { - "markdownDescription": "Whether to run additional style lints.", + "markdownDescription": "Run additional style lints.", "default": false, "type": "boolean" } } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.warningsAsHint": { - "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.", + "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code and will not show up\nin the `Problems Panel`.", "default": [], "type": "array", "items": { @@ -1486,10 +1573,10 @@ } }, { - "title": "diagnostics", + "title": "Diagnostics", "properties": { "rust-analyzer.diagnostics.warningsAsInfo": { - "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.", + "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in\nthe `Problems Panel`.", "default": [], "type": "array", "items": { @@ -1499,10 +1586,10 @@ } }, { - "title": "files", + "title": "Files", "properties": { "rust-analyzer.files.exclude": { - "markdownDescription": "These paths (file/directories) will be ignored by rust-analyzer. They are\nrelative to the workspace root, and globs are not supported. You may\nalso need to add the folders to Code's `files.watcherExclude`.", + "markdownDescription": "List of files to ignore\n\nThese paths (file/directories) will be ignored by rust-analyzer. They are relative to\nthe workspace root, and globs are not supported. You may also need to add the folders to\nCode's `files.watcherExclude`.", "default": [], "type": "array", "items": { @@ -1512,7 +1599,7 @@ } }, { - "title": "files", + "title": "Files", "properties": { "rust-analyzer.files.watcher": { "markdownDescription": "Controls file watching implementation.", @@ -1530,167 +1617,167 @@ } }, { - "title": "highlightRelated", + "title": "Highlight Related", "properties": { "rust-analyzer.highlightRelated.branchExitPoints.enable": { - "markdownDescription": "Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).", + "markdownDescription": "Highlight related return values while the cursor is on any `match`, `if`, or match arm\narrow (`=>`).", "default": true, "type": "boolean" } } }, { - "title": "highlightRelated", + "title": "Highlight Related", "properties": { "rust-analyzer.highlightRelated.breakPoints.enable": { - "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", + "markdownDescription": "Highlight related references while the cursor is on `break`, `loop`, `while`, or `for`\nkeywords.", "default": true, "type": "boolean" } } }, { - "title": "highlightRelated", + "title": "Highlight Related", "properties": { "rust-analyzer.highlightRelated.closureCaptures.enable": { - "markdownDescription": "Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.", + "markdownDescription": "Highlight all captures of a closure while the cursor is on the `|` or move keyword of a closure.", "default": true, "type": "boolean" } } }, { - "title": "highlightRelated", + "title": "Highlight Related", "properties": { "rust-analyzer.highlightRelated.exitPoints.enable": { - "markdownDescription": "Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).", + "markdownDescription": "Highlight all exit points while the cursor is on any `return`, `?`, `fn`, or return type\narrow (`->`).", "default": true, "type": "boolean" } } }, { - "title": "highlightRelated", + "title": "Highlight Related", "properties": { "rust-analyzer.highlightRelated.references.enable": { - "markdownDescription": "Enables highlighting of related references while the cursor is on any identifier.", + "markdownDescription": "Highlight related references while the cursor is on any identifier.", "default": true, "type": "boolean" } } }, { - "title": "highlightRelated", + "title": "Highlight Related", "properties": { "rust-analyzer.highlightRelated.yieldPoints.enable": { - "markdownDescription": "Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.", + "markdownDescription": "Highlight all break points for a loop or block context while the cursor is on any\n`async` or `await` keywords.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.debug.enable": { - "markdownDescription": "Whether to show `Debug` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "markdownDescription": "Show `Debug` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.enable": { - "markdownDescription": "Whether to show HoverActions in Rust files.", + "markdownDescription": "Show HoverActions in Rust files.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.gotoTypeDef.enable": { - "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "markdownDescription": "Show `Go to Type Definition` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.implementations.enable": { - "markdownDescription": "Whether to show `Implementations` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "markdownDescription": "Show `Implementations` action. Only applies when `#rust-analyzer.hover.actions.enable#`\nis set.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.references.enable": { - "markdownDescription": "Whether to show `References` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "markdownDescription": "Show `References` action. Only applies when `#rust-analyzer.hover.actions.enable#` is\nset.", "default": false, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.run.enable": { - "markdownDescription": "Whether to show `Run` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` is set.", + "markdownDescription": "Show `Run` action. Only applies when `#rust-analyzer.hover.actions.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.actions.updateTest.enable": { - "markdownDescription": "Whether to show `Update Test` action. Only applies when\n`#rust-analyzer.hover.actions.enable#` and `#rust-analyzer.hover.actions.run.enable#` are set.", + "markdownDescription": "Show `Update Test` action. Only applies when `#rust-analyzer.hover.actions.enable#` and\n`#rust-analyzer.hover.actions.run.enable#` are set.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.documentation.enable": { - "markdownDescription": "Whether to show documentation on hover.", + "markdownDescription": "Show documentation on hover.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.documentation.keywords.enable": { - "markdownDescription": "Whether to show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.", + "markdownDescription": "Show keyword hover popups. Only applies when\n`#rust-analyzer.hover.documentation.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.dropGlue.enable": { - "markdownDescription": "Whether to show drop glue information on hover.", + "markdownDescription": "Show drop glue information on hover.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.links.enable": { "markdownDescription": "Use markdown syntax for links on hover.", @@ -1700,10 +1787,10 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.maxSubstitutionLength": { - "markdownDescription": "Whether to show what types are used as generic arguments in calls etc. on hover, and what is their max length to show such types, beyond it they will be shown with ellipsis.\n\nThis can take three values: `null` means \"unlimited\", the string `\"hide\"` means to not show generic substitutions at all, and a number means to limit them to X characters.\n\nThe default is 20 characters.", + "markdownDescription": "Show what types are used as generic arguments in calls etc. on hover, and limit the max\nlength to show such types, beyond which they will be shown with ellipsis.\n\nThis can take three values: `null` means \"unlimited\", the string `\"hide\"` means to not\nshow generic substitutions at all, and a number means to limit them to X characters.\n\nThe default is 20 characters.", "default": 20, "anyOf": [ { @@ -1723,7 +1810,7 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.memoryLayout.alignment": { "markdownDescription": "How to render the align information in a memory layout hover.", @@ -1750,17 +1837,17 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.memoryLayout.enable": { - "markdownDescription": "Whether to show memory layout data on hover.", + "markdownDescription": "Show memory layout data on hover.", "default": true, "type": "boolean" } } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.memoryLayout.niches": { "markdownDescription": "How to render the niche information in a memory layout hover.", @@ -1773,7 +1860,7 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.memoryLayout.offset": { "markdownDescription": "How to render the offset information in a memory layout hover.", @@ -1800,7 +1887,7 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.memoryLayout.padding": { "markdownDescription": "How to render the padding information in a memory layout hover.", @@ -1827,7 +1914,7 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.memoryLayout.size": { "markdownDescription": "How to render the size information in a memory layout hover.", @@ -1854,7 +1941,7 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.show.enumVariants": { "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.", @@ -1868,10 +1955,10 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.show.fields": { - "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if empty.", + "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if\nempty.", "default": 5, "type": [ "null", @@ -1882,7 +1969,7 @@ } }, { - "title": "hover", + "title": "Hover", "properties": { "rust-analyzer.hover.show.traitAssocItems": { "markdownDescription": "How many associated items of a trait to display when hovering a trait.", @@ -1896,17 +1983,17 @@ } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.granularity.enforce": { - "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.", + "markdownDescription": "Enforce the import granularity setting for all files. If set to false rust-analyzer will\ntry to keep import styles consistent per file.", "default": false, "type": "boolean" } } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.granularity.group": { "markdownDescription": "How imports should be grouped into use statements.", @@ -1930,27 +2017,27 @@ } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.group.enable": { - "markdownDescription": "Group inserted imports by the [following order](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are separated by newlines.", + "markdownDescription": "Group inserted imports by the [following\norder](https://rust-analyzer.github.io/book/features.html#auto-import). Groups are\nseparated by newlines.", "default": true, "type": "boolean" } } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.merge.glob": { - "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.", + "markdownDescription": "Allow import insertion to merge new imports into single path glob imports like `use\nstd::fmt::*;`.", "default": true, "type": "boolean" } } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.preferNoStd": { "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.", @@ -1960,17 +2047,17 @@ } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.preferPrelude": { - "markdownDescription": "Whether to prefer import paths containing a `prelude` module.", + "markdownDescription": "Prefer import paths containing a `prelude` module.", "default": false, "type": "boolean" } } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.prefix": { "markdownDescription": "The path structure for newly inserted paths to use.", @@ -1990,47 +2077,47 @@ } }, { - "title": "imports", + "title": "Imports", "properties": { "rust-analyzer.imports.prefixExternPrelude": { - "markdownDescription": "Whether to prefix external (including std, core) crate imports with `::`. e.g. \"use ::std::io::Read;\".", + "markdownDescription": "Prefix external (including std, core) crate imports with `::`.\n\nE.g. `use ::std::io::Read;`.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.bindingModeHints.enable": { - "markdownDescription": "Whether to show inlay type hints for binding modes.", + "markdownDescription": "Show inlay type hints for binding modes.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.chainingHints.enable": { - "markdownDescription": "Whether to show inlay type hints for method chains.", + "markdownDescription": "Show inlay type hints for method chains.", "default": true, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.closingBraceHints.enable": { - "markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.", + "markdownDescription": "Show inlay hints after a closing `}` to indicate what item it belongs to.", "default": true, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.closingBraceHints.minLines": { "markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).", @@ -2041,20 +2128,20 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.closureCaptureHints.enable": { - "markdownDescription": "Whether to show inlay hints for closure captures.", + "markdownDescription": "Show inlay hints for closure captures.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.closureReturnTypeHints.enable": { - "markdownDescription": "Whether to show inlay type hints for return types of closures.", + "markdownDescription": "Show inlay type hints for return types of closures.", "default": "never", "type": "string", "enum": [ @@ -2071,7 +2158,7 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.closureStyle": { "markdownDescription": "Closure notation in type and chaining inlay hints.", @@ -2093,10 +2180,10 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.discriminantHints.enable": { - "markdownDescription": "Whether to show enum variant discriminant hints.", + "markdownDescription": "Show enum variant discriminant hints.", "default": "never", "type": "string", "enum": [ @@ -2113,10 +2200,10 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": { - "markdownDescription": "Whether to show inlay hints for type adjustments.", + "markdownDescription": "Show inlay hints for type adjustments.", "default": "never", "type": "string", "enum": [ @@ -2133,20 +2220,20 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe": { - "markdownDescription": "Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.", + "markdownDescription": "Hide inlay hints for type adjustments outside of `unsafe` blocks.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.expressionAdjustmentHints.mode": { - "markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).", + "markdownDescription": "Show inlay hints as postfix ops (`.*` instead of `*`, etc).", "default": "prefix", "type": "string", "enum": [ @@ -2165,60 +2252,60 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.genericParameterHints.const.enable": { - "markdownDescription": "Whether to show const generic parameter name inlay hints.", + "markdownDescription": "Show const generic parameter name inlay hints.", "default": true, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.genericParameterHints.lifetime.enable": { - "markdownDescription": "Whether to show generic lifetime parameter name inlay hints.", + "markdownDescription": "Show generic lifetime parameter name inlay hints.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.genericParameterHints.type.enable": { - "markdownDescription": "Whether to show generic type parameter name inlay hints.", + "markdownDescription": "Show generic type parameter name inlay hints.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.implicitDrops.enable": { - "markdownDescription": "Whether to show implicit drop hints.", + "markdownDescription": "Show implicit drop hints.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.implicitSizedBoundHints.enable": { - "markdownDescription": "Whether to show inlay hints for the implied type parameter `Sized` bound.", + "markdownDescription": "Show inlay hints for the implied type parameter `Sized` bound.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { - "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", + "markdownDescription": "Show inlay type hints for elided lifetimes in function signatures.", "default": "never", "type": "string", "enum": [ @@ -2235,17 +2322,17 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.lifetimeElisionHints.useParameterNames": { - "markdownDescription": "Whether to prefer using parameter names as the name for elided lifetime hints if possible.", + "markdownDescription": "Prefer using parameter names as the name for elided lifetime hints if possible.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.maxLength": { "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.", @@ -2259,30 +2346,30 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.parameterHints.enable": { - "markdownDescription": "Whether to show function parameter name inlay hints at the call\nsite.", + "markdownDescription": "Show function parameter name inlay hints at the call site.", "default": true, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.rangeExclusiveHints.enable": { - "markdownDescription": "Whether to show exclusive range inlay hints.", + "markdownDescription": "Show exclusive range inlay hints.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.reborrowHints.enable": { - "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.", + "markdownDescription": "Show inlay hints for compiler inserted reborrows.\n\nThis setting is deprecated in favor of\n#rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.", "default": "never", "type": "string", "enum": [ @@ -2299,7 +2386,7 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.renderColons": { "markdownDescription": "Whether to render leading colons for type hints, and trailing colons for parameter hints.", @@ -2309,57 +2396,57 @@ } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.typeHints.enable": { - "markdownDescription": "Whether to show inlay type hints for variables.", + "markdownDescription": "Show inlay type hints for variables.", "default": true, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": { - "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.", + "markdownDescription": "Hide inlay type hints for `let` statements that initialize to a closure.\n\nOnly applies to closures with blocks, same as\n`#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.typeHints.hideClosureParameter": { - "markdownDescription": "Whether to hide inlay parameter type hints for closures.", + "markdownDescription": "Hide inlay parameter type hints for closures.", "default": false, "type": "boolean" } } }, { - "title": "inlayHints", + "title": "Inlay Hints", "properties": { "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": { - "markdownDescription": "Whether to hide inlay type hints for constructors.", + "markdownDescription": "Hide inlay type hints for constructors.", "default": false, "type": "boolean" } } }, { - "title": "interpret", + "title": "Interpret", "properties": { "rust-analyzer.interpret.tests": { - "markdownDescription": "Enables the experimental support for interpreting tests.", + "markdownDescription": "Enable the experimental support for interpreting tests.", "default": false, "type": "boolean" } } }, { - "title": "joinLines", + "title": "Join Lines", "properties": { "rust-analyzer.joinLines.joinAssignments": { "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.", @@ -2369,7 +2456,7 @@ } }, { - "title": "joinLines", + "title": "Join Lines", "properties": { "rust-analyzer.joinLines.joinElseIf": { "markdownDescription": "Join lines inserts else between consecutive ifs.", @@ -2379,7 +2466,7 @@ } }, { - "title": "joinLines", + "title": "Join Lines", "properties": { "rust-analyzer.joinLines.removeTrailingComma": { "markdownDescription": "Join lines removes trailing commas.", @@ -2389,7 +2476,7 @@ } }, { - "title": "joinLines", + "title": "Join Lines", "properties": { "rust-analyzer.joinLines.unwrapTrivialBlock": { "markdownDescription": "Join lines unwraps trivial blocks.", @@ -2399,37 +2486,37 @@ } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.debug.enable": { - "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.enable": { - "markdownDescription": "Whether to show CodeLens in Rust files.", + "markdownDescription": "Show CodeLens in Rust files.", "default": true, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.implementations.enable": { - "markdownDescription": "Whether to show `Implementations` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.location": { "markdownDescription": "Where to render annotations.", @@ -2447,70 +2534,70 @@ } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.references.adt.enable": { - "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `References` lens for Struct, Enum, and Union. Only applies when\n`#rust-analyzer.lens.enable#` is set.", "default": false, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.references.enumVariant.enable": { - "markdownDescription": "Whether to show `References` lens for Enum Variants.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `References` lens for Enum Variants. Only applies when\n`#rust-analyzer.lens.enable#` is set.", "default": false, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.references.method.enable": { - "markdownDescription": "Whether to show `Method References` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", "default": false, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.references.trait.enable": { - "markdownDescription": "Whether to show `References` lens for Trait.\nOnly applies when `#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `References` lens for Trait. Only applies when `#rust-analyzer.lens.enable#` is\nset.", "default": false, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.run.enable": { - "markdownDescription": "Whether to show `Run` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", + "markdownDescription": "Show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", "default": true, "type": "boolean" } } }, { - "title": "lens", + "title": "Lens", "properties": { "rust-analyzer.lens.updateTest.enable": { - "markdownDescription": "Whether to show `Update Test` lens. Only applies when\n`#rust-analyzer.lens.enable#` and `#rust-analyzer.lens.run.enable#` are set.", + "markdownDescription": "Show `Update Test` lens. Only applies when `#rust-analyzer.lens.enable#` and\n`#rust-analyzer.lens.run.enable#` are set.", "default": true, "type": "boolean" } } }, { - "title": "general", + "title": "rust-analyzer", "properties": { "rust-analyzer.linkedProjects": { - "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON\nobjects in `rust-project.json` format.", + "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\n\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, `.rs` files (which\nwill be treated as standalone files) or JSON objects in `rust-project.json` format.", "default": [], "type": "array", "items": { @@ -2523,7 +2610,7 @@ } }, { - "title": "lru", + "title": "Lru", "properties": { "rust-analyzer.lru.capacity": { "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.", @@ -2538,30 +2625,30 @@ } }, { - "title": "lru", + "title": "Lru", "properties": { "rust-analyzer.lru.query.capacities": { - "markdownDescription": "Sets the LRU capacity of the specified queries.", + "markdownDescription": "The LRU capacity of the specified queries.", "default": {}, "type": "object" } } }, { - "title": "notifications", + "title": "Notifications", "properties": { "rust-analyzer.notifications.cargoTomlNotFound": { - "markdownDescription": "Whether to show `can't find Cargo.toml` error message.", + "markdownDescription": "Show `can't find Cargo.toml` error message.", "default": true, "type": "boolean" } } }, { - "title": "general", + "title": "rust-analyzer", "properties": { "rust-analyzer.numThreads": { - "markdownDescription": "How many worker threads in the main loop. The default `null` means to pick automatically.", + "markdownDescription": "The number of worker threads in the main loop. The default `null` means to pick\nautomatically.", "default": null, "anyOf": [ { @@ -2588,7 +2675,7 @@ } }, { - "title": "procMacro", + "title": "Proc Macro", "properties": { "rust-analyzer.procMacro.attributes.enable": { "markdownDescription": "Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.", @@ -2598,7 +2685,7 @@ } }, { - "title": "procMacro", + "title": "Proc Macro", "properties": { "rust-analyzer.procMacro.enable": { "markdownDescription": "Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.", @@ -2608,7 +2695,7 @@ } }, { - "title": "procMacro", + "title": "Proc Macro", "properties": { "rust-analyzer.procMacro.ignored": { "markdownDescription": "These proc-macros will be ignored when trying to expand them.\n\nThis config takes a map of crate names with the exported proc-macro names to ignore as values.", @@ -2618,7 +2705,7 @@ } }, { - "title": "procMacro", + "title": "Proc Macro", "properties": { "rust-analyzer.procMacro.server": { "markdownDescription": "Internal config, path to proc-macro server executable.", @@ -2631,7 +2718,7 @@ } }, { - "title": "references", + "title": "References", "properties": { "rust-analyzer.references.excludeImports": { "markdownDescription": "Exclude imports from find-all-references.", @@ -2641,7 +2728,7 @@ } }, { - "title": "references", + "title": "References", "properties": { "rust-analyzer.references.excludeTests": { "markdownDescription": "Exclude tests from find-all-references and call-hierarchy.", @@ -2651,7 +2738,7 @@ } }, { - "title": "runnables", + "title": "Runnables", "properties": { "rust-analyzer.runnables.command": { "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", @@ -2664,7 +2751,7 @@ } }, { - "title": "runnables", + "title": "Runnables", "properties": { "rust-analyzer.runnables.extraArgs": { "markdownDescription": "Additional arguments to be passed to cargo for runnables such as\ntests or binaries. For example, it may be `--release`.", @@ -2677,7 +2764,7 @@ } }, { - "title": "runnables", + "title": "Runnables", "properties": { "rust-analyzer.runnables.extraTestBinaryArgs": { "markdownDescription": "Additional arguments to be passed through Cargo to launched tests, benchmarks, or\ndoc-tests.\n\nUnless the launched target uses a\n[custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),\nthey will end up being interpreted as options to\n[`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).", @@ -2692,7 +2779,7 @@ } }, { - "title": "rustc", + "title": "Rustc", "properties": { "rust-analyzer.rustc.source": { "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.", @@ -2705,7 +2792,7 @@ } }, { - "title": "rustfmt", + "title": "Rustfmt", "properties": { "rust-analyzer.rustfmt.extraArgs": { "markdownDescription": "Additional arguments to `rustfmt`.", @@ -2718,7 +2805,7 @@ } }, { - "title": "rustfmt", + "title": "Rustfmt", "properties": { "rust-analyzer.rustfmt.overrideCommand": { "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting. This should be the equivalent of `rustfmt` here, and\nnot that of `cargo fmt`. The file contents will be passed on the\nstandard input and the formatted result will be read from the\nstandard output.", @@ -2734,7 +2821,7 @@ } }, { - "title": "rustfmt", + "title": "Rustfmt", "properties": { "rust-analyzer.rustfmt.rangeFormatting.enable": { "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.", @@ -2744,7 +2831,7 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.doc.comment.inject.enable": { "markdownDescription": "Inject additional highlighting into doc comments.\n\nWhen enabled, rust-analyzer will highlight rust source in doc comments as well as intra\ndoc links.", @@ -2754,17 +2841,17 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.nonStandardTokens": { - "markdownDescription": "Whether the server is allowed to emit non-standard tokens and modifiers.", + "markdownDescription": "Emit non-standard tokens and modifiers\n\nWhen enabled, rust-analyzer will emit tokens and modifiers that are not part of the\nstandard set of semantic tokens.", "default": true, "type": "boolean" } } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.operator.enable": { "markdownDescription": "Use semantic tokens for operators.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for operator tokens when\nthey are tagged with modifiers.", @@ -2774,7 +2861,7 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.operator.specialization.enable": { "markdownDescription": "Use specialized semantic tokens for operators.\n\nWhen enabled, rust-analyzer will emit special token types for operator tokens instead\nof the generic `operator` token type.", @@ -2784,7 +2871,7 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.punctuation.enable": { "markdownDescription": "Use semantic tokens for punctuation.\n\nWhen disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when\nthey are tagged with modifiers or have a special role.", @@ -2794,7 +2881,7 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.punctuation.separate.macro.bang": { "markdownDescription": "When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro\ncalls.", @@ -2804,7 +2891,7 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.punctuation.specialization.enable": { "markdownDescription": "Use specialized semantic tokens for punctuation.\n\nWhen enabled, rust-analyzer will emit special token types for punctuation tokens instead\nof the generic `punctuation` token type.", @@ -2814,7 +2901,7 @@ } }, { - "title": "semanticHighlighting", + "title": "Semantic Highlighting", "properties": { "rust-analyzer.semanticHighlighting.strings.enable": { "markdownDescription": "Use semantic tokens for strings.\n\nIn some editors (e.g. vscode) semantic tokens override other highlighting grammars.\nBy disabling semantic tokens for strings, other grammars can be used to highlight\ntheir contents.", @@ -2824,7 +2911,7 @@ } }, { - "title": "signatureInfo", + "title": "Signature Info", "properties": { "rust-analyzer.signatureInfo.detail": { "markdownDescription": "Show full signature of the callable. Only shows parameters if disabled.", @@ -2842,7 +2929,7 @@ } }, { - "title": "signatureInfo", + "title": "Signature Info", "properties": { "rust-analyzer.signatureInfo.documentation.enable": { "markdownDescription": "Show documentation.", @@ -2852,10 +2939,10 @@ } }, { - "title": "typing", + "title": "Typing", "properties": { "rust-analyzer.typing.triggerChars": { - "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", + "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing\n expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in\n expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the\n expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", "default": "=.", "type": [ "null", @@ -2865,7 +2952,7 @@ } }, { - "title": "vfs", + "title": "Vfs", "properties": { "rust-analyzer.vfs.extraIncludes": { "markdownDescription": "Additional paths to include in the VFS. Generally for code that is\ngenerated or otherwise managed by a build system outside of Cargo,\nthough Cargo might be the eventual consumer.", @@ -2878,10 +2965,10 @@ } }, { - "title": "workspace", + "title": "Workspace", "properties": { "rust-analyzer.workspace.discoverConfig": { - "markdownDescription": "Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].\n\n[`DiscoverWorkspaceConfig`] also requires setting `progress_label` and `files_to_watch`.\n`progress_label` is used for the title in progress indicators, whereas `files_to_watch`\nis used to determine which build system-specific files should be watched in order to\nreload rust-analyzer.\n\nBelow is an example of a valid configuration:\n```json\n\"rust-analyzer.workspace.discoverConfig\": {\n \"command\": [\n \"rust-project\",\n \"develop-json\"\n ],\n \"progressLabel\": \"rust-analyzer\",\n \"filesToWatch\": [\n \"BUCK\"\n ]\n}\n```\n\n## On `DiscoverWorkspaceConfig::command`\n\n**Warning**: This format is provisional and subject to change.\n\n[`DiscoverWorkspaceConfig::command`] *must* return a JSON object\ncorresponding to `DiscoverProjectData::Finished`:\n\n```norun\n#[derive(Debug, Clone, Deserialize, Serialize)]\n#[serde(tag = \"kind\")]\n#[serde(rename_all = \"snake_case\")]\nenum DiscoverProjectData {\n Finished { buildfile: Utf8PathBuf, project: ProjectJsonData },\n Error { error: String, source: Option },\n Progress { message: String },\n}\n```\n\nAs JSON, `DiscoverProjectData::Finished` is:\n\n```json\n{\n // the internally-tagged representation of the enum.\n \"kind\": \"finished\",\n // the file used by a non-Cargo build system to define\n // a package or target.\n \"buildfile\": \"rust-analyzer/BUILD\",\n // the contents of a rust-project.json, elided for brevity\n \"project\": {\n \"sysroot\": \"foo\",\n \"crates\": []\n }\n}\n```\n\nIt is encouraged, but not required, to use the other variants on\n`DiscoverProjectData` to provide a more polished end-user experience.\n\n`DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`,\nwhich will be substituted with the JSON-serialized form of the following\nenum:\n\n```norun\n#[derive(PartialEq, Clone, Debug, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub enum DiscoverArgument {\n Path(AbsPathBuf),\n Buildfile(AbsPathBuf),\n}\n```\n\nThe JSON representation of `DiscoverArgument::Path` is:\n\n```json\n{\n \"path\": \"src/main.rs\"\n}\n```\n\nSimilarly, the JSON representation of `DiscoverArgument::Buildfile` is:\n\n```json\n{\n \"buildfile\": \"BUILD\"\n}\n```\n\n`DiscoverArgument::Path` is used to find and generate a `rust-project.json`,\nand therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to\nto update an existing workspace. As a reference for implementors,\nbuck2's `rust-project` will likely be useful:\nhttps://github.com/facebook/buck2/tree/main/integrations/rust-project.", + "markdownDescription": "Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].\n\n[`DiscoverWorkspaceConfig`] also requires setting `progress_label` and `files_to_watch`.\n`progress_label` is used for the title in progress indicators, whereas `files_to_watch`\nis used to determine which build system-specific files should be watched in order to\nreload rust-analyzer.\n\nBelow is an example of a valid configuration:\n```json\n\"rust-analyzer.workspace.discoverConfig\": {\n \"command\": [\n \"rust-project\",\n \"develop-json\"\n ],\n \"progressLabel\": \"rust-analyzer\",\n \"filesToWatch\": [\n \"BUCK\"\n ]\n}\n```\n\n## On `DiscoverWorkspaceConfig::command`\n\n**Warning**: This format is provisional and subject to change.\n\n[`DiscoverWorkspaceConfig::command`] *must* return a JSON object corresponding to\n`DiscoverProjectData::Finished`:\n\n```norun\n#[derive(Debug, Clone, Deserialize, Serialize)]\n#[serde(tag = \"kind\")]\n#[serde(rename_all = \"snake_case\")]\nenum DiscoverProjectData {\n Finished { buildfile: Utf8PathBuf, project: ProjectJsonData },\n Error { error: String, source: Option },\n Progress { message: String },\n}\n```\n\nAs JSON, `DiscoverProjectData::Finished` is:\n\n```json\n{\n // the internally-tagged representation of the enum.\n \"kind\": \"finished\",\n // the file used by a non-Cargo build system to define\n // a package or target.\n \"buildfile\": \"rust-analyzer/BUILD\",\n // the contents of a rust-project.json, elided for brevity\n \"project\": {\n \"sysroot\": \"foo\",\n \"crates\": []\n }\n}\n```\n\nIt is encouraged, but not required, to use the other variants on `DiscoverProjectData`\nto provide a more polished end-user experience.\n\n`DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`, which will be\nsubstituted with the JSON-serialized form of the following enum:\n\n```norun\n#[derive(PartialEq, Clone, Debug, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub enum DiscoverArgument {\n Path(AbsPathBuf),\n Buildfile(AbsPathBuf),\n}\n```\n\nThe JSON representation of `DiscoverArgument::Path` is:\n\n```json\n{\n \"path\": \"src/main.rs\"\n}\n```\n\nSimilarly, the JSON representation of `DiscoverArgument::Buildfile` is:\n\n```json\n{\n \"buildfile\": \"BUILD\"\n}\n```\n\n`DiscoverArgument::Path` is used to find and generate a `rust-project.json`, and\ntherefore, a workspace, whereas `DiscoverArgument::buildfile` is used to to update an\nexisting workspace. As a reference for implementors, buck2's `rust-project` will likely\nbe useful: https://github.com/facebook/buck2/tree/main/integrations/rust-project.", "default": null, "anyOf": [ { @@ -2912,7 +2999,7 @@ } }, { - "title": "workspace", + "title": "Workspace", "properties": { "rust-analyzer.workspace.symbol.search.excludeImports": { "markdownDescription": "Exclude all imports from workspace symbol search.\n\nIn addition to regular imports (which are always excluded),\nthis option removes public imports (better known as re-exports)\nand removes imports that rename the imported symbol.", @@ -2922,7 +3009,7 @@ } }, { - "title": "workspace", + "title": "Workspace", "properties": { "rust-analyzer.workspace.symbol.search.kind": { "markdownDescription": "Workspace symbol search kind.", @@ -2940,7 +3027,7 @@ } }, { - "title": "workspace", + "title": "Workspace", "properties": { "rust-analyzer.workspace.symbol.search.limit": { "markdownDescription": "Limits the number of items returned from a workspace symbol search (Defaults to 128).\nSome clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.\nOther clients requires all results upfront and might require a higher limit.", @@ -2951,7 +3038,7 @@ } }, { - "title": "workspace", + "title": "Workspace", "properties": { "rust-analyzer.workspace.symbol.search.scope": { "markdownDescription": "Workspace symbol search scope.", From 0e3d408c29c7e1b54ba514dfb728eb762719b15b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:24:58 +0000 Subject: [PATCH 007/242] Remove LtoModuleCodegen Most uses of it either contain a fat or thin lto module. Only WorkItem::LTO could contain both, but splitting that enum variant doesn't complicate things much. --- src/back/lto.rs | 15 +++++++-------- src/lib.rs | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index 10fce860b777..e554dd2500bd 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -24,7 +24,7 @@ use std::sync::Arc; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; @@ -176,7 +176,7 @@ pub(crate) fn run_fat( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result, FatalError> { +) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -201,7 +201,7 @@ fn fat_lto( mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> Result, FatalError> { +) -> Result, FatalError> { let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -334,7 +334,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - Ok(LtoModuleCodegen::Fat(module)) + Ok(module) } pub struct ModuleBuffer(PathBuf); @@ -358,7 +358,7 @@ pub(crate) fn run_thin( cgcx: &CodegenContext, modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, dcx)?; @@ -427,7 +427,7 @@ fn thin_lto( tmp_path: TempDir, cached_modules: Vec<(SerializedModule, WorkProduct)>, //_symbols_below_threshold: &[String], -) -> Result<(Vec>, Vec), FatalError> { +) -> Result<(Vec>, Vec), FatalError> { let _timer = cgcx.prof.generic_activity("LLVM_thin_lto_global_analysis"); info!("going for that thin, thin LTO"); @@ -573,8 +573,7 @@ fn thin_lto( }*/ info!(" - {}: re-compiled", module_name); - opt_jobs - .push(LtoModuleCodegen::Thin(ThinModule { shared: shared.clone(), idx: module_index })); + opt_jobs.push(ThinModule { shared: shared.clone(), idx: module_index }); } // Save the current ThinLTO import information for the next compilation diff --git a/src/lib.rs b/src/lib.rs index a912678ef2a1..a151a0ab7553 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,7 +97,7 @@ use gccjit::{CType, Context, OptimizationLevel}; use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, }; @@ -361,7 +361,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result, FatalError> { + ) -> Result, FatalError> { back::lto::run_fat(cgcx, modules, cached_modules) } @@ -369,7 +369,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - ) -> Result<(Vec>, Vec), FatalError> { + ) -> Result<(Vec>, Vec), FatalError> { back::lto::run_thin(cgcx, modules, cached_modules) } From d9f9bcf18f7b8c997daad39ee726c50f1316fa60 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 14:43:09 +0000 Subject: [PATCH 008/242] Move dcx creation into WriteBackendMethods::codegen --- src/back/write.rs | 4 +++- src/lib.rs | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/back/write.rs b/src/back/write.rs index d03d063bdace..113abe70805b 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -16,10 +16,12 @@ use crate::{GccCodegenBackend, GccContext}; pub(crate) fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { + let dcx = cgcx.create_dcx(); + let dcx = dcx.handle(); + let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/src/lib.rs b/src/lib.rs index a151a0ab7553..34452bdd2005 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -408,11 +408,10 @@ impl WriteBackendMethods for GccCodegenBackend { fn codegen( cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> Result { - back::write::codegen(cgcx, dcx, module, config) + back::write::codegen(cgcx, module, config) } fn prepare_thin( From 9404a1192421c29828167eb6962f5099793619d1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:09:10 +0000 Subject: [PATCH 009/242] Remove unused config param from WriteBackendMethods::autodiff --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 34452bdd2005..8e63ebc84940 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -437,7 +437,6 @@ impl WriteBackendMethods for GccCodegenBackend { _cgcx: &CodegenContext, _module: &ModuleCodegen, _diff_functions: Vec, - _config: &ModuleConfig, ) -> Result<(), FatalError> { unimplemented!() } From bf4daef80cab63ba6d2a0889927e9fce4828c6f9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:22:32 +0000 Subject: [PATCH 010/242] Merge run_fat_lto, optimize_fat and autodiff into run_and_optimize_fat_lto --- src/lib.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8e63ebc84940..75c36fffec98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -357,11 +357,16 @@ impl WriteBackendMethods for GccCodegenBackend { type ThinData = ThinData; type ThinBuffer = ThinBuffer; - fn run_fat_lto( + fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, + diff_fncs: Vec, ) -> Result, FatalError> { + if !diff_fncs.is_empty() { + unimplemented!(); + } + back::lto::run_fat(cgcx, modules, cached_modules) } @@ -391,14 +396,6 @@ impl WriteBackendMethods for GccCodegenBackend { Ok(()) } - fn optimize_fat( - _cgcx: &CodegenContext, - _module: &mut ModuleCodegen, - ) -> Result<(), FatalError> { - // TODO(antoyo) - Ok(()) - } - fn optimize_thin( cgcx: &CodegenContext, thin: ThinModule, @@ -432,14 +429,6 @@ impl WriteBackendMethods for GccCodegenBackend { ) -> Result, FatalError> { back::write::link(cgcx, dcx, modules) } - - fn autodiff( - _cgcx: &CodegenContext, - _module: &ModuleCodegen, - _diff_functions: Vec, - ) -> Result<(), FatalError> { - unimplemented!() - } } /// This is the entrypoint for a hot plugged rustc_codegen_gccjit From 7cce6aff07fa81c4a69deec899a1b87348f727de Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 3 Jul 2025 09:17:48 -0700 Subject: [PATCH 011/242] Make __rust_alloc_error_handler_should_panic a function --- src/allocator.rs | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index cf8aa500c778..0d8dc93274f9 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,6 +1,6 @@ -use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type}; #[cfg(feature = "master")] -use gccjit::{FnAttribute, VarAttribute}; +use gccjit::FnAttribute; +use gccjit::{Context, FunctionType, RValue, ToRValue, Type}; use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, @@ -71,15 +71,13 @@ pub(crate) unsafe fn codegen( None, ); - let name = mangle_internal_symbol(tcx, OomStrategy::SYMBOL); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - #[cfg(feature = "master")] - global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); - let value = tcx.sess.opts.unstable_opts.oom.should_panic(); - let value = context.new_rvalue_from_int(i8, value as i32); - global.global_set_initializer_rvalue(value); + create_const_value_function( + tcx, + context, + &mangle_internal_symbol(tcx, OomStrategy::SYMBOL), + i8, + context.new_rvalue_from_int(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as i32), + ); create_wrapper_function( tcx, @@ -91,6 +89,30 @@ pub(crate) unsafe fn codegen( ); } +fn create_const_value_function( + tcx: TyCtxt<'_>, + context: &Context<'_>, + name: &str, + output: Type<'_>, + value: RValue<'_>, +) { + let func = context.new_function(None, FunctionType::Exported, output, &[], name, false); + + #[cfg(feature = "master")] + func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( + tcx.sess.default_visibility(), + ))); + + func.add_attribute(FnAttribute::AlwaysInline); + + if tcx.sess.must_emit_unwind_tables() { + // TODO(antoyo): emit unwind tables. + } + + let block = func.new_block("entry"); + block.end_with_return(None, value); +} + fn create_wrapper_function( tcx: TyCtxt<'_>, context: &Context<'_>, From 7b1674d5d0f395bd49434f0cec2f74c26b378362 Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sat, 5 Jul 2025 15:58:04 +0100 Subject: [PATCH 012/242] Use `object` crate from crates.io to fix windows build error --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + src/lib.rs | 1 - 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index b20c181a8cbf..7f35c1a80bda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,6 +143,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.20.2" @@ -179,6 +188,7 @@ dependencies = [ "boml", "gccjit", "lang_tester", + "object", "tempfile", ] diff --git a/Cargo.toml b/Cargo.toml index c284e3f060b8..05b0431b6ba9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ master = ["gccjit/master"] default = ["master"] [dependencies] +object = { version = "0.37.0", default-features = false, features = ["std", "read"] } gccjit = "2.7" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } diff --git a/src/lib.rs b/src/lib.rs index a912678ef2a1..56afdd55bf99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,6 @@ #![allow(clippy::needless_lifetimes, clippy::uninlined_format_args)] // Some "regular" crates we want to share with rustc -extern crate object; extern crate smallvec; // FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed. #[allow(unused_extern_crates)] From 214311beb05883c5d07200d28cc926e2acfbaaad Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sat, 5 Jul 2025 17:23:39 +0100 Subject: [PATCH 013/242] Make tempfile a normal dependency --- Cargo.toml | 2 +- src/lib.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 05b0431b6ba9..193348d1ef60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ default = ["master"] [dependencies] object = { version = "0.37.0", default-features = false, features = ["std", "read"] } +tempfile = "3.20" gccjit = "2.7" #gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } @@ -32,7 +33,6 @@ gccjit = "2.7" [dev-dependencies] boml = "0.3.1" lang_tester = "0.8.0" -tempfile = "3.20" [profile.dev] # By compiling dependencies with optimizations, performing tests gets much faster. diff --git a/src/lib.rs b/src/lib.rs index 56afdd55bf99..1a6eec0ed0bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,11 +26,9 @@ #![deny(clippy::pattern_type_mismatch)] #![allow(clippy::needless_lifetimes, clippy::uninlined_format_args)] -// Some "regular" crates we want to share with rustc +// These crates are pulled from the sysroot because they are part of +// rustc's public API, so we need to ensure version compatibility. extern crate smallvec; -// FIXME(antoyo): clippy bug: remove the #[allow] when it's fixed. -#[allow(unused_extern_crates)] -extern crate tempfile; #[macro_use] extern crate tracing; From 303a795ac5d9e60c4524fadebd36d0a8f95d8e9c Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Sun, 29 Jun 2025 12:11:51 +0200 Subject: [PATCH 014/242] compiler: Parse `p-` specs in datalayout string, allow definition of custom default data address space --- src/common.rs | 2 +- src/consts.rs | 4 ++-- src/intrinsic/mod.rs | 2 +- src/intrinsic/simd.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common.rs b/src/common.rs index dd582834faca..32713eb56c6e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -162,7 +162,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } fn const_usize(&self, i: u64) -> RValue<'gcc> { - let bit_size = self.data_layout().pointer_size.bits(); + let bit_size = self.data_layout().pointer_size().bits(); if bit_size < 64 { // make sure it doesn't overflow assert!(i < (1 << bit_size)); diff --git a/src/consts.rs b/src/consts.rs index b43f9b24c6a3..c04c75e1b11f 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -294,7 +294,7 @@ pub(crate) fn const_alloc_to_gcc_uncached<'gcc>( let alloc = alloc.inner(); let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); let dl = cx.data_layout(); - let pointer_size = dl.pointer_size.bytes() as usize; + let pointer_size = dl.pointer_size().bytes() as usize; let mut next_offset = 0; for &(offset, prov) in alloc.provenance().ptrs().iter() { @@ -331,7 +331,7 @@ pub(crate) fn const_alloc_to_gcc_uncached<'gcc>( ), abi::Scalar::Initialized { value: Primitive::Pointer(address_space), - valid_range: WrappingRange::full(dl.pointer_size), + valid_range: WrappingRange::full(dl.pointer_size()), }, cx.type_i8p_ext(address_space), )); diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index 497605978fe2..0753ac1aeb84 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -541,7 +541,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. - layout.size() <= self.data_layout().pointer_size * 2 + layout.size() <= self.data_layout().pointer_size() * 2 } }; diff --git a/src/intrinsic/simd.rs b/src/intrinsic/simd.rs index 2e508813fc3b..350915a277e3 100644 --- a/src/intrinsic/simd.rs +++ b/src/intrinsic/simd.rs @@ -1184,7 +1184,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let lhs = args[0].immediate(); let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; - let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; + let ptr_bits = bx.tcx().data_layout.pointer_size().bits() as _; let (signed, elem_width, elem_ty) = match *in_elem.kind() { ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits) / 8, bx.cx.type_int_from_ty(i)), ty::Uint(i) => { From dffe77dbabf273e811929580825c6d474a5a605a Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 28 Jun 2025 23:40:02 +0000 Subject: [PATCH 015/242] Remove unused allow attrs --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1a6eec0ed0bf..d8fae1ca47d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ #![doc(rust_logo)] #![feature(rustdoc_internals)] #![feature(rustc_private)] -#![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] From 46836c352d86268ad88fb406337413539b48ca32 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:58:46 +0200 Subject: [PATCH 016/242] Remove support for dynamic allocas --- src/builder.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index b1785af444a1..28d1ec7d8956 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -926,10 +926,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } - fn dynamic_alloca(&mut self, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { - unimplemented!(); - } - fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); From 3d5b1774db136b03a80279f2829e58863056ff3a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 12 Mar 2025 10:26:37 +0000 Subject: [PATCH 017/242] Add opaque TypeId handles for CTFE --- src/common.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/common.rs b/src/common.rs index 32713eb56c6e..28848ca61845 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,7 +1,6 @@ use gccjit::{LValue, RValue, ToRValue, Type}; -use rustc_abi as abi; -use rustc_abi::HasDataLayout; use rustc_abi::Primitive::Pointer; +use rustc_abi::{self as abi, HasDataLayout}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; @@ -282,6 +281,13 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { let init = self.const_data_from_alloc(alloc); self.static_addr_of(init, alloc.inner().align, None) } + GlobalAlloc::TypeId { .. } => { + let val = self.const_usize(offset.bytes()); + // This is still a variable of pointer type, even though we only use the provenance + // of that pointer in CTFE and Miri. But to make LLVM's type system happy, + // we need an int-to-ptr cast here (it doesn't matter at all which provenance that picks). + return self.context.new_cast(None, val, ty); + } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); self.get_static(def_id).get_address(None) From e55baf9f7ada72ed9f661194065154a09aab3a9e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 11:12:54 +0200 Subject: [PATCH 018/242] use `codegen_instance_attrs` where an instance is (easily) available --- src/attributes.rs | 2 +- src/callee.rs | 2 +- src/mono_item.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index bf0927dc590b..7a1ae6ca9c8b 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -87,7 +87,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); #[cfg(feature = "master")] { diff --git a/src/callee.rs b/src/callee.rs index 189ac7cd7792..e7ca95af594c 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -105,7 +105,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/src/mono_item.rs b/src/mono_item.rs index 539e3ac85076..51f35cbdee47 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -53,7 +53,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); let decl = self.declare_fn(symbol_name, fn_abi); - //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + //let attrs = self.tcx.codegen_instance_attrs(instance.def); attributes::from_fn_attrs(self, decl, instance); From d088fb739b40c083d3dd74185c4e1b05c86839ce Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Jul 2025 18:31:20 +0200 Subject: [PATCH 019/242] Merge commit 'f682d09eefc6700b9e5851ef193847959acf4fac' into subtree-update_cg_gcc_2025-07-18 --- .github/workflows/m68k.yml | 40 +- .github/workflows/release.yml | 3 +- build_system/build_sysroot/Cargo.lock | 502 -------------------------- build_system/build_sysroot/Cargo.toml | 39 -- build_system/build_sysroot/lib.rs | 1 - build_system/src/build.rs | 38 +- build_system/src/config.rs | 5 - build_system/src/utils.rs | 13 - doc/tips.md | 6 +- example/mini_core_hello_world.rs | 16 +- rust-toolchain | 2 +- src/builder.rs | 6 +- src/lib.rs | 7 +- src/mono_item.rs | 2 +- tests/failing-ui-tests.txt | 2 + tests/run/asm.rs | 1 + tests/run/float.rs | 16 +- tests/run/int.rs | 2 - tests/run/volatile.rs | 3 +- tests/run/volatile2.rs | 6 +- 20 files changed, 85 insertions(+), 625 deletions(-) delete mode 100644 build_system/build_sysroot/Cargo.lock delete mode 100644 build_system/build_sysroot/Cargo.toml delete mode 100644 build_system/build_sysroot/lib.rs diff --git a/.github/workflows/m68k.yml b/.github/workflows/m68k.yml index 245bee7f2a3b..759d0d59e268 100644 --- a/.github/workflows/m68k.yml +++ b/.github/workflows/m68k.yml @@ -14,8 +14,6 @@ permissions: env: # Enable backtraces for easier debugging RUST_BACKTRACE: 1 - # TODO: remove when confish.sh is removed. - OVERWRITE_TARGET_TRIPLE: m68k-unknown-linux-gnu jobs: build: @@ -59,14 +57,12 @@ jobs: - name: Setup path to libgccjit run: | - sudo dpkg -i gcc-m68k-15.deb + sudo dpkg --force-overwrite -i gcc-m68k-15.deb echo 'gcc-path = "/usr/lib/"' > config.toml - name: Set env run: | echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV - - #- name: Cache rust repository ## We only clone the rust repository for rustc tests @@ -86,16 +82,20 @@ jobs: - name: Build sample project with target defined as JSON spec run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json - ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh clean all - name: Build run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu - ./y.sh test --mini-tests - CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests + ./y.sh build --sysroot --features compiler-builtins-no-f16-f128 --target-triple m68k-unknown-linux-gnu + ./y.sh test --mini-tests --target-triple m68k-unknown-linux-gnu + # FIXME: since https://github.com/rust-lang/rust/pull/140809, we cannot run programs for architectures not + # supported by the object crate, since this adds a dependency on symbols.o for the panic runtime. + # And as such, a wrong order of the object files in the linker command now fails with an undefined reference + # to some symbols like __rustc::rust_panic. + #CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests --target-triple m68k-unknown-linux-gnu ./y.sh clean all - name: Prepare dependencies @@ -104,9 +104,23 @@ jobs: git config --global user.name "User" ./y.sh prepare --cross - - name: Run tests - run: | - ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} + # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above. + #- name: Run tests + #run: | + #./y.sh test --target-triple m68k-unknown-linux-gnu --release --clean --build-sysroot --sysroot-features compiler-builtins-no-f16-f128 ${{ matrix.commands }} + + # FIXME: We cannot run programs for architectures not supported by the object crate. See comment above. + #- name: Run Hello World! + #run: | + #./y.sh build --target-triple m68k-unknown-linux-gnu + + #vm_dir=$(pwd)/vm + #cd tests/hello-world + #CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../../y.sh cargo build --target m68k-unknown-linux-gnu + #sudo cp target/m68k-unknown-linux-gnu/debug/hello_world $vm_dir/home/ + #sudo chroot $vm_dir qemu-m68k-static /home/hello_world > hello_world_stdout + #expected_output="40" + #test $(cat hello_world_stdout) == $expected_output || (echo "Output differs. Actual output: $(cat hello_world_stdout)"; exit 1) # Summary job for the merge queue. # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1d8eaf9a141f..b7e2583aad39 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,8 @@ jobs: - name: Run tests run: | # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros. - echo -n 'lto = "fat"' >> build_system/build_sysroot/Cargo.toml + # FIXME(antoyo): this should probably not be needed since we embed the LTO bitcode. + printf '[profile.release]\nlto = "fat"\n' >> build/build_sysroot/sysroot_src/library/Cargo.toml EMBED_LTO_BITCODE=1 ./y.sh test --release --clean --release-sysroot --build-sysroot --keep-lto-tests ${{ matrix.commands }} - name: Run y.sh cargo build diff --git a/build_system/build_sysroot/Cargo.lock b/build_system/build_sysroot/Cargo.lock deleted file mode 100644 index 0c75977ee798..000000000000 --- a/build_system/build_sysroot/Cargo.lock +++ /dev/null @@ -1,502 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "compiler_builtins", - "gimli", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "alloc" -version = "0.0.0" -dependencies = [ - "compiler_builtins", - "core", -] - -[[package]] -name = "alloctests" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", -] - -[[package]] -name = "cc" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "compiler_builtins" -version = "0.1.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895" -dependencies = [ - "cc", - "rustc-std-workspace-core", -] - -[[package]] -name = "core" -version = "0.0.0" - -[[package]] -name = "coretests" -version = "0.0.0" -dependencies = [ - "rand", - "rand_xorshift", -] - -[[package]] -name = "dlmalloc" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-core", - "windows-sys", -] - -[[package]] -name = "fortanix-sgx-abi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cafc2274c10fab234f176b25903ce17e690fca7597090d50880e047a0389c5" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", - "unicode-width", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "hashbrown" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "hermit-abi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -dependencies = [ - "rustc-std-workspace-core", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "compiler_builtins", - "memchr", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "panic_abort" -version = "0.0.0" -dependencies = [ - "alloc", - "compiler_builtins", - "core", - "libc", -] - -[[package]] -name = "panic_unwind" -version = "0.0.0" -dependencies = [ - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "libc", - "unwind", -] - -[[package]] -name = "proc_macro" -version = "0.0.0" -dependencies = [ - "core", - "rustc-literal-escaper", - "std", -] - -[[package]] -name = "profiler_builtins" -version = "0.0.0" -dependencies = [ - "cc", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "r-efi-alloc" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203" -dependencies = [ - "compiler_builtins", - "r-efi", - "rustc-std-workspace-core", -] - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" - -[[package]] -name = "rand_xorshift" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", -] - -[[package]] -name = "rustc-literal-escaper" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" -dependencies = [ - "rustc-std-workspace-std", -] - -[[package]] -name = "rustc-std-workspace-alloc" -version = "1.99.0" -dependencies = [ - "alloc", -] - -[[package]] -name = "rustc-std-workspace-core" -version = "1.99.0" -dependencies = [ - "core", -] - -[[package]] -name = "rustc-std-workspace-std" -version = "1.99.0" -dependencies = [ - "std", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "std" -version = "0.0.0" -dependencies = [ - "addr2line", - "alloc", - "cfg-if", - "compiler_builtins", - "core", - "dlmalloc", - "fortanix-sgx-abi", - "hashbrown", - "hermit-abi", - "libc", - "miniz_oxide", - "object", - "panic_abort", - "panic_unwind", - "r-efi", - "r-efi-alloc", - "rand", - "rand_xorshift", - "rustc-demangle", - "std_detect", - "unwind", - "wasi", - "windows-targets 0.0.0", -] - -[[package]] -name = "std_detect" -version = "0.1.5" -dependencies = [ - "cfg-if", - "compiler_builtins", - "libc", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "sysroot" -version = "0.0.0" -dependencies = [ - "proc_macro", - "profiler_builtins", - "std", - "test", -] - -[[package]] -name = "test" -version = "0.0.0" -dependencies = [ - "core", - "getopts", - "libc", - "std", -] - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] - -[[package]] -name = "unwind" -version = "0.0.0" -dependencies = [ - "cfg-if", - "compiler_builtins", - "core", - "libc", - "unwinding", -] - -[[package]] -name = "unwinding" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" -dependencies = [ - "compiler_builtins", - "gimli", - "rustc-std-workspace-core", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.0.0" - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/build_system/build_sysroot/Cargo.toml b/build_system/build_sysroot/Cargo.toml deleted file mode 100644 index 29a3bcec304c..000000000000 --- a/build_system/build_sysroot/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -authors = ["rustc_codegen_gcc devs"] -name = "sysroot" -version = "0.0.0" -resolver = "2" - -[dependencies] -core = { path = "./sysroot_src/library/core" } -compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } -alloc = { path = "./sysroot_src/library/alloc" } -std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } -test = { path = "./sysroot_src/library/test" } -proc_macro = { path = "./sysroot_src/library/proc_macro" } - -[patch.crates-io] -rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } -rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } -rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } -compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } - -# For compiler-builtins we always use a high number of codegen units. -# The goal here is to place every single intrinsic into its own object -# file to avoid symbol clashes with the system libgcc if possible. Note -# that this number doesn't actually produce this many object files, we -# just don't create more than this number of object files. -# -# It's a bit of a bummer that we have to pass this here, unfortunately. -# Ideally this would be specified through an env var to Cargo so Cargo -# knows how many CGUs are for this specific crate, but for now -# per-crate configuration isn't specifiable in the environment. -[profile.dev.package.compiler_builtins] -codegen-units = 10000 - -[profile.release.package.compiler_builtins] -codegen-units = 10000 - -[profile.release] -debug = "limited" -#lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed. diff --git a/build_system/build_sysroot/lib.rs b/build_system/build_sysroot/lib.rs deleted file mode 100644 index 0c9ac1ac8e4b..000000000000 --- a/build_system/build_sysroot/lib.rs +++ /dev/null @@ -1 +0,0 @@ -#![no_std] diff --git a/build_system/src/build.rs b/build_system/src/build.rs index ecc4c1b2fe22..94b40319f4a7 100644 --- a/build_system/src/build.rs +++ b/build_system/src/build.rs @@ -5,7 +5,7 @@ use std::path::Path; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ - copy_file, create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir, + create_dir, get_sysroot_dir, run_command, run_command_with_output_and_env, walk_dir, }; #[derive(Default)] @@ -53,11 +53,11 @@ impl BuildArg { } } -fn cleanup_sysroot_previous_build(start_dir: &Path) { +fn cleanup_sysroot_previous_build(library_dir: &Path) { // Cleanup for previous run // Clean target dir except for build scripts and incremental cache let _ = walk_dir( - start_dir.join("target"), + library_dir.join("target"), &mut |dir: &Path| { for top in &["debug", "release"] { let _ = fs::remove_dir_all(dir.join(top).join("build")); @@ -95,31 +95,13 @@ fn cleanup_sysroot_previous_build(start_dir: &Path) { &mut |_| Ok(()), false, ); - - let _ = fs::remove_file(start_dir.join("Cargo.lock")); - let _ = fs::remove_file(start_dir.join("test_target/Cargo.lock")); - let _ = fs::remove_dir_all(start_dir.join("sysroot")); -} - -pub fn create_build_sysroot_content(start_dir: &Path) -> Result<(), String> { - if !start_dir.is_dir() { - create_dir(start_dir)?; - } - copy_file("build_system/build_sysroot/Cargo.toml", start_dir.join("Cargo.toml"))?; - copy_file("build_system/build_sysroot/Cargo.lock", start_dir.join("Cargo.lock"))?; - - let src_dir = start_dir.join("src"); - if !src_dir.is_dir() { - create_dir(&src_dir)?; - } - copy_file("build_system/build_sysroot/lib.rs", start_dir.join("src/lib.rs")) } pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Result<(), String> { let start_dir = get_sysroot_dir(); - cleanup_sysroot_previous_build(&start_dir); - create_build_sysroot_content(&start_dir)?; + let library_dir = start_dir.join("sysroot_src").join("library"); + cleanup_sysroot_previous_build(&library_dir); // Builds libs let mut rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default(); @@ -157,9 +139,13 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(&cg_rustflags); } + args.push(&"--features"); + args.push(&"backtrace"); + let mut env = env.clone(); env.insert("RUSTFLAGS".to_string(), rustflags); - run_command_with_output_and_env(&args, Some(&start_dir), Some(&env))?; + let sysroot_dir = library_dir.join("sysroot"); + run_command_with_output_and_env(&args, Some(&sysroot_dir), Some(&env))?; // Copy files to sysroot let sysroot_path = start_dir.join(format!("sysroot/lib/rustlib/{}/lib/", config.target_triple)); @@ -169,7 +155,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ()) }; walk_dir( - start_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)), + library_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)), &mut copier.clone(), &mut copier, false, @@ -178,7 +164,7 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu // Copy the source files to the sysroot (Rust for Linux needs this). let sysroot_src_path = start_dir.join("sysroot/lib/rustlib/src/rust"); create_dir(&sysroot_src_path)?; - run_command(&[&"cp", &"-r", &start_dir.join("sysroot_src/library/"), &sysroot_src_path], None)?; + run_command(&[&"cp", &"-r", &library_dir, &sysroot_src_path], None)?; Ok(()) } diff --git a/build_system/src/config.rs b/build_system/src/config.rs index 650c030ca539..a5f802e293a9 100644 --- a/build_system/src/config.rs +++ b/build_system/src/config.rs @@ -352,11 +352,6 @@ impl ConfigInfo { None => return Err("no host found".to_string()), }; - if self.target_triple.is_empty() - && let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") - { - self.target_triple = overwrite.clone(); - } if self.target_triple.is_empty() { self.target_triple = self.host_triple.clone(); } diff --git a/build_system/src/utils.rs b/build_system/src/utils.rs index d77707d5f17a..fc948c54b24a 100644 --- a/build_system/src/utils.rs +++ b/build_system/src/utils.rs @@ -303,19 +303,6 @@ pub fn create_dir>(path: P) -> Result<(), String> { }) } -pub fn copy_file, T: AsRef>(from: F, to: T) -> Result<(), String> { - fs::copy(&from, &to) - .map_err(|error| { - format!( - "Failed to copy file `{}` into `{}`: {:?}", - from.as_ref().display(), - to.as_ref().display(), - error - ) - }) - .map(|_| ()) -} - /// This function differs from `git_clone` in how it handles *where* the repository will be cloned. /// In `git_clone`, it is cloned in the provided path. In this function, the path you provide is /// the parent folder. So if you pass "a" as folder and try to clone "b.git", it will be cloned into diff --git a/doc/tips.md b/doc/tips.md index 86c22db186e0..e62c3402a292 100644 --- a/doc/tips.md +++ b/doc/tips.md @@ -62,14 +62,14 @@ generate it in [gimple.md](./doc/gimple.md). * Run `./y.sh prepare --cross` so that the sysroot is patched for the cross-compiling case. * Set the path to the cross-compiling libgccjit in `gcc-path` (in `config.toml`). - * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. Currently, the linker name is hardcoded as being `$TARGET-gcc`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`. - * Build your project by specifying the target: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target m68k-unknown-linux-gnu`. + * Make sure you have the linker for your target (for instance `m68k-unknown-linux-gnu-gcc`) in your `$PATH`. You can specify which linker to use via `CG_RUSTFLAGS="-Clinker="`, for instance: `CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc"`. Specify the target when building the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu`. + * Build your project by specifying the target and the linker to use: `CG_RUSTFLAGS="-Clinker=m68k-unknown-linux-gnu-gcc" ../y.sh cargo build --target m68k-unknown-linux-gnu`. If the target is not yet supported by the Rust compiler, create a [target specification file](https://docs.rust-embedded.org/embedonomicon/custom-target.html) (note that the `arch` specified in this file must be supported by the rust compiler). Then, you can use it the following way: * Add the target specification file using `--target` as an **absolute** path to build the sysroot: `./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target $(pwd)/m68k-unknown-linux-gnu.json` - * Build your project by specifying the target specification file: `OVERWRITE_TARGET_TRIPLE=m68k-unknown-linux-gnu ../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. + * Build your project by specifying the target specification file: `../y.sh cargo build --target path/to/m68k-unknown-linux-gnu.json`. If you get the following error: diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 6b6f71edaf8c..358f265a6b85 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -6,7 +6,7 @@ )] #![no_core] #![allow(dead_code, internal_features, non_camel_case_types)] -#![rustfmt::skip] +#![rustfmt_skip] extern crate mini_core; @@ -198,10 +198,24 @@ fn main() { assert_eq!(intrinsics::align_of::() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); +<<<<<<< HEAD assert!(!const { intrinsics::needs_drop::() }); assert!(!const { intrinsics::needs_drop::<[u8]>() }); assert!(const { intrinsics::needs_drop::() }); assert!(const { intrinsics::needs_drop::() }); +======= + /* + * TODO: re-enable in the next sync. + let u8_needs_drop = const { intrinsics::needs_drop::() }; + assert!(!u8_needs_drop); + let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() }; + assert!(!slice_needs_drop); + let noisy_drop = const { intrinsics::needs_drop::() }; + assert!(noisy_drop); + let noisy_unsized_drop = const { intrinsics::needs_drop::() }; + assert!(noisy_unsized_drop); + */ +>>>>>>> f682d09eefc6700b9e5851ef193847959acf4fac Unique { pointer: 0 as *const &str, diff --git a/rust-toolchain b/rust-toolchain index bccbc6cd2c5c..2fe8ec4647fa 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-06-28" +channel = "nightly-2025-07-04" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/src/builder.rs b/src/builder.rs index 28d1ec7d8956..a4ec4bf8deac 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -971,7 +971,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer()); - ptr.dereference(self.location).to_rvalue() + // (FractalFir): We insert a local here, to ensure this volatile load can't move across + // blocks. + let local = self.current_func().new_local(self.location, ty, "volatile_tmp"); + self.block.add_assignment(self.location, local, ptr.dereference(self.location).to_rvalue()); + local.to_rvalue() } fn atomic_load( diff --git a/src/lib.rs b/src/lib.rs index d81bcc597756..af416929ea73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -273,6 +273,10 @@ fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { } impl ExtraBackendMethods for GccCodegenBackend { + fn supports_parallel(&self) -> bool { + false + } + fn codegen_allocator( &self, tcx: TyCtxt<'_>, @@ -341,8 +345,7 @@ impl Deref for SyncContext { } unsafe impl Send for SyncContext {} -// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". -// TODO: disable it here by returning false in CodegenBackend::supports_parallel(). +// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "CodegenBackend::supports_parallel()". unsafe impl Sync for SyncContext {} impl WriteBackendMethods for GccCodegenBackend { diff --git a/src/mono_item.rs b/src/mono_item.rs index 51f35cbdee47..ff188c437dae 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -64,7 +64,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if linkage != Linkage::Internal && self.tcx.is_compiler_builtins(LOCAL_CRATE) { #[cfg(feature = "master")] decl.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - } else { + } else if visibility != Visibility::Default { #[cfg(feature = "master")] decl.add_attribute(FnAttribute::Visibility(base::visibility_to_gcc(visibility))); } diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 544d0bfc7105..6979c04d5343 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -80,3 +80,5 @@ tests/ui/uninhabited/uninhabited-transparent-return-abi.rs tests/ui/coroutine/panic-drops-resume.rs tests/ui/coroutine/panic-drops.rs tests/ui/coroutine/panic-safe.rs +tests/ui/process/nofile-limit.rs +tests/ui/simd/intrinsic/generic-arithmetic-pass.rs diff --git a/tests/run/asm.rs b/tests/run/asm.rs index 2dbf43be664d..9b15a28d8298 100644 --- a/tests/run/asm.rs +++ b/tests/run/asm.rs @@ -16,6 +16,7 @@ add_asm: ret" ); +#[cfg(target_arch = "x86_64")] extern "C" { fn add_asm(a: i64, b: i64) -> i64; } diff --git a/tests/run/float.rs b/tests/run/float.rs index 424fa1cf4ad5..df555f383fe0 100644 --- a/tests/run/float.rs +++ b/tests/run/float.rs @@ -3,8 +3,6 @@ // Run-time: // status: 0 -#![feature(const_black_box)] - fn main() { use std::hint::black_box; @@ -15,14 +13,14 @@ fn main() { }}; } - check!(i32, (black_box(0.0f32) as i32)); + check!(i32, black_box(0.0f32) as i32); - check!(u64, (black_box(f32::NAN) as u64)); - check!(u128, (black_box(f32::NAN) as u128)); + check!(u64, black_box(f32::NAN) as u64); + check!(u128, black_box(f32::NAN) as u128); - check!(i64, (black_box(f64::NAN) as i64)); - check!(u64, (black_box(f64::NAN) as u64)); + check!(i64, black_box(f64::NAN) as i64); + check!(u64, black_box(f64::NAN) as u64); - check!(i16, (black_box(f32::MIN) as i16)); - check!(i16, (black_box(f32::MAX) as i16)); + check!(i16, black_box(f32::MIN) as i16); + check!(i16, black_box(f32::MAX) as i16); } diff --git a/tests/run/int.rs b/tests/run/int.rs index 47b5dea46f8d..e20ecc23679d 100644 --- a/tests/run/int.rs +++ b/tests/run/int.rs @@ -3,8 +3,6 @@ // Run-time: // status: 0 -#![feature(const_black_box)] - fn main() { use std::hint::black_box; diff --git a/tests/run/volatile.rs b/tests/run/volatile.rs index 8b0433125936..94a7bdc5c066 100644 --- a/tests/run/volatile.rs +++ b/tests/run/volatile.rs @@ -5,13 +5,14 @@ use std::mem::MaybeUninit; +#[allow(dead_code)] #[derive(Debug)] struct Struct { pointer: *const (), func: unsafe fn(*const ()), } -fn func(ptr: *const ()) { +fn func(_ptr: *const ()) { } fn main() { diff --git a/tests/run/volatile2.rs b/tests/run/volatile2.rs index a177b817ab35..bdcb82598789 100644 --- a/tests/run/volatile2.rs +++ b/tests/run/volatile2.rs @@ -6,8 +6,6 @@ mod libc { #[link(name = "c")] extern "C" { - pub fn puts(s: *const u8) -> i32; - pub fn sigaction(signum: i32, act: *const sigaction, oldact: *mut sigaction) -> i32; pub fn mmap(addr: *mut (), len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut (); pub fn mprotect(addr: *mut (), len: usize, prot: i32) -> i32; @@ -61,7 +59,7 @@ fn main() { panic!("error: mmap failed"); } - let p_count = (&mut COUNT) as *mut u32; + let p_count = (&raw mut COUNT) as *mut u32; p_count.write_volatile(0); // Trigger segfaults @@ -94,7 +92,7 @@ fn main() { } unsafe extern "C" fn segv_handler(_: i32, _: *mut (), _: *mut ()) { - let p_count = (&mut COUNT) as *mut u32; + let p_count = (&raw mut COUNT) as *mut u32; p_count.write_volatile(p_count.read_volatile() + 1); let count = p_count.read_volatile(); From 4475b1c988aa94ad311fe83de9f0d0c9dbe08cb4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 18 Jul 2025 22:35:30 +0200 Subject: [PATCH 020/242] Remove forgotten git annotations --- example/mini_core_hello_world.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 358f265a6b85..85489f850e24 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -198,12 +198,6 @@ fn main() { assert_eq!(intrinsics::align_of::() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); -<<<<<<< HEAD - assert!(!const { intrinsics::needs_drop::() }); - assert!(!const { intrinsics::needs_drop::<[u8]>() }); - assert!(const { intrinsics::needs_drop::() }); - assert!(const { intrinsics::needs_drop::() }); -======= /* * TODO: re-enable in the next sync. let u8_needs_drop = const { intrinsics::needs_drop::() }; @@ -215,7 +209,6 @@ fn main() { let noisy_unsized_drop = const { intrinsics::needs_drop::() }; assert!(noisy_unsized_drop); */ ->>>>>>> f682d09eefc6700b9e5851ef193847959acf4fac Unique { pointer: 0 as *const &str, From 5b2c61edbe508163ad11cde0f35278417d7c26b3 Mon Sep 17 00:00:00 2001 From: Alisa Sireneva Date: Sat, 19 Jul 2025 18:18:01 +0300 Subject: [PATCH 021/242] Document guarantees of poisoning This mostly documents the current behavior of `Mutex` and `RwLock` as imperfect. It's unlikely that the situation improves significantly in the future, and even if it does, the rules will probably be more complicated than "poisoning is completely reliable", so this is a conservative guarantee. We also explicitly specify that `OnceLock` never poisons, even though it has an API similar to mutexes. --- library/std/src/sync/once_lock.rs | 2 ++ library/std/src/sync/poison.rs | 24 +++++++------ library/std/src/sync/poison/mutex.rs | 52 ++++++++++++++++++++++----- library/std/src/sync/poison/once.rs | 6 +++- library/std/src/sync/poison/rwlock.rs | 8 ++--- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index a5c3a6c46a43..b224044cbe09 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -16,6 +16,8 @@ use crate::sync::Once; /// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes /// initialized once written. /// +/// Unlike [`Mutex`](crate::sync::Mutex), `OnceLock` is never poisoned on panic. +/// /// [`OnceCell`]: crate::cell::OnceCell /// [`LazyLock`]: crate::sync::LazyLock /// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index 0c05f152ef84..e928b6772cc8 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -2,15 +2,16 @@ //! //! # Poisoning //! -//! All synchronization objects in this module implement a strategy called "poisoning" -//! where if a thread panics while holding the exclusive access granted by the primitive, -//! the state of the primitive is set to "poisoned". -//! This information is then propagated to all other threads +//! All synchronization objects in this module implement a strategy called +//! "poisoning" where a primitive becomes poisoned if it recognizes that some +//! thread has panicked while holding the exclusive access granted by the +//! primitive. This information is then propagated to all other threads //! to signify that the data protected by this primitive is likely tainted //! (some invariant is not being upheld). //! -//! The specifics of how this "poisoned" state affects other threads -//! depend on the primitive. See [#Overview] below. +//! The specifics of how this "poisoned" state affects other threads and whether +//! the panics are recognized reliably or on a best-effort basis depend on the +//! primitive. See [#Overview] below. //! //! For the alternative implementations that do not employ poisoning, //! see `std::sync::nonpoisoning`. @@ -34,14 +35,15 @@ //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at //! most one thread at a time is able to access some data. //! -//! [`Mutex::lock()`] returns a [`LockResult`], -//! providing a way to deal with the poisoned state. -//! See [`Mutex`'s documentation](Mutex#poisoning) for more. +//! Panicking while holding the lock typically poisons the mutex, but it is +//! not guaranteed to detect this condition in all circumstances. +//! [`Mutex::lock()`] returns a [`LockResult`], providing a way to deal with +//! the poisoned state. See [`Mutex`'s documentation](Mutex#poisoning) for more. //! //! - [`Once`]: A thread-safe way to run a piece of code only once. //! Mostly useful for implementing one-time global initialization. //! -//! [`Once`] is poisoned if the piece of code passed to +//! [`Once`] is reliably poisoned if the piece of code passed to //! [`Once::call_once()`] or [`Once::call_once_force()`] panics. //! When in poisoned state, subsequent calls to [`Once::call_once()`] will panic too. //! [`Once::call_once_force()`] can be used to clear the poisoned state. @@ -51,7 +53,7 @@ //! writer at a time. In some cases, this can be more efficient than //! a mutex. //! -//! This implementation, like [`Mutex`], will become poisoned on a panic. +//! This implementation, like [`Mutex`], usually becomes poisoned on a panic. //! Note, however, that an `RwLock` may only be poisoned if a panic occurs //! while it is locked exclusively (write mode). If a panic occurs in any reader, //! then the lock will not be poisoned. diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 30325be685c3..15dfe116133b 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -18,20 +18,54 @@ use crate::sys::sync as sys; /// # Poisoning /// /// The mutexes in this module implement a strategy called "poisoning" where a -/// mutex is considered poisoned whenever a thread panics while holding the -/// mutex. Once a mutex is poisoned, all other threads are unable to access the -/// data by default as it is likely tainted (some invariant is not being -/// upheld). +/// mutex becomes poisoned if it recognizes that the thread holding it has +/// panicked. /// -/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a +/// Once a mutex is poisoned, all other threads are unable to access the data by +/// default as it is likely tainted (some invariant is not being upheld). For a +/// mutex, this means that the [`lock`] and [`try_lock`] methods return a /// [`Result`] which indicates whether a mutex has been poisoned or not. Most /// usage of a mutex will simply [`unwrap()`] these results, propagating panics /// among threads to ensure that a possibly invalid invariant is not witnessed. /// -/// A poisoned mutex, however, does not prevent all access to the underlying -/// data. The [`PoisonError`] type has an [`into_inner`] method which will return -/// the guard that would have otherwise been returned on a successful lock. This -/// allows access to the data, despite the lock being poisoned. +/// Poisoning is only advisory: the [`PoisonError`] type has an [`into_inner`] +/// method which will return the guard that would have otherwise been returned +/// on a successful lock. This allows access to the data, despite the lock being +/// poisoned. +/// +/// In addition, the panic detection is not ideal, so even unpoisoned mutexes +/// need to be handled with care, since certain panics may have been skipped. +/// Therefore, `unsafe` code cannot rely on poisoning for soundness. Here's an +/// example of **incorrect** use of poisoning: +/// +/// ```rust +/// use std::sync::Mutex; +/// +/// struct MutexBox { +/// data: Mutex<*mut T>, +/// } +/// +/// impl MutexBox { +/// pub fn new(value: T) -> Self { +/// Self { +/// data: Mutex::new(Box::into_raw(Box::new(value))), +/// } +/// } +/// +/// pub fn replace_with(&self, f: impl FnOnce(T) -> T) { +/// let ptr = self.data.lock().expect("poisoned"); +/// // While `f` is running, the data is moved out of `*ptr`. If `f` +/// // panics, `*ptr` keeps pointing at a dropped value. The intention +/// // is that this will poison the mutex, so the following calls to +/// // `replace_with` will panic without reading `*ptr`. But since +/// // poisoning is not guaranteed to occur, this can lead to +/// // use-after-free. +/// unsafe { +/// (*ptr).write(f((*ptr).read())); +/// } +/// } +/// } +/// ``` /// /// [`new`]: Self::new /// [`lock`]: Self::lock diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs index 103e51954079..faf2913c5473 100644 --- a/library/std/src/sync/poison/once.rs +++ b/library/std/src/sync/poison/once.rs @@ -136,7 +136,8 @@ impl Once { /// it will *poison* this [`Once`] instance, causing all future invocations of /// `call_once` to also panic. /// - /// This is similar to [poisoning with mutexes][poison]. + /// This is similar to [poisoning with mutexes][poison], but this mechanism + /// is guaranteed to never skip panics within `f`. /// /// [poison]: struct.Mutex.html#poisoning #[inline] @@ -293,6 +294,9 @@ impl Once { /// Blocks the current thread until initialization has completed, ignoring /// poisoning. + /// + /// If this [`Once`] has been poisoned, this function blocks until it + /// becomes completed, unlike [`Once::wait()`], which panics in this case. #[stable(feature = "once_wait", since = "1.86.0")] pub fn wait_force(&self) { if !self.inner.is_completed() { diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 934a173425a8..0a50b6c2d8f1 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -46,10 +46,10 @@ use crate::sys::sync as sys; /// /// # Poisoning /// -/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however, -/// that an `RwLock` may only be poisoned if a panic occurs while it is locked -/// exclusively (write mode). If a panic occurs in any reader, then the lock -/// will not be poisoned. +/// An `RwLock`, like [`Mutex`], will usually become poisoned on a panic. Note, +/// however, that an `RwLock` may only be poisoned if a panic occurs while it is +/// locked exclusively (write mode). If a panic occurs in any reader, then the +/// lock will not be poisoned. /// /// # Examples /// From 41199f39d89135408763eee492fd2a5270828030 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 19 Jul 2025 11:17:38 -0700 Subject: [PATCH 022/242] `available_parallelism`: Add documentation for why we don't look at `ulimit` --- library/std/src/thread/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 6075173db47f..c80ea9cf4f00 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -2012,6 +2012,9 @@ fn _assert_sync_and_send() { /// which may take time on systems with large numbers of mountpoints. /// (This does not apply to cgroup v2, or to processes not in a /// cgroup.) +/// - It does not attempt to take `ulimit` into account. If there is a limit set on the number of +/// threads, `available_parallelism` cannot know how much of that limit a Rust program should +/// take, or know in a reliable and race-free way how much of that limit is already taken. /// /// On all targets: /// - It may overcount the amount of parallelism available when running in a VM From 8b8ffa8b4e58c2c451a53ae428718edf111922e0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Jul 2025 07:42:28 +0000 Subject: [PATCH 023/242] Merge modules and cached_modules for fat LTO The modules vec can already contain serialized modules and there is no need to distinguish between cached and non-cached cgus at LTO time. --- src/back/lto.rs | 12 ------------ src/lib.rs | 3 +-- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index e554dd2500bd..9f2842d7abc8 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -175,7 +175,6 @@ fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> { pub(crate) fn run_fat( cgcx: &CodegenContext, modules: Vec>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); @@ -186,7 +185,6 @@ pub(crate) fn run_fat( cgcx, dcx, modules, - cached_modules, lto_data.upstream_modules, lto_data.tmp_path, //<o_data.symbols_below_threshold, @@ -197,7 +195,6 @@ fn fat_lto( cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, modules: Vec>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], @@ -211,21 +208,12 @@ fn fat_lto( // modules that are serialized in-memory. // * `in_memory` contains modules which are already parsed and in-memory, // such as from multi-CGU builds. - // - // All of `cached_modules` (cached from previous incremental builds) can - // immediately go onto the `serialized_modules` modules list and then we can - // split the `modules` array into these two lists. let mut in_memory = Vec::new(); - serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { - info!("pushing cached module {:?}", wp.cgu_name); - (buffer, CString::new(wp.cgu_name).unwrap()) - })); for module in modules { match module { FatLtoInput::InMemory(m) => in_memory.push(m), FatLtoInput::Serialized { name, buffer } => { info!("pushing serialized module {:?}", name); - let buffer = SerializedModule::Local(buffer); serialized_modules.push((buffer, CString::new(name).unwrap())); } } diff --git a/src/lib.rs b/src/lib.rs index af416929ea73..3fbbaacf1bbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -359,14 +359,13 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_and_optimize_fat_lto( cgcx: &CodegenContext, modules: Vec>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, diff_fncs: Vec, ) -> Result, FatalError> { if !diff_fncs.is_empty() { unimplemented!(); } - back::lto::run_fat(cgcx, modules, cached_modules) + back::lto::run_fat(cgcx, modules) } fn run_thin_lto( From 803ada77a5104911ca972926610d2d4b9f3f511e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Jul 2025 14:59:53 +0000 Subject: [PATCH 024/242] Move LTO symbol export calculation from backends to cg_ssa --- messages.ftl | 8 ------ src/back/lto.rs | 74 ++++++------------------------------------------- src/errors.rs | 13 --------- 3 files changed, 8 insertions(+), 87 deletions(-) diff --git a/messages.ftl b/messages.ftl index 55a28bc9493e..a70ac08f01ae 100644 --- a/messages.ftl +++ b/messages.ftl @@ -3,12 +3,4 @@ codegen_gcc_unwinding_inline_asm = codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err} -codegen_gcc_dynamic_linking_with_lto = - cannot prefer dynamic linking when performing LTO - .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO - -codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs - -codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` - codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) diff --git a/src/back/lto.rs b/src/back/lto.rs index 9f2842d7abc8..e075aa8480aa 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -24,36 +24,24 @@ use std::sync::Arc; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; -use rustc_codegen_ssa::back::symbol_export; +use rustc_codegen_ssa::back::lto::{ + SerializedModule, ThinModule, ThinShared, exported_symbols_for_lto, +}; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; use rustc_errors::{DiagCtxtHandle, FatalError}; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; -use rustc_session::config::{CrateType, Lto}; +use rustc_session::config::Lto; use rustc_target::spec::RelocModel; use tempfile::{TempDir, tempdir}; use crate::back::write::save_temp_bitcode; -use crate::errors::{DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib}; +use crate::errors::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level}; -pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { - match crate_type { - CrateType::Executable - | CrateType::Dylib - | CrateType::Staticlib - | CrateType::Cdylib - | CrateType::Sdylib => true, - CrateType::Rlib | CrateType::ProcMacro => false, - } -} - struct LtoData { // TODO(antoyo): use symbols_below_threshold. //symbols_below_threshold: Vec, @@ -65,15 +53,8 @@ fn prepare_lto( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, ) -> Result { - let export_threshold = match cgcx.lto { - // We're just doing LTO for our one crate - Lto::ThinLocal => SymbolExportLevel::Rust, - - // We're doing LTO for the entire crate graph - Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&cgcx.crate_types), - - Lto::No => panic!("didn't request LTO but we're doing LTO"), - }; + // FIXME(bjorn3): Limit LTO exports to these symbols + let _symbols_below_threshold = exported_symbols_for_lto(cgcx, dcx)?; let tmp_path = match tempdir() { Ok(tmp_path) => tmp_path, @@ -83,20 +64,6 @@ fn prepare_lto( } }; - let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| { - if info.level.is_below_threshold(export_threshold) || info.used { - Some(name.clone()) - } else { - None - } - }; - let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); - let mut symbols_below_threshold = { - let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold"); - exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::>() - }; - info!("{} symbols to preserve in this crate", symbols_below_threshold.len()); - // If we're performing LTO for the entire crate graph, then for each of our // upstream dependencies, find the corresponding rlib and load the bitcode // from the archive. @@ -105,32 +72,7 @@ fn prepare_lto( // with either fat or thin LTO let mut upstream_modules = Vec::new(); if cgcx.lto != Lto::ThinLocal { - // Make sure we actually can run LTO - for crate_type in cgcx.crate_types.iter() { - if !crate_type_allows_lto(*crate_type) { - dcx.emit_err(LtoDisallowed); - return Err(FatalError); - } - if *crate_type == CrateType::Dylib && !cgcx.opts.unstable_opts.dylib_lto { - dcx.emit_err(LtoDylib); - return Err(FatalError); - } - } - - if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto { - dcx.emit_err(DynamicLinkingWithLTO); - return Err(FatalError); - } - - for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { - let exported_symbols = - cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); - { - let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold"); - symbols_below_threshold - .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter)); - } - + for &(_cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { let archive_data = unsafe { Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib") }; diff --git a/src/errors.rs b/src/errors.rs index b7e7343460fb..0aa16bd88b43 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -14,19 +14,6 @@ pub(crate) struct CopyBitcode { pub err: std::io::Error, } -#[derive(Diagnostic)] -#[diag(codegen_gcc_dynamic_linking_with_lto)] -#[note] -pub(crate) struct DynamicLinkingWithLTO; - -#[derive(Diagnostic)] -#[diag(codegen_gcc_lto_disallowed)] -pub(crate) struct LtoDisallowed; - -#[derive(Diagnostic)] -#[diag(codegen_gcc_lto_dylib)] -pub(crate) struct LtoDylib; - #[derive(Diagnostic)] #[diag(codegen_gcc_lto_bitcode_from_rlib)] pub(crate) struct LtoBitcodeFromRlib { From df5367810bb1af76f82f9dff4a727bee8e54f3bc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 15:57:20 +0000 Subject: [PATCH 025/242] Merge exported_symbols computation into exported_symbols_for_lto And move exported_symbols_for_lto call from backends to cg_ssa. --- src/back/lto.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index e075aa8480aa..f957bb7f101b 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -24,9 +24,7 @@ use std::sync::Arc; use gccjit::{Context, OutputKind}; use object::read::archive::ArchiveFile; -use rustc_codegen_ssa::back::lto::{ - SerializedModule, ThinModule, ThinShared, exported_symbols_for_lto, -}; +use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; @@ -54,7 +52,7 @@ fn prepare_lto( dcx: DiagCtxtHandle<'_>, ) -> Result { // FIXME(bjorn3): Limit LTO exports to these symbols - let _symbols_below_threshold = exported_symbols_for_lto(cgcx, dcx)?; + let _symbols_below_threshold = &cgcx.exported_symbols_for_lto; let tmp_path = match tempdir() { Ok(tmp_path) => tmp_path, From ecab766c2cc08d22205c01b6ad6c903389ea480d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 16:06:10 +0000 Subject: [PATCH 026/242] Move exported_symbols_for_lto out of CodegenContext --- src/back/lto.rs | 3 --- src/lib.rs | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index f957bb7f101b..d107e56fa35a 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -51,9 +51,6 @@ fn prepare_lto( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, ) -> Result { - // FIXME(bjorn3): Limit LTO exports to these symbols - let _symbols_below_threshold = &cgcx.exported_symbols_for_lto; - let tmp_path = match tempdir() { Ok(tmp_path) => tmp_path, Err(error) => { diff --git a/src/lib.rs b/src/lib.rs index 3fbbaacf1bbb..c8bf5bd8f67b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -358,6 +358,8 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_and_optimize_fat_lto( cgcx: &CodegenContext, + // FIXME(bjorn3): Limit LTO exports to these symbols + _exported_symbols_for_lto: &[String], modules: Vec>, diff_fncs: Vec, ) -> Result, FatalError> { @@ -370,6 +372,8 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_thin_lto( cgcx: &CodegenContext, + // FIXME(bjorn3): Limit LTO exports to these symbols + _exported_symbols_for_lto: &[String], modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result<(Vec>, Vec), FatalError> { From 28ccfad3a8478c4bf160d9ab30671eb1a4429590 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 16:59:30 +0000 Subject: [PATCH 027/242] Remove each_linked_rlib_for_lto from CodegenContext --- src/back/lto.rs | 9 ++++++--- src/lib.rs | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/back/lto.rs b/src/back/lto.rs index d107e56fa35a..d558dfbc1c45 100644 --- a/src/back/lto.rs +++ b/src/back/lto.rs @@ -49,6 +49,7 @@ struct LtoData { fn prepare_lto( cgcx: &CodegenContext, + each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>, ) -> Result { let tmp_path = match tempdir() { @@ -67,7 +68,7 @@ fn prepare_lto( // with either fat or thin LTO let mut upstream_modules = Vec::new(); if cgcx.lto != Lto::ThinLocal { - for &(_cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { + for path in each_linked_rlib_for_lto { let archive_data = unsafe { Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib") }; @@ -111,11 +112,12 @@ fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> { /// for further optimization. pub(crate) fn run_fat( cgcx: &CodegenContext, + each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - let lto_data = prepare_lto(cgcx, dcx)?; + let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx)?; /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ fat_lto( @@ -281,12 +283,13 @@ impl ModuleBufferMethods for ModuleBuffer { /// can simply be copied over from the incr. comp. cache. pub(crate) fn run_thin( cgcx: &CodegenContext, + each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result<(Vec>, Vec), FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); - let lto_data = prepare_lto(cgcx, dcx)?; + let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx)?; if cgcx.opts.cg.linker_plugin_lto.enabled() { unreachable!( "We should never reach this case if the LTO step \ diff --git a/src/lib.rs b/src/lib.rs index c8bf5bd8f67b..71765c511381 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,6 +81,7 @@ mod type_of; use std::any::Any; use std::fmt::Debug; use std::ops::Deref; +use std::path::PathBuf; #[cfg(not(feature = "master"))] use std::sync::atomic::AtomicBool; #[cfg(not(feature = "master"))] @@ -360,6 +361,7 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], + each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, diff_fncs: Vec, ) -> Result, FatalError> { @@ -367,17 +369,18 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - back::lto::run_fat(cgcx, modules) + back::lto::run_fat(cgcx, each_linked_rlib_for_lto, modules) } fn run_thin_lto( cgcx: &CodegenContext, // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], + each_linked_rlib_for_lto: &[PathBuf], modules: Vec<(String, Self::ThinBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> Result<(Vec>, Vec), FatalError> { - back::lto::run_thin(cgcx, modules, cached_modules) + back::lto::run_thin(cgcx, each_linked_rlib_for_lto, modules, cached_modules) } fn print_pass_timings(&self) { From c1be95ca0c2be04060da7a01f6892e5e6f2ef9dc Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 21 Jul 2025 14:16:43 -0400 Subject: [PATCH 028/242] Add missing inline attribute --- src/allocator.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 0d8dc93274f9..66258390d909 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -99,11 +99,14 @@ fn create_const_value_function( let func = context.new_function(None, FunctionType::Exported, output, &[], name, false); #[cfg(feature = "master")] - func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( - tcx.sess.default_visibility(), - ))); + { + func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc( + tcx.sess.default_visibility(), + ))); - func.add_attribute(FnAttribute::AlwaysInline); + func.add_attribute(FnAttribute::AlwaysInline); + func.add_attribute(FnAttribute::Inline); + } if tcx.sess.must_emit_unwind_tables() { // TODO(antoyo): emit unwind tables. From cf80eeec1650add1e24f114841154484fa051b70 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 21 Jul 2025 14:42:45 -0400 Subject: [PATCH 029/242] Fix clippy warnings --- build_system/src/abi_test.rs | 2 +- build_system/src/fuzz.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build_system/src/abi_test.rs b/build_system/src/abi_test.rs index 3c1531be27a5..a85886d87f36 100644 --- a/build_system/src/abi_test.rs +++ b/build_system/src/abi_test.rs @@ -31,7 +31,7 @@ pub fn run() -> Result<(), String> { Some("clones/abi-cafe".as_ref()), true, ) - .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?; + .map_err(|err| format!("Git clone failed with message: {err:?}!"))?; // Configure abi-cafe to use the exact same rustc version we use - this is crucial. // Otherwise, the concept of ABI compatibility becomes meanignless. std::fs::copy("rust-toolchain", "clones/abi-cafe/rust-toolchain") diff --git a/build_system/src/fuzz.rs b/build_system/src/fuzz.rs index 453211366b31..9714ce29af90 100644 --- a/build_system/src/fuzz.rs +++ b/build_system/src/fuzz.rs @@ -43,18 +43,18 @@ pub fn run() -> Result<(), String> { "--start" => { start = str::parse(&args.next().ok_or_else(|| "Fuzz start not provided!".to_string())?) - .map_err(|err| (format!("Fuzz start not a number {err:?}!")))?; + .map_err(|err| format!("Fuzz start not a number {err:?}!"))?; } "--count" => { count = str::parse(&args.next().ok_or_else(|| "Fuzz count not provided!".to_string())?) - .map_err(|err| (format!("Fuzz count not a number {err:?}!")))?; + .map_err(|err| format!("Fuzz count not a number {err:?}!"))?; } "-j" | "--jobs" => { threads = str::parse( &args.next().ok_or_else(|| "Fuzz thread count not provided!".to_string())?, ) - .map_err(|err| (format!("Fuzz thread count not a number {err:?}!")))?; + .map_err(|err| format!("Fuzz thread count not a number {err:?}!"))?; } _ => return Err(format!("Unknown option {arg}")), } @@ -66,7 +66,7 @@ pub fn run() -> Result<(), String> { Some("clones/rustlantis".as_ref()), true, ) - .map_err(|err| (format!("Git clone failed with message: {err:?}!")))?; + .map_err(|err| format!("Git clone failed with message: {err:?}!"))?; // Ensure that we are on the newest rustlantis commit. let cmd: &[&dyn AsRef] = &[&"git", &"pull", &"origin"]; From 18cc4f06a5252f0868be4ea620076247da68077c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 21 Jul 2025 14:45:00 -0400 Subject: [PATCH 030/242] Fix spelling mistakes --- src/lib.rs | 4 ++-- tools/cspell_dicts/rustc_codegen_gcc.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index af416929ea73..5e65a36f2737 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,9 +360,9 @@ impl WriteBackendMethods for GccCodegenBackend { cgcx: &CodegenContext, modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, - diff_fncs: Vec, + diff_functions: Vec, ) -> Result, FatalError> { - if !diff_fncs.is_empty() { + if !diff_functions.is_empty() { unimplemented!(); } diff --git a/tools/cspell_dicts/rustc_codegen_gcc.txt b/tools/cspell_dicts/rustc_codegen_gcc.txt index 31023e50ffa1..b19d7f67eab3 100644 --- a/tools/cspell_dicts/rustc_codegen_gcc.txt +++ b/tools/cspell_dicts/rustc_codegen_gcc.txt @@ -8,6 +8,7 @@ clzll cmse codegened csky +ctfe ctlz ctpop cttz @@ -47,6 +48,7 @@ mavx mcmodel minimumf minnumf +miri monomorphization monomorphizations monomorphized From af8cb1da142645c1d546e7c9ad66b17b50e16ffe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 21 Jul 2025 14:22:51 +0200 Subject: [PATCH 031/242] Rename `tests/assembly` into `tests/assembly-llvm` --- build_system/src/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index cbb0f9493838..bc0fdd40b6e8 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -588,7 +588,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"always", &"--stage", &"0", - &"tests/assembly/asm", + &"tests/assembly-llvm/asm", &"--compiletest-rustc-args", &rustc_args, ], From d466953088a41ce98acfcd53961ef07b887f074a Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:03:49 -0400 Subject: [PATCH 032/242] Fix failing UI tests --- tests/failing-ui-tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 6979c04d5343..f7040055874e 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -10,7 +10,7 @@ tests/ui/iterators/iter-sum-overflow-overflow-checks.rs tests/ui/mir/mir_drop_order.rs tests/ui/mir/mir_let_chains_drop_order.rs tests/ui/mir/mir_match_guard_let_chains_drop_order.rs -tests/ui/oom_unwind.rs +tests/ui/panics/oom-panic-unwind.rs tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs tests/ui/panic-runtime/abort.rs tests/ui/panic-runtime/link-to-abort.rs From a4fb5794e60883625fed8d25e9e55c649f9fb70c Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:14:31 -0400 Subject: [PATCH 033/242] Fix compilation of overflow addition --- src/int.rs | 30 +++++++++++++++++++++++++++++- src/lib.rs | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/int.rs b/src/int.rs index 6f21ce9352b5..53e49e71e2bf 100644 --- a/src/int.rs +++ b/src/int.rs @@ -4,12 +4,15 @@ // cSpell:words cmpti divti modti mulodi muloti udivti umodti -use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; +use gccjit::{ + BinaryOp, CType, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp, +}; use rustc_abi::{CanonAbi, Endian, ExternAbi}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode}; +use rustc_type_ir::{Interner, TyKind}; use crate::builder::{Builder, ToGccComp}; use crate::common::{SignType, TypeReflection}; @@ -351,6 +354,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? .new_local(self.location, rhs.get_type(), "binopResult") .get_address(self.location); + let new_type = type_kind_to_gcc_type(new_kind); + let new_type = self.context.new_c_type(new_type); + let lhs = self.context.new_cast(self.location, lhs, new_type); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); (res.dereference(self.location).to_rvalue(), overflow) } @@ -1042,3 +1048,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { self.context.new_array_constructor(None, typ, &values) } } + +fn type_kind_to_gcc_type(kind: TyKind) -> CType { + use rustc_middle::ty::IntTy::*; + use rustc_middle::ty::UintTy::*; + use rustc_middle::ty::{Int, Uint}; + + match kind { + Int(I8) => CType::Int8t, + Int(I16) => CType::Int16t, + Int(I32) => CType::Int32t, + Int(I64) => CType::Int64t, + Int(I128) => CType::Int128t, + + Uint(U8) => CType::UInt8t, + Uint(U16) => CType::UInt16t, + Uint(U32) => CType::UInt32t, + Uint(U64) => CType::UInt64t, + Uint(U128) => CType::UInt128t, + + _ => unimplemented!("Kind: {:?}", kind), + } +} diff --git a/src/lib.rs b/src/lib.rs index 5e65a36f2737..92808123d6a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_symbol_mangling; extern crate rustc_target; +extern crate rustc_type_ir; // This prevents duplicating functions and statics that are already part of the host rustc process. #[allow(unused_extern_crates)] From 27f3a97747cd46676c4fe2a4afd77009f3b98a46 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:16:06 -0400 Subject: [PATCH 034/242] Use a bitcast in Builder::ret to support non-native integers --- src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index a4ec4bf8deac..3cd464b61e14 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -540,8 +540,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn ret(&mut self, mut value: RValue<'gcc>) { let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { - // NOTE: due to opaque pointers now being used, we need to cast here. - value = self.context.new_cast(self.location, value, expected_return_type); + // NOTE: due to opaque pointers now being used, we need to bitcast here. + value = self.context.new_bitcast(self.location, value, expected_return_type); } self.llbb().end_with_return(self.location, value); } From a5bd9d6635831b09457ce39b1eacdc30ec306cd4 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:17:43 -0400 Subject: [PATCH 035/242] Fix spelling mistake --- tools/cspell_dicts/rustc_codegen_gcc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cspell_dicts/rustc_codegen_gcc.txt b/tools/cspell_dicts/rustc_codegen_gcc.txt index b19d7f67eab3..4fb018b3ecd8 100644 --- a/tools/cspell_dicts/rustc_codegen_gcc.txt +++ b/tools/cspell_dicts/rustc_codegen_gcc.txt @@ -26,6 +26,7 @@ fwrapv gimple hrtb immediates +interner liblto llbb llcx From 9ea18272eceae790619661b421dcec7fe1f0e41b Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:26:31 -0400 Subject: [PATCH 036/242] Fix sysroot compilation in release mode --- src/int.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/int.rs b/src/int.rs index 53e49e71e2bf..5180f1e6d3ed 100644 --- a/src/int.rs +++ b/src/int.rs @@ -170,9 +170,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { if a_type.is_vector() { // Vector types need to be bitcast. // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. - b = self.context.new_bitcast(self.location, b, a.get_type()); + b = self.context.new_bitcast(self.location, b, a_type); } else { - b = self.context.new_cast(self.location, b, a.get_type()); + b = self.context.new_cast(self.location, b, a_type); } } self.context.new_binary_op(self.location, operation, a_type, a, b) @@ -219,13 +219,22 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { operation_name: &str, signed: bool, a: RValue<'gcc>, - b: RValue<'gcc>, + mut b: RValue<'gcc>, ) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) { + if !a_type.is_compatible_with(b_type) { + if a_type.is_vector() { + // Vector types need to be bitcast. + // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. + b = self.context.new_bitcast(self.location, b, a_type); + } else { + b = self.context.new_cast(self.location, b, a_type); + } + } self.context.new_binary_op(self.location, operation, a_type, a, b) } else { debug_assert!(a_type.dyncast_array().is_some()); @@ -626,7 +635,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } - pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + pub fn gcc_xor(&self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { let a_type = a.get_type(); let b_type = b.get_type(); if a_type.is_vector() && b_type.is_vector() { @@ -634,6 +643,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { a ^ b } else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) { + if !a_type.is_compatible_with(b_type) { + b = self.context.new_cast(self.location, b, a_type); + } a ^ b } else { self.concat_low_high_rvalues( From de5cf685461967da8351a4d54ba96c5da5349eae Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:27:07 -0400 Subject: [PATCH 037/242] Remove failing UI test --- tests/failing-ui-tests.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index f7040055874e..9a806e5ba522 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -14,7 +14,6 @@ tests/ui/panics/oom-panic-unwind.rs tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs tests/ui/panic-runtime/abort.rs tests/ui/panic-runtime/link-to-abort.rs -tests/ui/unwind-no-uwtable.rs tests/ui/parser/unclosed-delimiter-in-dep.rs tests/ui/consts/missing_span_in_backtrace.rs tests/ui/drop/dynamic-drop.rs From ba18e20501d18c05859534b93796c4ca5100ad8f Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:28:44 -0400 Subject: [PATCH 038/242] Remove failing run-make test --- tests/failing-run-make-tests.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/failing-run-make-tests.txt b/tests/failing-run-make-tests.txt index 842533cd3c62..29032b321fa7 100644 --- a/tests/failing-run-make-tests.txt +++ b/tests/failing-run-make-tests.txt @@ -6,7 +6,6 @@ tests/run-make/doctests-keep-binaries/ tests/run-make/doctests-runtool/ tests/run-make/emit-shared-files/ tests/run-make/exit-code/ -tests/run-make/issue-22131/ tests/run-make/issue-64153/ tests/run-make/llvm-ident/ tests/run-make/native-link-modifier-bundle/ From 041be62e5f365434741195e5870ba355103a44d0 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:44:42 -0400 Subject: [PATCH 039/242] Add failing UI tests --- tests/failing-ui-tests.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 9a806e5ba522..4dc9507f28f1 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -81,3 +81,6 @@ tests/ui/coroutine/panic-drops.rs tests/ui/coroutine/panic-safe.rs tests/ui/process/nofile-limit.rs tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +tests/ui/linking/no-gc-encapsulation-symbols.rs +tests/ui/panics/unwind-force-no-unwind-tables.rs +tests/ui/attributes/fn-align-dyn.rs From 3c35d9b3eb46e6fa5645f93a6d04d13374f58b67 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 11:44:52 -0400 Subject: [PATCH 040/242] Add missing cast in gcc_checked_binop --- src/int.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/int.rs b/src/int.rs index 5180f1e6d3ed..64b612553cfc 100644 --- a/src/int.rs +++ b/src/int.rs @@ -366,6 +366,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let new_type = type_kind_to_gcc_type(new_kind); let new_type = self.context.new_c_type(new_type); let lhs = self.context.new_cast(self.location, lhs, new_type); + let rhs = self.context.new_cast(self.location, rhs, new_type); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); (res.dereference(self.location).to_rvalue(), overflow) } From d3a61f88e87b69574b691405024eacaa0d134518 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 13:06:52 -0400 Subject: [PATCH 041/242] Remove failing UI test --- tests/failing-lto-tests.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/failing-lto-tests.txt b/tests/failing-lto-tests.txt index b9126fb73a77..b1ae1e91078b 100644 --- a/tests/failing-lto-tests.txt +++ b/tests/failing-lto-tests.txt @@ -28,6 +28,5 @@ tests/ui/macros/macro-comma-behavior-rpass.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs tests/ui/macros/stringify.rs -tests/ui/reexport-test-harness-main.rs tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs tests/ui/binding/fn-arg-incomplete-pattern-drop-order.rs From d05542af7a07de7e58dc9a695125a3b50146ea82 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Tue, 22 Jul 2025 13:07:12 -0400 Subject: [PATCH 042/242] Add missing cast in gcc_checked_binop --- src/int.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/int.rs b/src/int.rs index 64b612553cfc..9dc1fcf5fc8b 100644 --- a/src/int.rs +++ b/src/int.rs @@ -367,6 +367,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let new_type = self.context.new_c_type(new_type); let lhs = self.context.new_cast(self.location, lhs, new_type); let rhs = self.context.new_cast(self.location, rhs, new_type); + let res = self.context.new_cast(self.location, res, new_type.make_pointer()); let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); (res.dereference(self.location).to_rvalue(), overflow) } From 293f95fb0cd27970e147697aa9500acdc22fd0e6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 11 Jul 2025 13:45:51 -0500 Subject: [PATCH 043/242] add regression test for RUST-143222 --- .../reexport/auxiliary/wrap-unnamable-type.rs | 12 ++++++++++++ .../rustdoc/reexport/wrapped-unnamble-type-143222.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs create mode 100644 tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs diff --git a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs new file mode 100644 index 000000000000..8ce0a0de5448 --- /dev/null +++ b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs @@ -0,0 +1,12 @@ +pub trait Assoc { + type Ty; +} + +pub struct Foo(::Ty); + +const _: () = { + impl crate::Assoc for Foo { + type Ty = Bar; + } + pub struct Bar; +}; diff --git a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs new file mode 100644 index 000000000000..005a5c0b98ad --- /dev/null +++ b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Z normalize-docs --document-private-items -Zunstable-options --show-type-layout +//@ aux-build:wrap-unnamable-type.rs +//@ build-aux-docs + +#![crate_name = "foo"] + +extern crate wrap_unnamable_type as helper; +//extern crate helper; +//@ has 'foo/struct.Foo.html' +//@ !hasraw - '_/struct.Bar.html' +#[doc(inline)] +pub use helper::Foo; From 4762694e4a4d04295c578a344d217e34067c608c Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 12 Jul 2025 15:05:30 -0500 Subject: [PATCH 044/242] rustdoc: never try to link to unnamable types --- src/librustdoc/html/format.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index be8a2d511e91..f4cf819fc59d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -368,6 +368,8 @@ pub(crate) enum HrefError { Private, // Not in external cache, href link should be in same page NotInExternalCache, + /// Refers to an unnamable item, such as one defined within a function or const block. + UnnamableItem, } /// This function is to get the external macro path because they are not in the cache used in @@ -498,7 +500,13 @@ fn url_parts( builder.extend(module_fqp.iter().copied()); Ok(builder) } - ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to)), + ExternalLocation::Local => { + if module_fqp.iter().any(|sym| sym.as_str() == "_") { + Err(HrefError::UnnamableItem) + } else { + Ok(href_relative_parts(module_fqp, relative_to)) + } + } ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt), } } From 94700f8f3fd4fc3f3a0e563aa94d4a399691d88f Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 14 Jul 2025 12:31:58 -0500 Subject: [PATCH 045/242] fix regression test --- tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs | 2 +- tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs index 8ce0a0de5448..7f8e346c8bea 100644 --- a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs +++ b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs @@ -4,7 +4,7 @@ pub trait Assoc { pub struct Foo(::Ty); -const _: () = { +const _X: () = { impl crate::Assoc for Foo { type Ty = Bar; } diff --git a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs index 005a5c0b98ad..9a8893786f5f 100644 --- a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs +++ b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs @@ -2,11 +2,15 @@ //@ aux-build:wrap-unnamable-type.rs //@ build-aux-docs +// regression test for https://github.com/rust-lang/rust/issues/143222 +// makes sure normalizing docs does not cause us to link to unnamable types +// in cross-crate reexports. + #![crate_name = "foo"] extern crate wrap_unnamable_type as helper; -//extern crate helper; + //@ has 'foo/struct.Foo.html' -//@ !hasraw - '_/struct.Bar.html' +//@ !hasraw - 'struct.Bar.html' #[doc(inline)] pub use helper::Foo; From f57283d6141fcc430e739fc2ad633e8997a66310 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 15 Jul 2025 16:06:03 -0500 Subject: [PATCH 046/242] rustdoc: actually never link to unnamable types --- src/librustdoc/html/format.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f4cf819fc59d..90d385aa1359 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -481,6 +481,20 @@ fn generate_item_def_id_path( Ok((url_parts, shortty, fqp)) } +/// Checks if the given defid refers to an item that is unnamable, such as one defined in a const block. +fn is_unnamable(tcx: TyCtxt<'_>, did: DefId) -> bool { + let mut cur_did = did; + while let Some(parent) = tcx.opt_parent(cur_did) { + match tcx.def_kind(parent) { + // items defined in these can be linked to + DefKind::Mod | DefKind::Impl { .. } | DefKind::ForeignMod => cur_did = parent, + // everything else does not have docs generated for it + _ => return true, + } + } + return false; +} + fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] } } @@ -500,13 +514,7 @@ fn url_parts( builder.extend(module_fqp.iter().copied()); Ok(builder) } - ExternalLocation::Local => { - if module_fqp.iter().any(|sym| sym.as_str() == "_") { - Err(HrefError::UnnamableItem) - } else { - Ok(href_relative_parts(module_fqp, relative_to)) - } - } + ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to)), ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt), } } @@ -560,6 +568,9 @@ pub(crate) fn href_with_root_path( } _ => original_did, }; + if is_unnamable(cx.tcx(), did) { + return Err(HrefError::UnnamableItem); + } let cache = cx.cache(); let relative_to = &cx.current; From 05a62c8a1172795709219aa5afc833eb1ab57c25 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 19 Jul 2025 14:26:47 -0500 Subject: [PATCH 047/242] impl items are never unnamable --- src/librustdoc/html/format.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 90d385aa1359..457af8e994d7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -486,8 +486,14 @@ fn is_unnamable(tcx: TyCtxt<'_>, did: DefId) -> bool { let mut cur_did = did; while let Some(parent) = tcx.opt_parent(cur_did) { match tcx.def_kind(parent) { - // items defined in these can be linked to - DefKind::Mod | DefKind::Impl { .. } | DefKind::ForeignMod => cur_did = parent, + // items defined in these can be linked to, as long as they are visible + DefKind::Mod | DefKind::ForeignMod => cur_did = parent, + // items in impls can be linked to, + // as long as we can link to the item the impl is on. + // since associated traits are not a thing, + // it should not be possible to refer to an impl item if + // the base type is not namable. + DefKind::Impl { .. } => return false, // everything else does not have docs generated for it _ => return true, } From 45231fa599583edc95843aaa4f23b12f762e01e7 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Wed, 23 Jul 2025 00:00:01 +0000 Subject: [PATCH 048/242] [rustdoc] Display unsafe attrs with edition 2024 `unsafe()` wrappers. --- src/librustdoc/clean/types.rs | 6 +++--- tests/rustdoc/attribute-rendering.rs | 6 +++--- tests/rustdoc/attributes-2021-edition.rs | 14 ++++++++++++++ tests/rustdoc/attributes-re-export-2021-edition.rs | 13 +++++++++++++ tests/rustdoc/attributes-re-export.rs | 2 +- tests/rustdoc/attributes.rs | 13 +++++++++---- tests/rustdoc/reexport/reexport-attrs.rs | 6 +++--- 7 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 tests/rustdoc/attributes-2021-edition.rs create mode 100644 tests/rustdoc/attributes-re-export-2021-edition.rs diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5ac5da24299f..64e707ad9d36 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -768,13 +768,13 @@ impl Item { .iter() .filter_map(|attr| match attr { hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { - Some(format!("#[link_section = \"{name}\"]")) + Some(format!("#[unsafe(link_section = \"{name}\")]")) } hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { - Some("#[no_mangle]".to_string()) + Some("#[unsafe(no_mangle)]".to_string()) } hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { - Some(format!("#[export_name = \"{name}\"]")) + Some(format!("#[unsafe(export_name = \"{name}\")]")) } hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { Some("#[non_exhaustive]".to_string()) diff --git a/tests/rustdoc/attribute-rendering.rs b/tests/rustdoc/attribute-rendering.rs index 841533814c38..bf9b81077f35 100644 --- a/tests/rustdoc/attribute-rendering.rs +++ b/tests/rustdoc/attribute-rendering.rs @@ -1,7 +1,7 @@ #![crate_name = "foo"] //@ has 'foo/fn.f.html' -//@ has - //*[@'class="rust item-decl"]' '#[export_name = "f"] pub fn f()' -#[export_name = "\ -f"] +//@ has - //*[@'class="rust item-decl"]' '#[unsafe(export_name = "f")] pub fn f()' +#[unsafe(export_name = "\ +f")] pub fn f() {} diff --git a/tests/rustdoc/attributes-2021-edition.rs b/tests/rustdoc/attributes-2021-edition.rs new file mode 100644 index 000000000000..b5028d8c8525 --- /dev/null +++ b/tests/rustdoc/attributes-2021-edition.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 +#![crate_name = "foo"] + +//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +#[no_mangle] +pub extern "C" fn f() {} + +//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "bar")]' +#[export_name = "bar"] +pub extern "C" fn g() {} + +//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]' +#[link_section = ".text"] +pub extern "C" fn example() {} diff --git a/tests/rustdoc/attributes-re-export-2021-edition.rs b/tests/rustdoc/attributes-re-export-2021-edition.rs new file mode 100644 index 000000000000..04ee6c273dd6 --- /dev/null +++ b/tests/rustdoc/attributes-re-export-2021-edition.rs @@ -0,0 +1,13 @@ +// Tests that attributes are correctly copied onto a re-exported item. +//@ edition:2024 +#![crate_name = "re_export"] + +//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +pub use thingymod::thingy as thingy2; + +mod thingymod { + #[unsafe(no_mangle)] + pub fn thingy() { + + } +} diff --git a/tests/rustdoc/attributes-re-export.rs b/tests/rustdoc/attributes-re-export.rs index 458826ea8a35..820276f83c09 100644 --- a/tests/rustdoc/attributes-re-export.rs +++ b/tests/rustdoc/attributes-re-export.rs @@ -2,7 +2,7 @@ //@ edition:2021 #![crate_name = "re_export"] -//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[no_mangle]' +//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' pub use thingymod::thingy as thingy2; mod thingymod { diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs index e34468a88b11..34487a891277 100644 --- a/tests/rustdoc/attributes.rs +++ b/tests/rustdoc/attributes.rs @@ -1,13 +1,18 @@ +//@ edition: 2024 #![crate_name = "foo"] -//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[no_mangle]' -#[no_mangle] +//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +#[unsafe(no_mangle)] pub extern "C" fn f() {} -//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[export_name = "bar"]' -#[export_name = "bar"] +//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "bar")]' +#[unsafe(export_name = "bar")] pub extern "C" fn g() {} +//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]' +#[unsafe(link_section = ".text")] +pub extern "C" fn example() {} + //@ has foo/struct.Repr.html '//pre[@class="rust item-decl"]' '#[repr(C, align(8))]' #[repr(C, align(8))] pub struct Repr; diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs index 0ec645841f0b..aec0a11c0c6a 100644 --- a/tests/rustdoc/reexport/reexport-attrs.rs +++ b/tests/rustdoc/reexport/reexport-attrs.rs @@ -4,13 +4,13 @@ extern crate reexports_attrs; -//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[no_mangle]' +//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' pub use reexports_attrs::f0; -//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[link_section = ".here"]' +//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]' pub use reexports_attrs::f1; -//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[export_name = "f2export"]' +//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]' pub use reexports_attrs::f2; //@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]' From 2b640216aea9527c67c82cfc781d979247ac6028 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 23 Jul 2025 09:56:54 -0400 Subject: [PATCH 049/242] Fix gcc_icmp with non-native integers --- src/int.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/int.rs b/src/int.rs index 9dc1fcf5fc8b..9fb7f6bad684 100644 --- a/src/int.rs +++ b/src/int.rs @@ -494,11 +494,27 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let lhs_low = self.context.new_cast(self.location, self.low(lhs), unsigned_type); let rhs_low = self.context.new_cast(self.location, self.low(rhs), unsigned_type); + let mut lhs_high = self.high(lhs); + let mut rhs_high = self.high(rhs); + + match op { + IntPredicate::IntUGT + | IntPredicate::IntUGE + | IntPredicate::IntULT + | IntPredicate::IntULE => { + lhs_high = self.context.new_cast(self.location, lhs_high, unsigned_type); + rhs_high = self.context.new_cast(self.location, rhs_high, unsigned_type); + } + // TODO(antoyo): we probably need to handle signed comparison for unsigned + // integers. + _ => (), + } + let condition = self.context.new_comparison( self.location, ComparisonOp::LessThan, - self.high(lhs), - self.high(rhs), + lhs_high, + rhs_high, ); self.llbb().end_with_conditional(self.location, condition, block1, block2); @@ -512,8 +528,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let condition = self.context.new_comparison( self.location, ComparisonOp::GreaterThan, - self.high(lhs), - self.high(rhs), + lhs_high, + rhs_high, ); block2.end_with_conditional(self.location, condition, block3, block4); From d636a6590ce1429ff011e04bb0b4d393dc382226 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 24 Jul 2025 17:15:36 +0500 Subject: [PATCH 050/242] moved 35 tests to organized locations --- .../issue-11709.rs => block-result/blocks-without-results.rs} | 0 .../issue-12033.rs => borrowck/refcell-borrow-comparison.rs} | 0 .../ui/{issues/issue-12127.rs => closures/fnonce-moved-twice.rs} | 0 .../{issues/issue-11958.rs => closures/moved-upvar-mut-rebind.rs} | 0 .../issue-12860.rs => collections/hashset-connected-border.rs} | 0 .../vec-macro-in-static-array.rs} | 0 .../format-message-windows-ffi.rs} | 0 .../{issues/issue-13105.rs => fn/anonymous-parameters-trait.rs} | 0 tests/ui/{issues/issue-12729.rs => imports/use-in-impl-scope.rs} | 0 .../{issues/issue-12677.rs => iterators/bytes-iterator-clone.rs} | 0 .../issue-13167.rs => iterators/phf-map-entries-iterator.rs} | 0 .../issue-13058.rs => lifetimes/iterator-trait-lifetime-error.rs} | 0 .../struct-lifetime-field-assignment.rs} | 0 .../{issues/issue-12863.rs => match/function-in-pattern-error.rs} | 0 .../issue-13027.rs => match/guard-literal-range-shadow.rs} | 0 .../ui/{issues/issue-11844.rs => match/option-result-mismatch.rs} | 0 .../issue-13466.rs => match/option-result-type-param-mismatch.rs} | 0 tests/ui/{issues/issue-12567.rs => match/slice-move-out-error.rs} | 0 .../issue-11869.rs => match/string-literal-match-patterns.rs} | 0 .../{issues/issue-12285.rs => match/struct-reference-patterns.rs} | 0 .../issue-12920.rs => panics/explicit-panic-unreachable.rs} | 0 .../ui/{issues/issue-13202.rs => panics/unwrap-or-panic-input.rs} | 0 .../issue-13407.rs => privacy/private-unit-struct-assignment.rs} | 0 .../issue-13214.rs => statics/enum-with-static-str-variant.rs} | 0 .../issue-12041.rs => threads/moved-value-in-thread-loop.rs} | 0 .../{issues/issue-12744.rs => traits/any-trait-object-debug.rs} | 0 .../issue-13204.rs => traits/default-method-lifetime-params.rs} | 0 .../{issues/issue-13264.rs => traits/deref-chain-method-calls.rs} | 0 .../{issues/issue-13434.rs => traits/fnonce-repro-trait-impl.rs} | 0 .../{issues/issue-13323.rs => traits/matcher-trait-equality.rs} | 0 .../{issues/issue-11820.rs => traits/reference-clone-noclone.rs} | 0 .../isize-usize-mismatch-error.rs} | 0 .../issue-12909.rs => type-inference/type-collect-inference.rs} | 0 .../issue-11771.rs => type-inference/unit-type-add-error.rs} | 0 .../{issues/issue-11740.rs => unsafe/unsafe-transmute-in-find.rs} | 0 35 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-11709.rs => block-result/blocks-without-results.rs} (100%) rename tests/ui/{issues/issue-12033.rs => borrowck/refcell-borrow-comparison.rs} (100%) rename tests/ui/{issues/issue-12127.rs => closures/fnonce-moved-twice.rs} (100%) rename tests/ui/{issues/issue-11958.rs => closures/moved-upvar-mut-rebind.rs} (100%) rename tests/ui/{issues/issue-12860.rs => collections/hashset-connected-border.rs} (100%) rename tests/ui/{issues/issue-13446.rs => const-generics/vec-macro-in-static-array.rs} (100%) rename tests/ui/{issues/issue-13259-windows-tcb-trash.rs => extern/format-message-windows-ffi.rs} (100%) rename tests/ui/{issues/issue-13105.rs => fn/anonymous-parameters-trait.rs} (100%) rename tests/ui/{issues/issue-12729.rs => imports/use-in-impl-scope.rs} (100%) rename tests/ui/{issues/issue-12677.rs => iterators/bytes-iterator-clone.rs} (100%) rename tests/ui/{issues/issue-13167.rs => iterators/phf-map-entries-iterator.rs} (100%) rename tests/ui/{issues/issue-13058.rs => lifetimes/iterator-trait-lifetime-error.rs} (100%) rename tests/ui/{issues/issue-13405.rs => lifetimes/struct-lifetime-field-assignment.rs} (100%) rename tests/ui/{issues/issue-12863.rs => match/function-in-pattern-error.rs} (100%) rename tests/ui/{issues/issue-13027.rs => match/guard-literal-range-shadow.rs} (100%) rename tests/ui/{issues/issue-11844.rs => match/option-result-mismatch.rs} (100%) rename tests/ui/{issues/issue-13466.rs => match/option-result-type-param-mismatch.rs} (100%) rename tests/ui/{issues/issue-12567.rs => match/slice-move-out-error.rs} (100%) rename tests/ui/{issues/issue-11869.rs => match/string-literal-match-patterns.rs} (100%) rename tests/ui/{issues/issue-12285.rs => match/struct-reference-patterns.rs} (100%) rename tests/ui/{issues/issue-12920.rs => panics/explicit-panic-unreachable.rs} (100%) rename tests/ui/{issues/issue-13202.rs => panics/unwrap-or-panic-input.rs} (100%) rename tests/ui/{issues/issue-13407.rs => privacy/private-unit-struct-assignment.rs} (100%) rename tests/ui/{issues/issue-13214.rs => statics/enum-with-static-str-variant.rs} (100%) rename tests/ui/{issues/issue-12041.rs => threads/moved-value-in-thread-loop.rs} (100%) rename tests/ui/{issues/issue-12744.rs => traits/any-trait-object-debug.rs} (100%) rename tests/ui/{issues/issue-13204.rs => traits/default-method-lifetime-params.rs} (100%) rename tests/ui/{issues/issue-13264.rs => traits/deref-chain-method-calls.rs} (100%) rename tests/ui/{issues/issue-13434.rs => traits/fnonce-repro-trait-impl.rs} (100%) rename tests/ui/{issues/issue-13323.rs => traits/matcher-trait-equality.rs} (100%) rename tests/ui/{issues/issue-11820.rs => traits/reference-clone-noclone.rs} (100%) rename tests/ui/{issues/issue-13359.rs => type-inference/isize-usize-mismatch-error.rs} (100%) rename tests/ui/{issues/issue-12909.rs => type-inference/type-collect-inference.rs} (100%) rename tests/ui/{issues/issue-11771.rs => type-inference/unit-type-add-error.rs} (100%) rename tests/ui/{issues/issue-11740.rs => unsafe/unsafe-transmute-in-find.rs} (100%) diff --git a/tests/ui/issues/issue-11709.rs b/tests/ui/block-result/blocks-without-results.rs similarity index 100% rename from tests/ui/issues/issue-11709.rs rename to tests/ui/block-result/blocks-without-results.rs diff --git a/tests/ui/issues/issue-12033.rs b/tests/ui/borrowck/refcell-borrow-comparison.rs similarity index 100% rename from tests/ui/issues/issue-12033.rs rename to tests/ui/borrowck/refcell-borrow-comparison.rs diff --git a/tests/ui/issues/issue-12127.rs b/tests/ui/closures/fnonce-moved-twice.rs similarity index 100% rename from tests/ui/issues/issue-12127.rs rename to tests/ui/closures/fnonce-moved-twice.rs diff --git a/tests/ui/issues/issue-11958.rs b/tests/ui/closures/moved-upvar-mut-rebind.rs similarity index 100% rename from tests/ui/issues/issue-11958.rs rename to tests/ui/closures/moved-upvar-mut-rebind.rs diff --git a/tests/ui/issues/issue-12860.rs b/tests/ui/collections/hashset-connected-border.rs similarity index 100% rename from tests/ui/issues/issue-12860.rs rename to tests/ui/collections/hashset-connected-border.rs diff --git a/tests/ui/issues/issue-13446.rs b/tests/ui/const-generics/vec-macro-in-static-array.rs similarity index 100% rename from tests/ui/issues/issue-13446.rs rename to tests/ui/const-generics/vec-macro-in-static-array.rs diff --git a/tests/ui/issues/issue-13259-windows-tcb-trash.rs b/tests/ui/extern/format-message-windows-ffi.rs similarity index 100% rename from tests/ui/issues/issue-13259-windows-tcb-trash.rs rename to tests/ui/extern/format-message-windows-ffi.rs diff --git a/tests/ui/issues/issue-13105.rs b/tests/ui/fn/anonymous-parameters-trait.rs similarity index 100% rename from tests/ui/issues/issue-13105.rs rename to tests/ui/fn/anonymous-parameters-trait.rs diff --git a/tests/ui/issues/issue-12729.rs b/tests/ui/imports/use-in-impl-scope.rs similarity index 100% rename from tests/ui/issues/issue-12729.rs rename to tests/ui/imports/use-in-impl-scope.rs diff --git a/tests/ui/issues/issue-12677.rs b/tests/ui/iterators/bytes-iterator-clone.rs similarity index 100% rename from tests/ui/issues/issue-12677.rs rename to tests/ui/iterators/bytes-iterator-clone.rs diff --git a/tests/ui/issues/issue-13167.rs b/tests/ui/iterators/phf-map-entries-iterator.rs similarity index 100% rename from tests/ui/issues/issue-13167.rs rename to tests/ui/iterators/phf-map-entries-iterator.rs diff --git a/tests/ui/issues/issue-13058.rs b/tests/ui/lifetimes/iterator-trait-lifetime-error.rs similarity index 100% rename from tests/ui/issues/issue-13058.rs rename to tests/ui/lifetimes/iterator-trait-lifetime-error.rs diff --git a/tests/ui/issues/issue-13405.rs b/tests/ui/lifetimes/struct-lifetime-field-assignment.rs similarity index 100% rename from tests/ui/issues/issue-13405.rs rename to tests/ui/lifetimes/struct-lifetime-field-assignment.rs diff --git a/tests/ui/issues/issue-12863.rs b/tests/ui/match/function-in-pattern-error.rs similarity index 100% rename from tests/ui/issues/issue-12863.rs rename to tests/ui/match/function-in-pattern-error.rs diff --git a/tests/ui/issues/issue-13027.rs b/tests/ui/match/guard-literal-range-shadow.rs similarity index 100% rename from tests/ui/issues/issue-13027.rs rename to tests/ui/match/guard-literal-range-shadow.rs diff --git a/tests/ui/issues/issue-11844.rs b/tests/ui/match/option-result-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-11844.rs rename to tests/ui/match/option-result-mismatch.rs diff --git a/tests/ui/issues/issue-13466.rs b/tests/ui/match/option-result-type-param-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-13466.rs rename to tests/ui/match/option-result-type-param-mismatch.rs diff --git a/tests/ui/issues/issue-12567.rs b/tests/ui/match/slice-move-out-error.rs similarity index 100% rename from tests/ui/issues/issue-12567.rs rename to tests/ui/match/slice-move-out-error.rs diff --git a/tests/ui/issues/issue-11869.rs b/tests/ui/match/string-literal-match-patterns.rs similarity index 100% rename from tests/ui/issues/issue-11869.rs rename to tests/ui/match/string-literal-match-patterns.rs diff --git a/tests/ui/issues/issue-12285.rs b/tests/ui/match/struct-reference-patterns.rs similarity index 100% rename from tests/ui/issues/issue-12285.rs rename to tests/ui/match/struct-reference-patterns.rs diff --git a/tests/ui/issues/issue-12920.rs b/tests/ui/panics/explicit-panic-unreachable.rs similarity index 100% rename from tests/ui/issues/issue-12920.rs rename to tests/ui/panics/explicit-panic-unreachable.rs diff --git a/tests/ui/issues/issue-13202.rs b/tests/ui/panics/unwrap-or-panic-input.rs similarity index 100% rename from tests/ui/issues/issue-13202.rs rename to tests/ui/panics/unwrap-or-panic-input.rs diff --git a/tests/ui/issues/issue-13407.rs b/tests/ui/privacy/private-unit-struct-assignment.rs similarity index 100% rename from tests/ui/issues/issue-13407.rs rename to tests/ui/privacy/private-unit-struct-assignment.rs diff --git a/tests/ui/issues/issue-13214.rs b/tests/ui/statics/enum-with-static-str-variant.rs similarity index 100% rename from tests/ui/issues/issue-13214.rs rename to tests/ui/statics/enum-with-static-str-variant.rs diff --git a/tests/ui/issues/issue-12041.rs b/tests/ui/threads/moved-value-in-thread-loop.rs similarity index 100% rename from tests/ui/issues/issue-12041.rs rename to tests/ui/threads/moved-value-in-thread-loop.rs diff --git a/tests/ui/issues/issue-12744.rs b/tests/ui/traits/any-trait-object-debug.rs similarity index 100% rename from tests/ui/issues/issue-12744.rs rename to tests/ui/traits/any-trait-object-debug.rs diff --git a/tests/ui/issues/issue-13204.rs b/tests/ui/traits/default-method-lifetime-params.rs similarity index 100% rename from tests/ui/issues/issue-13204.rs rename to tests/ui/traits/default-method-lifetime-params.rs diff --git a/tests/ui/issues/issue-13264.rs b/tests/ui/traits/deref-chain-method-calls.rs similarity index 100% rename from tests/ui/issues/issue-13264.rs rename to tests/ui/traits/deref-chain-method-calls.rs diff --git a/tests/ui/issues/issue-13434.rs b/tests/ui/traits/fnonce-repro-trait-impl.rs similarity index 100% rename from tests/ui/issues/issue-13434.rs rename to tests/ui/traits/fnonce-repro-trait-impl.rs diff --git a/tests/ui/issues/issue-13323.rs b/tests/ui/traits/matcher-trait-equality.rs similarity index 100% rename from tests/ui/issues/issue-13323.rs rename to tests/ui/traits/matcher-trait-equality.rs diff --git a/tests/ui/issues/issue-11820.rs b/tests/ui/traits/reference-clone-noclone.rs similarity index 100% rename from tests/ui/issues/issue-11820.rs rename to tests/ui/traits/reference-clone-noclone.rs diff --git a/tests/ui/issues/issue-13359.rs b/tests/ui/type-inference/isize-usize-mismatch-error.rs similarity index 100% rename from tests/ui/issues/issue-13359.rs rename to tests/ui/type-inference/isize-usize-mismatch-error.rs diff --git a/tests/ui/issues/issue-12909.rs b/tests/ui/type-inference/type-collect-inference.rs similarity index 100% rename from tests/ui/issues/issue-12909.rs rename to tests/ui/type-inference/type-collect-inference.rs diff --git a/tests/ui/issues/issue-11771.rs b/tests/ui/type-inference/unit-type-add-error.rs similarity index 100% rename from tests/ui/issues/issue-11771.rs rename to tests/ui/type-inference/unit-type-add-error.rs diff --git a/tests/ui/issues/issue-11740.rs b/tests/ui/unsafe/unsafe-transmute-in-find.rs similarity index 100% rename from tests/ui/issues/issue-11740.rs rename to tests/ui/unsafe/unsafe-transmute-in-find.rs From 5ae2d42a8c80807c7e3ae7e8aff165fb4d8e046f Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 7 Nov 2024 15:33:45 -0600 Subject: [PATCH 051/242] get rid of some false negatives in rustdoc::broken_intra_doc_links rustdoc will not try to do intra-doc linking if the "path" of a link looks too much like a "real url". however, only inline links ([text](url)) can actually contain a url, other types of links (reference links, shortcut links) contain a *reference* which is later resolved to an actual url. the "path" in this case cannot be a url, and therefore it should not be skipped due to looking like a url. Co-authored-by: Michael Howell --- .../passes/collect_intra_doc_links.rs | 13 ++++++-- tests/rustdoc-ui/bad-intra-doc.rs | 13 ++++++++ tests/rustdoc-ui/bad-intra-doc.stderr | 31 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc-ui/bad-intra-doc.rs create mode 100644 tests/rustdoc-ui/bad-intra-doc.stderr diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5a9aa2a94c8b..97f8a2be10b2 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -941,13 +941,20 @@ fn preprocess_link( ori_link: &MarkdownLink, dox: &str, ) -> Option> { + // certain link kinds cannot have their path be urls, + // so they should not be ignored, no matter how much they look like urls. + // e.g. [https://example.com/] is not a link to example.com. + let can_be_url = ori_link.kind != LinkType::ShortcutUnknown + && ori_link.kind != LinkType::CollapsedUnknown + && ori_link.kind != LinkType::ReferenceUnknown; + // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { return None; } // Bail early for real links. - if ori_link.link.contains('/') { + if can_be_url && ori_link.link.contains('/') { return None; } @@ -972,7 +979,7 @@ fn preprocess_link( Ok(None) => (None, link, link), Err((err_msg, relative_range)) => { // Only report error if we would not have ignored this link. See issue #83859. - if !should_ignore_link_with_disambiguators(link) { + if !(can_be_url && should_ignore_link_with_disambiguators(link)) { let disambiguator_range = match range_between_backticks(&ori_link.range, dox) { MarkdownLinkRange::Destination(no_backticks_range) => { MarkdownLinkRange::Destination( @@ -989,7 +996,7 @@ fn preprocess_link( } }; - if should_ignore_link(path_str) { + if can_be_url && should_ignore_link(path_str) { return None; } diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/bad-intra-doc.rs new file mode 100644 index 000000000000..7bc55756e670 --- /dev/null +++ b/tests/rustdoc-ui/bad-intra-doc.rs @@ -0,0 +1,13 @@ +#![no_std] +#![deny(rustdoc::broken_intra_doc_links)] + +// regression test for https://github.com/rust-lang/rust/issues/54191 + +/// this is not a link to [`example.com`] //~ERROR unresolved link +/// +/// this link [`has spaces in it`]. +/// +/// attempted link to method: [`Foo.bar()`] //~ERROR unresolved link +/// +/// classic broken intra-doc link: [`Bar`] //~ERROR unresolved link +pub struct Foo; diff --git a/tests/rustdoc-ui/bad-intra-doc.stderr b/tests/rustdoc-ui/bad-intra-doc.stderr new file mode 100644 index 000000000000..9533792b35b6 --- /dev/null +++ b/tests/rustdoc-ui/bad-intra-doc.stderr @@ -0,0 +1,31 @@ +error: unresolved link to `example.com` + --> $DIR/bad-intra-doc.rs:6:29 + | +LL | /// this is not a link to [`example.com`] + | ^^^^^^^^^^^ no item named `example.com` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` +note: the lint level is defined here + --> $DIR/bad-intra-doc.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `Foo.bar` + --> $DIR/bad-intra-doc.rs:10:33 + | +LL | /// attempted link to method: [`Foo.bar()`] + | ^^^^^^^^^ no item named `Foo.bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Bar` + --> $DIR/bad-intra-doc.rs:12:38 + | +LL | /// classic broken intra-doc link: [`Bar`] + | ^^^ no item named `Bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to 3 previous errors + From 87d7d80cec060690c9055fa93cb29dfe5eb79ce9 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 8 Nov 2024 13:59:56 -0600 Subject: [PATCH 052/242] adjust more unit tests to reflect more aggressive intra-doc linting --- .../disambiguator-endswith-named-suffix.rs | 30 ++--- ...disambiguator-endswith-named-suffix.stderr | 122 +++++++++++++++++- tests/rustdoc-ui/intra-doc/weird-syntax.rs | 2 +- .../rustdoc-ui/intra-doc/weird-syntax.stderr | 24 ++++ .../lints/redundant_explicit_links-utf8.rs | 14 +- .../redundant_explicit_links-utf8.stderr | 59 +++++++++ 6 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs index 1174e16dd53f..cb277d529ce7 100644 --- a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs +++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs @@ -2,67 +2,67 @@ //@ normalize-stderr: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" //! [struct@m!()] //~ WARN: unmatched disambiguator `struct` and suffix `!()` -//! [struct@m!{}] +//! [struct@m!{}] //~ WARN: unmatched disambiguator `struct` and suffix `!{}` //! [struct@m![]] //! [struct@f()] //~ WARN: unmatched disambiguator `struct` and suffix `()` //! [struct@m!] //~ WARN: unmatched disambiguator `struct` and suffix `!` //! //! [enum@m!()] //~ WARN: unmatched disambiguator `enum` and suffix `!()` -//! [enum@m!{}] +//! [enum@m!{}] //~ WARN: unmatched disambiguator `enum` and suffix `!{}` //! [enum@m![]] //! [enum@f()] //~ WARN: unmatched disambiguator `enum` and suffix `()` //! [enum@m!] //~ WARN: unmatched disambiguator `enum` and suffix `!` //! //! [trait@m!()] //~ WARN: unmatched disambiguator `trait` and suffix `!()` -//! [trait@m!{}] +//! [trait@m!{}] //~ WARN: unmatched disambiguator `trait` and suffix `!{}` //! [trait@m![]] //! [trait@f()] //~ WARN: unmatched disambiguator `trait` and suffix `()` //! [trait@m!] //~ WARN: unmatched disambiguator `trait` and suffix `!` //! //! [module@m!()] //~ WARN: unmatched disambiguator `module` and suffix `!()` -//! [module@m!{}] +//! [module@m!{}] //~ WARN: unmatched disambiguator `module` and suffix `!{}` //! [module@m![]] //! [module@f()] //~ WARN: unmatched disambiguator `module` and suffix `()` //! [module@m!] //~ WARN: unmatched disambiguator `module` and suffix `!` //! //! [mod@m!()] //~ WARN: unmatched disambiguator `mod` and suffix `!()` -//! [mod@m!{}] +//! [mod@m!{}] //~ WARN: unmatched disambiguator `mod` and suffix `!{}` //! [mod@m![]] //! [mod@f()] //~ WARN: unmatched disambiguator `mod` and suffix `()` //! [mod@m!] //~ WARN: unmatched disambiguator `mod` and suffix `!` //! //! [const@m!()] //~ WARN: unmatched disambiguator `const` and suffix `!()` -//! [const@m!{}] +//! [const@m!{}] //~ WARN: unmatched disambiguator `const` and suffix `!{}` //! [const@m![]] //! [const@f()] //~ WARN: incompatible link kind for `f` //! [const@m!] //~ WARN: unmatched disambiguator `const` and suffix `!` //! //! [constant@m!()] //~ WARN: unmatched disambiguator `constant` and suffix `!()` -//! [constant@m!{}] +//! [constant@m!{}] //~ WARN: unmatched disambiguator `constant` and suffix `!{}` //! [constant@m![]] //! [constant@f()] //~ WARN: incompatible link kind for `f` //! [constant@m!] //~ WARN: unmatched disambiguator `constant` and suffix `!` //! //! [static@m!()] //~ WARN: unmatched disambiguator `static` and suffix `!()` -//! [static@m!{}] +//! [static@m!{}] //~ WARN: unmatched disambiguator `static` and suffix `!{}` //! [static@m![]] //! [static@f()] //~ WARN: incompatible link kind for `f` //! [static@m!] //~ WARN: unmatched disambiguator `static` and suffix `!` //! //! [function@m!()] //~ WARN: unmatched disambiguator `function` and suffix `!()` -//! [function@m!{}] +//! [function@m!{}] //~ WARN: unmatched disambiguator `function` and suffix `!{}` //! [function@m![]] //! [function@f()] //! [function@m!] //~ WARN: unmatched disambiguator `function` and suffix `!` //! //! [fn@m!()] //~ WARN: unmatched disambiguator `fn` and suffix `!()` -//! [fn@m!{}] +//! [fn@m!{}] //~ WARN: unmatched disambiguator `fn` and suffix `!{}` //! [fn@m![]] //! [fn@f()] //! [fn@m!] //~ WARN: unmatched disambiguator `fn` and suffix `!` //! //! [method@m!()] //~ WARN: unmatched disambiguator `method` and suffix `!()` -//! [method@m!{}] +//! [method@m!{}] //~ WARN: unmatched disambiguator `method` and suffix `!{}` //! [method@m![]] //! [method@f()] //! [method@m!] //~ WARN: unmatched disambiguator `method` and suffix `!` @@ -74,13 +74,13 @@ //! [derive@m!] //~ WARN: incompatible link kind for `m` //! //! [type@m!()] //~ WARN: unmatched disambiguator `type` and suffix `!()` -//! [type@m!{}] +//! [type@m!{}] //~ WARN: unmatched disambiguator `type` and suffix `!{}` //! [type@m![]] //! [type@f()] //~ WARN: unmatched disambiguator `type` and suffix `()` //! [type@m!] //~ WARN: unmatched disambiguator `type` and suffix `!` //! //! [value@m!()] //~ WARN: unmatched disambiguator `value` and suffix `!()` -//! [value@m!{}] +//! [value@m!{}] //~ WARN: unmatched disambiguator `value` and suffix `!{}` //! [value@m![]] //! [value@f()] //! [value@m!] //~ WARN: unmatched disambiguator `value` and suffix `!` @@ -92,13 +92,13 @@ //! [macro@m!] //! //! [prim@m!()] //~ WARN: unmatched disambiguator `prim` and suffix `!()` -//! [prim@m!{}] +//! [prim@m!{}] //~ WARN: unmatched disambiguator `prim` and suffix `!{}` //! [prim@m![]] //! [prim@f()] //~ WARN: unmatched disambiguator `prim` and suffix `()` //! [prim@m!] //~ WARN: unmatched disambiguator `prim` and suffix `!` //! //! [primitive@m!()] //~ WARN: unmatched disambiguator `primitive` and suffix `!()` -//! [primitive@m!{}] +//! [primitive@m!{}] //~ WARN: unmatched disambiguator `primitive` and suffix `!{}` //! [primitive@m![]] //! [primitive@f()] //~ WARN: unmatched disambiguator `primitive` and suffix `()` //! [primitive@m!] //~ WARN: unmatched disambiguator `primitive` and suffix `!` diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr index f4e40a488738..184033859688 100644 --- a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr +++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr @@ -7,6 +7,14 @@ LL | //! [struct@m!()] = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default +warning: unmatched disambiguator `struct` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:5:6 + | +LL | //! [struct@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `struct` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:7:6 | @@ -31,6 +39,14 @@ LL | //! [enum@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `enum` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:11:6 + | +LL | //! [enum@m!{}] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `enum` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:13:6 | @@ -55,6 +71,14 @@ LL | //! [trait@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `trait` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:17:6 + | +LL | //! [trait@m!{}] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `trait` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:19:6 | @@ -79,6 +103,14 @@ LL | //! [module@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `module` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:23:6 + | +LL | //! [module@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `module` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:25:6 | @@ -103,6 +135,14 @@ LL | //! [mod@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `mod` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:29:6 + | +LL | //! [mod@m!{}] + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `mod` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:31:6 | @@ -127,6 +167,14 @@ LL | //! [const@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `const` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:35:6 + | +LL | //! [const@m!{}] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: incompatible link kind for `f` --> $DIR/disambiguator-endswith-named-suffix.rs:37:6 | @@ -155,6 +203,14 @@ LL | //! [constant@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `constant` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:41:6 + | +LL | //! [constant@m!{}] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: incompatible link kind for `f` --> $DIR/disambiguator-endswith-named-suffix.rs:43:6 | @@ -183,6 +239,14 @@ LL | //! [static@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `static` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:47:6 + | +LL | //! [static@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: incompatible link kind for `f` --> $DIR/disambiguator-endswith-named-suffix.rs:49:6 | @@ -211,6 +275,14 @@ LL | //! [function@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `function` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:53:6 + | +LL | //! [function@m!{}] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `function` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:56:6 | @@ -227,6 +299,14 @@ LL | //! [fn@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `fn` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:59:6 + | +LL | //! [fn@m!{}] + | ^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `fn` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:62:6 | @@ -243,6 +323,14 @@ LL | //! [method@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `method` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:65:6 + | +LL | //! [method@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `method` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:68:6 | @@ -303,6 +391,14 @@ LL | //! [type@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `type` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:77:6 + | +LL | //! [type@m!{}] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `type` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:79:6 | @@ -327,6 +423,14 @@ LL | //! [value@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `value` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:83:6 + | +LL | //! [value@m!{}] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `value` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:86:6 | @@ -351,6 +455,14 @@ LL | //! [prim@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `prim` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:95:6 + | +LL | //! [prim@m!{}] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `prim` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:97:6 | @@ -375,6 +487,14 @@ LL | //! [primitive@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `primitive` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:101:6 + | +LL | //! [primitive@m!{}] + | ^^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `primitive` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:103:6 | @@ -391,5 +511,5 @@ LL | //! [primitive@m!] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators -warning: 46 warnings emitted +warning: 61 warnings emitted diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index d2a922b2b624..1c5977b1bc33 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -65,7 +65,7 @@ pub struct XLinkToCloneWithStartSpace; /// [x][struct@Clone ] //~ERROR link pub struct XLinkToCloneWithEndSpace; -/// [x][Clone\(\)] not URL-shaped enough +/// [x][Clone\(\)] //~ERROR link pub struct XLinkToCloneWithEscapedParens; /// [x][`Clone`] not URL-shaped enough diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index ad813f0f9b62..3a567e409eff 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -123,6 +123,14 @@ LL - /// [x][struct@Clone ] LL + /// [x][trait@Clone ] | +error: unresolved link to `Clone\(\)` + --> $DIR/weird-syntax.rs:68:9 + | +LL | /// [x][Clone\(\)] + | ^^^^^^^^^ no item named `Clone\(\)` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | @@ -299,5 +307,21 @@ LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:132:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolves to the trait `Clone`, which is not a function + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:137:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolved to a trait, which is not a struct + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + error: aborting due to 27 previous errors diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs index 4f4590d45fc8..81cd6c73d1c1 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs @@ -1,18 +1,24 @@ //@ check-pass -/// [`…foo`] [`…bar`] [`Err`] +/// [`…foo`] //~ WARN: unresolved link +/// [`…bar`] //~ WARN: unresolved link +/// [`Err`] pub struct Broken {} -/// [`…`] [`…`] [`Err`] +/// [`…`] //~ WARN: unresolved link +/// [`…`] //~ WARN: unresolved link +/// [`Err`] pub struct Broken2 {} -/// [`…`][…] [`…`][…] [`Err`] +/// [`…`][…] //~ WARN: unresolved link +/// [`…`][…] //~ WARN: unresolved link +/// [`Err`] pub struct Broken3 {} /// […………………………][Broken3] pub struct Broken4 {} -/// [Broken3][…………………………] +/// [Broken3][…………………………] //~ WARN: unresolved link pub struct Broken5 {} pub struct Err; diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr new file mode 100644 index 000000000000..0a5ff68b9081 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr @@ -0,0 +1,59 @@ +warning: unresolved link to `…foo` + --> $DIR/redundant_explicit_links-utf8.rs:3:7 + | +LL | /// [`…foo`] + | ^^^^ no item named `…foo` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: unresolved link to `…bar` + --> $DIR/redundant_explicit_links-utf8.rs:4:7 + | +LL | /// [`…bar`] + | ^^^^ no item named `…bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:8:7 + | +LL | /// [`…`] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:9:7 + | +LL | /// [`…`] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:13:11 + | +LL | /// [`…`][…] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:14:11 + | +LL | /// [`…`][…] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…………………………` + --> $DIR/redundant_explicit_links-utf8.rs:21:15 + | +LL | /// [Broken3][…………………………] + | ^^^^^^^^^^ no item named `…………………………` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: 7 warnings emitted + From a7da4b829d328f129e342917908b70c5f4b98abc Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 18 Apr 2025 15:32:56 -0500 Subject: [PATCH 053/242] rustdoc::broken_intra_doc_links: no backticks = use old behavior this is in an effort to reduce the amount of code churn caused by this lint triggering on text that was never meant to be a link. a more principled hierustic for ignoring lints is not possible without extensive changes, due to the lint emitting code being so far away from the link collecting code, and the fact that only the link collecting code has access to details about how the link appears in the unnormalized markdown. --- src/librustdoc/passes/collect_intra_doc_links.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 97f8a2be10b2..08f0d4015fca 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -996,7 +996,9 @@ fn preprocess_link( } }; - if can_be_url && should_ignore_link(path_str) { + // If there's no backticks, be lenient revert to old behavior. + // This is to prevent churn by linting on stuff that isn't meant to be a link. + if (can_be_url || !ori_link.link.contains('`')) && should_ignore_link(path_str) { return None; } From 041348110e2e526a80efd5adfc2909c716cbb37f Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 18 Apr 2025 17:15:11 -0500 Subject: [PATCH 054/242] rustdoc: update tests to match new lint behavior --- tests/rustdoc-ui/bad-intra-doc.rs | 2 ++ tests/rustdoc-ui/intra-doc/weird-syntax.rs | 2 +- .../rustdoc-ui/intra-doc/weird-syntax.stderr | 24 ------------------- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/bad-intra-doc.rs index 7bc55756e670..c24a848d8985 100644 --- a/tests/rustdoc-ui/bad-intra-doc.rs +++ b/tests/rustdoc-ui/bad-intra-doc.rs @@ -10,4 +10,6 @@ /// attempted link to method: [`Foo.bar()`] //~ERROR unresolved link /// /// classic broken intra-doc link: [`Bar`] //~ERROR unresolved link +/// +/// no backticks, so we let this one slide: [Foo.bar()] pub struct Foo; diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index 1c5977b1bc33..9f18f67fc44a 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -65,7 +65,7 @@ pub struct XLinkToCloneWithStartSpace; /// [x][struct@Clone ] //~ERROR link pub struct XLinkToCloneWithEndSpace; -/// [x][Clone\(\)] //~ERROR link +/// [x][Clone\(\)] pub struct XLinkToCloneWithEscapedParens; /// [x][`Clone`] not URL-shaped enough diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index 3a567e409eff..ad813f0f9b62 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -123,14 +123,6 @@ LL - /// [x][struct@Clone ] LL + /// [x][trait@Clone ] | -error: unresolved link to `Clone\(\)` - --> $DIR/weird-syntax.rs:68:9 - | -LL | /// [x][Clone\(\)] - | ^^^^^^^^^ no item named `Clone\(\)` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | @@ -307,21 +299,5 @@ LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: unresolved link to `Clone` - --> $DIR/weird-syntax.rs:132:9 - | -LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolves to the trait `Clone`, which is not a function - | - = help: to link to the trait, prefix with `trait@`: trait@Clone - -error: incompatible link kind for `Clone` - --> $DIR/weird-syntax.rs:137:9 - | -LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolved to a trait, which is not a struct - | - = help: to link to the trait, prefix with `trait@`: trait@Clone - error: aborting due to 27 previous errors From 6a7d4882a207890c75ca09ce19810d90ac9cfde6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 18 Apr 2025 20:23:05 -0500 Subject: [PATCH 055/242] rustdoc::broken_intra_doc_links: only be lenient with shortcut links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit collapsed links and reference links have a pretty particular syntax, it seems unlikely they would show up on accident. Co-authored-by: León Orell Valerian Liehr --- .../passes/collect_intra_doc_links.rs | 27 +++++++++++++++---- tests/rustdoc-ui/intra-doc/weird-syntax.rs | 2 +- .../rustdoc-ui/intra-doc/weird-syntax.stderr | 10 ++++++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 08f0d4015fca..c9fa3a4837f2 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -944,9 +944,10 @@ fn preprocess_link( // certain link kinds cannot have their path be urls, // so they should not be ignored, no matter how much they look like urls. // e.g. [https://example.com/] is not a link to example.com. - let can_be_url = ori_link.kind != LinkType::ShortcutUnknown - && ori_link.kind != LinkType::CollapsedUnknown - && ori_link.kind != LinkType::ReferenceUnknown; + let can_be_url = !matches!( + ori_link.kind, + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown | LinkType::ReferenceUnknown + ); // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { @@ -996,9 +997,25 @@ fn preprocess_link( } }; - // If there's no backticks, be lenient revert to old behavior. + // If there's no backticks, be lenient and revert to the old behavior. // This is to prevent churn by linting on stuff that isn't meant to be a link. - if (can_be_url || !ori_link.link.contains('`')) && should_ignore_link(path_str) { + // only shortcut links have simple enough syntax that they + // are likely to be written accidentally, collapsed and reference links + // need 4 metachars, and reference links will not usually use + // backticks in the reference name. + // therefore, only shortcut syntax gets the lenient behavior. + // + // here's a truth table for how link kinds that cannot be urls are handled: + // + // |-------------------------------------------------------| + // | | is shortcut link | not shortcut link | + // |--------------|--------------------|-------------------| + // | has backtick | never ignore | never ignore | + // | no backtick | ignore if url-like | never ignore | + // |-------------------------------------------------------| + let ignore_urllike = + can_be_url || (ori_link.kind == LinkType::ShortcutUnknown && !ori_link.link.contains('`')); + if ignore_urllike && should_ignore_link(path_str) { return None; } diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index 9f18f67fc44a..1c5977b1bc33 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -65,7 +65,7 @@ pub struct XLinkToCloneWithStartSpace; /// [x][struct@Clone ] //~ERROR link pub struct XLinkToCloneWithEndSpace; -/// [x][Clone\(\)] +/// [x][Clone\(\)] //~ERROR link pub struct XLinkToCloneWithEscapedParens; /// [x][`Clone`] not URL-shaped enough diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index ad813f0f9b62..7f2fc1fe6256 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -123,6 +123,14 @@ LL - /// [x][struct@Clone ] LL + /// [x][trait@Clone ] | +error: unresolved link to `Clone\(\)` + --> $DIR/weird-syntax.rs:68:9 + | +LL | /// [x][Clone\(\)] + | ^^^^^^^^^ no item named `Clone\(\)` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | @@ -299,5 +307,5 @@ LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors From bd85df192d07660511b711cd7d4cae5b5a85577a Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 19 Apr 2025 10:51:40 -0500 Subject: [PATCH 056/242] move bad-intra-doc test into intra-doc dir --- tests/rustdoc-ui/{ => intra-doc}/bad-intra-doc.rs | 0 tests/rustdoc-ui/{ => intra-doc}/bad-intra-doc.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/rustdoc-ui/{ => intra-doc}/bad-intra-doc.rs (100%) rename tests/rustdoc-ui/{ => intra-doc}/bad-intra-doc.stderr (100%) diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/intra-doc/bad-intra-doc.rs similarity index 100% rename from tests/rustdoc-ui/bad-intra-doc.rs rename to tests/rustdoc-ui/intra-doc/bad-intra-doc.rs diff --git a/tests/rustdoc-ui/bad-intra-doc.stderr b/tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr similarity index 100% rename from tests/rustdoc-ui/bad-intra-doc.stderr rename to tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr From effcd540608f4e58f17a2161a6c8344c0a92f8cf Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Thu, 24 Jul 2025 18:22:51 +0200 Subject: [PATCH 057/242] Make tier 3 musl targets link dynamically by default Since we don't build std for these and don't provide any support for them, these can trivially be changed to link dynamically by default. Signed-off-by: Jens Reidel --- .../rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs | 1 - .../src/spec/targets/mips64_unknown_linux_muslabi64.rs | 2 -- .../src/spec/targets/powerpc64_unknown_linux_musl.rs | 2 -- .../rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs | 2 -- .../src/spec/targets/powerpc_unknown_linux_muslspe.rs | 2 -- .../src/spec/targets/riscv32gc_unknown_linux_musl.rs | 2 -- .../rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs | 2 -- .../src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs | 2 -- 8 files changed, 15 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs index f7416a7e0fde..1abf0537cda7 100644 --- a/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/hexagon_unknown_linux_musl.rs @@ -7,7 +7,6 @@ pub(crate) fn target() -> Target { // FIXME: HVX length defaults are per-CPU base.features = "-small-data,+hvx-length128b".into(); - base.crt_static_default = false; base.has_rpath = true; base.linker_flavor = LinkerFlavor::Unix(Cc::Yes); diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index f95ce7563549..94ecd3590a93 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -23,8 +23,6 @@ pub(crate) fn target() -> Target { abi: "abi64".into(), endian: Endian::Big, mcount: "_mcount".into(), - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - crt_static_default: true, llvm_abiname: "n64".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index 4dc76f0936c9..482b6790dadc 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -10,8 +10,6 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.max_atomic_width = Some(64); base.stack_probes = StackProbeType::Inline; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; base.abi = "elfv2".into(); base.llvm_abiname = "elfv2".into(); diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs index 316b62d941b4..f39142d01018 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_musl.rs @@ -9,8 +9,6 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); base.max_atomic_width = Some(32); base.stack_probes = StackProbeType::Inline; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { llvm_target: "powerpc-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs index 30d0d9cb60a7..8ddb45483b3b 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs @@ -9,8 +9,6 @@ pub(crate) fn target() -> Target { base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mspe"]); base.max_atomic_width = Some(32); base.stack_probes = StackProbeType::Inline; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { llvm_target: "powerpc-unknown-linux-muslspe".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs index 938b39b10c64..eb592cca1c81 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_musl.rs @@ -23,8 +23,6 @@ pub(crate) fn target() -> Target { llvm_abiname: "ilp32d".into(), max_atomic_width: Some(32), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - crt_static_default: true, ..base::linux_musl::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index e9522ac760e1..0cdbb626739d 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -13,8 +13,6 @@ pub(crate) fn target() -> Target { base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - base.crt_static_default = true; Target { llvm_target: "s390x-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs index 81c502bfeada..e026595439f4 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7neon_unknown_linux_musleabihf.rs @@ -27,8 +27,6 @@ pub(crate) fn target() -> Target { features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".into(), max_atomic_width: Some(64), mcount: "\u{1}mcount".into(), - // FIXME(compiler-team#422): musl targets should be dynamically linked by default. - crt_static_default: true, ..base::linux_musl::opts() }, } From a73d7e3ab9cc29cb427c1463d1a02b89dd7728b6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 24 Jul 2025 12:37:46 -0500 Subject: [PATCH 058/242] fix up issues with internal compiler docs revealed by stricter lint --- compiler/rustc_mir_transform/src/elaborate_drop.rs | 4 ++++ compiler/rustc_thread_pool/src/sleep/mod.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index de96b1f255a6..de60772b17ea 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -611,6 +611,7 @@ where /// /// For example, with 3 fields, the drop ladder is /// + /// ```text /// .d0: /// ELAB(drop location.0 [target=.d1, unwind=.c1]) /// .d1: @@ -621,8 +622,10 @@ where /// ELAB(drop location.1 [target=.c2]) /// .c2: /// ELAB(drop location.2 [target=`self.unwind`]) + /// ``` /// /// For possible-async drops in coroutines we also need dropline ladder + /// ```text /// .d0 (mainline): /// ELAB(drop location.0 [target=.d1, unwind=.c1, drop=.e1]) /// .d1 (mainline): @@ -637,6 +640,7 @@ where /// ELAB(drop location.1 [target=.e2, unwind=.c2]) /// .e2 (dropline): /// ELAB(drop location.2 [target=`self.drop`, unwind=`self.unwind`]) + /// ``` /// /// NOTE: this does not clear the master drop flag, so you need /// to point succ/unwind on a `drop_ladder_bottom`. diff --git a/compiler/rustc_thread_pool/src/sleep/mod.rs b/compiler/rustc_thread_pool/src/sleep/mod.rs index 31bf7184b42d..aa6666092147 100644 --- a/compiler/rustc_thread_pool/src/sleep/mod.rs +++ b/compiler/rustc_thread_pool/src/sleep/mod.rs @@ -44,7 +44,7 @@ impl SleepData { /// jobs are published, and it either blocks threads or wakes them in response to these /// events. See the [`README.md`] in this module for more details. /// -/// [`README.md`] README.md +/// [`README.md`]: README.md pub(super) struct Sleep { /// One "sleep state" per worker. Used to track if a worker is sleeping and to have /// them block. From 35404461e29343ec61eb79ca8408ae31f8941452 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Fri, 25 Jul 2025 10:57:38 +0800 Subject: [PATCH 059/242] Fix gen panics doc template for debug_assert And add assert_eq, assert_ne, assert_matches support Input: ```rust pub fn $0foo(x: bool) { debug_assert!(x); } ``` Old: ```rust /// . /// /// # Panics /// /// Panics if . pub fn foo(x: bool) { debug_assert!(x); } ``` This PR fixes: ```rust /// . pub fn foo(x: bool) { debug_assert!(x); } ``` --- .../generate_documentation_template.rs | 68 +++++++++++++++++-- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs index d4d1b3490cb6..68587f0cb5bc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -313,12 +313,28 @@ fn crate_name(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option { /// `None` if function without a body; some bool to guess if function can panic fn can_panic(ast_func: &ast::Fn) -> Option { let body = ast_func.body()?.to_string(); - let can_panic = body.contains("panic!(") - // FIXME it would be better to not match `debug_assert*!` macro invocations - || body.contains("assert!(") - || body.contains(".unwrap()") - || body.contains(".expect("); - Some(can_panic) + let mut iter = body.chars(); + let assert_postfix = |s| { + ["!(", "_eq!(", "_ne!(", "_matches!("].iter().any(|postfix| str::starts_with(s, postfix)) + }; + + while !iter.as_str().is_empty() { + let s = iter.as_str(); + iter.next(); + if s.strip_prefix("debug_assert").is_some_and(assert_postfix) { + iter.nth(10); + continue; + } + if s.strip_prefix("assert").is_some_and(assert_postfix) + || s.starts_with("panic!(") + || s.starts_with(".unwrap()") + || s.starts_with(".expect(") + { + return Some(true); + } + } + + Some(false) } /// Helper function to get the name that should be given to `self` arguments @@ -677,6 +693,24 @@ pub fn panics_if(a: bool) { ); } + #[test] + fn guesses_debug_assert_macro_cannot_panic() { + check_assist( + generate_documentation_template, + r#" +pub fn $0debug_panics_if_not(a: bool) { + debug_assert!(a == true); +} +"#, + r#" +/// . +pub fn debug_panics_if_not(a: bool) { + debug_assert!(a == true); +} +"#, + ); + } + #[test] fn guesses_assert_macro_can_panic() { check_assist( @@ -699,6 +733,28 @@ pub fn panics_if_not(a: bool) { ); } + #[test] + fn guesses_assert_eq_macro_can_panic() { + check_assist( + generate_documentation_template, + r#" +pub fn $0panics_if_not(a: bool) { + assert_eq!(a, true); +} +"#, + r#" +/// . +/// +/// # Panics +/// +/// Panics if . +pub fn panics_if_not(a: bool) { + assert_eq!(a, true); +} +"#, + ); + } + #[test] fn guesses_unwrap_can_panic() { check_assist( From da4687bafe4ff78a9816797c3b74b6bcc0c5a3bc Mon Sep 17 00:00:00 2001 From: Alisa Sireneva Date: Fri, 25 Jul 2025 16:09:29 +0300 Subject: [PATCH 060/242] Link to Mutex poisoning docs from RwLock docs --- library/std/src/sync/poison/rwlock.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 0a50b6c2d8f1..2c92602bc878 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -46,11 +46,13 @@ use crate::sys::sync as sys; /// /// # Poisoning /// -/// An `RwLock`, like [`Mutex`], will usually become poisoned on a panic. Note, +/// An `RwLock`, like [`Mutex`], will [usually] become poisoned on a panic. Note, /// however, that an `RwLock` may only be poisoned if a panic occurs while it is /// locked exclusively (write mode). If a panic occurs in any reader, then the /// lock will not be poisoned. /// +/// [usually]: super::Mutex#poisoning +/// /// # Examples /// /// ``` From 5b8c61494f85a58759dad04194c8353de07d75e1 Mon Sep 17 00:00:00 2001 From: Alisa Sireneva Date: Fri, 25 Jul 2025 21:03:09 +0300 Subject: [PATCH 061/242] Add a list of failure conditions for poisoning --- library/std/src/sync/poison/mutex.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 15dfe116133b..317e5fc3bfb9 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -35,8 +35,20 @@ use crate::sys::sync as sys; /// /// In addition, the panic detection is not ideal, so even unpoisoned mutexes /// need to be handled with care, since certain panics may have been skipped. -/// Therefore, `unsafe` code cannot rely on poisoning for soundness. Here's an -/// example of **incorrect** use of poisoning: +/// Here is a non-exhaustive list of situations where this might occur: +/// +/// - If a mutex is locked while a panic is underway, e.g. within a [`Drop`] +/// implementation or a [panic hook], panicking for the second time while the +/// lock is held will leave the mutex unpoisoned. Note that while double panic +/// usually aborts the program, [`catch_unwind`] can prevent this. +/// +/// - Locking and unlocking the mutex across different panic contexts, e.g. by +/// storing the guard to a [`Cell`] within [`Drop::drop`] and accessing it +/// outside, or vice versa, can affect poisoning status in an unexpected way. +/// +/// While this rarely happens in realistic code, `unsafe` code cannot rely on +/// poisoning for soundness, since the behavior of poisoning can depend on +/// outside context. Here's an example of **incorrect** use of poisoning: /// /// ```rust /// use std::sync::Mutex; @@ -58,8 +70,8 @@ use crate::sys::sync as sys; /// // panics, `*ptr` keeps pointing at a dropped value. The intention /// // is that this will poison the mutex, so the following calls to /// // `replace_with` will panic without reading `*ptr`. But since -/// // poisoning is not guaranteed to occur, this can lead to -/// // use-after-free. +/// // poisoning is not guaranteed to occur if this is run from a panic +/// // hook, this can lead to use-after-free. /// unsafe { /// (*ptr).write(f((*ptr).read())); /// } @@ -73,6 +85,9 @@ use crate::sys::sync as sys; /// [`unwrap()`]: Result::unwrap /// [`PoisonError`]: super::PoisonError /// [`into_inner`]: super::PoisonError::into_inner +/// [panic hook]: crate::panic::set_hook +/// [`catch_unwind`]: crate::panic::catch_unwind +/// [`Cell`]: crate::cell::Cell /// /// # Examples /// From c1d06cccaed537c799838dc5338dda28bbace52b Mon Sep 17 00:00:00 2001 From: Alisa Sireneva Date: Fri, 25 Jul 2025 22:14:02 +0300 Subject: [PATCH 062/242] Add a note on foreign exceptions --- library/std/src/sync/poison/mutex.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 317e5fc3bfb9..363220baf7b9 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -46,6 +46,9 @@ use crate::sys::sync as sys; /// storing the guard to a [`Cell`] within [`Drop::drop`] and accessing it /// outside, or vice versa, can affect poisoning status in an unexpected way. /// +/// - Foreign exceptions do not currently trigger poisoning even in absence of +/// other panics. +/// /// While this rarely happens in realistic code, `unsafe` code cannot rely on /// poisoning for soundness, since the behavior of poisoning can depend on /// outside context. Here's an example of **incorrect** use of poisoning: From d852f7cb123cde2f0ed12ef09ef3bf58de391a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Fri, 25 Jul 2025 21:21:42 +0200 Subject: [PATCH 063/242] Implement support for explicit tail calls in the MIR block builders and the LLVM codegen backend. --- messages.ftl | 2 ++ src/builder.rs | 15 +++++++++++++++ src/errors.rs | 4 ++++ 3 files changed, 21 insertions(+) diff --git a/messages.ftl b/messages.ftl index a70ac08f01ae..b9b77b7d18c6 100644 --- a/messages.ftl +++ b/messages.ftl @@ -4,3 +4,5 @@ codegen_gcc_unwinding_inline_asm = codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err} codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) + +codegen_gcc_explicit_tail_calls_unsupported = explicit tail calls with the 'become' keyword are not implemented in the GCC backend diff --git a/src/builder.rs b/src/builder.rs index a4ec4bf8deac..4aee211e2efa 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; +use crate::errors; use crate::intrinsic::llvm; use crate::type_of::LayoutGccExt; @@ -1742,6 +1743,20 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { call } + fn tail_call( + &mut self, + _llty: Self::Type, + _fn_attrs: Option<&CodegenFnAttrs>, + _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + _llfn: Self::Value, + _args: &[Self::Value], + _funclet: Option<&Self::Funclet>, + _instance: Option>, + ) { + // FIXME: implement support for explicit tail calls like rustc_codegen_llvm. + self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported); + } + fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { // FIXME(antoyo): this does not zero-extend. self.gcc_int_cast(value, dest_typ) diff --git a/src/errors.rs b/src/errors.rs index 0aa16bd88b43..b252c39c0c05 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -19,3 +19,7 @@ pub(crate) struct CopyBitcode { pub(crate) struct LtoBitcodeFromRlib { pub gcc_err: String, } + +#[derive(Diagnostic)] +#[diag(codegen_gcc_explicit_tail_calls_unsupported)] +pub(crate) struct ExplicitTailCallsUnsupported; From 3352dfc4a232fa6f38db3ea3ed465f56e6c8f85b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 17:27:08 -0700 Subject: [PATCH 064/242] Skip formatting for some compiler documentation code These examples feature Rust code that's presented primarily to illustrate how its compilation would be handled, and these examples are formatted to highlight those aspects in ways that rustfmt wouldn't preserve. Turn formatting off in those examples. (Doc code isn't formatted yet, but this will make it easier to enable doc code formatting in the future.) --- compiler/rustc_borrowck/src/region_infer/mod.rs | 2 +- compiler/rustc_hir/src/def.rs | 2 +- compiler/rustc_mir_dataflow/src/impls/initialized.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 5f1b655c6b60..d3bf9f0ec4a6 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -417,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// minimum values. /// /// For example: - /// ``` + /// ```ignore (illustrative) /// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ } /// ``` /// would initialize two variables like so: diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index ca57c4f31641..5024c85e2a8a 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -356,7 +356,7 @@ impl DefKind { /// For example, everything prefixed with `/* Res */` in this example has /// an associated `Res`: /// -/// ``` +/// ```ignore (illustrative) /// fn str_to_string(s: & /* Res */ str) -> /* Res */ String { /// /* Res */ String::from(/* Res */ s) /// } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 085757f0fb6e..ebf43300f98a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -108,6 +108,7 @@ impl<'tcx> MaybePlacesSwitchIntData<'tcx> { /// /// ```rust /// struct S; +/// #[rustfmt::skip] /// fn foo(pred: bool) { // maybe-init: /// // {} /// let a = S; let mut b = S; let c; let d; // {a, b} @@ -197,6 +198,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> { /// /// ```rust /// struct S; +/// #[rustfmt::skip] /// fn foo(pred: bool) { // maybe-uninit: /// // {a, b, c, d} /// let a = S; let mut b = S; let c; let d; // { c, d} @@ -289,6 +291,7 @@ impl<'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { /// /// ```rust /// struct S; +/// #[rustfmt::skip] /// fn foo(pred: bool) { // ever-init: /// // { } /// let a = S; let mut b = S; let c; let d; // {a, b } From 715088094c2e2ef31158b4767ceacfba62c8e6ef Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 17:35:47 -0700 Subject: [PATCH 065/242] Improve and regularize comment placement in doc code Because doc code does not get automatically formatted, some doc code has creative placements of comments that automatic formatting can't handle. Reformat those comments to make the resulting code support standard Rust formatting without breaking; this is generally an improvement to readability as well. Some comments are not indented to the prevailing indent, and are instead aligned under some bit of code. Indent them to the prevailing indent, and put spaces *inside* the comments to align them with code. Some comments span several lines of code (which aren't the line the comment is about) and expect alignment. Reformat them into one comment not broken up by unrelated intervening code. Some comments are placed on the same line as an opening brace, placing them effectively inside the subsequent block, such that formatting would typically format them like a line of that block. Move those comments to attach them to what they apply to. Some comments are placed on the same line as a one-line braced block, effectively attaching them to the closing brace, even though they're about the code inside the block. Reformat to make sure the comment will stay on the same line as the code it's commenting. --- compiler/rustc_hir/src/def.rs | 2 +- .../src/check/compare_impl_item.rs | 2 +- compiler/rustc_hir_typeck/src/upvar.rs | 4 +--- .../src/infer/outlives/obligations.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 12 +++++++---- compiler/rustc_middle/src/mir/mod.rs | 3 ++- .../src/builder/expr/as_operand.rs | 4 +++- compiler/rustc_span/src/hygiene.rs | 4 +++- compiler/rustc_thread_pool/src/scope/mod.rs | 6 +++--- library/alloc/src/vec/mod.rs | 2 +- library/core/src/cell.rs | 6 +++--- library/core/src/hint.rs | 2 -- library/core/src/iter/mod.rs | 6 ++++-- library/core/src/macros/mod.rs | 10 +++++++-- library/core/src/marker.rs | 3 +-- library/core/src/mem/maybe_uninit.rs | 21 +++++++++---------- library/core/src/result.rs | 2 +- 17 files changed, 51 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 5024c85e2a8a..0ef70a6ecaa8 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -417,7 +417,7 @@ pub enum Res { /// } /// /// impl Foo for Bar { - /// fn foo() -> Box { // SelfTyAlias + /// fn foo() -> Box { /// let _: Self; // SelfTyAlias /// /// todo!() diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e24426f9fedc..bd9125363fc4 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -425,7 +425,7 @@ impl<'tcx> TypeFolder> for RemapLateParam<'tcx> { /// /// trait Foo { /// fn bar() -> impl Deref; -/// // ^- RPITIT #1 ^- RPITIT #2 +/// // ^- RPITIT #1 ^- RPITIT #2 /// } /// /// impl Foo for () { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index be774106abf8..7ebdba9f80aa 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -2391,13 +2391,11 @@ fn migration_suggestion_for_2229( /// let mut p = Point { x: 10, y: 10 }; /// /// let c = || { -/// p.x += 10; -/// // ^ E1 ^ +/// p.x += 10; // E1 /// // ... /// // More code /// // ... /// p.x += 10; // E2 -/// // ^ E2 ^ /// }; /// ``` /// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow), diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a8520c0e71dd..d6243d727aca 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -36,7 +36,7 @@ //! fn bar(a: T, b: impl for<'a> Fn(&'a T)) {} //! fn foo(x: T) { //! bar(x, |y| { /* ... */}) -//! // ^ closure arg +//! // ^ closure arg //! } //! ``` //! diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 42a1e7377f4b..1b1735ab2bf5 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -533,8 +533,10 @@ impl<'tcx> TyCtxt<'tcx> { /// ``` /// fn foo(x: usize) -> bool { /// if x == 1 { - /// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding - /// } else { // to this, it will return `foo`'s `HirId`. + /// // If `get_fn_id_for_return_block` gets passed the `id` corresponding to this, it + /// // will return `foo`'s `HirId`. + /// true + /// } else { /// false /// } /// } @@ -543,8 +545,10 @@ impl<'tcx> TyCtxt<'tcx> { /// ```compile_fail,E0308 /// fn foo(x: usize) -> bool { /// loop { - /// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding - /// } // to this, it will return `None`. + /// // If `get_fn_id_for_return_block` gets passed the `id` corresponding to this, it + /// // will return `None`. + /// true + /// } /// false /// } /// ``` diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e819aa2d8f81..c55c7fc6002c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1017,7 +1017,8 @@ pub struct LocalDecl<'tcx> { /// ``` /// fn foo(x: &str) { /// #[allow(unused_mut)] - /// let mut x: u32 = { // <- one unused mut + /// let mut x: u32 = { + /// //^ one unused mut /// let mut y: u32 = x.parse().unwrap(); /// y + 2 /// }; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs index 982e7aa8246b..6a4222239904 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_operand.rs @@ -57,7 +57,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// ``` /// #![feature(unsized_fn_params)] /// # use core::fmt::Debug; - /// fn foo(_p: dyn Debug) { /* ... */ } + /// fn foo(_p: dyn Debug) { + /// /* ... */ + /// } /// /// fn bar(box_p: Box) { foo(*box_p); } /// ``` diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index c3080875da80..6ea774eeccaa 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -756,7 +756,9 @@ impl SyntaxContext { /// /// ```rust /// #![feature(decl_macro)] - /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty. + /// mod foo { + /// pub fn f() {} // `f`'s `SyntaxContext` is empty. + /// } /// m!(f); /// macro m($f:ident) { /// mod bar { diff --git a/compiler/rustc_thread_pool/src/scope/mod.rs b/compiler/rustc_thread_pool/src/scope/mod.rs index 382303839650..677009a9bc3d 100644 --- a/compiler/rustc_thread_pool/src/scope/mod.rs +++ b/compiler/rustc_thread_pool/src/scope/mod.rs @@ -501,9 +501,9 @@ impl<'scope> Scope<'scope> { /// let mut value_c = None; /// rayon::scope(|s| { /// s.spawn(|s1| { - /// // ^ this is the same scope as `s`; this handle `s1` - /// // is intended for use by the spawned task, - /// // since scope handles cannot cross thread boundaries. + /// // ^ this is the same scope as `s`; this handle `s1` + /// // is intended for use by the spawned task, + /// // since scope handles cannot cross thread boundaries. /// /// value_a = Some(22); /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 9856e9c18ec6..387adab70c68 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3778,8 +3778,8 @@ impl Vec { /// while i < vec.len() - end_items { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); - /// # extracted.push(val); /// // your code here + /// # extracted.push(val); /// } else { /// i += 1; /// } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d6d1bf2effae..d67408cae1b9 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2068,9 +2068,9 @@ impl fmt::Display for RefMut<'_, T> { /// implies exclusive access to its `T`: /// /// ```rust -/// #![forbid(unsafe_code)] // with exclusive accesses, -/// // `UnsafeCell` is a transparent no-op wrapper, -/// // so no need for `unsafe` here. +/// #![forbid(unsafe_code)] +/// // with exclusive accesses, `UnsafeCell` is a transparent no-op wrapper, so no need for +/// // `unsafe` here. /// use std::cell::UnsafeCell; /// /// let mut x: UnsafeCell = 42.into(); diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 696d323c66d2..c72eeb9a9c97 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -649,8 +649,6 @@ pub const fn must_use(value: T) -> T { /// } /// } /// ``` -/// -/// #[unstable(feature = "likely_unlikely", issue = "136873")] #[inline(always)] pub const fn likely(b: bool) -> bool { diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 7ca41d224a0a..56ca1305b601 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -233,10 +233,12 @@ //! //! ``` //! let mut values = vec![41]; -//! for x in &mut values { // same as `values.iter_mut()` +//! for x in &mut values { +//! // ^ same as `values.iter_mut()` //! *x += 1; //! } -//! for x in &values { // same as `values.iter()` +//! for x in &values { +//! // ^ same as `values.iter()` //! assert_eq!(*x, 42); //! } //! assert_eq!(values.len(), 1); diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 8ac6ce2242d4..ae75d166d0cf 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -271,7 +271,10 @@ pub macro cfg_select($($tt:tt)*) { /// // expression given. /// debug_assert!(true); /// -/// fn some_expensive_computation() -> bool { true } // a very simple function +/// fn some_expensive_computation() -> bool { +/// // Some expensive computation here +/// true +/// } /// debug_assert!(some_expensive_computation()); /// /// // assert with a custom message @@ -1545,7 +1548,10 @@ pub(crate) mod builtin { /// // expression given. /// assert!(true); /// - /// fn some_computation() -> bool { true } // a very simple function + /// fn some_computation() -> bool { + /// // Some expensive computation here + /// true + /// } /// /// assert!(some_computation()); /// diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 45277a1c82d3..ba00ee17b652 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -138,8 +138,7 @@ unsafe impl Send for &T {} /// impl Bar for Impl { } /// /// let x: &dyn Foo = &Impl; // OK -/// // let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot -/// // be made into an object +/// // let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot be made into an object /// ``` /// /// [trait object]: ../../book/ch17-02-trait-objects.html diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 34d8370da7ec..c160360cfacf 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -773,8 +773,7 @@ impl MaybeUninit { /// // Initialize the `MaybeUninit` using `Cell::set`: /// unsafe { /// b.assume_init_ref().set(true); - /// // ^^^^^^^^^^^^^^^ - /// // Reference to an uninitialized `Cell`: UB! + /// //^^^^^^^^^^^^^^^ Reference to an uninitialized `Cell`: UB! /// } /// ``` #[stable(feature = "maybe_uninit_ref", since = "1.55.0")] @@ -864,9 +863,9 @@ impl MaybeUninit { /// { /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); /// reader.read_exact(unsafe { buffer.assume_init_mut() })?; - /// // ^^^^^^^^^^^^^^^^^^^^^^^^ - /// // (mutable) reference to uninitialized memory! - /// // This is undefined behavior. + /// // ^^^^^^^^^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. /// Ok(unsafe { buffer.assume_init() }) /// } /// ``` @@ -884,13 +883,13 @@ impl MaybeUninit { /// let foo: Foo = unsafe { /// let mut foo = MaybeUninit::::uninit(); /// ptr::write(&mut foo.assume_init_mut().a as *mut u32, 1337); - /// // ^^^^^^^^^^^^^^^^^^^^^ - /// // (mutable) reference to uninitialized memory! - /// // This is undefined behavior. + /// // ^^^^^^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. /// ptr::write(&mut foo.assume_init_mut().b as *mut u8, 42); - /// // ^^^^^^^^^^^^^^^^^^^^^ - /// // (mutable) reference to uninitialized memory! - /// // This is undefined behavior. + /// // ^^^^^^^^^^^^^^^^^^^^^ + /// // (mutable) reference to uninitialized memory! + /// // This is undefined behavior. /// foo.assume_init() /// }; /// ``` diff --git a/library/core/src/result.rs b/library/core/src/result.rs index f65257ff59b9..4db7e5021edb 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1544,7 +1544,7 @@ impl Result { /// /// ```no_run /// let x: Result = Err("emergency failure"); - /// unsafe { x.unwrap_unchecked(); } // Undefined behavior! + /// unsafe { x.unwrap_unchecked() }; // Undefined behavior! /// ``` #[inline] #[track_caller] From b6c54a97b3ce019b48a7e98f952532b9d1670834 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 17:52:13 -0700 Subject: [PATCH 066/242] Avoid placing `// FIXME` comments inside doc code blocks This leads tools like rustfmt to get confused, because the doc code block effectively spans two doc comments. As a result, the tools think the first code block is unclosed, and the subsequent terminator opens a new block. Move the FIXME comments outside the doc code blocks, instead. --- library/alloc/src/string.rs | 4 ++-- library/alloc/src/vec/mod.rs | 8 ++++---- library/core/src/primitive_docs.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index a189c00a6b61..3bcc9920c99f 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -265,12 +265,12 @@ use crate::vec::{self, Vec}; /// You can look at these with the [`as_ptr`], [`len`], and [`capacity`] /// methods: /// +// FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// use std::mem; /// /// let story = String::from("Once upon a time..."); /// -// FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent automatically dropping the String's data /// let mut story = mem::ManuallyDrop::new(story); /// @@ -970,13 +970,13 @@ impl String { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// use std::mem; /// /// unsafe { /// let s = String::from("hello"); /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent automatically dropping the String's data /// let mut s = mem::ManuallyDrop::new(s); /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 387adab70c68..3a182fe341f3 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -566,13 +566,13 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// use std::ptr; /// use std::mem; /// /// let v = vec![1, 2, 3]; /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -674,6 +674,7 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// #![feature(box_vec_non_null)] /// @@ -682,7 +683,6 @@ impl Vec { /// /// let v = vec![1, 2, 3]; /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -994,6 +994,7 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// #![feature(allocator_api)] /// @@ -1007,7 +1008,6 @@ impl Vec { /// v.push(2); /// v.push(3); /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); @@ -1114,6 +1114,7 @@ impl Vec { /// /// # Examples /// + // FIXME Update this when vec_into_raw_parts is stabilized /// ``` /// #![feature(allocator_api, box_vec_non_null)] /// @@ -1127,7 +1128,6 @@ impl Vec { /// v.push(2); /// v.push(3); /// - // FIXME Update this when vec_into_raw_parts is stabilized /// // Prevent running `v`'s destructor so we are in complete control /// // of the allocation. /// let mut v = mem::ManuallyDrop::new(v); diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 9a1ba7d1728c..1c824e336bed 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -271,6 +271,7 @@ mod prim_bool {} /// When the compiler sees a value of type `!` in a [coercion site], it implicitly inserts a /// coercion to allow the type checker to infer any type: /// +// FIXME: use `core::convert::absurd` here instead, once it's merged /// ```rust,ignore (illustrative-and-has-placeholders) /// // this /// let x: u8 = panic!(); @@ -281,7 +282,6 @@ mod prim_bool {} /// // where absurd is a function with the following signature /// // (it's sound, because `!` always marks unreachable code): /// fn absurd(_: !) -> T { ... } -// FIXME: use `core::convert::absurd` here instead, once it's merged /// ``` /// /// This can lead to compilation errors if the type cannot be inferred: From 56c5b1df941664567d3c1f820d5861fdb25a3ca4 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 17:53:58 -0700 Subject: [PATCH 067/242] Add parentheses around expression arguments to `..` This makes it easier for humans to parse, and improves the result of potential future automatic formatting. --- library/core/src/iter/traits/iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 10f9d464f7d7..29313867ff26 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -807,7 +807,7 @@ pub trait Iterator { /// might be preferable to keep a functional style with longer iterators: /// /// ``` - /// (0..5).flat_map(|x| x * 100 .. x * 110) + /// (0..5).flat_map(|x| (x * 100)..(x * 110)) /// .enumerate() /// .filter(|&(i, x)| (i + x) % 3 == 0) /// .for_each(|(i, x)| println!("{i}:{x}")); From 1e2d58798fab4aa6275acf3746e1aec5340fc97f Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 17:55:45 -0700 Subject: [PATCH 068/242] Avoid making the start of a doc code block conditional Placing the opening triple-backquote inside a `cfg_attr` makes many tools confused, including syntax highlighters (e.g. vim's) and rustfmt. Instead, use a `cfg` inside the doc code block. --- library/std/src/path.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index d9c34d4fa045..055e7f814800 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3259,8 +3259,8 @@ impl Path { /// /// # Examples /// - #[cfg_attr(unix, doc = "```no_run")] - #[cfg_attr(not(unix), doc = "```ignore")] + /// ```rust,no_run + /// # #[cfg(unix)] { /// use std::path::Path; /// use std::os::unix::fs::symlink; /// @@ -3268,6 +3268,7 @@ impl Path { /// symlink("/origin_does_not_exist/", link_path).unwrap(); /// assert_eq!(link_path.is_symlink(), true); /// assert_eq!(link_path.exists(), false); + /// # } /// ``` /// /// # See Also From 534b1355efe3fc0dc962634773b0f6b1474bad13 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 26 Jul 2025 11:41:25 +0200 Subject: [PATCH 069/242] tests: Add test for basic line-by-line stepping in a debugger Let's wait with lldb testing until the test works properly with gdb. --- tests/debuginfo/basic-stepping.rs | 47 +++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/debuginfo/basic-stepping.rs diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs new file mode 100644 index 000000000000..6e1344d22a50 --- /dev/null +++ b/tests/debuginfo/basic-stepping.rs @@ -0,0 +1,47 @@ +//! Test that stepping through a simple program with a debugger one line at a +//! time works intuitively, e.g. that `next` takes you to the next source line. +//! Regression test for . + +//@ ignore-aarch64: Doesn't work yet. +//@ compile-flags: -g + +// gdb-command: run +// FIXME(#97083): Should we be able to break on initialization of zero-sized types? +// FIXME(#97083): Right now the first breakable line is: +// gdb-check: let mut c = 27; +// gdb-command: next +// gdb-check: let d = c = 99; +// gdb-command: next +// FIXME(#33013): gdb-check: let e = "hi bob"; +// FIXME(#33013): gdb-command: next +// FIXME(#33013): gdb-check: let f = b"hi bob"; +// FIXME(#33013): gdb-command: next +// FIXME(#33013): gdb-check: let g = b'9'; +// FIXME(#33013): gdb-command: next +// FIXME(#33013): gdb-check: let h = ["whatever"; 8]; +// FIXME(#33013): gdb-command: next +// gdb-check: let i = [1,2,3,4]; +// gdb-command: next +// gdb-check: let j = (23, "hi"); +// gdb-command: next +// gdb-check: let k = 2..3; +// gdb-command: next +// gdb-check: let l = &i[k]; +// gdb-command: next +// gdb-check: let m: *const() = &a; + +fn main () { + let a = (); // #break + let b : [i32; 0] = []; + let mut c = 27; + let d = c = 99; + let e = "hi bob"; + let f = b"hi bob"; + let g = b'9'; + let h = ["whatever"; 8]; + let i = [1,2,3,4]; + let j = (23, "hi"); + let k = 2..3; + let l = &i[k]; + let m: *const() = &a; +} From 013b3eb8055d730f152e9a26df0317ef16f0f86b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 18:03:07 +0000 Subject: [PATCH 070/242] Remove support for -Zcombine-cgu Nobody seems to actually use this, while still adding some extra complexity to the already rather complex codegen coordinator code. It is also not supported by any backend other than the LLVM backend. --- src/back/write.rs | 9 --------- src/lib.rs | 8 -------- 2 files changed, 17 deletions(-) diff --git a/src/back/write.rs b/src/back/write.rs index 113abe70805b..c1231142c658 100644 --- a/src/back/write.rs +++ b/src/back/write.rs @@ -4,7 +4,6 @@ use gccjit::{Context, OutputKind}; use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; -use rustc_errors::DiagCtxtHandle; use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; use rustc_span::fatal_error::FatalError; @@ -258,14 +257,6 @@ pub(crate) fn codegen( )) } -pub(crate) fn link( - _cgcx: &CodegenContext, - _dcx: DiagCtxtHandle<'_>, - mut _modules: Vec>, -) -> Result, FatalError> { - unimplemented!(); -} - pub(crate) fn save_temp_bitcode( cgcx: &CodegenContext, _module: &ModuleCodegen, diff --git a/src/lib.rs b/src/lib.rs index 71765c511381..a31206825007 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -426,14 +426,6 @@ impl WriteBackendMethods for GccCodegenBackend { fn serialize_module(_module: ModuleCodegen) -> (String, Self::ModuleBuffer) { unimplemented!(); } - - fn run_link( - cgcx: &CodegenContext, - dcx: DiagCtxtHandle<'_>, - modules: Vec>, - ) -> Result, FatalError> { - back::write::link(cgcx, dcx, modules) - } } /// This is the entrypoint for a hot plugged rustc_codegen_gccjit From a1f5a6d781d65949fe08c149a695d4cd926cc755 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Jul 2025 00:47:33 +0000 Subject: [PATCH 071/242] Perform check_private_in_public by module. --- compiler/rustc_interface/src/passes.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 7 +- compiler/rustc_privacy/src/lib.rs | 4 +- .../ui/privacy/private-in-public-warn.stderr | 72 +++++++++---------- tests/ui/privacy/projections.stderr | 26 +++---- 5 files changed, 59 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fb6897c7d895..aaabf7df42d7 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1147,7 +1147,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { parallel!( { - tcx.ensure_ok().check_private_in_public(()); + tcx.par_hir_for_each_module(|module| { + tcx.ensure_ok().check_private_in_public(module) + }) }, { tcx.par_hir_for_each_module(|module| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 587349d4cf41..7a625f4fee73 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1390,8 +1390,11 @@ rustc_queries! { eval_always desc { "checking effective visibilities" } } - query check_private_in_public(_: ()) { - desc { "checking for private elements in public interfaces" } + query check_private_in_public(module_def_id: LocalModDefId) { + desc { |tcx| + "checking for private elements in public interfaces for {}", + describe_as_module(module_def_id, tcx) + } } query reachable_set(_: ()) -> &'tcx LocalDefIdSet { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6fd2b7fc12f0..1a062c63a6fe 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1854,12 +1854,12 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx.arena.alloc(visitor.effective_visibilities) } -fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { +fn check_private_in_public(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let effective_visibilities = tcx.effective_visibilities(()); // Check for private types in public interfaces. let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities }; - let crate_items = tcx.hir_crate_items(()); + let crate_items = tcx.hir_module_items(module_def_id); for id in crate_items.free_items() { checker.check_item(id); } diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index 86f6be85a071..edcffaf6b70a 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -93,6 +93,42 @@ LL | struct Priv; LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type +error: type `types::Priv` is more private than the item `types::ES` + --> $DIR/private-in-public-warn.rs:27:9 + | +LL | pub static ES: Priv; + | ^^^^^^^^^^^^^^^^^^^ static `types::ES` is reachable at visibility `pub(crate)` + | +note: but type `types::Priv` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:9:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + +error: type `types::Priv` is more private than the item `types::ef1` + --> $DIR/private-in-public-warn.rs:28:9 + | +LL | pub fn ef1(arg: Priv); + | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)` + | +note: but type `types::Priv` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:9:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + +error: type `types::Priv` is more private than the item `types::ef2` + --> $DIR/private-in-public-warn.rs:29:9 + | +LL | pub fn ef2() -> Priv; + | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)` + | +note: but type `types::Priv` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:9:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + error: trait `traits::PrivTr` is more private than the item `traits::Alias` --> $DIR/private-in-public-warn.rs:42:5 | @@ -359,42 +395,6 @@ note: but type `Priv2` is only usable at visibility `pub(self)` LL | struct Priv2; | ^^^^^^^^^^^^ -error: type `types::Priv` is more private than the item `types::ES` - --> $DIR/private-in-public-warn.rs:27:9 - | -LL | pub static ES: Priv; - | ^^^^^^^^^^^^^^^^^^^ static `types::ES` is reachable at visibility `pub(crate)` - | -note: but type `types::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:9:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - -error: type `types::Priv` is more private than the item `types::ef1` - --> $DIR/private-in-public-warn.rs:28:9 - | -LL | pub fn ef1(arg: Priv); - | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)` - | -note: but type `types::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:9:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - -error: type `types::Priv` is more private than the item `types::ef2` - --> $DIR/private-in-public-warn.rs:29:9 - | -LL | pub fn ef2() -> Priv; - | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)` - | -note: but type `types::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:9:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - warning: bounds on generic parameters in type aliases are not enforced --> $DIR/private-in-public-warn.rs:42:23 | diff --git a/tests/ui/privacy/projections.stderr b/tests/ui/privacy/projections.stderr index 010d77998e34..addb6a075a28 100644 --- a/tests/ui/privacy/projections.stderr +++ b/tests/ui/privacy/projections.stderr @@ -1,16 +1,3 @@ -warning: type `Priv` is more private than the item `Leak` - --> $DIR/projections.rs:3:5 - | -LL | pub type Leak = Priv; - | ^^^^^^^^^^^^^ type alias `Leak` is reachable at visibility `pub(crate)` - | -note: but type `Priv` is only usable at visibility `pub(self)` - --> $DIR/projections.rs:2:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - = note: `#[warn(private_interfaces)]` on by default - error[E0446]: private type `Priv` in public interface --> $DIR/projections.rs:24:5 | @@ -29,6 +16,19 @@ LL | struct Priv; LL | type A = T::A; | ^^^^^^^^^^^^^^^^ can't leak private type +warning: type `Priv` is more private than the item `Leak` + --> $DIR/projections.rs:3:5 + | +LL | pub type Leak = Priv; + | ^^^^^^^^^^^^^ type alias `Leak` is reachable at visibility `pub(crate)` + | +note: but type `Priv` is only usable at visibility `pub(self)` + --> $DIR/projections.rs:2:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + = note: `#[warn(private_interfaces)]` on by default + error: type `Priv` is private --> $DIR/projections.rs:14:15 | From 1d5a582ba03f2ecda47a2c904bedb17adf5ee2dd Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Sun, 27 Jul 2025 21:53:35 +0900 Subject: [PATCH 072/242] refactor: conpare text of name_ref instead of syntax name_ref --- .../crates/ide-assists/src/handlers/inline_type_alias.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index 4511072b041b..f667d6259354 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -322,7 +322,10 @@ fn create_replacement( replacements.push((syntax.clone(), new_lifetime.syntax().clone_for_update())); } - } else if let Some(replacement_syntax) = const_and_type_map.0.get(syntax_str) { + } else if let Some(name_ref) = ast::NameRef::cast(syntax.clone()) { + let Some(replacement_syntax) = const_and_type_map.0.get(&name_ref.to_string()) else { + continue; + }; let new_string = replacement_syntax.to_string(); let new = if new_string == "_" { make::wildcard_pat().syntax().clone_for_update() From b3ea82f2eb0a5d9b895111b8b1eb165cd4da58a3 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Sun, 27 Jul 2025 22:04:25 +0900 Subject: [PATCH 073/242] Migrate `inline_type_alias` assist to use `SyntaxEditor` --- .../src/handlers/inline_type_alias.rs | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index f667d6259354..62535531435d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -9,10 +9,10 @@ use ide_db::{ search::FileReference, }; use itertools::Itertools; +use syntax::syntax_editor::SyntaxEditor; use syntax::{ AstNode, NodeOrToken, SyntaxNode, ast::{self, HasGenericParams, HasName, make}, - ted, }; use crate::{ @@ -68,37 +68,41 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) let mut definition_deleted = false; let mut inline_refs_for_file = |file_id, refs: Vec| { - builder.edit_file(file_id); + let source = ctx.sema.parse(file_id); + let mut editor = builder.make_editor(source.syntax()); let (path_types, path_type_uses) = split_refs_and_uses(builder, refs, |path_type| { path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) }); - path_type_uses .iter() .flat_map(ast_to_remove_for_path_in_use_stmt) - .for_each(|x| builder.delete(x.syntax().text_range())); + .for_each(|x| editor.delete(x.syntax())); + for (target, replacement) in path_types.into_iter().filter_map(|path_type| { - let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); - let target = path_type.syntax().text_range(); + let replacement = + inline(&ast_alias, &path_type)?.replace_generic(&concrete_type); + let target = path_type.syntax().clone(); Some((target, replacement)) }) { - builder.replace(target, replacement); + editor.replace(target, replacement); } - if file_id == ctx.vfs_file_id() { - builder.delete(ast_alias.syntax().text_range()); + if file_id.file_id(ctx.db()) == ctx.vfs_file_id() { + editor.delete(ast_alias.syntax()); definition_deleted = true; } + builder.add_file_edits(file_id.file_id(ctx.db()), editor); }; for (file_id, refs) in usages.into_iter() { - inline_refs_for_file(file_id.file_id(ctx.db()), refs); + inline_refs_for_file(file_id, refs); } if !definition_deleted { - builder.edit_file(ctx.vfs_file_id()); - builder.delete(ast_alias.syntax().text_range()); + let mut editor = builder.make_editor(ast_alias.syntax()); + editor.delete(ast_alias.syntax()); + builder.add_file_edits(ctx.vfs_file_id(), editor) } }, ) @@ -146,23 +150,26 @@ pub(crate) fn inline_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> O } } - let target = alias_instance.syntax().text_range(); - acc.add( AssistId::refactor_inline("inline_type_alias"), "Inline type alias", - target, - |builder| builder.replace(target, replacement.to_text(&concrete_type)), + alias_instance.syntax().text_range(), + |builder| { + let mut editor = builder.make_editor(alias_instance.syntax()); + let replace = replacement.replace_generic(&concrete_type); + editor.replace(alias_instance.syntax(), replace); + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, ) } impl Replacement { - fn to_text(&self, concrete_type: &ast::Type) -> String { + fn replace_generic(&self, concrete_type: &ast::Type) -> SyntaxNode { match self { Replacement::Generic { lifetime_map, const_and_type_map } => { create_replacement(lifetime_map, const_and_type_map, concrete_type) } - Replacement::Plain => concrete_type.to_string(), + Replacement::Plain => concrete_type.syntax().clone_subtree().clone_for_update(), } } } @@ -299,15 +306,14 @@ fn create_replacement( lifetime_map: &LifetimeMap, const_and_type_map: &ConstAndTypeMap, concrete_type: &ast::Type, -) -> String { - let updated_concrete_type = concrete_type.clone_for_update(); - let mut replacements = Vec::new(); - let mut removals = Vec::new(); +) -> SyntaxNode { + let updated_concrete_type = concrete_type.syntax().clone_subtree(); + let mut editor = SyntaxEditor::new(updated_concrete_type.clone()); - for syntax in updated_concrete_type.syntax().descendants() { - let syntax_string = syntax.to_string(); - let syntax_str = syntax_string.as_str(); + let mut replacements: Vec<(SyntaxNode, SyntaxNode)> = Vec::new(); + let mut removals: Vec> = Vec::new(); + for syntax in updated_concrete_type.descendants() { if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) { if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) { if new_lifetime.text() == "'_" { @@ -338,14 +344,13 @@ fn create_replacement( } for (old, new) in replacements { - ted::replace(old, new); + editor.replace(old, new); } for syntax in removals { - ted::remove(syntax); + editor.delete(syntax); } - - updated_concrete_type.to_string() + editor.finish().new_root().clone() } fn get_type_alias(ctx: &AssistContext<'_>, path: &ast::PathType) -> Option { From b1b7077b42668ebee51c28eac86786567711ab91 Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Sat, 26 Jul 2025 22:31:41 +0900 Subject: [PATCH 074/242] remove ted from convert_tuple_struct_to_named_struct Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- .../handlers/convert_tuple_struct_to_named_struct.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 80756197fb70..44361560f486 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -3,7 +3,8 @@ use ide_db::defs::{Definition, NameRefClass}; use syntax::{ SyntaxKind, SyntaxNode, ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility}, - match_ast, ted, + match_ast, + syntax_editor::{Position, SyntaxEditor}, }; use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder}; @@ -93,12 +94,13 @@ fn edit_struct_def( names: Vec, ) { let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| { - let field = ast::make::record_field(f.visibility(), name, f.ty()?).clone_for_update(); - ted::insert_all( - ted::Position::first_child_of(field.syntax()), + let field = ast::make::record_field(f.visibility(), name, f.ty()?); + let mut editor = SyntaxEditor::new(field.syntax().clone()); + editor.insert_all( + Position::first_child_of(field.syntax()), f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(), ); - Some(field) + ast::RecordField::cast(editor.finish().new_root().clone()) }); let record_fields = ast::make::record_field_list(record_fields); let tuple_fields_text_range = tuple_fields.syntax().text_range(); From 85486a7bff683fd9ec241a92ca75f38659b4e76c Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Sat, 26 Jul 2025 23:20:31 +0900 Subject: [PATCH 075/242] migrate `fn edit_struct_def` in `convert_tuple_struct_to_named_struct` to SyntaxEditor Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- .../convert_tuple_struct_to_named_struct.rs | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 44361560f486..6d729c9ea995 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -1,10 +1,10 @@ use either::Either; use ide_db::defs::{Definition, NameRefClass}; use syntax::{ - SyntaxKind, SyntaxNode, + SyntaxKind, SyntaxNode, T, ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility}, match_ast, - syntax_editor::{Position, SyntaxEditor}, + syntax_editor::{Element, Position, SyntaxEditor}, }; use crate::{AssistContext, AssistId, Assists, assist_context::SourceChangeBuilder}; @@ -72,7 +72,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct( Either::Right(v) => Either::Right(ctx.sema.to_def(v)?), }; let target = strukt_or_variant.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range(); - + let syntax = strukt_or_variant.as_ref().either(|s| s.syntax(), |v| v.syntax()); acc.add( AssistId::refactor_rewrite("convert_tuple_struct_to_named_struct"), "Convert to named struct", @@ -81,58 +81,53 @@ pub(crate) fn convert_tuple_struct_to_named_struct( let names = generate_names(tuple_fields.fields()); edit_field_references(ctx, edit, tuple_fields.fields(), &names); edit_struct_references(ctx, edit, strukt_def, &names); - edit_struct_def(ctx, edit, &strukt_or_variant, tuple_fields, names); + let mut editor = edit.make_editor(syntax); + edit_struct_def(&mut editor, &strukt_or_variant, tuple_fields, names); + edit.add_file_edits(ctx.vfs_file_id(), editor); }, ) } fn edit_struct_def( - ctx: &AssistContext<'_>, - edit: &mut SourceChangeBuilder, + editor: &mut SyntaxEditor, strukt: &Either, tuple_fields: ast::TupleFieldList, names: Vec, ) { let record_fields = tuple_fields.fields().zip(names).filter_map(|(f, name)| { let field = ast::make::record_field(f.visibility(), name, f.ty()?); - let mut editor = SyntaxEditor::new(field.syntax().clone()); - editor.insert_all( + let mut field_editor = SyntaxEditor::new(field.syntax().clone()); + field_editor.insert_all( Position::first_child_of(field.syntax()), f.attrs().map(|attr| attr.syntax().clone_subtree().clone_for_update().into()).collect(), ); - ast::RecordField::cast(editor.finish().new_root().clone()) + ast::RecordField::cast(field_editor.finish().new_root().clone()) }); - let record_fields = ast::make::record_field_list(record_fields); - let tuple_fields_text_range = tuple_fields.syntax().text_range(); - - edit.edit_file(ctx.vfs_file_id()); + let record_fields = ast::make::record_field_list(record_fields).clone_for_update(); + let tuple_fields_before = Position::before(tuple_fields.syntax()); if let Either::Left(strukt) = strukt { if let Some(w) = strukt.where_clause() { - edit.delete(w.syntax().text_range()); - edit.insert( - tuple_fields_text_range.start(), - ast::make::tokens::single_newline().text(), - ); - edit.insert(tuple_fields_text_range.start(), w.syntax().text()); + editor.delete(w.syntax()); + let mut insert_element = Vec::new(); + insert_element.push(ast::make::tokens::single_newline().syntax_element()); + insert_element.push(w.syntax().clone_for_update().syntax_element()); if w.syntax().last_token().is_none_or(|t| t.kind() != SyntaxKind::COMMA) { - edit.insert(tuple_fields_text_range.start(), ","); + insert_element.push(ast::make::token(T![,]).into()); } - edit.insert( - tuple_fields_text_range.start(), - ast::make::tokens::single_newline().text(), - ); + insert_element.push(ast::make::tokens::single_newline().syntax_element()); + editor.insert_all(tuple_fields_before, insert_element); } else { - edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text()); + editor.insert(tuple_fields_before, ast::make::tokens::single_space()); } if let Some(t) = strukt.semicolon_token() { - edit.delete(t.text_range()); + editor.delete(t); } } else { - edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text()); + editor.insert(tuple_fields_before, ast::make::tokens::single_space()); } - edit.replace(tuple_fields_text_range, record_fields.to_string()); + editor.replace(tuple_fields.syntax(), record_fields.syntax()); } fn edit_struct_references( @@ -1015,8 +1010,7 @@ where pub struct $0Foo(#[my_custom_attr] u32); "#, r#" -pub struct Foo { #[my_custom_attr] -field1: u32 } +pub struct Foo { #[my_custom_attr]field1: u32 } "#, ); } From 8f898729220258b58d8044d4adaff14d45288fe6 Mon Sep 17 00:00:00 2001 From: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> Date: Sun, 27 Jul 2025 13:24:08 +0900 Subject: [PATCH 076/242] Migrate `convert_tuple_struct_to_named_struct' assist to use `SyntaxEditor' Signed-off-by: Hayashi Mikihiro <34ttrweoewiwe28@gmail.com> --- .../convert_tuple_struct_to_named_struct.rs | 103 ++++++++++++------ 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 6d729c9ea995..f4041f49419a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -1,7 +1,9 @@ use either::Either; +use hir::FileRangeWrapper; use ide_db::defs::{Definition, NameRefClass}; +use std::ops::RangeInclusive; use syntax::{ - SyntaxKind, SyntaxNode, T, + SyntaxElement, SyntaxKind, SyntaxNode, T, TextSize, ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility}, match_ast, syntax_editor::{Element, Position, SyntaxEditor}, @@ -80,8 +82,8 @@ pub(crate) fn convert_tuple_struct_to_named_struct( |edit| { let names = generate_names(tuple_fields.fields()); edit_field_references(ctx, edit, tuple_fields.fields(), &names); - edit_struct_references(ctx, edit, strukt_def, &names); let mut editor = edit.make_editor(syntax); + edit_struct_references(ctx, edit, strukt_def, &names); edit_struct_def(&mut editor, &strukt_or_variant, tuple_fields, names); edit.add_file_edits(ctx.vfs_file_id(), editor); }, @@ -142,27 +144,21 @@ fn edit_struct_references( }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); - let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> { + let edit_node = |node: SyntaxNode| -> Option { match_ast! { match node { ast::TupleStructPat(tuple_struct_pat) => { - let file_range = ctx.sema.original_range_opt(&node)?; - edit.edit_file(file_range.file_id.file_id(ctx.db())); - edit.replace( - file_range.range, - ast::make::record_pat_with_fields( - tuple_struct_pat.path()?, - ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map( - |(pat, name)| { - ast::make::record_pat_field( - ast::make::name_ref(&name.to_string()), - pat, - ) - }, - ), None), - ) - .to_string(), - ); + Some(ast::make::record_pat_with_fields( + tuple_struct_pat.path()?, + ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map( + |(pat, name)| { + ast::make::record_pat_field( + ast::make::name_ref(&name.to_string()), + pat, + ) + }, + ), None), + ).syntax().clone_for_update()) }, // for tuple struct creations like Foo(42) ast::CallExpr(call_expr) => { @@ -179,8 +175,7 @@ fn edit_struct_references( let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?; - edit.replace( - ctx.sema.original_range(&node).range, + Some( ast::make::record_expr( path, ast::make::record_expr_field_list(arg_list.args().zip(names).map( @@ -191,25 +186,58 @@ fn edit_struct_references( ) }, )), - ) - .to_string(), - ); + ).syntax().clone_for_update() + ) }, _ => return None, } } - Some(()) }; for (file_id, refs) in usages { - edit.edit_file(file_id.file_id(ctx.db())); - for r in refs { - for node in r.name.syntax().ancestors() { - if edit_node(edit, node).is_some() { - break; + let source = ctx.sema.parse(file_id); + let source = source.syntax(); + + let mut editor = edit.make_editor(source); + for r in refs.iter().rev() { + if let Some((old_node, new_node)) = r + .name + .syntax() + .ancestors() + .find_map(|node| Some((node.clone(), edit_node(node.clone())?))) + { + if let Some(old_node) = ctx.sema.original_syntax_node_rooted(&old_node) { + editor.replace(old_node, new_node); + } else { + let FileRangeWrapper { file_id: _, range } = ctx.sema.original_range(&old_node); + let parent = source.covering_element(range); + match parent { + SyntaxElement::Token(token) => { + editor.replace(token, new_node.syntax_element()); + } + SyntaxElement::Node(parent_node) => { + // replace the part of macro + // ``` + // foo!(a, Test::A(0)); + // ^^^^^^^^^^^^^^^ // parent_node + // ^^^^^^^^^^ // replace_range + // ``` + let start = parent_node + .children_with_tokens() + .find(|t| t.text_range().contains(range.start())); + let end = parent_node + .children_with_tokens() + .find(|t| t.text_range().contains(range.end() - TextSize::new(1))); + if let (Some(start), Some(end)) = (start, end) { + let replace_range = RangeInclusive::new(start, end); + editor.replace_all(replace_range, vec![new_node.into()]); + } + } + } } } } + edit.add_file_edits(file_id.file_id(ctx.db()), editor); } } @@ -227,12 +255,17 @@ fn edit_field_references( let def = Definition::Field(field); let usages = def.usages(&ctx.sema).all(); for (file_id, refs) in usages { - edit.edit_file(file_id.file_id(ctx.db())); + let source = ctx.sema.parse(file_id); + let source = source.syntax(); + let mut editor = edit.make_editor(source); for r in refs { - if let Some(name_ref) = r.name.as_name_ref() { - edit.replace(ctx.sema.original_range(name_ref.syntax()).range, name.text()); + if let Some(name_ref) = r.name.as_name_ref() + && let Some(original) = ctx.sema.original_ast_node(name_ref.clone()) + { + editor.replace(original.syntax(), name.syntax()); } } + edit.add_file_edits(file_id.file_id(ctx.db()), editor); } } } @@ -242,7 +275,7 @@ fn generate_names(fields: impl Iterator) -> Vec Date: Sun, 27 Jul 2025 22:11:55 +0000 Subject: [PATCH 077/242] Parallelize check_private_in_public. --- compiler/rustc_privacy/src/lib.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1a062c63a6fe..ce1c937121e2 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1594,7 +1594,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { self.effective_visibilities.effective_vis(def_id).copied() } - fn check_item(&mut self, id: ItemId) { + fn check_item(&self, id: ItemId) { let tcx = self.tcx; let def_id = id.owner_id.def_id; let item_visibility = tcx.local_visibility(def_id); @@ -1722,7 +1722,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> { } } - fn check_foreign_item(&mut self, id: ForeignItemId) { + fn check_foreign_item(&self, id: ForeignItemId) { let tcx = self.tcx; let def_id = id.owner_id.def_id; let item_visibility = tcx.local_visibility(def_id); @@ -1857,13 +1857,9 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { fn check_private_in_public(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let effective_visibilities = tcx.effective_visibilities(()); // Check for private types in public interfaces. - let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities }; + let checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities }; let crate_items = tcx.hir_module_items(module_def_id); - for id in crate_items.free_items() { - checker.check_item(id); - } - for id in crate_items.foreign_items() { - checker.check_foreign_item(id); - } + let _ = crate_items.par_items(|id| Ok(checker.check_item(id))); + let _ = crate_items.par_foreign_items(|id| Ok(checker.check_foreign_item(id))); } From 1b01decc1ca851e014b6951bdd7f2ac2f897adc9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Jul 2025 22:15:40 +0000 Subject: [PATCH 078/242] Do not fetch spans if not required. --- compiler/rustc_privacy/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ce1c937121e2..87d4d180e178 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1423,8 +1423,6 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; let vis = self.tcx.local_visibility(local_def_id); - let span = self.tcx.def_span(self.item_def_id.to_def_id()); - let vis_span = self.tcx.def_span(def_id); if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) { let vis_descr = match vis { ty::Visibility::Public => "public", @@ -1441,6 +1439,8 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } }; + let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let vis_span = self.tcx.def_span(def_id); self.tcx.dcx().emit_err(InPublicInterface { span, vis_descr, @@ -1463,6 +1463,8 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { } else { lint::builtin::PRIVATE_BOUNDS }; + let span = self.tcx.def_span(self.item_def_id.to_def_id()); + let vis_span = self.tcx.def_span(def_id); self.tcx.emit_node_span_lint( lint, self.tcx.local_def_id_to_hir_id(self.item_def_id), From 3e6f950d66008a7a15f38d10d5b19707c06602c7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 17 Jul 2025 06:09:15 +0200 Subject: [PATCH 079/242] avoid the need to specify if toc should be generated - this removes one external dependency, mdbook-toc - this steals code from rustc book --- .../rustc-dev-guide/.github/workflows/ci.yml | 4 +- src/doc/rustc-dev-guide/README.md | 6 +- src/doc/rustc-dev-guide/book.toml | 11 +- src/doc/rustc-dev-guide/pagetoc.css | 84 ++++++++++++++ src/doc/rustc-dev-guide/pagetoc.js | 104 ++++++++++++++++++ 5 files changed, 198 insertions(+), 11 deletions(-) create mode 100644 src/doc/rustc-dev-guide/pagetoc.css create mode 100644 src/doc/rustc-dev-guide/pagetoc.js diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml index daf5223cbd4a..6eabb999fb01 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml @@ -17,7 +17,6 @@ jobs: MDBOOK_VERSION: 0.4.48 MDBOOK_LINKCHECK2_VERSION: 0.9.1 MDBOOK_MERMAID_VERSION: 0.12.6 - MDBOOK_TOC_VERSION: 0.11.2 MDBOOK_OUTPUT__LINKCHECK__FOLLOW_WEB_LINKS: ${{ github.event_name != 'pull_request' }} DEPLOY_DIR: book/html BASE_SHA: ${{ github.event.pull_request.base.sha }} @@ -34,7 +33,7 @@ jobs: with: path: | ~/.cargo/bin - key: ${{ runner.os }}-${{ env.MDBOOK_VERSION }}--${{ env.MDBOOK_LINKCHECK2_VERSION }}--${{ env.MDBOOK_TOC_VERSION }}--${{ env.MDBOOK_MERMAID_VERSION }} + key: ${{ runner.os }}-${{ env.MDBOOK_VERSION }}--${{ env.MDBOOK_LINKCHECK2_VERSION }}--${{ env.MDBOOK_MERMAID_VERSION }} - name: Restore cached Linkcheck if: github.event_name == 'schedule' @@ -57,7 +56,6 @@ jobs: run: | cargo install mdbook --version ${{ env.MDBOOK_VERSION }} cargo install mdbook-linkcheck2 --version ${{ env.MDBOOK_LINKCHECK2_VERSION }} - cargo install mdbook-toc --version ${{ env.MDBOOK_TOC_VERSION }} cargo install mdbook-mermaid --version ${{ env.MDBOOK_MERMAID_VERSION }} - name: Check build diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index 5932da467ab2..1ad895aeda2e 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -43,7 +43,7 @@ rustdocs][rustdocs]. To build a local static HTML site, install [`mdbook`](https://github.com/rust-lang/mdBook) with: ``` -cargo install mdbook mdbook-linkcheck2 mdbook-toc mdbook-mermaid +cargo install mdbook mdbook-linkcheck2 mdbook-mermaid ``` and execute the following command in the root of the repository: @@ -67,8 +67,8 @@ ENABLE_LINKCHECK=1 mdbook serve ### Table of Contents -We use `mdbook-toc` to auto-generate TOCs for long sections. You can invoke the preprocessor by -including the `` marker at the place where you want the TOC. +Each page has a TOC that is automatically generated by `pagetoc.js`. +There is an associated `pagetoc.css`, for styling. ## Synchronizing josh subtree with rustc diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml index b84b1e7548a8..daf237ed9081 100644 --- a/src/doc/rustc-dev-guide/book.toml +++ b/src/doc/rustc-dev-guide/book.toml @@ -6,17 +6,18 @@ description = "A guide to developing the Rust compiler (rustc)" [build] create-missing = false -[preprocessor.toc] -command = "mdbook-toc" -renderer = ["html"] - [preprocessor.mermaid] command = "mdbook-mermaid" [output.html] git-repository-url = "https://github.com/rust-lang/rustc-dev-guide" edit-url-template = "https://github.com/rust-lang/rustc-dev-guide/edit/master/{path}" -additional-js = ["mermaid.min.js", "mermaid-init.js"] +additional-js = [ + "mermaid.min.js", + "mermaid-init.js", + "pagetoc.js", +] +additional-css = ["pagetoc.css"] [output.html.search] use-boolean-and = true diff --git a/src/doc/rustc-dev-guide/pagetoc.css b/src/doc/rustc-dev-guide/pagetoc.css new file mode 100644 index 000000000000..fa709194f375 --- /dev/null +++ b/src/doc/rustc-dev-guide/pagetoc.css @@ -0,0 +1,84 @@ +/* Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) */ + +:root { + --toc-width: 270px; + --center-content-toc-shift: calc(-1 * var(--toc-width) / 2); +} + +.nav-chapters { + /* adjust width of buttons that bring to the previous or the next page */ + min-width: 50px; +} + +@media only screen { + @media (max-width: 1179px) { + .sidebar-hidden #sidetoc { + display: none; + } + } + + @media (max-width: 1439px) { + .sidebar-visible #sidetoc { + display: none; + } + } + + @media (1180px <= width <= 1439px) { + .sidebar-hidden main { + position: relative; + left: var(--center-content-toc-shift); + } + } + + @media (1440px <= width <= 1700px) { + .sidebar-visible main { + position: relative; + left: var(--center-content-toc-shift); + } + } + + #sidetoc { + margin-left: calc(100% + 20px); + } + #pagetoc { + position: fixed; + /* adjust TOC width */ + width: var(--toc-width); + height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); + overflow: auto; + } + #pagetoc a { + border-left: 1px solid var(--sidebar-bg); + color: var(--fg); + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + } + #pagetoc a:hover, + #pagetoc a.active { + background: var(--sidebar-bg); + color: var(--sidebar-active) !important; + } + #pagetoc .active { + background: var(--sidebar-bg); + color: var(--sidebar-active); + } + #pagetoc .pagetoc-H2 { + padding-left: 20px; + } + #pagetoc .pagetoc-H3 { + padding-left: 40px; + } + #pagetoc .pagetoc-H4 { + padding-left: 60px; + } +} + +@media print { + #sidetoc { + display: none; + } +} diff --git a/src/doc/rustc-dev-guide/pagetoc.js b/src/doc/rustc-dev-guide/pagetoc.js new file mode 100644 index 000000000000..927a5b10749b --- /dev/null +++ b/src/doc/rustc-dev-guide/pagetoc.js @@ -0,0 +1,104 @@ +// Inspired by https://github.com/JorelAli/mdBook-pagetoc/tree/98ee241 (under WTFPL) + +let activeHref = location.href; +function updatePageToc(elem = undefined) { + let selectedPageTocElem = elem; + const pagetoc = document.getElementById("pagetoc"); + + function getRect(element) { + return element.getBoundingClientRect(); + } + + function overflowTop(container, element) { + return getRect(container).top - getRect(element).top; + } + + function overflowBottom(container, element) { + return getRect(container).bottom - getRect(element).bottom; + } + + // We've not selected a heading to highlight, and the URL needs updating + // so we need to find a heading based on the URL + if (selectedPageTocElem === undefined && location.href !== activeHref) { + activeHref = location.href; + for (const pageTocElement of pagetoc.children) { + if (pageTocElement.href === activeHref) { + selectedPageTocElem = pageTocElement; + } + } + } + + // We still don't have a selected heading, let's try and find the most + // suitable heading based on the scroll position + if (selectedPageTocElem === undefined) { + const margin = window.innerHeight / 3; + + const headers = document.getElementsByClassName("header"); + for (let i = 0; i < headers.length; i++) { + const header = headers[i]; + if (selectedPageTocElem === undefined && getRect(header).top >= 0) { + if (getRect(header).top < margin) { + selectedPageTocElem = header; + } else { + selectedPageTocElem = headers[Math.max(0, i - 1)]; + } + } + // a very long last section's heading is over the screen + if (selectedPageTocElem === undefined && i === headers.length - 1) { + selectedPageTocElem = header; + } + } + } + + // Remove the active flag from all pagetoc elements + for (const pageTocElement of pagetoc.children) { + pageTocElement.classList.remove("active"); + } + + // If we have a selected heading, set it to active and scroll to it + if (selectedPageTocElem !== undefined) { + for (const pageTocElement of pagetoc.children) { + if (selectedPageTocElem.href.localeCompare(pageTocElement.href) === 0) { + pageTocElement.classList.add("active"); + if (overflowTop(pagetoc, pageTocElement) > 0) { + pagetoc.scrollTop = pageTocElement.offsetTop; + } + if (overflowBottom(pagetoc, pageTocElement) < 0) { + pagetoc.scrollTop -= overflowBottom(pagetoc, pageTocElement); + } + } + } + } +} + +if (document.getElementById("sidetoc") === null && + document.getElementsByClassName("header").length > 0) { + // The sidetoc element doesn't exist yet, let's create it + + // Create the empty sidetoc and pagetoc elements + const sidetoc = document.createElement("div"); + const pagetoc = document.createElement("div"); + sidetoc.id = "sidetoc"; + pagetoc.id = "pagetoc"; + sidetoc.appendChild(pagetoc); + + // And append them to the current DOM + const main = document.querySelector('main'); + main.insertBefore(sidetoc, main.firstChild); + + // Populate sidebar on load + window.addEventListener("load", () => { + for (const header of document.getElementsByClassName("header")) { + const link = document.createElement("a"); + link.innerHTML = header.innerHTML; + link.href = header.hash; + link.classList.add("pagetoc-" + header.parentElement.tagName); + document.getElementById("pagetoc").appendChild(link); + link.onclick = () => updatePageToc(link); + } + updatePageToc(); + }); + + // Update page table of contents selected heading on scroll + window.addEventListener("scroll", () => updatePageToc()); +} From 65589ad33f544003e49cabeb0b76f6b1f0d3ce30 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 28 Jul 2025 11:45:21 +0200 Subject: [PATCH 080/242] remove the markers --- src/doc/rustc-dev-guide/src/asm.md | 2 -- src/doc/rustc-dev-guide/src/backend/backend-agnostic.md | 2 -- src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md | 2 -- src/doc/rustc-dev-guide/src/backend/monomorph.md | 2 -- src/doc/rustc-dev-guide/src/backend/updating-llvm.md | 2 -- .../src/borrow_check/moves_and_initialization/move_paths.md | 2 -- src/doc/rustc-dev-guide/src/borrow_check/region_inference.md | 2 -- .../src/borrow_check/region_inference/constraint_propagation.md | 2 -- .../src/borrow_check/region_inference/lifetime_parameters.md | 2 -- .../src/borrow_check/region_inference/member_constraints.md | 2 -- .../borrow_check/region_inference/placeholders_and_universes.md | 2 -- src/doc/rustc-dev-guide/src/bug-fix-procedure.md | 2 -- .../src/building/bootstrapping/what-bootstrapping-does.md | 2 -- src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md | 2 -- src/doc/rustc-dev-guide/src/building/new-target.md | 2 -- src/doc/rustc-dev-guide/src/building/optimized-build.md | 2 -- src/doc/rustc-dev-guide/src/building/suggested.md | 2 -- src/doc/rustc-dev-guide/src/compiler-debugging.md | 2 -- src/doc/rustc-dev-guide/src/compiler-src.md | 2 -- src/doc/rustc-dev-guide/src/const-eval/interpret.md | 2 -- src/doc/rustc-dev-guide/src/contributing.md | 2 -- src/doc/rustc-dev-guide/src/coroutine-closures.md | 2 -- src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md | 2 -- src/doc/rustc-dev-guide/src/diagnostics.md | 2 -- src/doc/rustc-dev-guide/src/early_late_parameters.md | 2 -- src/doc/rustc-dev-guide/src/getting-started.md | 2 -- src/doc/rustc-dev-guide/src/git.md | 2 -- src/doc/rustc-dev-guide/src/guides/editions.md | 2 -- src/doc/rustc-dev-guide/src/hir.md | 2 -- src/doc/rustc-dev-guide/src/implementing_new_features.md | 2 -- src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md | 2 -- src/doc/rustc-dev-guide/src/macro-expansion.md | 2 -- src/doc/rustc-dev-guide/src/mir/construction.md | 2 -- src/doc/rustc-dev-guide/src/mir/dataflow.md | 2 -- src/doc/rustc-dev-guide/src/mir/drop-elaboration.md | 2 -- src/doc/rustc-dev-guide/src/mir/index.md | 2 -- src/doc/rustc-dev-guide/src/name-resolution.md | 2 -- src/doc/rustc-dev-guide/src/normalization.md | 2 -- src/doc/rustc-dev-guide/src/overview.md | 2 -- src/doc/rustc-dev-guide/src/panic-implementation.md | 2 -- src/doc/rustc-dev-guide/src/profile-guided-optimization.md | 2 -- .../src/queries/incremental-compilation-in-detail.md | 2 -- src/doc/rustc-dev-guide/src/queries/incremental-compilation.md | 2 -- .../src/queries/query-evaluation-model-in-detail.md | 2 -- src/doc/rustc-dev-guide/src/queries/salsa.md | 2 -- src/doc/rustc-dev-guide/src/query.md | 2 -- src/doc/rustc-dev-guide/src/rustdoc-internals.md | 2 -- src/doc/rustc-dev-guide/src/rustdoc-internals/search.md | 2 -- src/doc/rustc-dev-guide/src/rustdoc.md | 2 -- src/doc/rustc-dev-guide/src/stability.md | 2 -- src/doc/rustc-dev-guide/src/stabilization_guide.md | 2 -- src/doc/rustc-dev-guide/src/test-implementation.md | 2 -- src/doc/rustc-dev-guide/src/tests/adding.md | 2 -- src/doc/rustc-dev-guide/src/tests/compiletest.md | 2 -- src/doc/rustc-dev-guide/src/tests/directives.md | 2 -- src/doc/rustc-dev-guide/src/tests/intro.md | 2 -- src/doc/rustc-dev-guide/src/tests/running.md | 2 -- src/doc/rustc-dev-guide/src/tests/ui.md | 2 -- src/doc/rustc-dev-guide/src/thir.md | 2 -- src/doc/rustc-dev-guide/src/tracing.md | 2 -- src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md | 2 -- src/doc/rustc-dev-guide/src/traits/lowering-to-logic.md | 2 -- src/doc/rustc-dev-guide/src/traits/resolution.md | 2 -- src/doc/rustc-dev-guide/src/ty.md | 2 -- src/doc/rustc-dev-guide/src/type-inference.md | 2 -- src/doc/rustc-dev-guide/src/typing_parameter_envs.md | 2 -- src/doc/rustc-dev-guide/src/variance.md | 2 -- src/doc/rustc-dev-guide/src/walkthrough.md | 2 -- 68 files changed, 136 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/asm.md b/src/doc/rustc-dev-guide/src/asm.md index 1bb493e73d58..b5857d5465e1 100644 --- a/src/doc/rustc-dev-guide/src/asm.md +++ b/src/doc/rustc-dev-guide/src/asm.md @@ -1,7 +1,5 @@ # Inline assembly - - ## Overview Inline assembly in rustc mostly revolves around taking an `asm!` macro invocation and plumbing it diff --git a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md index 0f81d3cb48a1..2fdda4eda99a 100644 --- a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md +++ b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md @@ -1,7 +1,5 @@ # Backend Agnostic Codegen - - [`rustc_codegen_ssa`] provides an abstract interface for all backends to implement, namely LLVM, [Cranelift], and [GCC]. diff --git a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md index c5ee00813a34..9ca4bcab078e 100644 --- a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md +++ b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md @@ -1,7 +1,5 @@ # Implicit caller location - - Approved in [RFC 2091], this feature enables the accurate reporting of caller location during panics initiated from functions like `Option::unwrap`, `Result::expect`, and `Index::index`. This feature adds the [`#[track_caller]`][attr-reference] attribute for functions, the diff --git a/src/doc/rustc-dev-guide/src/backend/monomorph.md b/src/doc/rustc-dev-guide/src/backend/monomorph.md index 7ebb4d2b1e81..e9d98597ee0d 100644 --- a/src/doc/rustc-dev-guide/src/backend/monomorph.md +++ b/src/doc/rustc-dev-guide/src/backend/monomorph.md @@ -1,7 +1,5 @@ # Monomorphization - - As you probably know, Rust has a very expressive type system that has extensive support for generic types. But of course, assembly is not generic, so we need to figure out the concrete types of all the generics before the code can diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index 18c822aad790..ebef15d40baf 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -1,7 +1,5 @@ # Updating LLVM - - Rust supports building against multiple LLVM versions: diff --git a/src/doc/rustc-dev-guide/src/borrow_check/moves_and_initialization/move_paths.md b/src/doc/rustc-dev-guide/src/borrow_check/moves_and_initialization/move_paths.md index ad9c75d62960..95518fbc0184 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/moves_and_initialization/move_paths.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/moves_and_initialization/move_paths.md @@ -1,7 +1,5 @@ # Move paths - - In reality, it's not enough to track initialization at the granularity of local variables. Rust also allows us to do moves and initialization at the field granularity: diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference.md index 85e71b4fa429..0d55ab955836 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference.md @@ -1,7 +1,5 @@ # Region inference (NLL) - - The MIR-based region checking code is located in [the `rustc_mir::borrow_check` module][nll]. diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/constraint_propagation.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/constraint_propagation.md index 4c30d25e0406..c3f8c03cb29f 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/constraint_propagation.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/constraint_propagation.md @@ -1,7 +1,5 @@ # Constraint propagation - - The main work of the region inference is **constraint propagation**, which is done in the [`propagate_constraints`] function. There are three sorts of constraints that are used in NLL, and we'll explain how diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/lifetime_parameters.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/lifetime_parameters.md index fadfac404569..2d337dbc020f 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/lifetime_parameters.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/lifetime_parameters.md @@ -1,7 +1,5 @@ # Universal regions - - "Universal regions" is the name that the code uses to refer to "named lifetimes" -- e.g., lifetime parameters and `'static`. The name derives from the fact that such lifetimes are "universally quantified" diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md index fd7c87ffcea7..2804c97724f5 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/member_constraints.md @@ -1,7 +1,5 @@ # Member constraints - - A member constraint `'m member of ['c_1..'c_N]` expresses that the region `'m` must be *equal* to some **choice regions** `'c_i` (for some `i`). These constraints cannot be expressed by users, but they diff --git a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/placeholders_and_universes.md b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/placeholders_and_universes.md index 91c8c4526119..11fd2a5fc7db 100644 --- a/src/doc/rustc-dev-guide/src/borrow_check/region_inference/placeholders_and_universes.md +++ b/src/doc/rustc-dev-guide/src/borrow_check/region_inference/placeholders_and_universes.md @@ -1,7 +1,5 @@ # Placeholders and universes - - From time to time we have to reason about regions that we can't concretely know. For example, consider this program: diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md index 55436261fdef..6b13c97023f5 100644 --- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md +++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md @@ -1,7 +1,5 @@ # Procedures for breaking changes - - This page defines the best practices procedure for making bug fixes or soundness corrections in the compiler that can cause existing code to stop compiling. This text is based on diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 2793ad438152..da425d8d39bb 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -1,7 +1,5 @@ # What Bootstrapping does - - [*Bootstrapping*][boot] is the process of using a compiler to compile itself. More accurately, it means using an older compiler to compile a newer version of the same compiler. diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index d29cd1448102..b07d3533f59b 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -1,7 +1,5 @@ # How to build and run the compiler - -
For `profile = "library"` users, or users who use `download-rustc = true | "if-unchanged"`, please be advised that diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index e11a2cd8ee57..436aec8ee265 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -6,8 +6,6 @@ relevant to your desired goal. See also the associated documentation in the [target tier policy]. - - [target tier policy]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target ## Specifying a new LLVM diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index 62dfaca89d24..863ed9749fb7 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -1,7 +1,5 @@ # Optimized build of the compiler - - There are multiple additional build configuration options and techniques that can be used to compile a build of `rustc` that is as optimized as possible (for example when building `rustc` for a Linux distribution). The status of these configuration options for various Rust targets is tracked [here]. diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index c046161e77f2..35c7e935b568 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -3,8 +3,6 @@ The full bootstrapping process takes quite a while. Here are some suggestions to make your life easier. - - ## Installing a pre-push hook CI will automatically fail your build if it doesn't pass `tidy`, our internal diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 102e20207792..edd2aa6c5f64 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -1,7 +1,5 @@ # Debugging the compiler - - This chapter contains a few tips to debug the compiler. These tips aim to be useful no matter what you are working on. Some of the other chapters have advice about specific parts of the compiler (e.g. the [Queries Debugging and diff --git a/src/doc/rustc-dev-guide/src/compiler-src.md b/src/doc/rustc-dev-guide/src/compiler-src.md index 00aa96226849..d67bacb1b339 100644 --- a/src/doc/rustc-dev-guide/src/compiler-src.md +++ b/src/doc/rustc-dev-guide/src/compiler-src.md @@ -1,7 +1,5 @@ # High-level overview of the compiler source - - Now that we have [seen what the compiler does][orgch], let's take a look at the structure of the [`rust-lang/rust`] repository, where the rustc source code lives. diff --git a/src/doc/rustc-dev-guide/src/const-eval/interpret.md b/src/doc/rustc-dev-guide/src/const-eval/interpret.md index 51a539de5cb6..08382b12ff00 100644 --- a/src/doc/rustc-dev-guide/src/const-eval/interpret.md +++ b/src/doc/rustc-dev-guide/src/const-eval/interpret.md @@ -1,7 +1,5 @@ # Interpreter - - The interpreter is a virtual machine for executing MIR without compiling to machine code. It is usually invoked via `tcx.const_eval_*` functions. The interpreter is shared between the compiler (for compile-time function diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index b3fcd79ec818..963bef3af8de 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -1,7 +1,5 @@ # Contribution procedures - - ## Bug reports While bugs are unfortunate, they're a reality in software. We can't fix what we diff --git a/src/doc/rustc-dev-guide/src/coroutine-closures.md b/src/doc/rustc-dev-guide/src/coroutine-closures.md index 48cdba44a9f5..2617c824a391 100644 --- a/src/doc/rustc-dev-guide/src/coroutine-closures.md +++ b/src/doc/rustc-dev-guide/src/coroutine-closures.md @@ -1,7 +1,5 @@ # Async closures/"coroutine-closures" - - Please read [RFC 3668](https://rust-lang.github.io/rfcs/3668-async-closures.html) to understand the general motivation of the feature. This is a very technical and somewhat "vertical" chapter; ideally we'd split this and sprinkle it across all the relevant chapters, but for the purposes of understanding async closures *holistically*, I've put this together all here in one chapter. ## Coroutine-closures -- a technical deep dive diff --git a/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md b/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md index ac629934e0a4..bd4f795ce03b 100644 --- a/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md +++ b/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md @@ -1,7 +1,5 @@ # Debugging support in the Rust compiler - - This document explains the state of debugging tools support in the Rust compiler (rustc). It gives an overview of GDB, LLDB, WinDbg/CDB, as well as infrastructure around Rust compiler to debug Rust code. diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md index 33f5441d36e4..82191e0a6eaf 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics.md +++ b/src/doc/rustc-dev-guide/src/diagnostics.md @@ -1,7 +1,5 @@ # Errors and lints - - A lot of effort has been put into making `rustc` have great error messages. This chapter is about how to emit compile errors and lints from the compiler. diff --git a/src/doc/rustc-dev-guide/src/early_late_parameters.md b/src/doc/rustc-dev-guide/src/early_late_parameters.md index 3f94b0905668..c472bdc2c481 100644 --- a/src/doc/rustc-dev-guide/src/early_late_parameters.md +++ b/src/doc/rustc-dev-guide/src/early_late_parameters.md @@ -1,8 +1,6 @@ # Early vs Late bound parameters - - > **NOTE**: This chapter largely talks about early/late bound as being solely relevant when discussing function item types/function definitions. This is potentially not completely true, async blocks and closures should likely be discussed somewhat in this chapter. ## What does it mean to be "early" bound or "late" bound diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index d6c5c3ac8521..04d2e37732fa 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -3,8 +3,6 @@ Thank you for your interest in contributing to Rust! There are many ways to contribute, and we appreciate all of them. - - If this is your first time contributing, the [walkthrough] chapter can give you a good example of how a typical contribution would go. diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 8726ddfce20c..447c6fd45467 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -1,7 +1,5 @@ # Using Git - - The Rust project uses [Git] to manage its source code. In order to contribute, you'll need some familiarity with its features so that your changes can be incorporated into the compiler. diff --git a/src/doc/rustc-dev-guide/src/guides/editions.md b/src/doc/rustc-dev-guide/src/guides/editions.md index 9a92d4ebcb51..b65fbb13cd18 100644 --- a/src/doc/rustc-dev-guide/src/guides/editions.md +++ b/src/doc/rustc-dev-guide/src/guides/editions.md @@ -1,7 +1,5 @@ # Editions - - This chapter gives an overview of how Edition support works in rustc. This assumes that you are familiar with what Editions are (see the [Edition Guide]). diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 72fb10701574..38ba33112f2e 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -1,7 +1,5 @@ # The HIR - - The HIR – "High-Level Intermediate Representation" – is the primary IR used in most of rustc. It is a compiler-friendly representation of the abstract syntax tree (AST) that is generated after parsing, macro expansion, and name diff --git a/src/doc/rustc-dev-guide/src/implementing_new_features.md b/src/doc/rustc-dev-guide/src/implementing_new_features.md index 76cf2386c826..00bce8599e43 100644 --- a/src/doc/rustc-dev-guide/src/implementing_new_features.md +++ b/src/doc/rustc-dev-guide/src/implementing_new_features.md @@ -1,7 +1,5 @@ # Implementing new language features - - When you want to implement a new significant feature in the compiler, you need to go through this process to make sure everything goes smoothly. **NOTE: This section is for *language* features, not *library* features, which use [a different process].** diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md index 880363b94bf2..288b90f33c3d 100644 --- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md +++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md @@ -1,7 +1,5 @@ # LLVM source-based code coverage - - `rustc` supports detailed source-based code and test coverage analysis with a command line option (`-C instrument-coverage`) that instruments Rust libraries and binaries with additional instructions and data, at compile time. diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index a90f717004f0..54d6d2b4e813 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -1,7 +1,5 @@ # Macro expansion - - Rust has a very powerful macro system. In the previous chapter, we saw how the parser sets aside macros to be expanded (using temporary [placeholders]). This chapter is about the process of expanding those macros iteratively until diff --git a/src/doc/rustc-dev-guide/src/mir/construction.md b/src/doc/rustc-dev-guide/src/mir/construction.md index f2559a22b955..8360d9ff1a8b 100644 --- a/src/doc/rustc-dev-guide/src/mir/construction.md +++ b/src/doc/rustc-dev-guide/src/mir/construction.md @@ -1,7 +1,5 @@ # MIR construction - - The lowering of [HIR] to [MIR] occurs for the following (probably incomplete) list of items: diff --git a/src/doc/rustc-dev-guide/src/mir/dataflow.md b/src/doc/rustc-dev-guide/src/mir/dataflow.md index 85e57dd839b8..970e61196c12 100644 --- a/src/doc/rustc-dev-guide/src/mir/dataflow.md +++ b/src/doc/rustc-dev-guide/src/mir/dataflow.md @@ -1,7 +1,5 @@ # Dataflow Analysis - - If you work on the MIR, you will frequently come across various flavors of [dataflow analysis][wiki]. `rustc` uses dataflow to find uninitialized variables, determine what variables are live across a generator `yield` diff --git a/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md b/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md index 3b321fd44d1d..4da612c83f0f 100644 --- a/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md +++ b/src/doc/rustc-dev-guide/src/mir/drop-elaboration.md @@ -1,7 +1,5 @@ # Drop elaboration - - ## Dynamic drops According to the [reference][reference-drop]: diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md index f355875aa156..8ba5f3ac8b78 100644 --- a/src/doc/rustc-dev-guide/src/mir/index.md +++ b/src/doc/rustc-dev-guide/src/mir/index.md @@ -1,7 +1,5 @@ # The MIR (Mid-level IR) - - MIR is Rust's _Mid-level Intermediate Representation_. It is constructed from [HIR](../hir.html). MIR was introduced in [RFC 1211]. It is a radically simplified form of Rust that is used for diff --git a/src/doc/rustc-dev-guide/src/name-resolution.md b/src/doc/rustc-dev-guide/src/name-resolution.md index 719ebce85536..2e96382f7797 100644 --- a/src/doc/rustc-dev-guide/src/name-resolution.md +++ b/src/doc/rustc-dev-guide/src/name-resolution.md @@ -1,7 +1,5 @@ # Name resolution - - In the previous chapters, we saw how the [*Abstract Syntax Tree* (`AST`)][ast] is built with all macros expanded. We saw how doing that requires doing some name resolution to resolve imports and macro names. In this chapter, we show diff --git a/src/doc/rustc-dev-guide/src/normalization.md b/src/doc/rustc-dev-guide/src/normalization.md index eb0962a41223..53e20f1c0db7 100644 --- a/src/doc/rustc-dev-guide/src/normalization.md +++ b/src/doc/rustc-dev-guide/src/normalization.md @@ -1,7 +1,5 @@ # Aliases and Normalization - - ## Aliases In Rust there are a number of types that are considered equal to some "underlying" type, for example inherent associated types, trait associated types, free type aliases (`type Foo = u32`), and opaque types (`-> impl RPIT`). We consider such types to be "aliases", alias types are represented by the [`TyKind::Alias`][tykind_alias] variant, with the kind of alias tracked by the [`AliasTyKind`][aliaskind] enum. diff --git a/src/doc/rustc-dev-guide/src/overview.md b/src/doc/rustc-dev-guide/src/overview.md index 8a1a22fad660..12b76828b5c3 100644 --- a/src/doc/rustc-dev-guide/src/overview.md +++ b/src/doc/rustc-dev-guide/src/overview.md @@ -1,7 +1,5 @@ # Overview of the compiler - - This chapter is about the overall process of compiling a program -- how everything fits together. diff --git a/src/doc/rustc-dev-guide/src/panic-implementation.md b/src/doc/rustc-dev-guide/src/panic-implementation.md index 468190ffccd5..dba3f2146d23 100644 --- a/src/doc/rustc-dev-guide/src/panic-implementation.md +++ b/src/doc/rustc-dev-guide/src/panic-implementation.md @@ -1,7 +1,5 @@ # Panicking in Rust - - ## Step 1: Invocation of the `panic!` macro. There are actually two panic macros - one defined in `core`, and one defined in `std`. diff --git a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md index 2fa810210451..4e3dadd406ec 100644 --- a/src/doc/rustc-dev-guide/src/profile-guided-optimization.md +++ b/src/doc/rustc-dev-guide/src/profile-guided-optimization.md @@ -1,7 +1,5 @@ # Profile-guided optimization - - `rustc` supports doing profile-guided optimization (PGO). This chapter describes what PGO is and how the support for it is implemented in `rustc`. diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index 18e0e25c5315..46e38832e64d 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -1,7 +1,5 @@ # Incremental compilation in detail - - The incremental compilation scheme is, in essence, a surprisingly simple extension to the overall query system. It relies on the fact that: diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation.md index 6e5b4e8cc499..731ff3287d9f 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation.md @@ -1,7 +1,5 @@ # Incremental compilation - - The incremental compilation scheme is, in essence, a surprisingly simple extension to the overall query system. We'll start by describing a slightly simplified variant of the real thing – the "basic algorithm" – diff --git a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md index 444e20bc580e..c1a4373f7dac 100644 --- a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md @@ -1,7 +1,5 @@ # The Query Evaluation Model in detail - - This chapter provides a deeper dive into the abstract model queries are built on. It does not go into implementation details but tries to explain the underlying logic. The examples here, therefore, have been stripped down and diff --git a/src/doc/rustc-dev-guide/src/queries/salsa.md b/src/doc/rustc-dev-guide/src/queries/salsa.md index 1a7b7fa9a683..dc7160edc22c 100644 --- a/src/doc/rustc-dev-guide/src/queries/salsa.md +++ b/src/doc/rustc-dev-guide/src/queries/salsa.md @@ -1,7 +1,5 @@ # How Salsa works - - This chapter is based on the explanation given by Niko Matsakis in this [video](https://www.youtube.com/watch?v=_muY4HjSqVw) about [Salsa](https://github.com/salsa-rs/salsa). To find out more you may diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 0ca1b360a701..8377a7b2f31a 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -1,7 +1,5 @@ # Queries: demand-driven compilation - - As described in [Overview of the compiler], the Rust compiler is still (as of July 2021) transitioning from a traditional "pass-based" setup to a "demand-driven" system. The compiler query diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals.md b/src/doc/rustc-dev-guide/src/rustdoc-internals.md index 0234d4a920ed..4affbafe4777 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals.md @@ -1,7 +1,5 @@ # Rustdoc Internals - - This page describes [`rustdoc`]'s passes and modes. For an overview of `rustdoc`, see the ["Rustdoc overview" chapter](./rustdoc.md). diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md index 3506431118ba..beff0a94c1ec 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/search.md @@ -7,8 +7,6 @@ in the crates in the doc bundle, and the second reads it, turns it into some in-memory structures, and scans them linearly to search. - - ## Search index format `search.js` calls this Raw, because it turns it into diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md index 52ae48c3735c..9290fcd3b41c 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc.md +++ b/src/doc/rustc-dev-guide/src/rustdoc.md @@ -9,8 +9,6 @@ For more details about how rustdoc works, see the [Rustdoc internals]: ./rustdoc-internals.md - - `rustdoc` uses `rustc` internals (and, of course, the standard library), so you will have to build the compiler and `std` once before you can build `rustdoc`. diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md index 230925252bac..d0cee54adb6a 100644 --- a/src/doc/rustc-dev-guide/src/stability.md +++ b/src/doc/rustc-dev-guide/src/stability.md @@ -6,8 +6,6 @@ APIs to use unstable APIs internally in the rustc standard library. **NOTE**: this section is for *library* features, not *language* features. For instructions on stabilizing a language feature see [Stabilizing Features](./stabilization_guide.md). - - ## unstable The `#[unstable(feature = "foo", issue = "1234", reason = "lorem ipsum")]` diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md index f155272e5a2c..e399930fc523 100644 --- a/src/doc/rustc-dev-guide/src/stabilization_guide.md +++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md @@ -6,8 +6,6 @@ Once an unstable feature has been well-tested with no outstanding concerns, anyone may push for its stabilization, though involving the people who have worked on it is prudent. Follow these steps: - - ## Write an RFC, if needed If the feature was part of a [lang experiment], the lang team generally will want to first accept an RFC before stabilization. diff --git a/src/doc/rustc-dev-guide/src/test-implementation.md b/src/doc/rustc-dev-guide/src/test-implementation.md index e906dd29f25f..f09d73631998 100644 --- a/src/doc/rustc-dev-guide/src/test-implementation.md +++ b/src/doc/rustc-dev-guide/src/test-implementation.md @@ -1,7 +1,5 @@ # The `#[test]` attribute - - Many Rust programmers rely on a built-in attribute called `#[test]`. All diff --git a/src/doc/rustc-dev-guide/src/tests/adding.md b/src/doc/rustc-dev-guide/src/tests/adding.md index 895eabfbd56a..e5c26bef11d0 100644 --- a/src/doc/rustc-dev-guide/src/tests/adding.md +++ b/src/doc/rustc-dev-guide/src/tests/adding.md @@ -1,7 +1,5 @@ # Adding new tests - - **In general, we expect every PR that fixes a bug in rustc to come accompanied by a regression test of some kind.** This test should fail in master but pass after the PR. These tests are really useful for preventing us from repeating the diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index a108dfdef9b3..4980ed845d6d 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -1,7 +1,5 @@ # Compiletest - - ## Introduction `compiletest` is the main test harness of the Rust test suite. It allows test diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 5c3ae359ba0b..a16be9b48255 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -1,7 +1,5 @@ # Compiletest directives - - diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md index 79b96c450a8d..b90c16d602c3 100644 --- a/src/doc/rustc-dev-guide/src/tests/intro.md +++ b/src/doc/rustc-dev-guide/src/tests/intro.md @@ -1,7 +1,5 @@ # Testing the compiler - - The Rust project runs a wide variety of different tests, orchestrated by the build system (`./x test`). This section gives a brief overview of the different testing tools. Subsequent chapters dive into [running tests](running.md) and diff --git a/src/doc/rustc-dev-guide/src/tests/running.md b/src/doc/rustc-dev-guide/src/tests/running.md index 6526fe9c2357..f6e313062cda 100644 --- a/src/doc/rustc-dev-guide/src/tests/running.md +++ b/src/doc/rustc-dev-guide/src/tests/running.md @@ -1,7 +1,5 @@ # Running tests - - You can run the entire test collection using `x`. But note that running the *entire* test collection is almost never what you want to do during local development because it takes a really long time. For local development, see the diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 782f78d76148..c1e67e1b755c 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -1,7 +1,5 @@ # UI tests - - UI tests are a particular [test suite](compiletest.md#test-suites) of compiletest. diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index 73d09ad80bf9..3d3dafaef49b 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -1,7 +1,5 @@ # The THIR - - The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for "High-Level Abstract IR", is another IR used by rustc that is generated after [type checking]. It is (as of January 2024) used for diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index 0cfdf306e92d..5e5b81fc65b2 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -1,7 +1,5 @@ # Using tracing to debug the compiler - - The compiler has a lot of [`debug!`] (or `trace!`) calls, which print out logging information at many points. These are very useful to at least narrow down the location of a bug if not to find it entirely, or just to orient yourself as to why the diff --git a/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md b/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md index 40fd4581bf3e..2884ca5a05a1 100644 --- a/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md +++ b/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md @@ -1,7 +1,5 @@ # Goals and clauses - - In logic programming terms, a **goal** is something that you must prove and a **clause** is something that you know is true. As described in the [lowering to logic](./lowering-to-logic.html) diff --git a/src/doc/rustc-dev-guide/src/traits/lowering-to-logic.md b/src/doc/rustc-dev-guide/src/traits/lowering-to-logic.md index 1248d434610b..cc8b3bf800cb 100644 --- a/src/doc/rustc-dev-guide/src/traits/lowering-to-logic.md +++ b/src/doc/rustc-dev-guide/src/traits/lowering-to-logic.md @@ -1,7 +1,5 @@ # Lowering to logic - - The key observation here is that the Rust trait system is basically a kind of logic, and it can be mapped onto standard logical inference rules. We can then look for solutions to those inference rules in a diff --git a/src/doc/rustc-dev-guide/src/traits/resolution.md b/src/doc/rustc-dev-guide/src/traits/resolution.md index c62b0593694f..ccb2b04268e8 100644 --- a/src/doc/rustc-dev-guide/src/traits/resolution.md +++ b/src/doc/rustc-dev-guide/src/traits/resolution.md @@ -1,7 +1,5 @@ # Trait resolution (old-style) - - This chapter describes the general process of _trait resolution_ and points out some non-obvious things. diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md index 767ac3fdba21..4055f475e992 100644 --- a/src/doc/rustc-dev-guide/src/ty.md +++ b/src/doc/rustc-dev-guide/src/ty.md @@ -1,7 +1,5 @@ # The `ty` module: representing types - - The `ty` module defines how the Rust compiler represents types internally. It also defines the *typing context* (`tcx` or `TyCtxt`), which is the central data structure in the compiler. diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md index 888eb2439c5b..2243205f129b 100644 --- a/src/doc/rustc-dev-guide/src/type-inference.md +++ b/src/doc/rustc-dev-guide/src/type-inference.md @@ -1,7 +1,5 @@ # Type inference - - Type inference is the process of automatic detection of the type of an expression. diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md index e21bc5155da1..db15467a47a0 100644 --- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md +++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md @@ -1,7 +1,5 @@ # Typing/Parameter Environments - - ## Typing Environments When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). diff --git a/src/doc/rustc-dev-guide/src/variance.md b/src/doc/rustc-dev-guide/src/variance.md index ad4fa4adfddb..7aa014071551 100644 --- a/src/doc/rustc-dev-guide/src/variance.md +++ b/src/doc/rustc-dev-guide/src/variance.md @@ -1,7 +1,5 @@ # Variance of type and lifetime parameters - - For a more general background on variance, see the [background] appendix. [background]: ./appendix/background.html diff --git a/src/doc/rustc-dev-guide/src/walkthrough.md b/src/doc/rustc-dev-guide/src/walkthrough.md index 48b3f8bb15d3..b4c3379347ed 100644 --- a/src/doc/rustc-dev-guide/src/walkthrough.md +++ b/src/doc/rustc-dev-guide/src/walkthrough.md @@ -1,7 +1,5 @@ # Walkthrough: a typical contribution - - There are _a lot_ of ways to contribute to the Rust compiler, including fixing bugs, improving performance, helping design features, providing feedback on existing features, etc. This chapter does not claim to scratch the surface. From 91bccd6ba8861fd91bcf0f682f50f78fdb38a450 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 24 Jul 2025 14:06:58 +0200 Subject: [PATCH 081/242] use `minicore` for fortanix assembly tests --- ...4-fortanix-unknown-sgx-lvi-generic-load.rs | 31 ++++++++++++------- ...64-fortanix-unknown-sgx-lvi-generic-ret.rs | 14 +++++++-- ...ortanix-unknown-sgx-lvi-inline-assembly.rs | 28 ++++++++++------- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs index f5e2f18e68e4..2892ff2882a7 100644 --- a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -1,17 +1,24 @@ -// Test LVI load hardening on SGX enclave code +// Test LVI load hardening on SGX enclave code, specifically that `ret` is rewritten. +//@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx +//@ compile-flags: --target x86_64-fortanix-unknown-sgx -Copt-level=0 +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] -pub extern "C" fn plus_one(r: &mut u64) { - *r = *r + 1; +pub extern "C" fn dereference(a: &mut u64) -> u64 { + // CHECK-LABEL: dereference + // CHECK: lfence + // CHECK: mov + // CHECK: popq [[REGISTER:%[a-z]+]] + // CHECK-NEXT: lfence + // CHECK-NEXT: jmpq *[[REGISTER]] + *a } - -// CHECK: plus_one -// CHECK: lfence -// CHECK-NEXT: incq -// CHECK: popq [[REGISTER:%[a-z]+]] -// CHECK-NEXT: lfence -// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs index f16d68fa2554..a0cedc3bc2da 100644 --- a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -1,12 +1,20 @@ // Test LVI ret hardening on generic rust code +//@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx +//@ compile-flags: --target x86_64-fortanix-unknown-sgx +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] pub extern "C" fn myret() {} -// CHECK: myret: +// CHECK-LABEL: myret: // CHECK: popq [[REGISTER:%[a-z]+]] // CHECK-NEXT: lfence // CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs index a729df8e1660..215fb4b804ac 100644 --- a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -1,13 +1,22 @@ // Test LVI load hardening on SGX inline assembly code +//@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx +//@ compile-flags: --target x86_64-fortanix-unknown-sgx +//@ needs-llvm-components: x86 -use std::arch::asm; +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] pub extern "C" fn get(ptr: *const u64) -> u64 { + // CHECK-LABEL: get + // CHECK: movq + // CHECK-NEXT: lfence let value: u64; unsafe { asm!("mov {}, [{}]", @@ -17,18 +26,13 @@ pub extern "C" fn get(ptr: *const u64) -> u64 { value } -// CHECK: get -// CHECK: movq -// CHECK-NEXT: lfence - #[no_mangle] pub extern "C" fn myret() { + // CHECK-LABEL: myret + // CHECK: shlq $0, (%rsp) + // CHECK-NEXT: lfence + // CHECK-NEXT: retq unsafe { asm!("ret"); } } - -// CHECK: myret -// CHECK: shlq $0, (%rsp) -// CHECK-NEXT: lfence -// CHECK-NEXT: retq From 8b90847416d5678d784942b46c05f8c97caef83d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 24 Jul 2025 14:07:32 +0200 Subject: [PATCH 082/242] update fortanix run-make test Make it more idiomatic with the new run-make infra --- .../x86_64-fortanix-unknown-sgx-lvi/rmake.rs | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs index e58762aeb6db..89754cdaf905 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs @@ -13,42 +13,56 @@ //@ only-x86_64-fortanix-unknown-sgx -use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, set_current_dir, target}; +use run_make_support::{ + cargo, cwd, llvm_filecheck, llvm_objdump, regex, run, set_current_dir, target, +}; fn main() { - let main_dir = cwd(); - set_current_dir("enclave"); - // HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. - // These come from the top-level Rust workspace, that this crate is not a - // member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - cmd("cargo") - .env("RUSTC_BOOTSTRAP", "1") + cargo() .arg("-v") - .arg("run") + .arg("build") .arg("--target") .arg(target()) + .current_dir("enclave") + .env("CC_x86_64_fortanix_unknown_sgx", "clang") + .env( + "CFLAGS_x86_64_fortanix_unknown_sgx", + "-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening", + ) + .env("CXX_x86_64_fortanix_unknown_sgx", "clang++") + .env( + "CXXFLAGS_x86_64_fortanix_unknown_sgx", + "-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening", + ) .run(); - set_current_dir(&main_dir); - // Rust has various ways of adding code to a binary: + + // Rust has several ways of including machine code into a binary: + // // - Rust code // - Inline assembly // - Global assembly // - C/C++ code compiled as part of Rust crates - // For those different kinds, we do have very small code examples that should be - // mitigated in some way. Mostly we check that ret instructions should no longer be present. + // + // For each of those, check that the mitigations are applied. Mostly we check + // that ret instructions are no longer present. + + // Check that normal rust code has the right mitigations. check("unw_getcontext", "unw_getcontext.checks"); check("__libunwind_Registers_x86_64_jumpto", "jumpto.checks"); check("std::io::stdio::_print::[[:alnum:]]+", "print.with_frame_pointers.checks"); + // Check that rust global assembly has the right mitigations. check("rust_plus_one_global_asm", "rust_plus_one_global_asm.checks"); + // Check that C code compiled using the `cc` crate has the right mitigations. check("cc_plus_one_c", "cc_plus_one_c.checks"); check("cc_plus_one_c_asm", "cc_plus_one_c_asm.checks"); check("cc_plus_one_cxx", "cc_plus_one_cxx.checks"); check("cc_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks"); check("cc_plus_one_asm", "cc_plus_one_asm.checks"); + // Check that C++ code compiled using the `cc` crate has the right mitigations. check("cmake_plus_one_c", "cmake_plus_one_c.checks"); check("cmake_plus_one_c_asm", "cmake_plus_one_c_asm.checks"); check("cmake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks"); @@ -71,8 +85,7 @@ fn check(func_re: &str, mut checks: &str) { .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") .args(&["--demangle", &format!("--disassemble-symbols={func}")]) .run() - .stdout_utf8(); - let dump = dump.as_bytes(); + .stdout(); // Unique case, must succeed at one of two possible tests. // This is because frame pointers are optional, and them being enabled requires From 6c7dc05f7d1f000cdb7de2390c8532545129e32d Mon Sep 17 00:00:00 2001 From: Caiweiran Date: Mon, 28 Jul 2025 11:58:38 +0000 Subject: [PATCH 083/242] Fix tests/codegen-llvm/simd/extract-insert-dyn.rs test failure on riscv64 --- tests/codegen-llvm/simd/extract-insert-dyn.rs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/codegen-llvm/simd/extract-insert-dyn.rs b/tests/codegen-llvm/simd/extract-insert-dyn.rs index 729f0145314a..9c17b82e5535 100644 --- a/tests/codegen-llvm/simd/extract-insert-dyn.rs +++ b/tests/codegen-llvm/simd/extract-insert-dyn.rs @@ -5,7 +5,8 @@ repr_simd, arm_target_feature, mips_target_feature, - s390x_target_feature + s390x_target_feature, + riscv_target_feature )] #![no_std] #![crate_type = "lib"] @@ -25,97 +26,105 @@ pub struct u32x16([u32; 16]); pub struct i8x16([i8; 16]); // CHECK-LABEL: dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 %idx +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 %idx #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { simd_extract_dyn(x, idx) } // CHECK-LABEL: literal_dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, 7) } // CHECK-LABEL: const_dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, const { 3 + 4 }) } // CHECK-LABEL: const_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { simd_extract(x, const { 3 + 4 }) } // CHECK-LABEL: dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 %idx #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { simd_insert_dyn(x, idx, e) } // CHECK-LABEL: literal_dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, 7, e) } // CHECK-LABEL: const_dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, const { 3 + 4 }, e) } // CHECK-LABEL: const_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert(x, const { 3 + 4 }, e) } From 0e53d8533bf0bb8d6bc59bb000fe7cc7a361902e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 16 Jun 2025 15:25:31 +0000 Subject: [PATCH 084/242] Fortify RemoveUnneededDrops test. --- ...annot_opt_generic.RemoveUnneededDrops.diff | 15 +++++++ ...neric.RemoveUnneededDrops.panic-abort.diff | 26 ------------ ...eric.RemoveUnneededDrops.panic-unwind.diff | 30 -------------- ...ed_drops.dont_opt.RemoveUnneededDrops.diff | 15 +++++++ ...t_opt.RemoveUnneededDrops.panic-abort.diff | 26 ------------ ..._opt.RemoveUnneededDrops.panic-unwind.diff | 30 -------------- ...nneeded_drops.opt.RemoveUnneededDrops.diff | 15 +++++++ ...s.opt.RemoveUnneededDrops.panic-abort.diff | 26 ------------ ....opt.RemoveUnneededDrops.panic-unwind.diff | 26 ------------ ....opt_generic_copy.RemoveUnneededDrops.diff | 15 +++++++ ..._copy.RemoveUnneededDrops.panic-abort.diff | 26 ------------ ...copy.RemoveUnneededDrops.panic-unwind.diff | 26 ------------ tests/mir-opt/remove_unneeded_drops.rs | 40 ++++++++++++++++--- 13 files changed, 94 insertions(+), 222 deletions(-) create mode 100644 tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff create mode 100644 tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff create mode 100644 tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff create mode 100644 tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff new file mode 100644 index 000000000000..52832e739051 --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `cannot_opt_generic` before RemoveUnneededDrops ++ // MIR for `cannot_opt_generic` after RemoveUnneededDrops + + fn cannot_opt_generic(_1: T) -> () { + let mut _0: (); + + bb0: { + drop(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index 0c73602bec84..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `cannot_opt_generic` before RemoveUnneededDrops -+ // MIR for `cannot_opt_generic` after RemoveUnneededDrops - - fn cannot_opt_generic(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index 59cce9fbcdd0..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `cannot_opt_generic` before RemoveUnneededDrops -+ // MIR for `cannot_opt_generic` after RemoveUnneededDrops - - fn cannot_opt_generic(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb2, unwind: bb1]; - } - - bb1 (cleanup): { - resume; - } - - bb2: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff new file mode 100644 index 000000000000..3d67cada5ddf --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `dont_opt` before RemoveUnneededDrops ++ // MIR for `dont_opt` after RemoveUnneededDrops + + fn dont_opt(_1: Vec) -> () { + let mut _0: (); + + bb0: { + drop(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index 428b366b5a68..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `dont_opt` before RemoveUnneededDrops -+ // MIR for `dont_opt` after RemoveUnneededDrops - - fn dont_opt(_1: Vec) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: std::vec::Vec; - scope 1 (inlined std::mem::drop::>) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index 445c1f82a96f..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `dont_opt` before RemoveUnneededDrops -+ // MIR for `dont_opt` after RemoveUnneededDrops - - fn dont_opt(_1: Vec) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: std::vec::Vec; - scope 1 (inlined std::mem::drop::>) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb2, unwind: bb1]; - } - - bb1 (cleanup): { - resume; - } - - bb2: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff new file mode 100644 index 000000000000..cb7e58ca1a1f --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `opt` before RemoveUnneededDrops ++ // MIR for `opt` after RemoveUnneededDrops + + fn opt(_1: bool) -> () { + let mut _0: (); + + bb0: { +- drop(_1) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index 01eb6d4901f7..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt` before RemoveUnneededDrops -+ // MIR for `opt` after RemoveUnneededDrops - - fn opt(_1: bool) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: bool; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index c2c3cb76e832..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt` before RemoveUnneededDrops -+ // MIR for `opt` after RemoveUnneededDrops - - fn opt(_1: bool) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: bool; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind continue]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff new file mode 100644 index 000000000000..1e166eee9fb0 --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `opt_generic_copy` before RemoveUnneededDrops ++ // MIR for `opt_generic_copy` after RemoveUnneededDrops + + fn opt_generic_copy(_1: T) -> () { + let mut _0: (); + + bb0: { +- drop(_1) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index a82ede6196ed..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt_generic_copy` before RemoveUnneededDrops -+ // MIR for `opt_generic_copy` after RemoveUnneededDrops - - fn opt_generic_copy(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index 6e7c9ead740f..000000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt_generic_copy` before RemoveUnneededDrops -+ // MIR for `opt_generic_copy` after RemoveUnneededDrops - - fn opt_generic_copy(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind continue]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.rs b/tests/mir-opt/remove_unneeded_drops.rs index cad79e0aa0cb..49dc611838e3 100644 --- a/tests/mir-opt/remove_unneeded_drops.rs +++ b/tests/mir-opt/remove_unneeded_drops.rs @@ -1,28 +1,56 @@ -// skip-filecheck -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ test-mir-pass: RemoveUnneededDrops + +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + // EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff +#[custom_mir(dialect = "runtime")] fn opt(x: bool) { - drop(x); + // CHECK-LABEL: fn opt( + // CHECK-NOT: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } // EMIT_MIR remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +#[custom_mir(dialect = "runtime")] fn dont_opt(x: Vec) { - drop(x); + // CHECK-LABEL: fn dont_opt( + // CHECK: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } // EMIT_MIR remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +#[custom_mir(dialect = "runtime")] fn opt_generic_copy(x: T) { - drop(x); + // CHECK-LABEL: fn opt_generic_copy( + // CHECK-NOT: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } // EMIT_MIR remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff // since the pass is not running on monomorphisized code, // we can't (but probably should) optimize this +#[custom_mir(dialect = "runtime")] fn cannot_opt_generic(x: T) { - drop(x); + // CHECK-LABEL: fn cannot_opt_generic( + // CHECK: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } fn main() { + // CHECK-LABEL: fn main( opt(true); opt_generic_copy(42); cannot_opt_generic(42); From 8b214fbf17d4e6f8e3ba38a26cffd741ac53adb8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 29 Jul 2025 08:31:08 +0200 Subject: [PATCH 085/242] fix: Do not require all rename definitions to be renameable --- src/tools/rust-analyzer/crates/ide/src/rename.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index a07c647c2cb8..6c1d142c3b05 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -35,13 +35,8 @@ pub(crate) fn prepare_rename( let syntax = source_file.syntax(); let res = find_definitions(&sema, syntax, position, &Name::new_symbol_root(sym::underscore))? - .map(|(frange, kind, def, _, _)| { - // ensure all ranges are valid - - if def.range_for_rename(&sema).is_none() { - bail!("No references found at position") - } - + .filter(|(_, _, def, _, _)| def.range_for_rename(&sema).is_some()) + .map(|(frange, kind, _, _, _)| { always!( frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id From ede338cd8f2353cfef3c3b8d51ae185ed5c45f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 29 Jul 2025 09:35:50 +0200 Subject: [PATCH 086/242] WIP: auth using GitHub app --- src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index ad570ee4595d..ea4d7532a9f2 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -9,12 +9,13 @@ on: jobs: pull: if: github.repository == 'rust-lang/rustc-dev-guide' - uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main + uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@ci-gh-app with: + github-app-id: ${{ vars.APP_CLIENT_ID }} zulip-stream-id: 196385 zulip-bot-email: "rustc-dev-guide-gha-notif-bot@rust-lang.zulipchat.com" pr-base-branch: master branch-name: rustc-pull secrets: zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }} - token: ${{ secrets.GITHUB_TOKEN }} + github-app-secret: ${{ secrets.APP_PRIVATE_KEY }} From 7e4ded41694c4f812efbcb207f21a3fa2ed649d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 29 Jul 2025 09:53:04 +0200 Subject: [PATCH 087/242] Remove `bot-pull-requests` triagebot config --- src/doc/rustc-dev-guide/triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index b3f4c2d281cd..3ac5d57a52b0 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -62,9 +62,6 @@ allow-unauthenticated = [ # Documentation at: https://forge.rust-lang.org/triagebot/issue-links.html [issue-links] -# Automatically close and reopen PRs made by bots to run CI on them -[bot-pull-requests] - [behind-upstream] days-threshold = 7 From 6a40a17051d38855b1a98bbce0021ec33ea29711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 29 Jul 2025 10:02:50 +0200 Subject: [PATCH 088/242] Use main branch of josh-sync for CI workflow --- src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index ea4d7532a9f2..04d6469aeaa4 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -9,7 +9,7 @@ on: jobs: pull: if: github.repository == 'rust-lang/rustc-dev-guide' - uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@ci-gh-app + uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main with: github-app-id: ${{ vars.APP_CLIENT_ID }} zulip-stream-id: 196385 From 1532b37010624c7657d6c9179cd6f01413bf7b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 29 Jul 2025 10:07:27 +0200 Subject: [PATCH 089/242] Use GH app for authenticating sync PRs --- src/tools/rust-analyzer/.github/workflows/rustc-pull.yml | 3 ++- src/tools/rust-analyzer/triagebot.toml | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml index 2a842f3b3114..37cf5f3726b2 100644 --- a/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml +++ b/src/tools/rust-analyzer/.github/workflows/rustc-pull.yml @@ -11,10 +11,11 @@ jobs: if: github.repository == 'rust-lang/rust-analyzer' uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main with: + github-app-id: ${{ vars.APP_CLIENT_ID }} zulip-stream-id: 185405 zulip-bot-email: "rust-analyzer-ci-bot@rust-lang.zulipchat.com" pr-base-branch: master branch-name: rustc-pull secrets: zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }} - token: ${{ secrets.GITHUB_TOKEN }} + github-app-secret: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index 27fdb672455b..c9862495bc0c 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -28,6 +28,3 @@ labels = ["has-merge-commits", "S-waiting-on-author"] # Prevents mentions in commits to avoid users being spammed [no-mentions] - -# Automatically close and reopen PRs made by bots to run CI on them -[bot-pull-requests] From bad05ff4ffa5a61dcc8787d40796f9533b33b750 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 29 Jul 2025 12:37:06 +0300 Subject: [PATCH 090/242] In generate_mut_trait_impl, don't add a tabstop if the client does not support snippets --- .../src/handlers/generate_mut_trait_impl.rs | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs index 9c4bcdd40304..ae1ae24d1ec1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -104,7 +104,14 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> format!("Generate `{trait_new}` impl from this `{trait_name}` trait"), target, |edit| { - edit.insert(target.start(), format!("$0{impl_def}\n\n{indent}")); + edit.insert( + target.start(), + if ctx.config.snippet_cap.is_some() { + format!("$0{impl_def}\n\n{indent}") + } else { + format!("{impl_def}\n\n{indent}") + }, + ); }, ) } @@ -161,7 +168,10 @@ fn process_ret_type(ref_ty: &ast::RetType) -> Option { #[cfg(test)] mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; + use crate::{ + AssistConfig, + tests::{TEST_CONFIG, check_assist, check_assist_not_applicable, check_assist_with_config}, + }; use super::*; @@ -402,6 +412,43 @@ impl Index$0 for [T; 3] {} pub trait AsRef {} impl AsRef$0 for [T; 3] {} +"#, + ); + } + + #[test] + fn no_snippets() { + check_assist_with_config( + generate_mut_trait_impl, + AssistConfig { snippet_cap: None, ..TEST_CONFIG }, + r#" +//- minicore: index +pub enum Axis { X = 0, Y = 1, Z = 2 } + +impl core::ops::Index$0 for [T; 3] { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + &self[index as usize] + } +} +"#, + r#" +pub enum Axis { X = 0, Y = 1, Z = 2 } + +impl core::ops::IndexMut for [T; 3] { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + &mut self[index as usize] + } +} + +impl core::ops::Index for [T; 3] { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + &self[index as usize] + } +} "#, ); } From ea1e24a989721a1d285d6de913be2be2b5101439 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 29 Jul 2025 14:40:14 +0300 Subject: [PATCH 091/242] When displaying a projection into a type parameter that has bounds as `impl Trait`, collect only the bounds of this projection It used to collect the bounds of them all. --- .../crates/hir-ty/src/display.rs | 26 ++++++++-------- .../crates/ide/src/inlay_hints.rs | 30 +++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index b3760e3a3822..f0e31ebd020c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -620,19 +620,19 @@ impl HirDisplay for ProjectionTy { .generic_predicates(id.parent) .iter() .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| match wc.skip_binders() { - WhereClause::Implemented(tr) => { - matches!( - tr.self_type_parameter(Interner).kind(Interner), - TyKind::Alias(_) - ) - } - WhereClause::TypeOutlives(t) => { - matches!(t.ty.kind(Interner), TyKind::Alias(_)) - } - // We shouldn't be here if these exist - WhereClause::AliasEq(_) => false, - WhereClause::LifetimeOutlives(_) => false, + .filter(|wc| { + let ty = match wc.skip_binders() { + WhereClause::Implemented(tr) => tr.self_type_parameter(Interner), + WhereClause::TypeOutlives(t) => t.ty.clone(), + // We shouldn't be here if these exist + WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => { + return false; + } + }; + let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else { + return false; + }; + proj == self }) .collect::>(); if !bounds.is_empty() { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 19e5509681aa..671fddb43630 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -1065,4 +1065,34 @@ fn bar() { "#, ); } + + #[test] + fn regression_20239() { + check_with_config( + InlayHintsConfig { parameter_hints: true, type_hints: true, ..DISABLED_CONFIG }, + r#" +//- minicore: fn +trait Iterator { + type Item; + fn map B>(self, f: F); +} +trait ToString { + fn to_string(&self); +} + +fn check_tostr_eq(left: L, right: R) +where + L: Iterator, + L::Item: ToString, + R: Iterator, + R::Item: ToString, +{ + left.map(|s| s.to_string()); + // ^ impl ToString + right.map(|s| s.to_string()); + // ^ impl ToString +} + "#, + ); + } } From cca89bcb7d54b4117c12ac17928c77f59aba37c5 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Tue, 29 Jul 2025 20:59:50 +0900 Subject: [PATCH 092/242] add `SyntaxFactory::record_expr` to hide clone_for_update --- .../convert_tuple_struct_to_named_struct.rs | 20 +++++++++++-------- .../src/ast/syntax_factory/constructors.rs | 18 +++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index f4041f49419a..b27ebcaa4edf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -4,7 +4,9 @@ use ide_db::defs::{Definition, NameRefClass}; use std::ops::RangeInclusive; use syntax::{ SyntaxElement, SyntaxKind, SyntaxNode, T, TextSize, - ast::{self, AstNode, HasAttrs, HasGenericParams, HasVisibility}, + ast::{ + self, AstNode, HasAttrs, HasGenericParams, HasVisibility, syntax_factory::SyntaxFactory, + }, match_ast, syntax_editor::{Element, Position, SyntaxEditor}, }; @@ -105,7 +107,8 @@ fn edit_struct_def( ); ast::RecordField::cast(field_editor.finish().new_root().clone()) }); - let record_fields = ast::make::record_field_list(record_fields).clone_for_update(); + let make = SyntaxFactory::without_mappings(); + let record_fields = make.record_field_list(record_fields); let tuple_fields_before = Position::before(tuple_fields.syntax()); if let Either::Left(strukt) = strukt { @@ -145,10 +148,11 @@ fn edit_struct_references( let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); let edit_node = |node: SyntaxNode| -> Option { + let make = SyntaxFactory::without_mappings(); match_ast! { match node { ast::TupleStructPat(tuple_struct_pat) => { - Some(ast::make::record_pat_with_fields( + Some(make.record_pat_with_fields( tuple_struct_pat.path()?, ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map( |(pat, name)| { @@ -158,7 +162,7 @@ fn edit_struct_references( ) }, ), None), - ).syntax().clone_for_update()) + ).syntax().clone()) }, // for tuple struct creations like Foo(42) ast::CallExpr(call_expr) => { @@ -174,9 +178,8 @@ fn edit_struct_references( } let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?; - Some( - ast::make::record_expr( + make.record_expr( path, ast::make::record_expr_field_list(arg_list.args().zip(names).map( |(expr, name)| { @@ -186,7 +189,7 @@ fn edit_struct_references( ) }, )), - ).syntax().clone_for_update() + ).syntax().clone() ) }, _ => return None, @@ -271,11 +274,12 @@ fn edit_field_references( } fn generate_names(fields: impl Iterator) -> Vec { + let make = SyntaxFactory::without_mappings(); fields .enumerate() .map(|(i, _)| { let idx = i + 1; - ast::make::name(&format!("field{idx}")).clone_for_update() + make.name(&format!("field{idx}")) }) .collect() } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 1ba610731512..738a26fed5d8 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -939,6 +939,24 @@ impl SyntaxFactory { ast } + pub fn record_expr( + &self, + path: ast::Path, + fields: ast::RecordExprFieldList, + ) -> ast::RecordExpr { + let ast = make::record_expr(path.clone(), fields.clone()).clone_for_update(); + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone()); + builder.map_node( + fields.syntax().clone(), + ast.record_expr_field_list().unwrap().syntax().clone(), + ); + builder.finish(&mut mapping); + } + ast + } + pub fn record_expr_field( &self, name: ast::NameRef, From 08c6768190176719c3d85b177579a96a8e7d01c5 Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Tue, 29 Jul 2025 23:09:59 +0900 Subject: [PATCH 093/242] replace `make::` to `SyntaxFactory::` in `inline_type_alias` --- .../src/handlers/inline_type_alias.rs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs index 62535531435d..ae8d130df23c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -9,10 +9,11 @@ use ide_db::{ search::FileReference, }; use itertools::Itertools; +use syntax::ast::syntax_factory::SyntaxFactory; use syntax::syntax_editor::SyntaxEditor; use syntax::{ AstNode, NodeOrToken, SyntaxNode, - ast::{self, HasGenericParams, HasName, make}, + ast::{self, HasGenericParams, HasName}, }; use crate::{ @@ -206,8 +207,8 @@ impl LifetimeMap { alias_generics: &ast::GenericParamList, ) -> Option { let mut inner = FxHashMap::default(); - - let wildcard_lifetime = make::lifetime("'_"); + let make = SyntaxFactory::without_mappings(); + let wildcard_lifetime = make.lifetime("'_"); let lifetimes = alias_generics .lifetime_params() .filter_map(|lp| lp.lifetime()) @@ -334,9 +335,10 @@ fn create_replacement( }; let new_string = replacement_syntax.to_string(); let new = if new_string == "_" { - make::wildcard_pat().syntax().clone_for_update() + let make = SyntaxFactory::without_mappings(); + make.wildcard_pat().syntax().clone() } else { - replacement_syntax.clone_for_update() + replacement_syntax.clone() }; replacements.push((syntax.clone(), new)); @@ -385,12 +387,15 @@ impl ConstOrTypeGeneric { } fn replacement_value(&self) -> Option { - Some(match self { - ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(), - ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(), - ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(), - ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(), - }) + Some( + match self { + ConstOrTypeGeneric::ConstArg(ca) => ca.expr()?.syntax().clone(), + ConstOrTypeGeneric::TypeArg(ta) => ta.syntax().clone(), + ConstOrTypeGeneric::ConstParam(cp) => cp.default_val()?.syntax().clone(), + ConstOrTypeGeneric::TypeParam(tp) => tp.default_type()?.syntax().clone(), + } + .clone_for_update(), + ) } } From 951a6f792de1861a271af2bc0b2adf46085f5972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 30 Jul 2025 08:11:01 +0200 Subject: [PATCH 094/242] Remove outdated ci.py reference --- src/doc/rustc-dev-guide/src/tests/docker.md | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/docker.md b/src/doc/rustc-dev-guide/src/tests/docker.md index 032da1ca1e8d..ae0939842237 100644 --- a/src/doc/rustc-dev-guide/src/tests/docker.md +++ b/src/doc/rustc-dev-guide/src/tests/docker.md @@ -6,12 +6,12 @@ need to install Docker on a Linux, Windows, or macOS system (typically Linux will be much faster than Windows or macOS because the latter use virtual machines to emulate a Linux environment). -Jobs running in CI are configured through a set of bash scripts, and it is not always trivial to reproduce their behavior locally. If you want to run a CI job locally in the simplest way possible, you can use a provided helper Python script that tries to replicate what happens on CI as closely as possible: +Jobs running in CI are configured through a set of bash scripts, and it is not always trivial to reproduce their behavior locally. If you want to run a CI job locally in the simplest way possible, you can use a provided helper `citool` that tries to replicate what happens on CI as closely as possible: ```bash -python3 src/ci/github-actions/ci.py run-local +cargo run --manifest-path src/ci/citool/Cargo.toml run-local # For example: -python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux-alt +cargo run --manifest-path src/ci/citool/Cargo.toml run-local dist-x86_64-linux-alt ``` If the above script does not work for you, you would like to have more control of the Docker image execution, or you want to understand what exactly happens during Docker job execution, then continue reading below. @@ -53,15 +53,6 @@ Some additional notes about using the interactive mode: containers. With the container name, run `docker exec -it /bin/bash` where `` is the container name like `4ba195e95cef`. -The approach described above is a relatively low-level interface for running the Docker images -directly. If you want to run a full CI Linux job locally with Docker, in a way that is as close to CI as possible, you can use the following command: - -```bash -cargo run --manifest-path src/ci/citool/Cargo.toml run-local -# For example: -cargo run --manifest-path src/ci/citool/Cargo.toml run-local dist-x86_64-linux-alt -``` - [Docker]: https://www.docker.com/ [`src/ci/docker`]: https://github.com/rust-lang/rust/tree/master/src/ci/docker [`src/ci/docker/run.sh`]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/run.sh From 4220587c2232e237a0c39a2c64b0bf046799434a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 29 Jul 2025 18:30:48 -0700 Subject: [PATCH 095/242] `AlignmentEnum` should just be `repr(usize)` now Since it's cfg'd instead of type-aliased --- library/core/src/ptr/alignment.rs | 8 +++++--- ...c_in_place.PreCodegen.after.32bit.panic-abort.mir | 12 ++++-------- ..._in_place.PreCodegen.after.32bit.panic-unwind.mir | 12 ++++-------- ...c_in_place.PreCodegen.after.64bit.panic-abort.mir | 12 ++++-------- ..._in_place.PreCodegen.after.64bit.panic-unwind.mir | 12 ++++-------- tests/mir-opt/pre-codegen/drop_boxed_slice.rs | 3 +-- 6 files changed, 22 insertions(+), 37 deletions(-) diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index bd5b4e21baa0..402634e49b37 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,3 +1,5 @@ +#![allow(clippy::enum_clike_unportable_variant)] + use crate::num::NonZero; use crate::ub_checks::assert_unsafe_precondition; use crate::{cmp, fmt, hash, mem, num}; @@ -241,7 +243,7 @@ impl const Default for Alignment { #[cfg(target_pointer_width = "16")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u16)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, @@ -263,7 +265,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "32")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u32)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, @@ -301,7 +303,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "64")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u64)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 2777bba893bb..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u32; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 2777bba893bb..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u32; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 2be0a478c852..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u64; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 2be0a478c852..ba6ce0ee5286 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u64; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index 11fb7afef0fb..9ceba9444b8d 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -13,7 +13,6 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum); // CHECK: [[D:_.+]] = discriminant([[C]]); - // CHECK: [[E:_.+]] = move [[D]] as usize (IntToInt); - // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[E]]) -> + // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) -> std::ptr::drop_in_place(ptr) } From 4f8d4ca1908e6179c4094d5843db6a29cb323d4d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 30 Jul 2025 16:27:33 +0800 Subject: [PATCH 096/242] Update `codegen_{cranelift,gcc}` and `opt-dist` to use `build.compiletest-allow-stage0` --- build_system/src/test.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build_system/src/test.rs b/build_system/src/test.rs index bc0fdd40b6e8..2c8271c36a94 100644 --- a/build_system/src/test.rs +++ b/build_system/src/test.rs @@ -561,8 +561,6 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc asm test suite"); - env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); - let codegen_backend_path = format!( "{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}", pwd = std::env::current_dir() @@ -588,6 +586,8 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> { &"always", &"--stage", &"0", + &"--set", + &"build.compiletest-allow-stage0=true", &"tests/assembly-llvm/asm", &"--compiletest-rustc-args", &rustc_args, @@ -1047,7 +1047,6 @@ where // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[TEST] rustc {test_type} test suite"); - env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string()); let extra = if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" }; @@ -1070,6 +1069,8 @@ where &"always", &"--stage", &"0", + &"--set", + &"build.compiletest-allow-stage0=true", &format!("tests/{test_type}"), &"--compiletest-rustc-args", &rustc_args, From 9fb99109b66626b51343ba6adee61274b0a67a50 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 30 Jul 2025 15:45:20 +0200 Subject: [PATCH 097/242] Regenerate intrinsics mapping --- src/intrinsic/archs.rs | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/intrinsic/archs.rs b/src/intrinsic/archs.rs index 915ed875e32f..d1b2a93243d2 100644 --- a/src/intrinsic/archs.rs +++ b/src/intrinsic/archs.rs @@ -95,8 +95,11 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "cubema" => "__builtin_amdgcn_cubema", "cubesc" => "__builtin_amdgcn_cubesc", "cubetc" => "__builtin_amdgcn_cubetc", + "cvt.f16.bf8" => "__builtin_amdgcn_cvt_f16_bf8", + "cvt.f16.fp8" => "__builtin_amdgcn_cvt_f16_fp8", "cvt.f32.bf8" => "__builtin_amdgcn_cvt_f32_bf8", "cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", + "cvt.f32.fp8.e5m3" => "__builtin_amdgcn_cvt_f32_fp8_e5m3", "cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", "cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8", @@ -181,6 +184,12 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "dot4.f32.fp8.bf8" => "__builtin_amdgcn_dot4_f32_fp8_bf8", "dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8", "ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", + "ds.atomic.async.barrier.arrive.b64" => { + "__builtin_amdgcn_ds_atomic_async_barrier_arrive_b64" + } + "ds.atomic.barrier.arrive.rtn.b64" => { + "__builtin_amdgcn_ds_atomic_barrier_arrive_rtn_b64" + } "ds.bpermute" => "__builtin_amdgcn_ds_bpermute", "ds.bpermute.fi.b32" => "__builtin_amdgcn_ds_bpermute_fi_b32", "ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", @@ -198,8 +207,32 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", "fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", "fdot2c.f32.bf16" => "__builtin_amdgcn_fdot2c_f32_bf16", + "flat.prefetch" => "__builtin_amdgcn_flat_prefetch", "fmul.legacy" => "__builtin_amdgcn_fmul_legacy", + "global.load.async.to.lds.b128" => { + "__builtin_amdgcn_global_load_async_to_lds_b128" + } + "global.load.async.to.lds.b32" => { + "__builtin_amdgcn_global_load_async_to_lds_b32" + } + "global.load.async.to.lds.b64" => { + "__builtin_amdgcn_global_load_async_to_lds_b64" + } + "global.load.async.to.lds.b8" => "__builtin_amdgcn_global_load_async_to_lds_b8", "global.load.lds" => "__builtin_amdgcn_global_load_lds", + "global.prefetch" => "__builtin_amdgcn_global_prefetch", + "global.store.async.from.lds.b128" => { + "__builtin_amdgcn_global_store_async_from_lds_b128" + } + "global.store.async.from.lds.b32" => { + "__builtin_amdgcn_global_store_async_from_lds_b32" + } + "global.store.async.from.lds.b64" => { + "__builtin_amdgcn_global_store_async_from_lds_b64" + } + "global.store.async.from.lds.b8" => { + "__builtin_amdgcn_global_store_async_from_lds_b8" + } "groupstaticsize" => "__builtin_amdgcn_groupstaticsize", "iglp.opt" => "__builtin_amdgcn_iglp_opt", "implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr", @@ -291,6 +324,7 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "s.incperflevel" => "__builtin_amdgcn_s_incperflevel", "s.memrealtime" => "__builtin_amdgcn_s_memrealtime", "s.memtime" => "__builtin_amdgcn_s_memtime", + "s.monitor.sleep" => "__builtin_amdgcn_s_monitor_sleep", "s.sendmsg" => "__builtin_amdgcn_s_sendmsg", "s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt", "s.setprio" => "__builtin_amdgcn_s_setprio", @@ -300,11 +334,15 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "s.sleep.var" => "__builtin_amdgcn_s_sleep_var", "s.ttracedata" => "__builtin_amdgcn_s_ttracedata", "s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm", + "s.wait.asynccnt" => "__builtin_amdgcn_s_wait_asynccnt", "s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", + "s.wait.tensorcnt" => "__builtin_amdgcn_s_wait_tensorcnt", "s.waitcnt" => "__builtin_amdgcn_s_waitcnt", "sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8", "sad.u16" => "__builtin_amdgcn_sad_u16", "sad.u8" => "__builtin_amdgcn_sad_u8", + "sat.pk4.i4.i8" => "__builtin_amdgcn_sat_pk4_i4_i8", + "sat.pk4.u4.u8" => "__builtin_amdgcn_sat_pk4_u4_u8", "sched.barrier" => "__builtin_amdgcn_sched_barrier", "sched.group.barrier" => "__builtin_amdgcn_sched_group_barrier", "sdot2" => "__builtin_amdgcn_sdot2", @@ -346,8 +384,13 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { "smfmac.i32.16x16x64.i8" => "__builtin_amdgcn_smfmac_i32_16x16x64_i8", "smfmac.i32.32x32x32.i8" => "__builtin_amdgcn_smfmac_i32_32x32x32_i8", "smfmac.i32.32x32x64.i8" => "__builtin_amdgcn_smfmac_i32_32x32x64_i8", + "struct.ptr.buffer.load.lds" => "__builtin_amdgcn_struct_ptr_buffer_load_lds", "sudot4" => "__builtin_amdgcn_sudot4", "sudot8" => "__builtin_amdgcn_sudot8", + "tensor.load.to.lds" => "__builtin_amdgcn_tensor_load_to_lds", + "tensor.load.to.lds.d2" => "__builtin_amdgcn_tensor_load_to_lds_d2", + "tensor.store.from.lds" => "__builtin_amdgcn_tensor_store_from_lds", + "tensor.store.from.lds.d2" => "__builtin_amdgcn_tensor_store_from_lds_d2", "udot2" => "__builtin_amdgcn_udot2", "udot4" => "__builtin_amdgcn_udot4", "udot8" => "__builtin_amdgcn_udot8", @@ -6326,6 +6369,23 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str { } s390(name, full_name) } + "spv" => { + #[allow(non_snake_case)] + fn spv(name: &str, full_name: &str) -> &'static str { + match name { + // spv + "num.subgroups" => "__builtin_spirv_num_subgroups", + "subgroup.id" => "__builtin_spirv_subgroup_id", + "subgroup.local.invocation.id" => { + "__builtin_spirv_subgroup_local_invocation_id" + } + "subgroup.max.size" => "__builtin_spirv_subgroup_max_size", + "subgroup.size" => "__builtin_spirv_subgroup_size", + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), + } + } + spv(name, full_name) + } "ve" => { #[allow(non_snake_case)] fn ve(name: &str, full_name: &str) -> &'static str { From 2918a2b5505299e0d4164a776c0bdc745bb69736 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 30 Jul 2025 15:31:18 +0200 Subject: [PATCH 098/242] Abtract away json protocol for proc-macro-srv --- src/tools/rust-analyzer/Cargo.lock | 32 ++++ .../crates/load-cargo/src/lib.rs | 2 +- .../proc-macro-api/src/legacy_protocol.rs | 172 ++++++++++++++++++ .../proc-macro-api/src/legacy_protocol/msg.rs | 25 +-- .../src/legacy_protocol/msg/flat.rs | 105 ++++++----- .../crates/proc-macro-api/src/lib.rs | 93 +++------- .../crates/proc-macro-api/src/process.rs | 113 +++++------- .../crates/proc-macro-srv-cli/Cargo.toml | 1 + .../crates/proc-macro-srv-cli/src/main.rs | 39 +++- .../proc-macro-srv-cli/src/main_loop.rs | 63 +++++-- .../crates/proc-macro-srv/src/lib.rs | 8 +- .../src/server_impl/token_id.rs | 53 +++--- .../crates/proc-macro-srv/src/tests/utils.rs | 14 +- .../rust-analyzer/crates/span/src/lib.rs | 12 -- 14 files changed, 472 insertions(+), 260 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol.rs diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index c19e8471647f..0cbbb5dd6de7 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -23,6 +23,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + [[package]] name = "anyhow" version = "1.0.98" @@ -287,6 +293,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "clap" +version = "4.5.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + [[package]] name = "countme" version = "3.0.1" @@ -1615,6 +1646,7 @@ dependencies = [ name = "proc-macro-srv-cli" version = "0.0.0" dependencies = [ + "clap", "proc-macro-api", "proc-macro-srv", "tt", diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 26ee698af081..98f415a522cb 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -533,7 +533,7 @@ impl ProcMacroExpander for Expander { current_dir, ) { Ok(Ok(subtree)) => Ok(subtree), - Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)), + Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err)), Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol.rs new file mode 100644 index 000000000000..ee96b899fe57 --- /dev/null +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol.rs @@ -0,0 +1,172 @@ +//! The initial proc-macro-srv protocol, soon to be deprecated. + +pub mod json; +pub mod msg; + +use std::{ + io::{BufRead, Write}, + sync::Arc, +}; + +use paths::AbsPath; +use span::Span; + +use crate::{ + ProcMacro, ProcMacroKind, ServerError, + legacy_protocol::{ + json::{read_json, write_json}, + msg::{ + ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response, + ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map, + flat::serialize_span_data_index_map, + }, + }, + process::ProcMacroServerProcess, + version, +}; + +pub(crate) use crate::legacy_protocol::msg::SpanMode; + +/// Legacy span type, only defined here as it is still used by the proc-macro server. +/// While rust-analyzer doesn't use this anymore at all, RustRover relies on the legacy type for +/// proc-macro expansion. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct SpanId(pub u32); + +impl std::fmt::Debug for SpanId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +pub(crate) fn version_check(srv: &ProcMacroServerProcess) -> Result { + let request = Request::ApiVersionCheck {}; + let response = send_task(srv, request)?; + + match response { + Response::ApiVersionCheck(version) => Ok(version), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +/// Enable support for rust-analyzer span mode if the server supports it. +pub(crate) fn enable_rust_analyzer_spans( + srv: &ProcMacroServerProcess, +) -> Result { + let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer }); + let response = send_task(srv, request)?; + + match response { + Response::SetConfig(ServerConfig { span_mode }) => Ok(span_mode), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +/// Finds proc-macros in a given dynamic library. +pub(crate) fn find_proc_macros( + srv: &ProcMacroServerProcess, + dylib_path: &AbsPath, +) -> Result, String>, ServerError> { + let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }; + + let response = send_task(srv, request)?; + + match response { + Response::ListMacros(it) => Ok(it), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +pub(crate) fn expand( + proc_macro: &ProcMacro, + subtree: tt::SubtreeView<'_, Span>, + attr: Option>, + env: Vec<(String, String)>, + def_site: Span, + call_site: Span, + mixed_site: Span, + current_dir: String, +) -> Result>, String>, crate::ServerError> +{ + let version = proc_macro.process.version(); + let mut span_data_table = SpanDataIndexMap::default(); + let def_site = span_data_table.insert_full(def_site).0; + let call_site = span_data_table.insert_full(call_site).0; + let mixed_site = span_data_table.insert_full(mixed_site).0; + let task = ExpandMacro { + data: ExpandMacroData { + macro_body: FlatTree::new(subtree, version, &mut span_data_table), + macro_name: proc_macro.name.to_string(), + attributes: attr.map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)), + has_global_spans: ExpnGlobals { + serialize: version >= version::HAS_GLOBAL_SPANS, + def_site, + call_site, + mixed_site, + }, + span_data_table: if proc_macro.process.rust_analyzer_spans() { + serialize_span_data_index_map(&span_data_table) + } else { + Vec::new() + }, + }, + lib: proc_macro.dylib_path.to_path_buf().into(), + env, + current_dir: Some(current_dir), + }; + + let response = send_task(&proc_macro.process, Request::ExpandMacro(Box::new(task)))?; + + match response { + Response::ExpandMacro(it) => Ok(it + .map(|tree| { + let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); + if proc_macro.needs_fixup_change() { + proc_macro.change_fixup_to_match_old_server(&mut expanded); + } + expanded + }) + .map_err(|msg| msg.0)), + Response::ExpandMacroExtended(it) => Ok(it + .map(|resp| { + let mut expanded = FlatTree::to_subtree_resolved( + resp.tree, + version, + &deserialize_span_data_index_map(&resp.span_data_table), + ); + if proc_macro.needs_fixup_change() { + proc_macro.change_fixup_to_match_old_server(&mut expanded); + } + expanded + }) + .map_err(|msg| msg.0)), + _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + } +} + +/// Sends a request to the proc-macro server and waits for a response. +fn send_task(srv: &ProcMacroServerProcess, req: Request) -> Result { + if let Some(server_error) = srv.exited() { + return Err(server_error.clone()); + } + + srv.send_task(send_request, req) +} + +/// Sends a request to the server and reads the response. +fn send_request( + mut writer: &mut dyn Write, + mut reader: &mut dyn BufRead, + req: Request, + buf: &mut String, +) -> Result, ServerError> { + req.write(write_json, &mut writer).map_err(|err| ServerError { + message: "failed to write request".into(), + io: Some(Arc::new(err)), + })?; + let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError { + message: "failed to read response".into(), + io: Some(Arc::new(err)), + })?; + Ok(res) +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs index 165936269d35..b795c4558956 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -1,5 +1,6 @@ //! Defines messages for cross-process message passing based on `ndjson` wire protocol pub(crate) mod flat; +pub use self::flat::*; use std::io::{self, BufRead, Write}; @@ -9,24 +10,6 @@ use serde_derive::{Deserialize, Serialize}; use crate::ProcMacroKind; -pub use self::flat::{ - FlatTree, SpanDataIndexMap, deserialize_span_data_index_map, serialize_span_data_index_map, -}; -pub use span::TokenId; - -// The versions of the server protocol -pub const NO_VERSION_CHECK_VERSION: u32 = 0; -pub const VERSION_CHECK_VERSION: u32 = 1; -pub const ENCODE_CLOSE_SPAN_VERSION: u32 = 2; -pub const HAS_GLOBAL_SPANS: u32 = 3; -pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4; -/// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field. -pub const EXTENDED_LEAF_DATA: u32 = 5; -pub const HASHED_AST_ID: u32 = 6; - -/// Current API version of the proc-macro protocol. -pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID; - /// Represents requests sent from the client to the proc-macro-srv. #[derive(Debug, Serialize, Deserialize)] pub enum Request { @@ -48,7 +31,7 @@ pub enum Request { } /// Defines the mode used for handling span data. -#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum SpanMode { /// Default mode, where spans are identified by an ID. #[default] @@ -210,6 +193,8 @@ mod tests { TopSubtreeBuilder, }; + use crate::version; + use super::*; fn fixture_token_tree() -> TopSubtree { @@ -308,7 +293,7 @@ mod tests { #[test] fn test_proc_macro_rpc_works() { let tt = fixture_token_tree(); - for v in RUST_ANALYZER_SPAN_SUPPORT..=CURRENT_API_VERSION { + for v in version::RUST_ANALYZER_SPAN_SUPPORT..=version::CURRENT_API_VERSION { let mut span_data_table = Default::default(); let task = ExpandMacro { data: ExpandMacroData { diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs index 597ffa05d203..fb3542d24f46 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs @@ -40,9 +40,12 @@ use std::collections::VecDeque; use intern::Symbol; use rustc_hash::FxHashMap; use serde_derive::{Deserialize, Serialize}; -use span::{EditionedFileId, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange, TokenId}; +use span::{EditionedFileId, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange}; -use crate::legacy_protocol::msg::{ENCODE_CLOSE_SPAN_VERSION, EXTENDED_LEAF_DATA}; +use crate::{ + legacy_protocol::SpanId, + version::{ENCODE_CLOSE_SPAN_VERSION, EXTENDED_LEAF_DATA}, +}; pub type SpanDataIndexMap = indexmap::IndexSet>; @@ -62,7 +65,7 @@ pub fn serialize_span_data_index_map(map: &SpanDataIndexMap) -> Vec { } pub fn deserialize_span_data_index_map(map: &[u32]) -> SpanDataIndexMap { - debug_assert!(map.len() % 5 == 0); + debug_assert!(map.len().is_multiple_of(5)); map.chunks_exact(5) .map(|span| { let &[file_id, ast_id, start, end, e] = span else { unreachable!() }; @@ -91,27 +94,27 @@ pub struct FlatTree { } struct SubtreeRepr { - open: TokenId, - close: TokenId, + open: SpanId, + close: SpanId, kind: tt::DelimiterKind, tt: [u32; 2], } struct LiteralRepr { - id: TokenId, + id: SpanId, text: u32, suffix: u32, kind: u16, } struct PunctRepr { - id: TokenId, + id: SpanId, char: char, spacing: tt::Spacing, } struct IdentRepr { - id: TokenId, + id: SpanId, text: u32, is_raw: bool, } @@ -122,7 +125,7 @@ impl FlatTree { version: u32, span_data_table: &mut SpanDataIndexMap, ) -> FlatTree { - let mut w = Writer { + let mut w = Writer:: { string_table: FxHashMap::default(), work: VecDeque::new(), span_data_table, @@ -159,8 +162,11 @@ impl FlatTree { } } - pub fn new_raw(subtree: tt::SubtreeView<'_, TokenId>, version: u32) -> FlatTree { - let mut w = Writer { + pub fn new_raw>( + subtree: tt::SubtreeView<'_, T::Span>, + version: u32, + ) -> FlatTree { + let mut w = Writer:: { string_table: FxHashMap::default(), work: VecDeque::new(), span_data_table: &mut (), @@ -202,7 +208,7 @@ impl FlatTree { version: u32, span_data_table: &SpanDataIndexMap, ) -> tt::TopSubtree { - Reader { + Reader:: { subtree: if version >= ENCODE_CLOSE_SPAN_VERSION { read_vec(self.subtree, SubtreeRepr::read_with_close_span) } else { @@ -227,8 +233,11 @@ impl FlatTree { .read() } - pub fn to_subtree_unresolved(self, version: u32) -> tt::TopSubtree { - Reader { + pub fn to_subtree_unresolved>( + self, + version: u32, + ) -> tt::TopSubtree { + Reader:: { subtree: if version >= ENCODE_CLOSE_SPAN_VERSION { read_vec(self.subtree, SubtreeRepr::read_with_close_span) } else { @@ -283,7 +292,7 @@ impl SubtreeRepr { 3 => tt::DelimiterKind::Bracket, other => panic!("bad kind {other}"), }; - SubtreeRepr { open: TokenId(open), close: TokenId(!0), kind, tt: [lo, len] } + SubtreeRepr { open: SpanId(open), close: SpanId(!0), kind, tt: [lo, len] } } fn write_with_close_span(self) -> [u32; 5] { let kind = match self.kind { @@ -302,7 +311,7 @@ impl SubtreeRepr { 3 => tt::DelimiterKind::Bracket, other => panic!("bad kind {other}"), }; - SubtreeRepr { open: TokenId(open), close: TokenId(close), kind, tt: [lo, len] } + SubtreeRepr { open: SpanId(open), close: SpanId(close), kind, tt: [lo, len] } } } @@ -311,13 +320,13 @@ impl LiteralRepr { [self.id.0, self.text] } fn read([id, text]: [u32; 2]) -> LiteralRepr { - LiteralRepr { id: TokenId(id), text, kind: 0, suffix: !0 } + LiteralRepr { id: SpanId(id), text, kind: 0, suffix: !0 } } fn write_with_kind(self) -> [u32; 4] { [self.id.0, self.text, self.kind as u32, self.suffix] } fn read_with_kind([id, text, kind, suffix]: [u32; 4]) -> LiteralRepr { - LiteralRepr { id: TokenId(id), text, kind: kind as u16, suffix } + LiteralRepr { id: SpanId(id), text, kind: kind as u16, suffix } } } @@ -335,7 +344,7 @@ impl PunctRepr { 1 => tt::Spacing::Joint, other => panic!("bad spacing {other}"), }; - PunctRepr { id: TokenId(id), char: char.try_into().unwrap(), spacing } + PunctRepr { id: SpanId(id), char: char.try_into().unwrap(), spacing } } } @@ -344,44 +353,46 @@ impl IdentRepr { [self.id.0, self.text] } fn read(data: [u32; 2]) -> IdentRepr { - IdentRepr { id: TokenId(data[0]), text: data[1], is_raw: false } + IdentRepr { id: SpanId(data[0]), text: data[1], is_raw: false } } fn write_with_rawness(self) -> [u32; 3] { [self.id.0, self.text, self.is_raw as u32] } fn read_with_rawness([id, text, is_raw]: [u32; 3]) -> IdentRepr { - IdentRepr { id: TokenId(id), text, is_raw: is_raw == 1 } + IdentRepr { id: SpanId(id), text, is_raw: is_raw == 1 } } } -trait InternableSpan: Copy { +pub trait SpanTransformer { type Table; - fn token_id_of(table: &mut Self::Table, s: Self) -> TokenId; - fn span_for_token_id(table: &Self::Table, id: TokenId) -> Self; + type Span: Copy; + fn token_id_of(table: &mut Self::Table, s: Self::Span) -> SpanId; + fn span_for_token_id(table: &Self::Table, id: SpanId) -> Self::Span; } - -impl InternableSpan for TokenId { +impl SpanTransformer for SpanId { type Table = (); - fn token_id_of((): &mut Self::Table, token_id: Self) -> TokenId { + type Span = Self; + fn token_id_of((): &mut Self::Table, token_id: Self::Span) -> SpanId { token_id } - fn span_for_token_id((): &Self::Table, id: TokenId) -> Self { + fn span_for_token_id((): &Self::Table, id: SpanId) -> Self::Span { id } } -impl InternableSpan for Span { +impl SpanTransformer for Span { type Table = SpanDataIndexMap; - fn token_id_of(table: &mut Self::Table, span: Self) -> TokenId { - TokenId(table.insert_full(span).0 as u32) + type Span = Self; + fn token_id_of(table: &mut Self::Table, span: Self::Span) -> SpanId { + SpanId(table.insert_full(span).0 as u32) } - fn span_for_token_id(table: &Self::Table, id: TokenId) -> Self { + fn span_for_token_id(table: &Self::Table, id: SpanId) -> Self::Span { *table.get_index(id.0 as usize).unwrap_or_else(|| &table[0]) } } -struct Writer<'a, 'span, S: InternableSpan> { - work: VecDeque<(usize, tt::iter::TtIter<'a, S>)>, +struct Writer<'a, 'span, S: SpanTransformer> { + work: VecDeque<(usize, tt::iter::TtIter<'a, S::Span>)>, string_table: FxHashMap, u32>, span_data_table: &'span mut S::Table, version: u32, @@ -394,8 +405,8 @@ struct Writer<'a, 'span, S: InternableSpan> { text: Vec, } -impl<'a, S: InternableSpan> Writer<'a, '_, S> { - fn write(&mut self, root: tt::SubtreeView<'a, S>) { +impl<'a, T: SpanTransformer> Writer<'a, '_, T> { + fn write(&mut self, root: tt::SubtreeView<'a, T::Span>) { let subtree = root.top_subtree(); self.enqueue(subtree, root.iter()); while let Some((idx, subtree)) = self.work.pop_front() { @@ -403,11 +414,11 @@ impl<'a, S: InternableSpan> Writer<'a, '_, S> { } } - fn token_id_of(&mut self, span: S) -> TokenId { - S::token_id_of(self.span_data_table, span) + fn token_id_of(&mut self, span: T::Span) -> SpanId { + T::token_id_of(self.span_data_table, span) } - fn subtree(&mut self, idx: usize, subtree: tt::iter::TtIter<'a, S>) { + fn subtree(&mut self, idx: usize, subtree: tt::iter::TtIter<'a, T::Span>) { let mut first_tt = self.token_tree.len(); let n_tt = subtree.clone().count(); // FIXME: `count()` walks over the entire iterator. self.token_tree.resize(first_tt + n_tt, !0); @@ -478,7 +489,11 @@ impl<'a, S: InternableSpan> Writer<'a, '_, S> { } } - fn enqueue(&mut self, subtree: &'a tt::Subtree, contents: tt::iter::TtIter<'a, S>) -> u32 { + fn enqueue( + &mut self, + subtree: &'a tt::Subtree, + contents: tt::iter::TtIter<'a, T::Span>, + ) -> u32 { let idx = self.subtree.len(); let open = self.token_id_of(subtree.delimiter.open); let close = self.token_id_of(subtree.delimiter.close); @@ -507,7 +522,7 @@ impl<'a, S: InternableSpan> Writer<'a, '_, S> { } } -struct Reader<'span, S: InternableSpan> { +struct Reader<'span, S: SpanTransformer> { version: u32, subtree: Vec, literal: Vec, @@ -518,11 +533,11 @@ struct Reader<'span, S: InternableSpan> { span_data_table: &'span S::Table, } -impl Reader<'_, S> { - pub(crate) fn read(self) -> tt::TopSubtree { - let mut res: Vec, Vec>)>> = +impl Reader<'_, T> { + pub(crate) fn read(self) -> tt::TopSubtree { + let mut res: Vec, Vec>)>> = vec![None; self.subtree.len()]; - let read_span = |id| S::span_for_token_id(self.span_data_table, id); + let read_span = |id| T::span_for_token_id(self.span_data_table, id); for i in (0..self.subtree.len()).rev() { let repr = &self.subtree[i]; let token_trees = &self.token_tree[repr.tt[0] as usize..repr.tt[1] as usize]; diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 516c7418bde8..97919b85b513 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -5,24 +5,29 @@ //! is used to provide basic infrastructure for communication between two //! processes: Client (RA itself), Server (the external program) -pub mod legacy_protocol { - pub mod json; - pub mod msg; -} +pub mod legacy_protocol; mod process; use paths::{AbsPath, AbsPathBuf}; use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use std::{fmt, io, sync::Arc, time::SystemTime}; -use crate::{ - legacy_protocol::msg::{ - ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, HASHED_AST_ID, - PanicMessage, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap, - deserialize_span_data_index_map, flat::serialize_span_data_index_map, - }, - process::ProcMacroServerProcess, -}; +use crate::process::ProcMacroServerProcess; + +/// The versions of the server protocol +pub mod version { + pub const NO_VERSION_CHECK_VERSION: u32 = 0; + pub const VERSION_CHECK_VERSION: u32 = 1; + pub const ENCODE_CLOSE_SPAN_VERSION: u32 = 2; + pub const HAS_GLOBAL_SPANS: u32 = 3; + pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4; + /// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field. + pub const EXTENDED_LEAF_DATA: u32 = 5; + pub const HASHED_AST_ID: u32 = 6; + + /// Current API version of the proc-macro protocol. + pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID; +} /// Represents different kinds of procedural macros that can be expanded by the external server. #[derive(Copy, Clone, Eq, PartialEq, Debug, serde_derive::Serialize, serde_derive::Deserialize)] @@ -163,7 +168,7 @@ impl ProcMacro { fn needs_fixup_change(&self) -> bool { let version = self.process.version(); - (RUST_ANALYZER_SPAN_SUPPORT..HASHED_AST_ID).contains(&version) + (version::RUST_ANALYZER_SPAN_SUPPORT..version::HASHED_AST_ID).contains(&version) } /// On some server versions, the fixup ast id is different than ours. So change it to match. @@ -204,7 +209,7 @@ impl ProcMacro { call_site: Span, mixed_site: Span, current_dir: String, - ) -> Result, PanicMessage>, ServerError> { + ) -> Result, String>, ServerError> { let (mut subtree, mut attr) = (subtree, attr); let (mut subtree_changed, mut attr_changed); if self.needs_fixup_change() { @@ -219,57 +224,15 @@ impl ProcMacro { } } - let version = self.process.version(); - - let mut span_data_table = SpanDataIndexMap::default(); - let def_site = span_data_table.insert_full(def_site).0; - let call_site = span_data_table.insert_full(call_site).0; - let mixed_site = span_data_table.insert_full(mixed_site).0; - let task = ExpandMacro { - data: ExpandMacroData { - macro_body: FlatTree::new(subtree, version, &mut span_data_table), - macro_name: self.name.to_string(), - attributes: attr - .map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)), - has_global_spans: ExpnGlobals { - serialize: version >= HAS_GLOBAL_SPANS, - def_site, - call_site, - mixed_site, - }, - span_data_table: if version >= RUST_ANALYZER_SPAN_SUPPORT { - serialize_span_data_index_map(&span_data_table) - } else { - Vec::new() - }, - }, - lib: self.dylib_path.to_path_buf().into(), + legacy_protocol::expand( + self, + subtree, + attr, env, - current_dir: Some(current_dir), - }; - - let response = self.process.send_task(Request::ExpandMacro(Box::new(task)))?; - - match response { - Response::ExpandMacro(it) => Ok(it.map(|tree| { - let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table); - if self.needs_fixup_change() { - self.change_fixup_to_match_old_server(&mut expanded); - } - expanded - })), - Response::ExpandMacroExtended(it) => Ok(it.map(|resp| { - let mut expanded = FlatTree::to_subtree_resolved( - resp.tree, - version, - &deserialize_span_data_index_map(&resp.span_data_table), - ); - if self.needs_fixup_change() { - self.change_fixup_to_match_old_server(&mut expanded); - } - expanded - })), - _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), - } + def_site, + call_site, + mixed_site, + current_dir, + ) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs index fcea75ef672a..278d9cbcda46 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs @@ -12,13 +12,8 @@ use stdx::JodChild; use crate::{ ProcMacroKind, ServerError, - legacy_protocol::{ - json::{read_json, write_json}, - msg::{ - CURRENT_API_VERSION, Message, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, - ServerConfig, SpanMode, - }, - }, + legacy_protocol::{self, SpanMode}, + version, }; /// Represents a process handling proc-macro communication. @@ -28,11 +23,16 @@ pub(crate) struct ProcMacroServerProcess { /// hence the lock on the state. state: Mutex, version: u32, - mode: SpanMode, + protocol: Protocol, /// Populated when the server exits. exited: OnceLock>, } +#[derive(Debug)] +enum Protocol { + LegacyJson { mode: SpanMode }, +} + /// Maintains the state of the proc-macro server process. #[derive(Debug)] struct ProcessSrvState { @@ -56,27 +56,26 @@ impl ProcMacroServerProcess { io::Result::Ok(ProcMacroServerProcess { state: Mutex::new(ProcessSrvState { process, stdin, stdout }), version: 0, - mode: SpanMode::Id, + protocol: Protocol::LegacyJson { mode: SpanMode::Id }, exited: OnceLock::new(), }) }; let mut srv = create_srv()?; tracing::info!("sending proc-macro server version check"); match srv.version_check() { - Ok(v) if v > CURRENT_API_VERSION => Err(io::Error::other( - format!( "The version of the proc-macro server ({v}) in your Rust toolchain is newer than the version supported by your rust-analyzer ({CURRENT_API_VERSION}). - This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain." - ), - )), + Ok(v) if v > version::CURRENT_API_VERSION => Err(io::Error::other( + format!( "The version of the proc-macro server ({v}) in your Rust toolchain is newer than the version supported by your rust-analyzer ({}). + This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain." + ,version::CURRENT_API_VERSION + ), + )), Ok(v) => { tracing::info!("Proc-macro server version: {v}"); srv.version = v; - if srv.version >= RUST_ANALYZER_SPAN_SUPPORT { - if let Ok(mode) = srv.enable_rust_analyzer_spans() { - srv.mode = mode; - } + if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT && let Ok(mode) = srv.enable_rust_analyzer_spans() { + srv.protocol = Protocol::LegacyJson { mode }; } - tracing::info!("Proc-macro server span mode: {:?}", srv.mode); + tracing::info!("Proc-macro server protocol: {:?}", srv.protocol); Ok(srv) } Err(e) => { @@ -98,25 +97,24 @@ impl ProcMacroServerProcess { self.version } + /// Enable support for rust-analyzer span mode if the server supports it. + pub(crate) fn rust_analyzer_spans(&self) -> bool { + match self.protocol { + Protocol::LegacyJson { mode } => mode == SpanMode::RustAnalyzer, + } + } + /// Checks the API version of the running proc-macro server. fn version_check(&self) -> Result { - let request = Request::ApiVersionCheck {}; - let response = self.send_task(request)?; - - match response { - Response::ApiVersionCheck(version) => Ok(version), - _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + match self.protocol { + Protocol::LegacyJson { .. } => legacy_protocol::version_check(self), } } /// Enable support for rust-analyzer span mode if the server supports it. fn enable_rust_analyzer_spans(&self) -> Result { - let request = Request::SetConfig(ServerConfig { span_mode: SpanMode::RustAnalyzer }); - let response = self.send_task(request)?; - - match response { - Response::SetConfig(ServerConfig { span_mode }) => Ok(span_mode), - _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + match self.protocol { + Protocol::LegacyJson { .. } => legacy_protocol::enable_rust_analyzer_spans(self), } } @@ -125,25 +123,24 @@ impl ProcMacroServerProcess { &self, dylib_path: &AbsPath, ) -> Result, String>, ServerError> { - let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }; - - let response = self.send_task(request)?; - - match response { - Response::ListMacros(it) => Ok(it), - _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }), + match self.protocol { + Protocol::LegacyJson { .. } => legacy_protocol::find_proc_macros(self, dylib_path), } } - /// Sends a request to the proc-macro server and waits for a response. - pub(crate) fn send_task(&self, req: Request) -> Result { - if let Some(server_error) = self.exited.get() { - return Err(server_error.0.clone()); - } - + pub(crate) fn send_task( + &self, + serialize_req: impl FnOnce( + &mut dyn Write, + &mut dyn BufRead, + Request, + &mut String, + ) -> Result, ServerError>, + req: Request, + ) -> Result { let state = &mut *self.state.lock().unwrap(); let mut buf = String::new(); - send_request(&mut state.stdin, &mut state.stdout, req, &mut buf) + serialize_req(&mut state.stdin, &mut state.stdout, req, &mut buf) .and_then(|res| { res.ok_or_else(|| { let message = "proc-macro server did not respond with data".to_owned(); @@ -162,10 +159,10 @@ impl ProcMacroServerProcess { Ok(None) | Err(_) => e, Ok(Some(status)) => { let mut msg = String::new(); - if !status.success() { - if let Some(stderr) = state.process.child.stderr.as_mut() { - _ = stderr.read_to_string(&mut msg); - } + if !status.success() + && let Some(stderr) = state.process.child.stderr.as_mut() + { + _ = stderr.read_to_string(&mut msg); } let server_error = ServerError { message: format!( @@ -242,21 +239,3 @@ fn mk_child<'a>( } cmd.spawn() } - -/// Sends a request to the server and reads the response. -fn send_request( - mut writer: &mut impl Write, - mut reader: &mut impl BufRead, - req: Request, - buf: &mut String, -) -> Result, ServerError> { - req.write(write_json, &mut writer).map_err(|err| ServerError { - message: "failed to write request".into(), - io: Some(Arc::new(err)), - })?; - let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError { - message: "failed to read response".into(), - io: Some(Arc::new(err)), - })?; - Ok(res) -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index ab421021b8bf..16ec3b0e2b2a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -14,6 +14,7 @@ publish = false proc-macro-srv.workspace = true proc-macro-api.workspace = true tt.workspace = true +clap = {version = "4.5.42", default-features = false, features = ["std"]} [features] sysroot-abi = ["proc-macro-srv/sysroot-abi"] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs index c47ed053254b..b6ebc562eac9 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs @@ -9,6 +9,7 @@ extern crate rustc_driver as _; #[cfg(any(feature = "sysroot-abi", rust_analyzer))] mod main_loop; +use clap::{Command, ValueEnum}; #[cfg(any(feature = "sysroot-abi", rust_analyzer))] use main_loop::run; @@ -23,12 +24,46 @@ fn main() -> std::io::Result<()> { ); std::process::exit(122); } + let matches = Command::new("proc-macro-srv") + .args(&[clap::Arg::new("format") + .long("format") + .action(clap::ArgAction::Set) + .default_value("json") + .value_parser(clap::builder::EnumValueParser::::new())]) + .get_matches(); + let &format = + matches.get_one::("format").expect("format value should always be present"); + run(format) +} - run() +#[derive(Copy, Clone)] +enum ProtocolFormat { + Json, + Postcard, +} + +impl ValueEnum for ProtocolFormat { + fn value_variants<'a>() -> &'a [Self] { + &[ProtocolFormat::Json] + } + + fn to_possible_value(&self) -> Option { + match self { + ProtocolFormat::Json => Some(clap::builder::PossibleValue::new("json")), + ProtocolFormat::Postcard => Some(clap::builder::PossibleValue::new("postcard")), + } + } + fn from_str(input: &str, _ignore_case: bool) -> Result { + match input { + "json" => Ok(ProtocolFormat::Json), + "postcard" => Ok(ProtocolFormat::Postcard), + _ => Err(format!("unknown protocol format: {input}")), + } + } } #[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))] -fn run() -> std::io::Result<()> { +fn run(_: ProtocolFormat) -> std::io::Result<()> { Err(std::io::Error::new( std::io::ErrorKind::Unsupported, "proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index f54dff1f2d82..6bf58eef3bb9 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -1,16 +1,47 @@ //! The main loop of the proc-macro server. use std::io; -use proc_macro_api::legacy_protocol::{ - json::{read_json, write_json}, - msg::{ - self, CURRENT_API_VERSION, ExpandMacroData, ExpnGlobals, Message, SpanMode, TokenId, - deserialize_span_data_index_map, serialize_span_data_index_map, +use proc_macro_api::{ + legacy_protocol::{ + json::{read_json, write_json}, + msg::{ + self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer, + deserialize_span_data_index_map, serialize_span_data_index_map, + }, }, + version::CURRENT_API_VERSION, }; -use proc_macro_srv::EnvSnapshot; +use proc_macro_srv::{EnvSnapshot, SpanId}; -pub(crate) fn run() -> io::Result<()> { +use crate::ProtocolFormat; + +struct SpanTrans; + +impl SpanTransformer for SpanTrans { + type Table = (); + type Span = SpanId; + fn token_id_of( + _: &mut Self::Table, + span: Self::Span, + ) -> proc_macro_api::legacy_protocol::SpanId { + proc_macro_api::legacy_protocol::SpanId(span.0 as u32) + } + fn span_for_token_id( + _: &Self::Table, + id: proc_macro_api::legacy_protocol::SpanId, + ) -> Self::Span { + SpanId(id.0 as u32) + } +} + +pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> { + match format { + ProtocolFormat::Json => run_json(), + ProtocolFormat::Postcard => unimplemented!(), + } +} + +fn run_json() -> io::Result<()> { fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind { match kind { proc_macro_srv::ProcMacroKind::CustomDerive => { @@ -54,13 +85,14 @@ pub(crate) fn run() -> io::Result<()> { } = *task; match span_mode { SpanMode::Id => msg::Response::ExpandMacro({ - let def_site = TokenId(def_site as u32); - let call_site = TokenId(call_site as u32); - let mixed_site = TokenId(mixed_site as u32); + let def_site = SpanId(def_site as u32); + let call_site = SpanId(call_site as u32); + let mixed_site = SpanId(mixed_site as u32); - let macro_body = macro_body.to_subtree_unresolved(CURRENT_API_VERSION); - let attributes = - attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION)); + let macro_body = + macro_body.to_subtree_unresolved::(CURRENT_API_VERSION); + let attributes = attributes + .map(|it| it.to_subtree_unresolved::(CURRENT_API_VERSION)); srv.expand( lib, @@ -74,7 +106,10 @@ pub(crate) fn run() -> io::Result<()> { mixed_site, ) .map(|it| { - msg::FlatTree::new_raw(tt::SubtreeView::new(&it), CURRENT_API_VERSION) + msg::FlatTree::new_raw::( + tt::SubtreeView::new(&it), + CURRENT_API_VERSION, + ) }) .map_err(msg::PanicMessage) }), diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 223c5a54b703..0f7c83979d56 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -41,10 +41,12 @@ use std::{ }; use paths::{Utf8Path, Utf8PathBuf}; -use span::{Span, TokenId}; +use span::Span; use crate::server_impl::TokenStream; +pub use crate::server_impl::token_id::SpanId; + #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum ProcMacroKind { CustomDerive, @@ -159,8 +161,8 @@ pub trait ProcMacroSrvSpan: Copy + Send { fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; } -impl ProcMacroSrvSpan for TokenId { - type Server = server_impl::token_id::TokenIdServer; +impl ProcMacroSrvSpan for SpanId { + type Server = server_impl::token_id::SpanIdServer; fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { Self::Server { call_site, def_site, mixed_site } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index b493b325e830..91e70ea243ae 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -1,4 +1,4 @@ -//! proc-macro server backend based on [`proc_macro_api::msg::TokenId`] as the backing span. +//! proc-macro server backend based on [`proc_macro_api::msg::SpanId`] as the backing span. //! This backend is rather inflexible, used by RustRover and older rust-analyzer versions. use std::ops::{Bound, Range}; @@ -7,25 +7,34 @@ use proc_macro::bridge::{self, server}; use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder}; -type Span = span::TokenId; +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct SpanId(pub u32); + +impl std::fmt::Debug for SpanId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +type Span = SpanId; type TokenStream = crate::server_impl::TokenStream; pub struct FreeFunctions; -pub struct TokenIdServer { +pub struct SpanIdServer { pub call_site: Span, pub def_site: Span, pub mixed_site: Span, } -impl server::Types for TokenIdServer { +impl server::Types for SpanIdServer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type Span = Span; type Symbol = Symbol; } -impl server::FreeFunctions for TokenIdServer { +impl server::FreeFunctions for SpanIdServer { fn injected_env_var(&mut self, _: &str) -> Option { None } @@ -41,7 +50,7 @@ impl server::FreeFunctions for TokenIdServer { fn emit_diagnostic(&mut self, _: bridge::Diagnostic) {} } -impl server::TokenStream for TokenIdServer { +impl server::TokenStream for SpanIdServer { fn is_empty(&mut self, stream: &Self::TokenStream) -> bool { stream.is_empty() } @@ -102,12 +111,12 @@ impl server::TokenStream for TokenIdServer { &mut self, stream: Self::TokenStream, ) -> Vec> { - // Can't join with `TokenId`. + // Can't join with `SpanId`. stream.into_bridge(&mut |first, _second| first) } } -impl server::Span for TokenIdServer { +impl server::Span for SpanIdServer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span.0) } @@ -174,14 +183,14 @@ impl server::Span for TokenIdServer { } } -impl server::Symbol for TokenIdServer { +impl server::Symbol for SpanIdServer { fn normalize_and_validate_ident(&mut self, string: &str) -> Result { // FIXME: nfc-normalize and validate idents Ok(::intern_symbol(string)) } } -impl server::Server for TokenIdServer { +impl server::Server for SpanIdServer { fn globals(&mut self) -> bridge::ExpnGlobals { bridge::ExpnGlobals { def_site: self.def_site, @@ -201,8 +210,6 @@ impl server::Server for TokenIdServer { #[cfg(test)] mod tests { - use span::TokenId; - use super::*; #[test] @@ -211,18 +218,18 @@ mod tests { token_trees: vec![ tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: Symbol::intern("struct"), - span: TokenId(0), + span: SpanId(0), is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: Symbol::intern("T"), - span: TokenId(0), + span: SpanId(0), is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Subtree(tt::Subtree { delimiter: tt::Delimiter { - open: TokenId(0), - close: TokenId(0), + open: SpanId(0), + close: SpanId(0), kind: tt::DelimiterKind::Brace, }, len: 0, @@ -238,8 +245,8 @@ mod tests { let subtree_paren_a = vec![ tt::TokenTree::Subtree(tt::Subtree { delimiter: tt::Delimiter { - open: TokenId(0), - close: TokenId(0), + open: SpanId(0), + close: SpanId(0), kind: tt::DelimiterKind::Parenthesis, }, len: 1, @@ -247,24 +254,24 @@ mod tests { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { is_raw: tt::IdentIsRaw::No, sym: Symbol::intern("a"), - span: TokenId(0), + span: SpanId(0), })), ]; - let t1 = TokenStream::from_str("(a)", TokenId(0)).unwrap(); + let t1 = TokenStream::from_str("(a)", SpanId(0)).unwrap(); assert_eq!(t1.token_trees.len(), 2); assert!(t1.token_trees[0..2] == subtree_paren_a); - let t2 = TokenStream::from_str("(a);", TokenId(0)).unwrap(); + let t2 = TokenStream::from_str("(a);", SpanId(0)).unwrap(); assert_eq!(t2.token_trees.len(), 3); assert!(t2.token_trees[0..2] == subtree_paren_a); - let underscore = TokenStream::from_str("_", TokenId(0)).unwrap(); + let underscore = TokenStream::from_str("_", SpanId(0)).unwrap(); assert!( underscore.token_trees[0] == tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: Symbol::intern("_"), - span: TokenId(0), + span: SpanId(0), is_raw: tt::IdentIsRaw::No, })) ); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs index 10af5662b5c0..7aa38576bb52 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs @@ -1,14 +1,12 @@ //! utils used in proc-macro tests use expect_test::Expect; -use span::{ - EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TokenId, -}; +use span::{EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext}; use tt::TextRange; -use crate::{EnvSnapshot, ProcMacroSrv, dylib, proc_macro_test_dylib_path}; +use crate::{EnvSnapshot, ProcMacroSrv, SpanId, dylib, proc_macro_test_dylib_path}; -fn parse_string(call_site: TokenId, src: &str) -> crate::server_impl::TokenStream { +fn parse_string(call_site: SpanId, src: &str) -> crate::server_impl::TokenStream { crate::server_impl::TokenStream::with_subtree(crate::server_impl::TopSubtree( syntax_bridge::parse_to_token_tree_static_span(span::Edition::CURRENT, call_site, src) .unwrap() @@ -59,9 +57,9 @@ fn assert_expand_impl( let path = proc_macro_test_dylib_path(); let expander = dylib::Expander::new(&path).unwrap(); - let def_site = TokenId(0); - let call_site = TokenId(1); - let mixed_site = TokenId(2); + let def_site = SpanId(0); + let call_site = SpanId(1); + let mixed_site = SpanId(2); let input_ts = parse_string(call_site, input).into_subtree(call_site); let attr_ts = attr.map(|attr| parse_string(call_site, attr).into_subtree(call_site)); let input_ts_string = format!("{input_ts:?}"); diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs index b81d08eed6d8..ae9e038459e5 100644 --- a/src/tools/rust-analyzer/crates/span/src/lib.rs +++ b/src/tools/rust-analyzer/crates/span/src/lib.rs @@ -203,15 +203,3 @@ pub struct HirFileId(pub salsa::Id); /// `println!("Hello, {}", world)`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MacroCallId(pub salsa::Id); - -/// Legacy span type, only defined here as it is still used by the proc-macro server. -/// While rust-analyzer doesn't use this anymore at all, RustRover relies on the legacy type for -/// proc-macro expansion. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct TokenId(pub u32); - -impl std::fmt::Debug for TokenId { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} From d71e972414b8a1fe188a31ed96fecbd157c3ddcf Mon Sep 17 00:00:00 2001 From: Hmikihiro <34ttrweoewiwe28@gmail.com> Date: Wed, 30 Jul 2025 00:03:53 +0900 Subject: [PATCH 099/242] add `SyntaxEditor::delete_all` to migrate utils.rs `add_trait_assoc_items_to_impl` --- .../crates/ide-assists/src/utils.rs | 59 ++++++++++--------- .../crates/syntax/src/syntax_editor.rs | 10 ++++ .../crates/syntax/src/syntax_editor/edits.rs | 26 ++++++++ 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 15c7a6a3fc26..c81a3a6f08d5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -23,12 +23,11 @@ use syntax::{ ast::{ self, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, edit::{AstNodeEdit, IndentLevel}, - edit_in_place::{AttrsOwnerEdit, Removable}, + edit_in_place::AttrsOwnerEdit, make, syntax_factory::SyntaxFactory, }, - syntax_editor::SyntaxEditor, - ted, + syntax_editor::{Removable, SyntaxEditor}, }; use crate::{ @@ -207,7 +206,7 @@ pub fn add_trait_assoc_items_to_impl( stdx::never!("formatted `AssocItem` could not be cast back to `AssocItem`"); } } - original_item.clone_for_update() + original_item } .reset_indent(); @@ -221,31 +220,37 @@ pub fn add_trait_assoc_items_to_impl( cloned_item.remove_attrs_and_docs(); cloned_item }) - .map(|item| { - match &item { - ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { - let body = AstNodeEdit::indent( - &make::block_expr( - None, - Some(match config.expr_fill_default { - ExprFillDefaultMode::Todo => make::ext::expr_todo(), - ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), - ExprFillDefaultMode::Default => make::ext::expr_todo(), - }), - ), - IndentLevel::single(), - ); - ted::replace(fn_.get_or_create_body().syntax(), body.syntax()); - } - ast::AssocItem::TypeAlias(type_alias) => { - if let Some(type_bound_list) = type_alias.type_bound_list() { - type_bound_list.remove() - } - } - _ => {} + .filter_map(|item| match item { + ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { + let fn_ = fn_.clone_subtree(); + let new_body = &make::block_expr( + None, + Some(match config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }), + ); + let new_body = AstNodeEdit::indent(new_body, IndentLevel::single()); + let mut fn_editor = SyntaxEditor::new(fn_.syntax().clone()); + fn_.replace_or_insert_body(&mut fn_editor, new_body); + let new_fn_ = fn_editor.finish().new_root().clone(); + ast::AssocItem::cast(new_fn_) } - AstNodeEdit::indent(&item, new_indent_level) + ast::AssocItem::TypeAlias(type_alias) => { + let type_alias = type_alias.clone_subtree(); + if let Some(type_bound_list) = type_alias.type_bound_list() { + let mut type_alias_editor = SyntaxEditor::new(type_alias.syntax().clone()); + type_bound_list.remove(&mut type_alias_editor); + let type_alias = type_alias_editor.finish().new_root().clone(); + ast::AssocItem::cast(type_alias) + } else { + Some(ast::AssocItem::TypeAlias(type_alias)) + } + } + item => Some(item), }) + .map(|item| AstNodeEdit::indent(&item, new_indent_level)) .collect() } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 5107754b1825..147b54c21a5f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -83,6 +83,16 @@ impl SyntaxEditor { self.changes.push(Change::Replace(element.syntax_element(), None)); } + pub fn delete_all(&mut self, range: RangeInclusive) { + if range.start() == range.end() { + self.delete(range.start()); + return; + } + + debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root)); + self.changes.push(Change::ReplaceAll(range, Vec::new())) + } + pub fn replace(&mut self, old: impl Element, new: impl Element) { let old = old.syntax_element(); debug_assert!(is_ancestor_or_self_of_element(&old, &self.root)); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index 840e76979792..9090f7c9eb14 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -153,6 +153,23 @@ impl ast::VariantList { } } +impl ast::Fn { + pub fn replace_or_insert_body(&self, editor: &mut SyntaxEditor, body: ast::BlockExpr) { + if let Some(old_body) = self.body() { + editor.replace(old_body.syntax(), body.syntax()); + } else { + let single_space = make::tokens::single_space(); + let elements = vec![single_space.into(), body.syntax().clone().into()]; + + if let Some(semicolon) = self.semicolon_token() { + editor.replace_with_many(semicolon, elements); + } else { + editor.insert_all(Position::last_child_of(self.syntax()), elements); + } + } + } +} + fn normalize_ws_between_braces(editor: &mut SyntaxEditor, node: &SyntaxNode) -> Option<()> { let make = SyntaxFactory::without_mappings(); let l = node @@ -184,6 +201,15 @@ pub trait Removable: AstNode { fn remove(&self, editor: &mut SyntaxEditor); } +impl Removable for ast::TypeBoundList { + fn remove(&self, editor: &mut SyntaxEditor) { + match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) { + Some(colon) => editor.delete_all(colon..=self.syntax().clone().into()), + None => editor.delete(self.syntax()), + } + } +} + impl Removable for ast::Use { fn remove(&self, editor: &mut SyntaxEditor) { let make = SyntaxFactory::without_mappings(); From 2ae048e1df765e0ba4c9638149552ea1eba82834 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Jul 2025 17:48:24 +0000 Subject: [PATCH 100/242] Distinguish appending and replacing self ty in predicates --- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../src/hir_ty_lowering/errors.rs | 4 +-- compiler/rustc_hir_typeck/src/coercion.rs | 10 ++++--- .../rustc_hir_typeck/src/method/suggest.rs | 8 +++--- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 2 +- .../src/solve/assembly/mod.rs | 6 ++--- .../src/solve/effect_goals.rs | 4 +-- .../src/solve/normalizes_to/mod.rs | 4 +-- .../src/solve/trait_goals.rs | 8 +++--- .../src/error_reporting/infer/region.rs | 2 +- .../traits/fulfillment_errors.rs | 6 ++--- .../src/error_reporting/traits/suggestions.rs | 9 ++++--- compiler/rustc_type_ir/src/predicate.rs | 26 ++++++++++++------- compiler/rustc_type_ir/src/ty_kind.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 2 +- 15 files changed, 53 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b2cfab37c1f6..85445cb3c004 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -493,7 +493,7 @@ fn suggestion_signature<'tcx>( let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto( tcx, assoc.container_id(tcx), - impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).args, + impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args, ); match assoc.kind { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index f73442fdebd4..3e446b7c656f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -888,8 +888,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { // `::Item = String`. let projection_term = pred.projection_term; - let quiet_projection_term = - projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); + let quiet_projection_term = projection_term + .with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); let term = pred.term; let obligation = format!("{projection_term} = {term}"); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6d67535da5fb..1737de02094c 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1800,11 +1800,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { .kind() .map_bound(|clause| match clause { ty::ClauseKind::Trait(trait_pred) => Some(ty::ClauseKind::Trait( - trait_pred.with_self_ty(fcx.tcx, ty), + trait_pred.with_replaced_self_ty(fcx.tcx, ty), )), - ty::ClauseKind::Projection(proj_pred) => Some( - ty::ClauseKind::Projection(proj_pred.with_self_ty(fcx.tcx, ty)), - ), + ty::ClauseKind::Projection(proj_pred) => { + Some(ty::ClauseKind::Projection( + proj_pred.with_replaced_self_ty(fcx.tcx, ty), + )) + } _ => None, }) .transpose()?; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e64af8fb7b38..468ad5744489 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1053,8 +1053,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pred = bound_predicate.rebind(pred); // `::Item = String`. let projection_term = pred.skip_binder().projection_term; - let quiet_projection_term = - projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); + let quiet_projection_term = projection_term + .with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO)); let term = pred.skip_binder().term; @@ -2157,7 +2157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.fresh_args_for_item(sugg_span, impl_did), ) - .with_self_ty(self.tcx, rcvr_ty), + .with_replaced_self_ty(self.tcx, rcvr_ty), idx, sugg_span, item, @@ -2196,7 +2196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_did, self.fresh_args_for_item(sugg_span, trait_did), ) - .with_self_ty(self.tcx, rcvr_ty), + .with_replaced_self_ty(self.tcx, rcvr_ty), idx, sugg_span, item, diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 6a985fc91e7d..b6afe184d07a 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -151,7 +151,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { obligation.predicate.kind().rebind( // (*) binder moved here ty::PredicateKind::Clause(ty::ClauseKind::Trait( - tpred.with_self_ty(self.tcx, new_self_ty), + tpred.with_replaced_self_ty(self.tcx, new_self_ty), )), ), ); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index b2d401463485..ad0811f5c6c7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -50,7 +50,7 @@ where fn trait_ref(self, cx: I) -> ty::TraitRef; - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self; + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self; fn trait_def_id(self, cx: I) -> I::DefId; @@ -376,8 +376,8 @@ where return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal = - goal.with(self.cx(), goal.predicate.with_self_ty(self.cx(), normalized_self_ty)); + let goal: Goal = goal + .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty)); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 61f3f9367f04..9a22bf58c035 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -29,8 +29,8 @@ where self.trait_ref } - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(cx, self_ty) + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_replaced_self_ty(cx, self_ty) } fn trait_def_id(self, _: I) -> I::DefId { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 1e0a90eb2eef..93434dce79fd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -99,8 +99,8 @@ where self.alias.trait_ref(cx) } - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(cx, self_ty) + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_replaced_self_ty(cx, self_ty) } fn trait_def_id(self, cx: I) -> I::DefId { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 650b85d99d2c..43c123f55dbe 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -33,8 +33,8 @@ where self.trait_ref } - fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(cx, self_ty) + fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_replaced_self_ty(cx, self_ty) } fn trait_def_id(self, _: I) -> I::DefId { @@ -1263,7 +1263,9 @@ where let goals = ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| { tys.into_iter() - .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))) + .map(|ty| { + goal.with(ecx.cx(), goal.predicate.with_replaced_self_ty(ecx.cx(), ty)) + }) .collect::>() }); ecx.add_goals(GoalSource::ImplWhereBound, goals); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index f3441a8d72aa..7369134420c6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -581,7 +581,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let trait_args = trait_ref .instantiate_identity() // Replace the explicit self type with `Self` for better suggestion rendering - .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) + .with_replaced_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) .args; let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) .rebase_onto(self.tcx, impl_def_id, trait_args); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1ac309da101f..a9e346a5cdb0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -512,7 +512,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && self.fallback_has_occurred { let predicate = leaf_trait_predicate.map_bound(|trait_pred| { - trait_pred.with_self_ty(self.tcx, tcx.types.unit) + trait_pred.with_replaced_self_ty(self.tcx, tcx.types.unit) }); let unit_obligation = obligation.with(tcx, predicate); if self.predicate_may_hold(&unit_obligation) { @@ -2364,8 +2364,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, ) -> PredicateObligation<'tcx> { - let trait_pred = - trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty)); + let trait_pred = trait_ref_and_ty + .map_bound(|(tr, new_self_ty)| tr.with_replaced_self_ty(self.tcx, new_self_ty)); Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index c182fd99b17b..718cff6d135b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3942,7 +3942,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id) && let Some(failed_pred) = failed_pred.as_trait_clause() - && let pred = failed_pred.map_bound(|pred| pred.with_self_ty(tcx, ty)) + && let pred = failed_pred.map_bound(|pred| pred.with_replaced_self_ty(tcx, ty)) && self.predicate_must_hold_modulo_regions(&Obligation::misc( tcx, expr.span, body_id, param_env, pred, )) @@ -4624,9 +4624,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(root_pred) = root_obligation.predicate.as_trait_clause() else { return }; let trait_ref = root_pred.map_bound(|root_pred| { - root_pred - .trait_ref - .with_self_ty(self.tcx, Ty::new_tup(self.tcx, &[root_pred.trait_ref.self_ty()])) + root_pred.trait_ref.with_replaced_self_ty( + self.tcx, + Ty::new_tup(self.tcx, &[root_pred.trait_ref.self_ty()]), + ) }); let obligation = diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 4643cd0ab850..c9489c98ccea 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -97,7 +97,7 @@ impl TraitRef { ) } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { TraitRef::new( interner, self.def_id, @@ -146,8 +146,11 @@ pub struct TraitPredicate { } impl TraitPredicate { - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { - Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), polarity: self.polarity } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { + trait_ref: self.trait_ref.with_replaced_self_ty(interner, self_ty), + polarity: self.polarity, + } } pub fn def_id(self) -> I::DefId { @@ -645,7 +648,7 @@ impl AliasTerm { self.args.type_at(0) } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { AliasTerm::new( interner, self.def_id, @@ -756,8 +759,11 @@ impl ProjectionPredicate { self.projection_term.self_ty() } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { - Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate { + Self { + projection_term: self.projection_term.with_replaced_self_ty(interner, self_ty), + ..self + } } pub fn trait_def_id(self, interner: I) -> I::DefId { @@ -814,8 +820,8 @@ impl NormalizesTo { self.alias.self_ty() } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo { - Self { alias: self.alias.with_self_ty(interner, self_ty), ..self } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo { + Self { alias: self.alias.with_replaced_self_ty(interner, self_ty), ..self } } pub fn trait_def_id(self, interner: I) -> I::DefId { @@ -849,8 +855,8 @@ impl HostEffectPredicate { self.trait_ref.self_ty() } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { - Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), ..self } + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { trait_ref: self.trait_ref.with_replaced_self_ty(interner, self_ty), ..self } } pub fn def_id(self) -> I::DefId { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 7c6654247505..a4be01e9eb51 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -475,7 +475,7 @@ impl AliasTy { self.args.type_at(0) } - pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { AliasTy::new( interner, self.def_id, diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 17d251a7bbb9..120a4b98a65a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -417,7 +417,7 @@ fn replace_types<'tcx>( { let projection = projection_predicate .projection_term - .with_self_ty(cx.tcx, new_ty) + .with_replaced_self_ty(cx.tcx, new_ty) .expect_ty(cx.tcx) .to_ty(cx.tcx); From 1a515e69490cdc3cee5325c4fc8d18baa502f38a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 30 Jul 2025 19:12:31 +0000 Subject: [PATCH 101/242] rustdoc-json: Add test for `#[macro_use]` attribute --- tests/rustdoc-json/attrs/macro_export.rs | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/rustdoc-json/attrs/macro_export.rs diff --git a/tests/rustdoc-json/attrs/macro_export.rs b/tests/rustdoc-json/attrs/macro_export.rs new file mode 100644 index 000000000000..1472aabb6ff5 --- /dev/null +++ b/tests/rustdoc-json/attrs/macro_export.rs @@ -0,0 +1,40 @@ +//@ compile-flags: --document-private-items + +//@ set exported_id = "$.index[?(@.name=='exported')].id" +//@ is "$.index[?(@.name=='exported')].attrs" '[{"other": "#[macro_export]"}]' +//@ is "$.index[?(@.name=='exported')].visibility" '"public"' + +#[macro_export] +macro_rules! exported { + () => {}; +} + +//@ set not_exported_id = "$.index[?(@.name=='not_exported')].id" +//@ is "$.index[?(@.name=='not_exported')].attrs" [] +//@ is "$.index[?(@.name=='not_exported')].visibility" '"crate"' +macro_rules! not_exported { + () => {}; +} + +//@ set module_id = "$.index[?(@.name=='module')].id" +pub mod module { + //@ set exported_from_mod_id = "$.index[?(@.name=='exported_from_mod')].id" + //@ is "$.index[?(@.name=='exported_from_mod')].attrs" '[{"other": "#[macro_export]"}]' + //@ is "$.index[?(@.name=='exported_from_mod')].visibility" '"public"' + #[macro_export] + macro_rules! exported_from_mod { + () => {}; + } + + //@ set not_exported_from_mod_id = "$.index[?(@.name=='not_exported_from_mod')].id" + //@ is "$.index[?(@.name=='not_exported_from_mod')].attrs" [] + //@ is "$.index[?(@.name=='not_exported_from_mod')].visibility" '"crate"' + macro_rules! not_exported_from_mod { + () => {}; + } +} +// The non-exported macro's are left in place, but the #[macro_export]'d ones +// are moved to the crate root. + +//@ is "$.index[?(@.name=='module')].inner.module.items[*]" $not_exported_from_mod_id +//@ ismany "$.index[?(@.name=='macro_export')].inner.module.items[*]" $exported_id $not_exported_id $module_id $exported_from_mod_id From a33e084afe698e0a025211abd6dc1c9a4bb22e9d Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 30 Jul 2025 19:57:32 +0000 Subject: [PATCH 102/242] rustdoc-json: Move `#[macro_export]` from `Other` to it's own variant --- src/librustdoc/json/conversions.rs | 8 ++++++-- src/rustdoc-json-types/lib.rs | 7 +++++-- tests/rustdoc-json/attrs/macro_export.rs | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 08bc0bb19505..fe69a5abee1a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -908,8 +908,12 @@ fn maybe_from_hir_attr( hir::Attribute::Parsed(kind) => kind, hir::Attribute::Unparsed(_) => { - // FIXME: We should handle `#[doc(hidden)]`. - return Some(other_attr(tcx, attr)); + return Some(if attr.has_name(sym::macro_export) { + Attribute::MacroExport + // FIXME: We should handle `#[doc(hidden)]`. + } else { + other_attr(tcx, attr) + }); } }; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 6235b0e8576f..40f89009a431 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Structured Attributes -pub const FORMAT_VERSION: u32 = 54; +// Latest feature: Add Attribute::MacroUse +pub const FORMAT_VERSION: u32 = 55; /// The root of the emitted JSON blob. /// @@ -216,6 +216,9 @@ pub enum Attribute { /// `#[must_use]` MustUse { reason: Option }, + /// `#[macro_export]` + MacroExport, + /// `#[export_name = "name"]` ExportName(String), diff --git a/tests/rustdoc-json/attrs/macro_export.rs b/tests/rustdoc-json/attrs/macro_export.rs index 1472aabb6ff5..5d487cf6a56e 100644 --- a/tests/rustdoc-json/attrs/macro_export.rs +++ b/tests/rustdoc-json/attrs/macro_export.rs @@ -1,7 +1,7 @@ //@ compile-flags: --document-private-items //@ set exported_id = "$.index[?(@.name=='exported')].id" -//@ is "$.index[?(@.name=='exported')].attrs" '[{"other": "#[macro_export]"}]' +//@ is "$.index[?(@.name=='exported')].attrs" '["macro_export"]' //@ is "$.index[?(@.name=='exported')].visibility" '"public"' #[macro_export] @@ -19,7 +19,7 @@ macro_rules! not_exported { //@ set module_id = "$.index[?(@.name=='module')].id" pub mod module { //@ set exported_from_mod_id = "$.index[?(@.name=='exported_from_mod')].id" - //@ is "$.index[?(@.name=='exported_from_mod')].attrs" '[{"other": "#[macro_export]"}]' + //@ is "$.index[?(@.name=='exported_from_mod')].attrs" '["macro_export"]' //@ is "$.index[?(@.name=='exported_from_mod')].visibility" '"public"' #[macro_export] macro_rules! exported_from_mod { From ee0118f8a1dbfcad06b8c09644553a3fc3e070d4 Mon Sep 17 00:00:00 2001 From: David Tenty Date: Wed, 30 Jul 2025 16:45:17 -0400 Subject: [PATCH 103/242] [test][AIX] ignore extern_weak linkage test The AIX linkage model doesn't support ELF style extern_weak semantic, so just skip this test, like other platforms that don't have it. --- tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs index 8c194ec50df4..ad7b06744781 100644 --- a/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs +++ b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs @@ -4,6 +4,7 @@ //@ ignore-emscripten no weak symbol support //@ ignore-apple no extern_weak linkage +//@ ignore-aix no extern_weak linkage //@ aux-build:lib.rs From 170ccbf434112f25f596898b1117942b4bafbd22 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Jul 2025 20:57:00 +0000 Subject: [PATCH 104/242] expand WF obligations when checking method calls --- .../src/check/compare_impl_item.rs | 16 +++++------ .../rustc_hir_typeck/src/method/confirm.rs | 28 ++++++++----------- compiler/rustc_hir_typeck/src/method/mod.rs | 21 +++++++------- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e24426f9fedc..daf5f6e7bb5b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -356,14 +356,14 @@ fn compare_method_predicate_entailment<'tcx>( } if !(impl_sig, trait_sig).references_error() { - ocx.register_obligation(traits::Obligation::new( - infcx.tcx, - cause, - param_env, - ty::ClauseKind::WellFormed( - Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)).into(), - ), - )); + for ty in unnormalized_impl_sig.inputs_and_output { + ocx.register_obligation(traits::Obligation::new( + infcx.tcx, + cause.clone(), + param_env, + ty::ClauseKind::WellFormed(ty.into()), + )); + } } // Check that all obligations are satisfied by the implementation's diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 8d9f7eaf1774..79996ff482e8 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -142,7 +142,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let (method_sig, method_predicates) = self.normalize(self.span, (method_sig, method_predicates)); - let method_sig = ty::Binder::dummy(method_sig); // Make sure nobody calls `drop()` explicitly. self.check_for_illegal_method_calls(pick); @@ -154,20 +153,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We won't add these if we encountered an illegal sized bound, so that we can use // a custom error in that case. if illegal_sized_bound.is_none() { - self.add_obligations( - Ty::new_fn_ptr(self.tcx, method_sig), - all_args, - method_predicates, - pick.item.def_id, - ); + self.add_obligations(method_sig, all_args, method_predicates, pick.item.def_id); } // Create the final `MethodCallee`. - let callee = MethodCallee { - def_id: pick.item.def_id, - args: all_args, - sig: method_sig.skip_binder(), - }; + let callee = MethodCallee { def_id: pick.item.def_id, args: all_args, sig: method_sig }; ConfirmResult { callee, illegal_sized_bound } } @@ -601,14 +591,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn add_obligations( &mut self, - fty: Ty<'tcx>, + sig: ty::FnSig<'tcx>, all_args: GenericArgsRef<'tcx>, method_predicates: ty::InstantiatedPredicates<'tcx>, def_id: DefId, ) { debug!( - "add_obligations: fty={:?} all_args={:?} method_predicates={:?} def_id={:?}", - fty, all_args, method_predicates, def_id + "add_obligations: sig={:?} all_args={:?} method_predicates={:?} def_id={:?}", + sig, all_args, method_predicates, def_id ); // FIXME: could replace with the following, but we already calculated `method_predicates`, @@ -637,7 +627,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the function type must also be well-formed (this is not // implied by the args being well-formed because of inherent // impls and late-bound regions - see issue #28609). - self.register_wf_obligation(fty.into(), self.span, ObligationCauseCode::WellFormed(None)); + for ty in sig.inputs_and_output { + self.register_wf_obligation( + ty.into(), + self.span, + ObligationCauseCode::WellFormed(None), + ); + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 316468b0a5d1..e37ea0316726 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -428,19 +428,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); // Also add an obligation for the method type being well-formed. - let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig)); debug!( - "lookup_method_in_trait: matched method method_ty={:?} obligation={:?}", - method_ty, obligation + "lookup_method_in_trait: matched method fn_sig={:?} obligation={:?}", + fn_sig, obligation ); - obligations.push(traits::Obligation::new( - tcx, - obligation.cause, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - method_ty.into(), - ))), - )); + for ty in fn_sig.inputs_and_output { + obligations.push(traits::Obligation::new( + tcx, + obligation.cause.clone(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into()))), + )); + } let callee = MethodCallee { def_id, args, sig: fn_sig }; debug!("callee = {:?}", callee); From 7d378192a7d0c7829b7ee32e292d24bd89d7ca3d Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 31 Jul 2025 04:16:57 +0000 Subject: [PATCH 105/242] Prepare for merging from rust-lang/rust This updates the rust-version file to 32e7a4b92b109c24e9822c862a7c74436b50e564. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index b631041b6bfa..1ced6098acf4 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -2b5e239c6b86cde974b0ef0f8e23754fb08ff3c5 +32e7a4b92b109c24e9822c862a7c74436b50e564 From 7b667e7811f4a4b496f38d25c5e824f13638cdbb Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 31 Jul 2025 00:44:22 +0800 Subject: [PATCH 106/242] Extend `is_case_difference` to handle digit-letter confusables Signed-off-by: xizheyin --- compiler/rustc_errors/src/emitter.rs | 135 ++++++++++++++---- compiler/rustc_errors/src/lib.rs | 11 +- .../tests/ui/match_str_case_mismatch.stderr | 2 +- tests/ui/error-codes/E0423.stderr | 2 +- .../ui/lint/lint-non-uppercase-usages.stderr | 2 +- tests/ui/parser/item-kw-case-mismatch.stderr | 6 +- tests/ui/parser/kw-in-trait-bounds.stderr | 8 +- .../ui/parser/misspelled-keywords/hrdt.stderr | 2 +- .../misspelled-keywords/impl-return.stderr | 2 +- .../parser/misspelled-keywords/static.stderr | 2 +- .../parser/misspelled-keywords/struct.stderr | 2 +- .../recover-fn-trait-from-fn-kw.stderr | 4 +- .../typod-const-in-const-param-def.stderr | 8 +- .../assoc-ct-for-assoc-method.stderr | 2 +- .../suggestions/bool_typo_err_suggest.stderr | 2 +- .../case-difference-suggestions.rs | 57 ++++++++ .../case-difference-suggestions.stderr | 99 +++++++++++++ .../suggestions/incorrect-variant-literal.svg | 2 +- 18 files changed, 290 insertions(+), 58 deletions(-) create mode 100644 tests/ui/suggestions/case-difference-suggestions.rs create mode 100644 tests/ui/suggestions/case-difference-suggestions.stderr diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 46a4a1868247..55a42d0426e1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -262,19 +262,11 @@ pub trait Emitter { format!("help: {msg}") } else { // Show the default suggestion text with the substitution - format!( - "help: {}{}: `{}`", - msg, - if self - .source_map() - .is_some_and(|sm| is_case_difference(sm, snippet, part.span,)) - { - " (notice the capitalization)" - } else { - "" - }, - snippet, - ) + let confusion_type = self + .source_map() + .map(|sm| detect_confusion_type(sm, snippet, part.span)) + .unwrap_or(ConfusionType::None); + format!("help: {}{}: `{}`", msg, confusion_type.label_text(), snippet,) }; primary_span.push_span_label(part.span, msg); @@ -2028,12 +2020,12 @@ impl HumanEmitter { buffer.append(0, ": ", Style::HeaderMsg); let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)]; - if suggestions - .iter() - .take(MAX_SUGGESTIONS) - .any(|(_, _, _, only_capitalization)| *only_capitalization) + if let Some(confusion_type) = + suggestions.iter().take(MAX_SUGGESTIONS).find_map(|(_, _, _, confusion_type)| { + if confusion_type.has_confusion() { Some(*confusion_type) } else { None } + }) { - msg.push((" (notice the capitalization difference)".into(), Style::NoStyle)); + msg.push((confusion_type.label_text().into(), Style::NoStyle)); } self.msgs_to_buffer( &mut buffer, @@ -3528,24 +3520,107 @@ pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool { } /// Whether the original and suggested code are visually similar enough to warrant extra wording. -pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool { - // FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode. +pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> ConfusionType { let found = match sm.span_to_snippet(sp) { Ok(snippet) => snippet, Err(e) => { warn!(error = ?e, "Invalid span {:?}", sp); - return false; + return ConfusionType::None; } }; - let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; - // All the chars that differ in capitalization are confusable (above): - let confusable = iter::zip(found.chars(), suggested.chars()) - .filter(|(f, s)| f != s) - .all(|(f, s)| ascii_confusables.contains(&f) || ascii_confusables.contains(&s)); - confusable && found.to_lowercase() == suggested.to_lowercase() - // FIXME: We sometimes suggest the same thing we already have, which is a - // bug, but be defensive against that here. - && found != suggested + + let mut has_case_confusion = false; + let mut has_digit_letter_confusion = false; + + if found.len() == suggested.len() { + let mut has_case_diff = false; + let mut has_digit_letter_confusable = false; + let mut has_other_diff = false; + + let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; + + let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')]; + + for (f, s) in iter::zip(found.chars(), suggested.chars()) { + if f != s { + if f.to_lowercase().to_string() == s.to_lowercase().to_string() { + // Check for case differences (any character that differs only in case) + if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) { + has_case_diff = true; + } else { + has_other_diff = true; + } + } else if digit_letter_confusables.contains(&(f, s)) + || digit_letter_confusables.contains(&(s, f)) + { + // Check for digit-letter confusables (like 0 vs O, 1 vs l, etc.) + has_digit_letter_confusable = true; + } else { + has_other_diff = true; + } + } + } + + // If we have case differences and no other differences + if has_case_diff && !has_other_diff && found != suggested { + has_case_confusion = true; + } + if has_digit_letter_confusable && !has_other_diff && found != suggested { + has_digit_letter_confusion = true; + } + } + + match (has_case_confusion, has_digit_letter_confusion) { + (true, true) => ConfusionType::Both, + (true, false) => ConfusionType::Case, + (false, true) => ConfusionType::DigitLetter, + (false, false) => ConfusionType::None, + } +} + +/// Represents the type of confusion detected between original and suggested code. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConfusionType { + /// No confusion detected + None, + /// Only case differences (e.g., "hello" vs "Hello") + Case, + /// Only digit-letter confusion (e.g., "0" vs "O", "1" vs "l") + DigitLetter, + /// Both case and digit-letter confusion + Both, +} + +impl ConfusionType { + /// Returns the appropriate label text for this confusion type. + pub fn label_text(&self) -> &'static str { + match self { + ConfusionType::None => "", + ConfusionType::Case => " (notice the capitalization)", + ConfusionType::DigitLetter => " (notice the digit/letter confusion)", + ConfusionType::Both => " (notice the capitalization and digit/letter confusion)", + } + } + + /// Combines two confusion types. If either is `Both`, the result is `Both`. + /// If one is `Case` and the other is `DigitLetter`, the result is `Both`. + /// Otherwise, returns the non-`None` type, or `None` if both are `None`. + pub fn combine(self, other: ConfusionType) -> ConfusionType { + match (self, other) { + (ConfusionType::None, other) => other, + (this, ConfusionType::None) => this, + (ConfusionType::Both, _) | (_, ConfusionType::Both) => ConfusionType::Both, + (ConfusionType::Case, ConfusionType::DigitLetter) + | (ConfusionType::DigitLetter, ConfusionType::Case) => ConfusionType::Both, + (ConfusionType::Case, ConfusionType::Case) => ConfusionType::Case, + (ConfusionType::DigitLetter, ConfusionType::DigitLetter) => ConfusionType::DigitLetter, + } + } + + /// Returns true if this confusion type represents any kind of confusion. + pub fn has_confusion(&self) -> bool { + *self != ConfusionType::None + } } pub(crate) fn should_show_source_code( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 381d780077d1..2534cddf1057 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -50,7 +50,7 @@ pub use diagnostic_impls::{ IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; -use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; +use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::StableHasher; @@ -308,7 +308,7 @@ impl CodeSuggestion { pub(crate) fn splice_lines( &self, sm: &SourceMap, - ) -> Vec<(String, Vec, Vec>, bool)> { + ) -> Vec<(String, Vec, Vec>, ConfusionType)> { // For the `Vec>` value, the first level of the vector // corresponds to the output snippet's lines, while the second level corresponds to the // substrings within that line that should be highlighted. @@ -414,14 +414,15 @@ impl CodeSuggestion { // We need to keep track of the difference between the existing code and the added // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; - let mut only_capitalization = false; + let mut confusion_type = ConfusionType::None; for part in &mut substitution.parts { // If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the // suggestion and snippet to look as if we just suggested to add // `"b"`, which is typically much easier for the user to understand. part.trim_trivial_replacements(sm); - only_capitalization |= is_case_difference(sm, &part.snippet, part.span); + let part_confusion = detect_confusion_type(sm, &part.snippet, part.span); + confusion_type = confusion_type.combine(part_confusion); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { let mut count = @@ -511,7 +512,7 @@ impl CodeSuggestion { if highlights.iter().all(|parts| parts.is_empty()) { None } else { - Some((buf, substitution.parts, highlights, only_capitalization)) + Some((buf, substitution.parts, highlights, confusion_type)) } }) .collect() diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index 8068edfff947..c2b58b952aaa 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -18,7 +18,7 @@ error: this `match` arm has a differing case than its expression LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ | -help: consider changing the case of this arm to respect `to_ascii_lowercase` (notice the capitalization difference) +help: consider changing the case of this arm to respect `to_ascii_lowercase` (notice the capitalization) | LL - "~!@#$%^&*()-_=+Foo" => {}, LL + "~!@#$%^&*()-_=+foo" => {}, diff --git a/tests/ui/error-codes/E0423.stderr b/tests/ui/error-codes/E0423.stderr index e50b8bd820cf..b699e53fb480 100644 --- a/tests/ui/error-codes/E0423.stderr +++ b/tests/ui/error-codes/E0423.stderr @@ -54,7 +54,7 @@ help: use struct literal syntax instead LL - let f = Foo(); LL + let f = Foo { a: val }; | -help: a function with a similar name exists (notice the capitalization difference) +help: a function with a similar name exists (notice the capitalization) | LL - let f = Foo(); LL + let f = foo(); diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr index 7c7e573a88ed..b34be31216d3 100644 --- a/tests/ui/lint/lint-non-uppercase-usages.stderr +++ b/tests/ui/lint/lint-non-uppercase-usages.stderr @@ -29,7 +29,7 @@ warning: const parameter `foo` should have an upper case name LL | fn foo() { | ^^^ | -help: convert the identifier to upper case (notice the capitalization difference) +help: convert the identifier to upper case (notice the capitalization) | LL - fn foo() { LL + fn foo() { diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr index df39eb10fdbe..d2a1eb7f2f52 100644 --- a/tests/ui/parser/item-kw-case-mismatch.stderr +++ b/tests/ui/parser/item-kw-case-mismatch.stderr @@ -4,7 +4,7 @@ error: keyword `use` is written in the wrong case LL | Use std::ptr::read; | ^^^ | -help: write it in the correct case (notice the capitalization difference) +help: write it in the correct case (notice the capitalization) | LL - Use std::ptr::read; LL + use std::ptr::read; @@ -28,7 +28,7 @@ error: keyword `fn` is written in the wrong case LL | async Fn _a() {} | ^^ | -help: write it in the correct case (notice the capitalization difference) +help: write it in the correct case (notice the capitalization) | LL - async Fn _a() {} LL + async fn _a() {} @@ -40,7 +40,7 @@ error: keyword `fn` is written in the wrong case LL | Fn _b() {} | ^^ | -help: write it in the correct case (notice the capitalization difference) +help: write it in the correct case (notice the capitalization) | LL - Fn _b() {} LL + fn _b() {} diff --git a/tests/ui/parser/kw-in-trait-bounds.stderr b/tests/ui/parser/kw-in-trait-bounds.stderr index 1892d0b62265..5a4adf3e37b4 100644 --- a/tests/ui/parser/kw-in-trait-bounds.stderr +++ b/tests/ui/parser/kw-in-trait-bounds.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn _f(_: impl fn(), _: &dyn fn()) LL + fn _f(_: impl fn(), _: &dyn fn()) @@ -16,7 +16,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn _f(_: impl fn(), _: &dyn fn()) LL + fn _f(_: impl Fn(), _: &dyn fn()) @@ -28,7 +28,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn _f(_: impl fn(), _: &dyn fn()) LL + fn _f(_: impl fn(), _: &dyn Fn()) @@ -40,7 +40,7 @@ error: expected identifier, found keyword `fn` LL | G: fn(), | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - G: fn(), LL + G: Fn(), diff --git a/tests/ui/parser/misspelled-keywords/hrdt.stderr b/tests/ui/parser/misspelled-keywords/hrdt.stderr index e5fc1a503820..497bd613bf45 100644 --- a/tests/ui/parser/misspelled-keywords/hrdt.stderr +++ b/tests/ui/parser/misspelled-keywords/hrdt.stderr @@ -4,7 +4,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found keyword LL | Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, | ^^^ expected one of 7 possible tokens | -help: write keyword `where` in lowercase (notice the capitalization difference) +help: write keyword `where` in lowercase (notice the capitalization) | LL - Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, LL + where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, diff --git a/tests/ui/parser/misspelled-keywords/impl-return.stderr b/tests/ui/parser/misspelled-keywords/impl-return.stderr index ff5391461a9f..d49d962d7e95 100644 --- a/tests/ui/parser/misspelled-keywords/impl-return.stderr +++ b/tests/ui/parser/misspelled-keywords/impl-return.stderr @@ -4,7 +4,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Display LL | fn code() -> Impl Display {} | ^^^^^^^ expected one of 7 possible tokens | -help: write keyword `impl` in lowercase (notice the capitalization difference) +help: write keyword `impl` in lowercase (notice the capitalization) | LL - fn code() -> Impl Display {} LL + fn code() -> impl Display {} diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr index e559f2be1091..0df40bcdc33b 100644 --- a/tests/ui/parser/misspelled-keywords/static.stderr +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -4,7 +4,7 @@ error: expected one of `!` or `::`, found `a` LL | Static a = 0; | ^ expected one of `!` or `::` | -help: write keyword `static` in lowercase (notice the capitalization difference) +help: write keyword `static` in lowercase (notice the capitalization) | LL - Static a = 0; LL + static a = 0; diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr index edbec3b9456b..af8614ef14b7 100644 --- a/tests/ui/parser/misspelled-keywords/struct.stderr +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -4,7 +4,7 @@ error: expected one of `!` or `::`, found `Foor` LL | Struct Foor { | ^^^^ expected one of `!` or `::` | -help: write keyword `struct` in lowercase (notice the capitalization difference) +help: write keyword `struct` in lowercase (notice the capitalization) | LL - Struct Foor { LL + struct Foor { diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr index 4e1fcaf49368..bd809e77a8f9 100644 --- a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr +++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn foo(_: impl fn() -> i32) {} | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn foo(_: impl fn() -> i32) {} LL + fn foo(_: impl Fn() -> i32) {} @@ -16,7 +16,7 @@ error: expected identifier, found keyword `fn` LL | fn foo2(_: T) {} | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn foo2(_: T) {} LL + fn foo2(_: T) {} diff --git a/tests/ui/parser/typod-const-in-const-param-def.stderr b/tests/ui/parser/typod-const-in-const-param-def.stderr index bf7168a01573..cc1600fe5cb8 100644 --- a/tests/ui/parser/typod-const-in-const-param-def.stderr +++ b/tests/ui/parser/typod-const-in-const-param-def.stderr @@ -4,7 +4,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn foo() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn foo() {} LL + pub fn foo() {} @@ -16,7 +16,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn baz() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn baz() {} LL + pub fn baz() {} @@ -28,7 +28,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn qux() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn qux() {} LL + pub fn qux() {} @@ -40,7 +40,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn quux() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn quux() {} LL + pub fn quux() {} diff --git a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr index 6d6fd9830384..47efe69cfc21 100644 --- a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr +++ b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr @@ -8,7 +8,7 @@ LL | let x: i32 = MyS::foo; | = note: expected type `i32` found fn item `fn() -> MyS {MyS::foo}` -help: try referring to the associated const `FOO` instead (notice the capitalization difference) +help: try referring to the associated const `FOO` instead (notice the capitalization) | LL - let x: i32 = MyS::foo; LL + let x: i32 = MyS::FOO; diff --git a/tests/ui/suggestions/bool_typo_err_suggest.stderr b/tests/ui/suggestions/bool_typo_err_suggest.stderr index faf799d0fda2..d46ce1ad8a9b 100644 --- a/tests/ui/suggestions/bool_typo_err_suggest.stderr +++ b/tests/ui/suggestions/bool_typo_err_suggest.stderr @@ -16,7 +16,7 @@ error[E0425]: cannot find value `False` in this scope LL | let y = False; | ^^^^^ not found in this scope | -help: you may want to use a bool value instead (notice the capitalization difference) +help: you may want to use a bool value instead (notice the capitalization) | LL - let y = False; LL + let y = false; diff --git a/tests/ui/suggestions/case-difference-suggestions.rs b/tests/ui/suggestions/case-difference-suggestions.rs new file mode 100644 index 000000000000..d554b6e93673 --- /dev/null +++ b/tests/ui/suggestions/case-difference-suggestions.rs @@ -0,0 +1,57 @@ +fn main() { + + // Simple case difference, no hit + let hello = "hello"; + println!("{}", Hello); //~ ERROR cannot find value `Hello` in this scope + + // Multiple case differences, hit + let myVariable = 10; + println!("{}", myvariable); //~ ERROR cannot find value `myvariable` in this scope + + // Case difference with special characters, hit + let user_name = "john"; + println!("{}", User_Name); //~ ERROR cannot find value `User_Name` in this scope + + // All uppercase vs all lowercase, hit + let FOO = 42; + println!("{}", foo); //~ ERROR cannot find value `foo` in this scope + + + // 0 vs O + let FFO0 = 100; + println!("{}", FFOO); //~ ERROR cannot find value `FFOO` in this scope + + let l1st = vec![1, 2, 3]; + println!("{}", list); //~ ERROR cannot find value `list` in this scope + + let S5 = "test"; + println!("{}", SS); //~ ERROR cannot find value `SS` in this scope + + let aS5 = "test"; + println!("{}", a55); //~ ERROR cannot find value `a55` in this scope + + let B8 = 8; + println!("{}", BB); //~ ERROR cannot find value `BB` in this scope + + let g9 = 9; + println!("{}", gg); //~ ERROR cannot find value `gg` in this scope + + let o1d = "old"; + println!("{}", old); //~ ERROR cannot find value `old` in this scope + + let new1 = "new"; + println!("{}", newl); //~ ERROR cannot find value `newl` in this scope + + let apple = "apple"; + println!("{}", app1e); //~ ERROR cannot find value `app1e` in this scope + + let a = 1; + println!("{}", A); //~ ERROR cannot find value `A` in this scope + + let worldlu = "world"; + println!("{}", world1U); //~ ERROR cannot find value `world1U` in this scope + + let myV4rlable = 42; + println!("{}", myv4r1able); //~ ERROR cannot find value `myv4r1able` in this scope + +} diff --git a/tests/ui/suggestions/case-difference-suggestions.stderr b/tests/ui/suggestions/case-difference-suggestions.stderr new file mode 100644 index 000000000000..c3d2410a6eb2 --- /dev/null +++ b/tests/ui/suggestions/case-difference-suggestions.stderr @@ -0,0 +1,99 @@ +error[E0425]: cannot find value `Hello` in this scope + --> $DIR/case-difference-suggestions.rs:5:20 + | +LL | println!("{}", Hello); + | ^^^^^ help: a local variable with a similar name exists: `hello` + +error[E0425]: cannot find value `myvariable` in this scope + --> $DIR/case-difference-suggestions.rs:9:20 + | +LL | println!("{}", myvariable); + | ^^^^^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `myVariable` + +error[E0425]: cannot find value `User_Name` in this scope + --> $DIR/case-difference-suggestions.rs:13:20 + | +LL | println!("{}", User_Name); + | ^^^^^^^^^ help: a local variable with a similar name exists: `user_name` + +error[E0425]: cannot find value `foo` in this scope + --> $DIR/case-difference-suggestions.rs:17:20 + | +LL | println!("{}", foo); + | ^^^ help: a local variable with a similar name exists (notice the capitalization): `FOO` + +error[E0425]: cannot find value `FFOO` in this scope + --> $DIR/case-difference-suggestions.rs:22:20 + | +LL | println!("{}", FFOO); + | ^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `FFO0` + +error[E0425]: cannot find value `list` in this scope + --> $DIR/case-difference-suggestions.rs:25:20 + | +LL | println!("{}", list); + | ^^^^ help: a local variable with a similar name exists: `l1st` + +error[E0425]: cannot find value `SS` in this scope + --> $DIR/case-difference-suggestions.rs:28:20 + | +LL | println!("{}", SS); + | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `S5` + +error[E0425]: cannot find value `a55` in this scope + --> $DIR/case-difference-suggestions.rs:31:20 + | +LL | println!("{}", a55); + | ^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `aS5` + +error[E0425]: cannot find value `BB` in this scope + --> $DIR/case-difference-suggestions.rs:34:20 + | +LL | println!("{}", BB); + | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `B8` + +error[E0425]: cannot find value `gg` in this scope + --> $DIR/case-difference-suggestions.rs:37:20 + | +LL | println!("{}", gg); + | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `g9` + +error[E0425]: cannot find value `old` in this scope + --> $DIR/case-difference-suggestions.rs:40:20 + | +LL | println!("{}", old); + | ^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `o1d` + +error[E0425]: cannot find value `newl` in this scope + --> $DIR/case-difference-suggestions.rs:43:20 + | +LL | println!("{}", newl); + | ^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `new1` + +error[E0425]: cannot find value `app1e` in this scope + --> $DIR/case-difference-suggestions.rs:46:20 + | +LL | println!("{}", app1e); + | ^^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `apple` + +error[E0425]: cannot find value `A` in this scope + --> $DIR/case-difference-suggestions.rs:49:20 + | +LL | println!("{}", A); + | ^ help: a local variable with a similar name exists: `a` + +error[E0425]: cannot find value `world1U` in this scope + --> $DIR/case-difference-suggestions.rs:52:20 + | +LL | println!("{}", world1U); + | ^^^^^^^ help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion): `worldlu` + +error[E0425]: cannot find value `myv4r1able` in this scope + --> $DIR/case-difference-suggestions.rs:55:20 + | +LL | println!("{}", myv4r1able); + | ^^^^^^^^^^ help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion): `myV4rlable` + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/incorrect-variant-literal.svg b/tests/ui/suggestions/incorrect-variant-literal.svg index 279fd30f2165..2cab1f4b60f6 100644 --- a/tests/ui/suggestions/incorrect-variant-literal.svg +++ b/tests/ui/suggestions/incorrect-variant-literal.svg @@ -455,7 +455,7 @@ | - help: there is a variant with a similar name (notice the capitalization difference) + help: there is a variant with a similar name (notice the capitalization) | From 897168169d3372056988ba5f37f2210855bc7c4a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 31 Jul 2025 09:26:05 +0200 Subject: [PATCH 107/242] Properly clean proc-macro-srv proc-macro temp dir --- src/tools/rust-analyzer/Cargo.lock | 84 +++++++++++++++++++ .../crates/proc-macro-srv-cli/Cargo.toml | 3 + .../crates/proc-macro-srv-cli/src/main.rs | 3 + .../proc-macro-srv-cli/src/main_loop.rs | 5 +- .../crates/proc-macro-srv/Cargo.toml | 2 + .../crates/proc-macro-srv/src/dylib.rs | 22 +++-- .../crates/proc-macro-srv/src/lib.rs | 22 +++-- .../crates/proc-macro-srv/src/tests/utils.rs | 2 +- 8 files changed, 125 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 0cbbb5dd6de7..53c2d044bbd2 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -50,6 +50,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -125,6 +134,12 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26c4925bc979b677330a8c7fe7a8c94af2dbb4a2d37b4a20a80d884400f46baa" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "camino" version = "1.1.10" @@ -318,6 +333,15 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.12", +] + [[package]] name = "countme" version = "3.0.1" @@ -339,6 +363,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -596,6 +626,15 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -622,6 +661,20 @@ dependencies = [ "hashbrown 0.15.4", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "hermit-abi" version = "0.5.2" @@ -1592,6 +1645,17 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "heapless", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -1639,6 +1703,7 @@ dependencies = [ "ra-ap-rustc_lexer 0.122.0", "span", "syntax-bridge", + "temp-dir", "tt", ] @@ -1647,6 +1712,7 @@ name = "proc-macro-srv-cli" version = "0.0.0" dependencies = [ "clap", + "postcard", "proc-macro-api", "proc-macro-srv", "tt", @@ -2023,6 +2089,15 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.20" @@ -2240,6 +2315,15 @@ dependencies = [ "vfs", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml index 16ec3b0e2b2a..91e9e62b084b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml @@ -15,10 +15,13 @@ proc-macro-srv.workspace = true proc-macro-api.workspace = true tt.workspace = true clap = {version = "4.5.42", default-features = false, features = ["std"]} +postcard = { version = "1.1.3", optional = true } [features] +default = ["postcard"] sysroot-abi = ["proc-macro-srv/sysroot-abi"] in-rust-tree = ["proc-macro-srv/in-rust-tree", "sysroot-abi"] +postcard = ["dep:postcard"] [[bin]] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs index b6ebc562eac9..97a622e453dd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs @@ -39,6 +39,7 @@ fn main() -> std::io::Result<()> { #[derive(Copy, Clone)] enum ProtocolFormat { Json, + #[cfg(feature = "postcard")] Postcard, } @@ -50,12 +51,14 @@ impl ValueEnum for ProtocolFormat { fn to_possible_value(&self) -> Option { match self { ProtocolFormat::Json => Some(clap::builder::PossibleValue::new("json")), + #[cfg(feature = "postcard")] ProtocolFormat::Postcard => Some(clap::builder::PossibleValue::new("postcard")), } } fn from_str(input: &str, _ignore_case: bool) -> Result { match input { "json" => Ok(ProtocolFormat::Json), + #[cfg(feature = "postcard")] "postcard" => Ok(ProtocolFormat::Postcard), _ => Err(format!("unknown protocol format: {input}")), } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 6bf58eef3bb9..46be8a21004d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -37,6 +37,7 @@ impl SpanTransformer for SpanTrans { pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> { match format { ProtocolFormat::Json => run_json(), + #[cfg(feature = "postcard")] ProtocolFormat::Postcard => unimplemented!(), } } @@ -96,7 +97,7 @@ fn run_json() -> io::Result<()> { srv.expand( lib, - env, + &env, current_dir, macro_name, macro_body, @@ -127,7 +128,7 @@ fn run_json() -> io::Result<()> { }); srv.expand( lib, - env, + &env, current_dir, macro_name, macro_body, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 4034f244393b..d037e715e703 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -16,6 +16,7 @@ doctest = false object.workspace = true libloading.workspace = true memmap2.workspace = true +temp-dir.workspace = true tt.workspace = true syntax-bridge.workspace = true @@ -26,6 +27,7 @@ intern.workspace = true ra-ap-rustc_lexer.workspace = true + [target.'cfg(unix)'.dependencies] libc.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index c49159df9916..095e9fa2e98e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -4,6 +4,7 @@ mod version; use proc_macro::bridge; use std::{fmt, fs, io, time::SystemTime}; +use temp_dir::TempDir; use libloading::Library; use object::Object; @@ -141,13 +142,16 @@ pub(crate) struct Expander { } impl Expander { - pub(crate) fn new(lib: &Utf8Path) -> Result { + pub(crate) fn new( + temp_dir: &TempDir, + lib: &Utf8Path, + ) -> Result { // Some libraries for dynamic loading require canonicalized path even when it is // already absolute let lib = lib.canonicalize_utf8()?; let modified_time = fs::metadata(&lib).and_then(|it| it.modified())?; - let path = ensure_file_with_lock_free_access(&lib)?; + let path = ensure_file_with_lock_free_access(temp_dir, &lib)?; let library = ProcMacroLibrary::open(path.as_ref())?; Ok(Expander { inner: library, _remove_on_drop: RemoveFileOnDrop(path), modified_time }) @@ -221,7 +225,10 @@ impl Drop for RemoveFileOnDrop { /// Copy the dylib to temp directory to prevent locking in Windows #[cfg(windows)] -fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result { +fn ensure_file_with_lock_free_access( + temp_dir: &TempDir, + path: &Utf8Path, +) -> io::Result { use std::collections::hash_map::RandomState; use std::hash::{BuildHasher, Hasher}; @@ -229,9 +236,7 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result return Ok(path.to_path_buf()); } - let mut to = Utf8PathBuf::from_path_buf(std::env::temp_dir()).unwrap(); - to.push("rust-analyzer-proc-macros"); - _ = fs::create_dir(&to); + let mut to = Utf8Path::from_path(temp_dir.path()).unwrap().to_owned(); let file_name = path.file_stem().ok_or_else(|| { io::Error::new(io::ErrorKind::InvalidInput, format!("File path is invalid: {path}")) @@ -248,6 +253,9 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result } #[cfg(unix)] -fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result { +fn ensure_file_with_lock_free_access( + _temp_dir: &TempDir, + path: &Utf8Path, +) -> io::Result { Ok(path.to_owned()) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 0f7c83979d56..29fe5aed2b1f 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -42,6 +42,7 @@ use std::{ use paths::{Utf8Path, Utf8PathBuf}; use span::Span; +use temp_dir::TempDir; use crate::server_impl::TokenStream; @@ -59,11 +60,16 @@ pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); pub struct ProcMacroSrv<'env> { expanders: Mutex>>, env: &'env EnvSnapshot, + temp_dir: TempDir, } impl<'env> ProcMacroSrv<'env> { pub fn new(env: &'env EnvSnapshot) -> Self { - Self { expanders: Default::default(), env } + Self { + expanders: Default::default(), + env, + temp_dir: TempDir::with_prefix("proc-macro-srv").unwrap(), + } } } @@ -73,7 +79,7 @@ impl ProcMacroSrv<'_> { pub fn expand( &self, lib: impl AsRef, - env: Vec<(String, String)>, + env: &[(String, String)], current_dir: Option>, macro_name: String, macro_body: tt::TopSubtree, @@ -131,7 +137,7 @@ impl ProcMacroSrv<'_> { fn expander(&self, path: &Utf8Path) -> Result, String> { let expander = || { - let expander = dylib::Expander::new(path) + let expander = dylib::Expander::new(&self.temp_dir, path) .map_err(|err| format!("Cannot create expander for {path}: {err}",)); expander.map(Arc::new) }; @@ -203,7 +209,7 @@ impl Default for EnvSnapshot { static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); struct EnvChange<'snap> { - changed_vars: Vec, + changed_vars: Vec<&'snap str>, prev_working_dir: Option, snap: &'snap EnvSnapshot, _guard: std::sync::MutexGuard<'snap, ()>, @@ -212,7 +218,7 @@ struct EnvChange<'snap> { impl<'snap> EnvChange<'snap> { fn apply( snap: &'snap EnvSnapshot, - new_vars: Vec<(String, String)>, + new_vars: &'snap [(String, String)], current_dir: Option<&Path>, ) -> EnvChange<'snap> { let guard = ENV_LOCK.lock().unwrap_or_else(std::sync::PoisonError::into_inner); @@ -232,11 +238,11 @@ impl<'snap> EnvChange<'snap> { EnvChange { snap, changed_vars: new_vars - .into_iter() + .iter() .map(|(k, v)| { // SAFETY: We have acquired the environment lock - unsafe { env::set_var(&k, v) }; - k + unsafe { env::set_var(k, v) }; + &**k }) .collect(), prev_working_dir, diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs index 7aa38576bb52..f5a76e30bbcb 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs @@ -55,7 +55,7 @@ fn assert_expand_impl( expect_spanned: Expect, ) { let path = proc_macro_test_dylib_path(); - let expander = dylib::Expander::new(&path).unwrap(); + let expander = dylib::Expander::new(&temp_dir::TempDir::new().unwrap(), &path).unwrap(); let def_site = SpanId(0); let call_site = SpanId(1); From 1975c98b73fd8ed79792557605f76ce053710dd8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 31 Jul 2025 09:53:26 +0200 Subject: [PATCH 108/242] Reorganize proc-macro-srv --- .../proc-macro-srv-cli/src/main_loop.rs | 10 +- .../crates/proc-macro-srv/src/dylib.rs | 203 +++++++++--------- .../src/{ => dylib}/proc_macros.rs | 23 +- .../crates/proc-macro-srv/src/lib.rs | 41 ++-- .../crates/proc-macro-srv/src/server_impl.rs | 2 +- 5 files changed, 131 insertions(+), 148 deletions(-) rename src/tools/rust-analyzer/crates/proc-macro-srv/src/{ => dylib}/proc_macros.rs (81%) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs index 46be8a21004d..703bc965db25 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs @@ -24,13 +24,13 @@ impl SpanTransformer for SpanTrans { _: &mut Self::Table, span: Self::Span, ) -> proc_macro_api::legacy_protocol::SpanId { - proc_macro_api::legacy_protocol::SpanId(span.0 as u32) + proc_macro_api::legacy_protocol::SpanId(span.0) } fn span_for_token_id( _: &Self::Table, id: proc_macro_api::legacy_protocol::SpanId, ) -> Self::Span { - SpanId(id.0 as u32) + SpanId(id.0) } } @@ -99,7 +99,7 @@ fn run_json() -> io::Result<()> { lib, &env, current_dir, - macro_name, + ¯o_name, macro_body, attributes, def_site, @@ -112,6 +112,7 @@ fn run_json() -> io::Result<()> { CURRENT_API_VERSION, ) }) + .map_err(|e| e.into_string().unwrap_or_default()) .map_err(msg::PanicMessage) }), SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({ @@ -130,7 +131,7 @@ fn run_json() -> io::Result<()> { lib, &env, current_dir, - macro_name, + ¯o_name, macro_body, attributes, def_site, @@ -151,6 +152,7 @@ fn run_json() -> io::Result<()> { tree, span_data_table, }) + .map_err(|e| e.into_string().unwrap_or_default()) .map_err(msg::PanicMessage) }), } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index 095e9fa2e98e..c8513a10675d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -1,5 +1,6 @@ //! Handles dynamic library loading for proc macro +mod proc_macros; mod version; use proc_macro::bridge; @@ -10,57 +11,56 @@ use libloading::Library; use object::Object; use paths::{Utf8Path, Utf8PathBuf}; -use crate::{ProcMacroKind, ProcMacroSrvSpan, proc_macros::ProcMacros, server_impl::TopSubtree}; +use crate::{ + PanicMessage, ProcMacroKind, ProcMacroSrvSpan, dylib::proc_macros::ProcMacros, + server_impl::TopSubtree, +}; -/// Loads dynamic library in platform dependent manner. -/// -/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) -/// and [here](https://github.com/rust-lang/rust/issues/60593). -/// -/// Usage of RTLD_DEEPBIND -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) -/// -/// It seems that on Windows that behaviour is default, so we do nothing in that case. -/// -/// # Safety -/// -/// The caller is responsible for ensuring that the path is valid proc-macro library -#[cfg(windows)] -unsafe fn load_library(file: &Utf8Path) -> Result { - // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library - unsafe { Library::new(file) } +pub(crate) struct Expander { + inner: ProcMacroLibrary, + modified_time: SystemTime, } -/// Loads dynamic library in platform dependent manner. -/// -/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) -/// and [here](https://github.com/rust-lang/rust/issues/60593). -/// -/// Usage of RTLD_DEEPBIND -/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) -/// -/// It seems that on Windows that behaviour is default, so we do nothing in that case. -/// -/// # Safety -/// -/// The caller is responsible for ensuring that the path is valid proc-macro library -#[cfg(unix)] -unsafe fn load_library(file: &Utf8Path) -> Result { - // not defined by POSIX, different values on mips vs other targets - #[cfg(target_env = "gnu")] - use libc::RTLD_DEEPBIND; - use libloading::os::unix::Library as UnixLibrary; - // defined by POSIX - use libloading::os::unix::RTLD_NOW; +impl Expander { + pub(crate) fn new( + temp_dir: &TempDir, + lib: &Utf8Path, + ) -> Result { + // Some libraries for dynamic loading require canonicalized path even when it is + // already absolute + let lib = lib.canonicalize_utf8()?; + let modified_time = fs::metadata(&lib).and_then(|it| it.modified())?; - // MUSL and bionic don't have it.. - #[cfg(not(target_env = "gnu"))] - const RTLD_DEEPBIND: std::os::raw::c_int = 0x0; + let path = ensure_file_with_lock_free_access(temp_dir, &lib)?; + let library = ProcMacroLibrary::open(path.as_ref())?; - // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library - unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) } + Ok(Expander { inner: library, modified_time }) + } + + pub(crate) fn expand( + &self, + macro_name: &str, + macro_body: TopSubtree, + attributes: Option>, + def_site: S, + call_site: S, + mixed_site: S, + ) -> Result, PanicMessage> + where + ::TokenStream: Default, + { + self.inner + .proc_macros + .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site) + } + + pub(crate) fn list_macros(&self) -> impl Iterator { + self.inner.proc_macros.list_macros() + } + + pub(crate) fn modified_time(&self) -> SystemTime { + self.modified_time + } } #[derive(Debug)] @@ -134,57 +134,6 @@ impl ProcMacroLibrary { } } -// Drop order matters as we can't remove the dylib before the library is unloaded -pub(crate) struct Expander { - inner: ProcMacroLibrary, - _remove_on_drop: RemoveFileOnDrop, - modified_time: SystemTime, -} - -impl Expander { - pub(crate) fn new( - temp_dir: &TempDir, - lib: &Utf8Path, - ) -> Result { - // Some libraries for dynamic loading require canonicalized path even when it is - // already absolute - let lib = lib.canonicalize_utf8()?; - let modified_time = fs::metadata(&lib).and_then(|it| it.modified())?; - - let path = ensure_file_with_lock_free_access(temp_dir, &lib)?; - let library = ProcMacroLibrary::open(path.as_ref())?; - - Ok(Expander { inner: library, _remove_on_drop: RemoveFileOnDrop(path), modified_time }) - } - - pub(crate) fn expand( - &self, - macro_name: &str, - macro_body: TopSubtree, - attributes: Option>, - def_site: S, - call_site: S, - mixed_site: S, - ) -> Result, String> - where - ::TokenStream: Default, - { - let result = self - .inner - .proc_macros - .expand(macro_name, macro_body, attributes, def_site, call_site, mixed_site); - result.map_err(|e| e.into_string().unwrap_or_default()) - } - - pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.inner.proc_macros.list_macros() - } - - pub(crate) fn modified_time(&self) -> SystemTime { - self.modified_time - } -} - fn invalid_data_err(e: impl Into>) -> io::Error { io::Error::new(io::ErrorKind::InvalidData, e) } @@ -214,15 +163,6 @@ fn find_registrar_symbol(obj: &object::File<'_>) -> object::Result io::Result { Ok(path.to_owned()) } + +/// Loads dynamic library in platform dependent manner. +/// +/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described +/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) +/// and [here](https://github.com/rust-lang/rust/issues/60593). +/// +/// Usage of RTLD_DEEPBIND +/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) +/// +/// It seems that on Windows that behaviour is default, so we do nothing in that case. +/// +/// # Safety +/// +/// The caller is responsible for ensuring that the path is valid proc-macro library +#[cfg(windows)] +unsafe fn load_library(file: &Utf8Path) -> Result { + // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library + unsafe { Library::new(file) } +} + +/// Loads dynamic library in platform dependent manner. +/// +/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described +/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) +/// and [here](https://github.com/rust-lang/rust/issues/60593). +/// +/// Usage of RTLD_DEEPBIND +/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) +/// +/// It seems that on Windows that behaviour is default, so we do nothing in that case. +/// +/// # Safety +/// +/// The caller is responsible for ensuring that the path is valid proc-macro library +#[cfg(unix)] +unsafe fn load_library(file: &Utf8Path) -> Result { + // not defined by POSIX, different values on mips vs other targets + #[cfg(target_env = "gnu")] + use libc::RTLD_DEEPBIND; + use libloading::os::unix::Library as UnixLibrary; + // defined by POSIX + use libloading::os::unix::RTLD_NOW; + + // MUSL and bionic don't have it.. + #[cfg(not(target_env = "gnu"))] + const RTLD_DEEPBIND: std::os::raw::c_int = 0x0; + + // SAFETY: The caller is responsible for ensuring that the path is valid proc-macro library + unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) } +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs similarity index 81% rename from src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs rename to src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs index 18532706c4aa..9b5721e370ac 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs @@ -75,20 +75,13 @@ impl ProcMacros { Err(bridge::PanicMessage::String(format!("proc-macro `{macro_name}` is missing")).into()) } - pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { - self.0 - .iter() - .map(|proc_macro| match proc_macro { - bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { - (trait_name.to_string(), ProcMacroKind::CustomDerive) - } - bridge::client::ProcMacro::Bang { name, .. } => { - (name.to_string(), ProcMacroKind::Bang) - } - bridge::client::ProcMacro::Attr { name, .. } => { - (name.to_string(), ProcMacroKind::Attr) - } - }) - .collect() + pub(crate) fn list_macros(&self) -> impl Iterator { + self.0.iter().map(|proc_macro| match *proc_macro { + bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { + (trait_name, ProcMacroKind::CustomDerive) + } + bridge::client::ProcMacro::Bang { name, .. } => (name, ProcMacroKind::Bang), + bridge::client::ProcMacro::Attr { name, .. } => (name, ProcMacroKind::Attr), + }) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 29fe5aed2b1f..cb97882c5854 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -27,7 +27,6 @@ extern crate ra_ap_rustc_lexer as rustc_lexer; extern crate rustc_lexer; mod dylib; -mod proc_macros; mod server_impl; use std::{ @@ -81,16 +80,17 @@ impl ProcMacroSrv<'_> { lib: impl AsRef, env: &[(String, String)], current_dir: Option>, - macro_name: String, + macro_name: &str, macro_body: tt::TopSubtree, attribute: Option>, def_site: S, call_site: S, mixed_site: S, - ) -> Result>, String> { + ) -> Result>, PanicMessage> { let snapped_env = self.env; - let expander = - self.expander(lib.as_ref()).map_err(|err| format!("failed to load macro: {err}"))?; + let expander = self.expander(lib.as_ref()).map_err(|err| PanicMessage { + message: Some(format!("failed to load macro: {err}")), + })?; let prev_env = EnvChange::apply(snapped_env, env, current_dir.as_ref().map(<_>::as_ref)); @@ -99,11 +99,11 @@ impl ProcMacroSrv<'_> { let result = thread::scope(|s| { let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) - .name(macro_name.clone()) + .name(macro_name.to_owned()) .spawn_scoped(s, move || { expander .expand( - ¯o_name, + macro_name, server_impl::TopSubtree(macro_body.0.into_vec()), attribute.map(|it| server_impl::TopSubtree(it.0.into_vec())), def_site, @@ -112,12 +112,7 @@ impl ProcMacroSrv<'_> { ) .map(|tt| tt.0) }); - let res = match thread { - Ok(handle) => handle.join(), - Err(e) => return Err(e.to_string()), - }; - - match res { + match thread.unwrap().join() { Ok(res) => res, Err(e) => std::panic::resume_unwind(e), } @@ -132,7 +127,7 @@ impl ProcMacroSrv<'_> { dylib_path: &Utf8Path, ) -> Result, String> { let expander = self.expander(dylib_path)?; - Ok(expander.list_macros()) + Ok(expander.list_macros().map(|(k, v)| (k.to_owned(), v)).collect()) } fn expander(&self, path: &Utf8Path) -> Result, String> { @@ -186,6 +181,8 @@ impl ProcMacroSrvSpan for Span { } } } + +#[derive(Debug, Clone)] pub struct PanicMessage { message: Option, } @@ -265,14 +262,14 @@ impl Drop for EnvChange<'_> { } } - if let Some(dir) = &self.prev_working_dir { - if let Err(err) = std::env::set_current_dir(dir) { - eprintln!( - "Failed to set the current working dir to {}. Error: {:?}", - dir.display(), - err - ) - } + if let Some(dir) = &self.prev_working_dir + && let Err(err) = std::env::set_current_dir(dir) + { + eprintln!( + "Failed to set the current working dir to {}. Error: {:?}", + dir.display(), + err + ) } } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index 662f6257642f..32ad32731ba6 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs @@ -209,7 +209,7 @@ pub(super) fn from_token_tree( token_trees.push(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { spacing: tt::Spacing::Alone, span: literal.span, - char: '-' as char, + char: '-', }))); symbol = Symbol::intern(&symbol.as_str()[1..]); } From 7543395f9540a1d6f9e1f9e390b457e3cfe5ee04 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 31 Jul 2025 10:04:42 +0200 Subject: [PATCH 109/242] Add version command to proc-macro-srv --- .../crates/proc-macro-api/src/process.rs | 27 +++++---- .../crates/proc-macro-srv-cli/build.rs | 48 ++++++++++++++- .../crates/proc-macro-srv-cli/src/main.rs | 24 ++++++-- .../crates/proc-macro-srv-cli/src/version.rs | 58 +++++++++++++++++++ 4 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs index 278d9cbcda46..fe274a027a80 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs @@ -63,16 +63,25 @@ impl ProcMacroServerProcess { let mut srv = create_srv()?; tracing::info!("sending proc-macro server version check"); match srv.version_check() { - Ok(v) if v > version::CURRENT_API_VERSION => Err(io::Error::other( - format!( "The version of the proc-macro server ({v}) in your Rust toolchain is newer than the version supported by your rust-analyzer ({}). - This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain." - ,version::CURRENT_API_VERSION - ), - )), + Ok(v) if v > version::CURRENT_API_VERSION => { + #[allow(clippy::disallowed_methods)] + let process_version = Command::new(process_path) + .arg("--version") + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).trim().to_owned()) + .unwrap_or_else(|_| "unknown version".to_owned()); + Err(io::Error::other(format!( + "Your installed proc-macro server is too new for your rust-analyzer. API version: {}, server version: {process_version}. \ + This will prevent proc-macro expansion from working. Please consider updating your rust-analyzer to ensure compatibility with your current toolchain.", + version::CURRENT_API_VERSION + ))) + } Ok(v) => { tracing::info!("Proc-macro server version: {v}"); srv.version = v; - if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT && let Ok(mode) = srv.enable_rust_analyzer_spans() { + if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT + && let Ok(mode) = srv.enable_rust_analyzer_spans() + { srv.protocol = Protocol::LegacyJson { mode }; } tracing::info!("Proc-macro server protocol: {:?}", srv.protocol); @@ -80,9 +89,7 @@ impl ProcMacroServerProcess { } Err(e) => { tracing::info!(%e, "proc-macro version check failed"); - Err( - io::Error::other(format!("proc-macro server version check failed: {e}")), - ) + Err(io::Error::other(format!("proc-macro server version check failed: {e}"))) } } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs index 07f914fece0e..12e7c8b05bac 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/build.rs @@ -1,5 +1,49 @@ -//! This teaches cargo about our cfg(rust_analyzer) +//! Construct version in the `commit-hash date channel` format + +use std::{env, path::PathBuf, process::Command}; fn main() { - println!("cargo:rustc-check-cfg=cfg(rust_analyzer)"); + set_rerun(); + set_commit_info(); + println!("cargo::rustc-check-cfg=cfg(rust_analyzer)"); +} + +fn set_rerun() { + println!("cargo:rerun-if-env-changed=CFG_RELEASE"); + + let mut manifest_dir = PathBuf::from( + env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is always set by cargo."), + ); + + while manifest_dir.parent().is_some() { + let head_ref = manifest_dir.join(".git/HEAD"); + if head_ref.exists() { + println!("cargo:rerun-if-changed={}", head_ref.display()); + return; + } + + manifest_dir.pop(); + } + + println!("cargo:warning=Could not find `.git/HEAD` from manifest dir!"); +} + +fn set_commit_info() { + #[allow(clippy::disallowed_methods)] + let output = match Command::new("git") + .arg("log") + .arg("-1") + .arg("--date=short") + .arg("--format=%H %h %cd") + .output() + { + Ok(output) if output.status.success() => output, + _ => return, + }; + let stdout = String::from_utf8(output.stdout).unwrap(); + let mut parts = stdout.split_whitespace(); + let mut next = || parts.next().unwrap(); + println!("cargo:rustc-env=RA_COMMIT_HASH={}", next()); + println!("cargo:rustc-env=RA_COMMIT_SHORT_HASH={}", next()); + println!("cargo:rustc-env=RA_COMMIT_DATE={}", next()) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs index 97a622e453dd..662d34865eff 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs @@ -2,11 +2,13 @@ //! Driver for proc macro server #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![cfg_attr(not(feature = "sysroot-abi"), allow(unused_crate_dependencies))] -#![allow(clippy::print_stderr)] +#![allow(clippy::print_stdout, clippy::print_stderr)] #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; +mod version; + #[cfg(any(feature = "sysroot-abi", rust_analyzer))] mod main_loop; use clap::{Command, ValueEnum}; @@ -25,12 +27,22 @@ fn main() -> std::io::Result<()> { std::process::exit(122); } let matches = Command::new("proc-macro-srv") - .args(&[clap::Arg::new("format") - .long("format") - .action(clap::ArgAction::Set) - .default_value("json") - .value_parser(clap::builder::EnumValueParser::::new())]) + .args(&[ + clap::Arg::new("format") + .long("format") + .action(clap::ArgAction::Set) + .default_value("json") + .value_parser(clap::builder::EnumValueParser::::new()), + clap::Arg::new("version") + .long("version") + .action(clap::ArgAction::SetTrue) + .help("Prints the version of the proc-macro-srv"), + ]) .get_matches(); + if matches.get_flag("version") { + println!("rust-analyzer-proc-macro-srv {}", version::version()); + return Ok(()); + } let &format = matches.get_one::("format").expect("format value should always be present"); run(format) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs new file mode 100644 index 000000000000..32499d055d1e --- /dev/null +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/version.rs @@ -0,0 +1,58 @@ +//! Code for representing rust-analyzer's release version number. +#![expect(dead_code)] + +use std::fmt; + +/// Information about the git repository where rust-analyzer was built from. +pub(crate) struct CommitInfo { + pub(crate) short_commit_hash: &'static str, + pub(crate) commit_hash: &'static str, + pub(crate) commit_date: &'static str, +} + +/// Cargo's version. +pub(crate) struct VersionInfo { + /// rust-analyzer's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc. + pub(crate) version: &'static str, + /// The release channel we were built for (stable/beta/nightly/dev). + /// + /// `None` if not built via bootstrap. + pub(crate) release_channel: Option<&'static str>, + /// Information about the Git repository we may have been built from. + /// + /// `None` if not built from a git repo. + pub(crate) commit_info: Option, +} + +impl fmt::Display for VersionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.version)?; + + if let Some(ci) = &self.commit_info { + write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?; + }; + Ok(()) + } +} + +/// Returns information about cargo's version. +pub(crate) const fn version() -> VersionInfo { + let version = match option_env!("CFG_RELEASE") { + Some(x) => x, + None => "0.0.0", + }; + + let release_channel = option_env!("CFG_RELEASE_CHANNEL"); + let commit_info = match ( + option_env!("RA_COMMIT_SHORT_HASH"), + option_env!("RA_COMMIT_HASH"), + option_env!("RA_COMMIT_DATE"), + ) { + (Some(short_commit_hash), Some(commit_hash), Some(commit_date)) => { + Some(CommitInfo { short_commit_hash, commit_hash, commit_date }) + } + _ => None, + }; + + VersionInfo { version, release_channel, commit_info } +} From a7b01aa04867ba0ee10f767f3819d47c45d9cc30 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 31 Jul 2025 10:30:22 +0200 Subject: [PATCH 110/242] `cargo clippy --fix` --- .../rust-analyzer/crates/cfg/src/cfg_expr.rs | 8 +- .../rust-analyzer/crates/hir-def/src/attr.rs | 8 +- .../crates/hir-def/src/expr_store/lower.rs | 37 ++--- .../hir-def/src/expr_store/lower/asm.rs | 8 +- .../hir-def/src/expr_store/lower/path.rs | 21 +-- .../crates/hir-def/src/expr_store/pretty.rs | 12 +- .../crates/hir-def/src/find_path.rs | 72 ++++---- .../crates/hir-def/src/item_scope.rs | 9 +- .../crates/hir-def/src/item_tree/lower.rs | 23 ++- .../crates/hir-def/src/lang_item.rs | 8 +- .../hir-def/src/macro_expansion_tests/mod.rs | 64 ++++--- .../crates/hir-def/src/nameres/collector.rs | 154 ++++++++--------- .../crates/hir-def/src/resolver.rs | 94 +++++------ .../crates/hir-expand/src/builtin/fn_macro.rs | 11 +- .../crates/hir-expand/src/cfg_process.rs | 8 +- .../crates/hir-expand/src/fixup.rs | 10 +- .../crates/hir-expand/src/lib.rs | 22 ++- .../crates/hir-expand/src/mod_path.rs | 21 +-- .../crates/hir-ty/src/autoderef.rs | 9 +- .../crates/hir-ty/src/builder.rs | 10 +- .../crates/hir-ty/src/chalk_db.rs | 64 +++---- .../crates/hir-ty/src/consteval.rs | 8 +- .../hir-ty/src/diagnostics/decl_check.rs | 8 +- .../crates/hir-ty/src/diagnostics/expr.rs | 18 +- .../hir-ty/src/diagnostics/match_check.rs | 8 +- .../hir-ty/src/diagnostics/unsafe_check.rs | 17 +- .../crates/hir-ty/src/display.rs | 121 +++++++------- .../crates/hir-ty/src/dyn_compatibility.rs | 25 ++- .../rust-analyzer/crates/hir-ty/src/infer.rs | 47 +++--- .../crates/hir-ty/src/infer/cast.rs | 37 ++--- .../crates/hir-ty/src/infer/closure.rs | 156 ++++++++---------- .../crates/hir-ty/src/infer/coerce.rs | 46 +++--- .../crates/hir-ty/src/infer/expr.rs | 75 ++++----- .../crates/hir-ty/src/infer/mutability.rs | 119 ++++++------- .../crates/hir-ty/src/infer/pat.rs | 31 ++-- .../rust-analyzer/crates/hir-ty/src/lower.rs | 8 +- .../crates/hir-ty/src/lower/path.rs | 120 +++++++------- .../crates/hir-ty/src/method_resolution.rs | 38 ++--- .../crates/hir-ty/src/mir/borrowck.rs | 5 +- .../crates/hir-ty/src/mir/eval.rs | 73 ++++---- .../crates/hir-ty/src/mir/eval/shim.rs | 76 +++++---- .../crates/hir-ty/src/mir/eval/shim/simd.rs | 11 +- .../crates/hir-ty/src/mir/lower.rs | 60 +++---- .../crates/hir-ty/src/mir/lower/as_place.rs | 17 +- .../hir-ty/src/mir/lower/pattern_matching.rs | 49 +++--- .../rust-analyzer/crates/hir-ty/src/traits.rs | 7 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 14 +- .../crates/hir/src/diagnostics.rs | 14 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 80 +++++---- .../rust-analyzer/crates/hir/src/semantics.rs | 93 +++++------ .../crates/hir/src/source_analyzer.rs | 83 +++++----- .../crates/hir/src/term_search.rs | 16 +- .../crates/hir/src/term_search/expr.rs | 8 +- .../src/handlers/add_lifetime_to_type.rs | 24 +-- .../src/handlers/add_missing_impl_members.rs | 14 +- .../src/handlers/apply_demorgan.rs | 8 +- .../src/handlers/convert_bool_then.rs | 23 ++- .../src/handlers/convert_closure_to_fn.rs | 57 ++++--- .../src/handlers/convert_from_to_tryfrom.rs | 19 +-- .../src/handlers/convert_into_to_from.rs | 8 +- .../convert_tuple_return_type_to_struct.rs | 8 +- .../convert_tuple_struct_to_named_struct.rs | 2 +- ...ert_two_arm_bool_match_to_matches_macro.rs | 8 +- .../src/handlers/desugar_try_expr.rs | 130 +++++++-------- .../src/handlers/expand_glob_import.rs | 10 +- .../src/handlers/extract_function.rs | 101 ++++++------ .../src/handlers/extract_module.rs | 81 +++++---- .../extract_struct_from_enum_variant.rs | 12 +- .../src/handlers/extract_type_alias.rs | 42 +++-- .../src/handlers/extract_variable.rs | 15 +- .../generate_documentation_template.rs | 18 +- .../src/handlers/generate_fn_type_alias.rs | 8 +- .../src/handlers/generate_function.rs | 8 +- .../src/handlers/generate_getter_or_setter.rs | 11 +- .../ide-assists/src/handlers/generate_impl.rs | 10 +- .../src/handlers/generate_trait_from_impl.rs | 22 +-- .../ide-assists/src/handlers/inline_call.rs | 49 +++--- .../src/handlers/move_const_to_impl.rs | 8 +- .../src/handlers/pull_assignment_up.rs | 16 +- .../ide-assists/src/handlers/raw_string.rs | 18 +- .../replace_qualified_name_with_use.rs | 8 +- .../src/handlers/unnecessary_async.rs | 8 +- .../src/handlers/unwrap_return_type.rs | 24 +-- .../ide-assists/src/handlers/unwrap_tuple.rs | 8 +- .../src/handlers/wrap_return_type.rs | 40 ++--- .../src/handlers/wrap_unwrap_cfg_attr.rs | 22 ++- .../crates/ide-assists/src/utils.rs | 48 +++--- .../crates/ide-completion/src/completions.rs | 17 +- .../ide-completion/src/completions/dot.rs | 11 +- .../src/completions/fn_param.rs | 8 +- .../src/completions/item_list/trait_impl.rs | 88 +++++----- .../ide-completion/src/completions/mod_.rs | 17 +- .../ide-completion/src/completions/pattern.rs | 21 ++- .../ide-completion/src/completions/postfix.rs | 153 ++++++++--------- .../ide-completion/src/completions/use_.rs | 8 +- .../ide-completion/src/completions/vis.rs | 10 +- .../ide-completion/src/context/analysis.rs | 140 +++++++--------- .../crates/ide-completion/src/item.rs | 8 +- .../crates/ide-completion/src/lib.rs | 14 +- .../crates/ide-completion/src/render.rs | 104 ++++++------ .../ide-completion/src/render/const_.rs | 8 +- .../ide-completion/src/render/function.rs | 34 ++-- .../ide-completion/src/render/type_alias.rs | 8 +- .../rust-analyzer/crates/ide-db/src/defs.rs | 64 ++++--- .../crates/ide-db/src/helpers.rs | 10 +- .../crates/ide-db/src/imports/insert_use.rs | 45 +++-- .../crates/ide-db/src/path_transform.rs | 98 ++++++----- .../rust-analyzer/crates/ide-db/src/rename.rs | 20 +-- .../rust-analyzer/crates/ide-db/src/search.rs | 83 +++++----- .../crates/ide-db/src/symbol_index.rs | 16 +- .../src/syntax_helpers/format_string.rs | 10 +- .../ide-db/src/syntax_helpers/node_ext.rs | 23 ++- .../ide-db/src/use_trivial_constructor.rs | 20 +-- .../src/handlers/json_is_not_rust.rs | 50 +++--- .../src/handlers/missing_fields.rs | 11 +- .../src/handlers/mutability_errors.rs | 24 +-- .../src/handlers/unlinked_file.rs | 14 +- .../crates/ide-diagnostics/src/lib.rs | 54 +++--- .../rust-analyzer/crates/ide-ssr/src/lib.rs | 21 ++- .../crates/ide-ssr/src/matching.rs | 101 ++++++------ .../crates/ide-ssr/src/replacing.rs | 28 ++-- .../crates/ide-ssr/src/resolving.rs | 61 +++---- .../crates/ide-ssr/src/search.rs | 27 ++- .../crates/ide/src/annotations.rs | 8 +- .../crates/ide/src/expand_macro.rs | 16 +- .../crates/ide/src/extend_selection.rs | 54 +++--- .../crates/ide/src/folding_ranges.rs | 88 +++++----- .../crates/ide/src/goto_definition.rs | 28 ++-- .../crates/ide/src/highlight_related.rs | 45 +++-- .../rust-analyzer/crates/ide/src/hover.rs | 13 +- .../crates/ide/src/hover/render.rs | 116 ++++++------- .../crates/ide/src/inlay_hints.rs | 12 +- .../crates/ide/src/inlay_hints/adjustment.rs | 8 +- .../crates/ide/src/inlay_hints/bind_pat.rs | 8 +- .../crates/ide/src/inlay_hints/chaining.rs | 11 +- .../ide/src/inlay_hints/closing_brace.rs | 10 +- .../crates/ide/src/inlay_hints/closure_ret.rs | 8 +- .../ide/src/inlay_hints/extern_block.rs | 8 +- .../ide/src/inlay_hints/generic_param.rs | 8 +- .../ide/src/inlay_hints/implicit_static.rs | 43 ++--- .../crates/ide/src/inlay_hints/lifetime.rs | 50 +++--- .../crates/ide/src/inlay_hints/param_name.rs | 8 +- .../crates/ide/src/join_lines.rs | 26 +-- .../crates/ide/src/parent_module.rs | 11 +- .../rust-analyzer/crates/ide/src/rename.rs | 8 +- .../rust-analyzer/crates/ide/src/runnables.rs | 34 ++-- .../crates/ide/src/signature_help.rs | 19 +-- .../crates/ide/src/static_index.rs | 8 +- .../ide/src/syntax_highlighting/highlight.rs | 39 +++-- .../crates/load-cargo/src/lib.rs | 8 +- .../rust-analyzer/crates/mbe/src/benchmark.rs | 32 ++-- .../crates/mbe/src/expander/matcher.rs | 12 +- .../crates/parser/src/grammar/expressions.rs | 69 ++++---- .../rust-analyzer/crates/parser/src/input.rs | 2 +- .../crates/parser/src/shortcuts.rs | 8 +- .../crates/query-group-macro/src/lib.rs | 16 +- .../crates/rust-analyzer/src/bin/main.rs | 12 +- .../rust-analyzer/src/cli/analysis_stats.rs | 107 ++++++------ .../rust-analyzer/src/cli/progress_report.rs | 10 +- .../rust-analyzer/src/cli/rustc_tests.rs | 8 +- .../crates/rust-analyzer/src/config.rs | 19 +-- .../src/config/patch_old_style.rs | 24 +-- .../rust-analyzer/src/diagnostics/to_proto.rs | 14 +- .../crates/rust-analyzer/src/flycheck.rs | 11 +- .../crates/rust-analyzer/src/global_state.rs | 26 +-- .../rust-analyzer/src/handlers/dispatch.rs | 8 +- .../src/handlers/notification.rs | 37 ++--- .../rust-analyzer/src/handlers/request.rs | 146 ++++++++-------- .../crates/rust-analyzer/src/main_loop.rs | 60 ++++--- .../crates/rust-analyzer/src/reload.rs | 14 +- .../rust-analyzer/crates/span/src/map.rs | 14 +- .../crates/syntax-bridge/src/lib.rs | 22 +-- .../src/prettify_macro_expansion.rs | 9 +- .../crates/syntax-bridge/src/tests.rs | 9 +- .../syntax-bridge/src/to_parser_input.rs | 20 +-- .../crates/syntax/src/ast/edit.rs | 24 +-- .../crates/syntax/src/ast/edit_in_place.rs | 41 +++-- .../crates/syntax/src/ast/prec.rs | 24 +-- .../crates/syntax/src/syntax_editor.rs | 8 +- .../rust-analyzer/crates/syntax/src/ted.rs | 42 ++--- .../crates/syntax/src/validation.rs | 92 +++++------ .../crates/test-fixture/src/lib.rs | 12 +- src/tools/rust-analyzer/crates/tt/src/lib.rs | 16 +- .../crates/vfs-notify/src/lib.rs | 79 +++++---- src/tools/rust-analyzer/xtask/src/codegen.rs | 10 +- .../rust-analyzer/xtask/src/publish/notes.rs | 140 ++++++++-------- 186 files changed, 3056 insertions(+), 3314 deletions(-) diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs index aed00aa9fc44..f83c21eb8d64 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs @@ -134,10 +134,10 @@ fn next_cfg_expr(it: &mut tt::iter::TtIter<'_, S>) -> Option { }; // Eat comma separator - if let Some(TtElement::Leaf(tt::Leaf::Punct(punct))) = it.peek() { - if punct.char == ',' { - it.next(); - } + if let Some(TtElement::Leaf(tt::Leaf::Punct(punct))) = it.peek() + && punct.char == ',' + { + it.next(); } Some(ret) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index b509e69b0d37..53250510f875 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -377,10 +377,10 @@ fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option { let mut align = None; if let Some(TtElement::Subtree(_, mut tt_iter)) = tts.peek() { tts.next(); - if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() { - if let Ok(a) = lit.symbol.as_str().parse() { - align = Align::from_bytes(a).ok(); - } + if let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = tt_iter.next() + && let Ok(a) = lit.symbol.as_str().parse() + { + align = Align::from_bytes(a).ok(); } } ReprOptions { align, ..Default::default() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index abd1382801dd..3b9281ffb9c1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -1487,13 +1487,13 @@ impl ExprCollector<'_> { ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr), ast::Expr::ParenExpr(e) => { // We special-case `(..)` for consistency with patterns. - if let Some(ast::Expr::RangeExpr(range)) = e.expr() { - if range.is_range_full() { - return Some(self.alloc_pat_from_expr( - Pat::Tuple { args: Box::default(), ellipsis: Some(0) }, - syntax_ptr, - )); - } + if let Some(ast::Expr::RangeExpr(range)) = e.expr() + && range.is_range_full() + { + return Some(self.alloc_pat_from_expr( + Pat::Tuple { args: Box::default(), ellipsis: Some(0) }, + syntax_ptr, + )); } return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr)); } @@ -2569,19 +2569,18 @@ impl ExprCollector<'_> { } } RibKind::MacroDef(macro_id) => { - if let Some((parent_ctx, label_macro_id)) = hygiene_info { - if label_macro_id == **macro_id { - // A macro is allowed to refer to labels from before its declaration. - // Therefore, if we got to the rib of its declaration, give up its hygiene - // and use its parent expansion. + if let Some((parent_ctx, label_macro_id)) = hygiene_info + && label_macro_id == **macro_id + { + // A macro is allowed to refer to labels from before its declaration. + // Therefore, if we got to the rib of its declaration, give up its hygiene + // and use its parent expansion. - hygiene_id = - HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db)); - hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| { - let expansion = self.db.lookup_intern_macro_call(expansion.into()); - (parent_ctx.parent(self.db), expansion.def) - }); - } + hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db)); + hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| { + let expansion = self.db.lookup_intern_macro_call(expansion.into()); + (parent_ctx.parent(self.db), expansion.def) + }); } } _ => {} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs index 3bc4afb5c8ac..230d1c934636 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs @@ -259,10 +259,10 @@ impl ExprCollector<'_> { } }; - if let Some(operand_idx) = operand_idx { - if let Some(position_span) = to_span(arg.position_span) { - mappings.push((position_span, operand_idx)); - } + if let Some(operand_idx) = operand_idx + && let Some(position_span) = to_span(arg.position_span) + { + mappings.push((position_span, operand_idx)); } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs index be006c98a582..579465e10f93 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/path.rs @@ -211,16 +211,17 @@ pub(super) fn lower_path( // Basically, even in rustc it is quite hacky: // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 // We follow what it did anyway :) - if segments.len() == 1 && kind == PathKind::Plain { - if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - let syn_ctxt = collector.expander.ctx_for_range(path.segment()?.syntax().text_range()); - if let Some(macro_call_id) = syn_ctxt.outer_expn(collector.db) { - if collector.db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner { - kind = match resolve_crate_root(collector.db, syn_ctxt) { - Some(crate_root) => PathKind::DollarCrate(crate_root), - None => PathKind::Crate, - } - } + if segments.len() == 1 + && kind == PathKind::Plain + && let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) + { + let syn_ctxt = collector.expander.ctx_for_range(path.segment()?.syntax().text_range()); + if let Some(macro_call_id) = syn_ctxt.outer_expn(collector.db) + && collector.db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner + { + kind = match resolve_crate_root(collector.db, syn_ctxt) { + Some(crate_root) => PathKind::DollarCrate(crate_root), + None => PathKind::Crate, } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index f1b011333d94..b81dcc1fe96d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -900,14 +900,12 @@ impl Printer<'_> { let field_name = arg.name.display(self.db, edition).to_string(); let mut same_name = false; - if let Pat::Bind { id, subpat: None } = &self.store[arg.pat] { - if let Binding { name, mode: BindingAnnotation::Unannotated, .. } = + if let Pat::Bind { id, subpat: None } = &self.store[arg.pat] + && let Binding { name, mode: BindingAnnotation::Unannotated, .. } = &self.store.assert_expr_only().bindings[*id] - { - if name.as_str() == field_name { - same_name = true; - } - } + && name.as_str() == field_name + { + same_name = true; } w!(p, "{}", field_name); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index dccfff002f23..faa0ef8ceec7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -107,11 +107,11 @@ struct FindPathCtx<'db> { /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option { // - if the item is a module, jump straight to module search - if !ctx.is_std_item { - if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { - return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len) - .map(|choice| choice.path); - } + if !ctx.is_std_item + && let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item + { + return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len) + .map(|choice| choice.path); } let may_be_in_scope = match ctx.prefix { @@ -226,15 +226,15 @@ fn find_path_for_module( } // - if the module can be referenced as self, super or crate, do that - if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) { - if ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate { - return Some(Choice { - path: ModPath::from_segments(kind, None), - path_text_len: path_kind_len(kind), - stability: Stable, - prefer_due_to_prelude: false, - }); - } + if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) + && (ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate) + { + return Some(Choice { + path: ModPath::from_segments(kind, None), + path_text_len: path_kind_len(kind), + stability: Stable, + prefer_due_to_prelude: false, + }); } // - if the module is in the prelude, return it by that path @@ -604,29 +604,29 @@ fn find_local_import_locations( &def_map[module.local_id] }; - if let Some((name, vis, declared)) = data.scope.name_of(item) { - if vis.is_visible_from(db, from) { - let is_pub_or_explicit = match vis { - Visibility::Module(_, VisibilityExplicitness::Explicit) => { - cov_mark::hit!(explicit_private_imports); - true - } - Visibility::Module(_, VisibilityExplicitness::Implicit) => { - cov_mark::hit!(discount_private_imports); - false - } - Visibility::PubCrate(_) => true, - Visibility::Public => true, - }; - - // Ignore private imports unless they are explicit. these could be used if we are - // in a submodule of this module, but that's usually not - // what the user wants; and if this module can import - // the item and we're a submodule of it, so can we. - // Also this keeps the cached data smaller. - if declared || is_pub_or_explicit { - cb(visited_modules, name, module); + if let Some((name, vis, declared)) = data.scope.name_of(item) + && vis.is_visible_from(db, from) + { + let is_pub_or_explicit = match vis { + Visibility::Module(_, VisibilityExplicitness::Explicit) => { + cov_mark::hit!(explicit_private_imports); + true } + Visibility::Module(_, VisibilityExplicitness::Implicit) => { + cov_mark::hit!(discount_private_imports); + false + } + Visibility::PubCrate(_) => true, + Visibility::Public => true, + }; + + // Ignore private imports unless they are explicit. these could be used if we are + // in a submodule of this module, but that's usually not + // what the user wants; and if this module can import + // the item and we're a submodule of it, so can we. + // Also this keeps the cached data smaller. + if declared || is_pub_or_explicit { + cb(visited_modules, name, module); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index efa439946850..8f526d1a2369 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -510,12 +510,11 @@ impl ItemScope { id: AttrId, idx: usize, ) { - if let Some(derives) = self.derive_macros.get_mut(&adt) { - if let Some(DeriveMacroInvocation { derive_call_ids, .. }) = + if let Some(derives) = self.derive_macros.get_mut(&adt) + && let Some(DeriveMacroInvocation { derive_call_ids, .. }) = derives.iter_mut().find(|&&mut DeriveMacroInvocation { attr_id, .. }| id == attr_id) - { - derive_call_ids[idx] = Some(call); - } + { + derive_call_ids[idx] = Some(call); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 5ab61c89394b..032b287cd6a8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -83,12 +83,12 @@ impl<'a> Ctx<'a> { .flat_map(|item| self.lower_mod_item(&item)) .collect(); - if let Some(ast::Expr::MacroExpr(tail_macro)) = stmts.expr() { - if let Some(call) = tail_macro.macro_call() { - cov_mark::hit!(macro_stmt_with_trailing_macro_expr); - if let Some(mod_item) = self.lower_mod_item(&call.into()) { - self.top_level.push(mod_item); - } + if let Some(ast::Expr::MacroExpr(tail_macro)) = stmts.expr() + && let Some(call) = tail_macro.macro_call() + { + cov_mark::hit!(macro_stmt_with_trailing_macro_expr); + if let Some(mod_item) = self.lower_mod_item(&call.into()) { + self.top_level.push(mod_item); } } @@ -112,12 +112,11 @@ impl<'a> Ctx<'a> { _ => None, }) .collect(); - if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() { - if let Some(call) = expr.macro_call() { - if let Some(mod_item) = self.lower_mod_item(&call.into()) { - self.top_level.push(mod_item); - } - } + if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() + && let Some(call) = expr.macro_call() + && let Some(mod_item) = self.lower_mod_item(&call.into()) + { + self.top_level.push(mod_item); } self.tree.vis.arena = self.visibilities.into_iter().collect(); self.tree.top_level = self.top_level.into_boxed_slice(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 750308026eec..d431f2140165 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -218,10 +218,10 @@ pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option for (_, module_data) in crate_def_map.modules() { for def in module_data.scope.declarations() { - if let ModuleDefId::TraitId(trait_) = def { - if db.attrs(trait_.into()).has_doc_notable_trait() { - traits.push(trait_); - } + if let ModuleDefId::TraitId(trait_) = def + && db.attrs(trait_.into()).has_doc_notable_trait() + { + traits.push(trait_); } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 5e95b061399a..e8ae499d27b2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -221,46 +221,42 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream _ => None, }; - if let Some(src) = src { - if let Some(file_id) = src.file_id.macro_file() { - if let MacroKind::Derive - | MacroKind::DeriveBuiltIn - | MacroKind::Attr - | MacroKind::AttrBuiltIn = file_id.kind(&db) - { - let call = file_id.call_node(&db); - let mut show_spans = false; - let mut show_ctxt = false; - for comment in - call.value.children_with_tokens().filter(|it| it.kind() == COMMENT) - { - show_spans |= comment.to_string().contains("+spans"); - show_ctxt |= comment.to_string().contains("+syntaxctxt"); - } - let pp = pretty_print_macro_expansion( - src.value, - db.span_map(src.file_id).as_ref(), - show_spans, - show_ctxt, - ); - format_to!(expanded_text, "\n{}", pp) - } + if let Some(src) = src + && let Some(file_id) = src.file_id.macro_file() + && let MacroKind::Derive + | MacroKind::DeriveBuiltIn + | MacroKind::Attr + | MacroKind::AttrBuiltIn = file_id.kind(&db) + { + let call = file_id.call_node(&db); + let mut show_spans = false; + let mut show_ctxt = false; + for comment in call.value.children_with_tokens().filter(|it| it.kind() == COMMENT) { + show_spans |= comment.to_string().contains("+spans"); + show_ctxt |= comment.to_string().contains("+syntaxctxt"); } + let pp = pretty_print_macro_expansion( + src.value, + db.span_map(src.file_id).as_ref(), + show_spans, + show_ctxt, + ); + format_to!(expanded_text, "\n{}", pp) } } for impl_id in def_map[local_id].scope.impls() { let src = impl_id.lookup(&db).source(&db); - if let Some(macro_file) = src.file_id.macro_file() { - if let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db) { - let pp = pretty_print_macro_expansion( - src.value.syntax().clone(), - db.span_map(macro_file.into()).as_ref(), - false, - false, - ); - format_to!(expanded_text, "\n{}", pp) - } + if let Some(macro_file) = src.file_id.macro_file() + && let MacroKind::DeriveBuiltIn | MacroKind::Derive = macro_file.kind(&db) + { + let pp = pretty_print_macro_expansion( + src.value.syntax().clone(), + db.span_map(macro_file.into()).as_ref(), + false, + false, + ); + format_to!(expanded_text, "\n{}", pp) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 0c3274d849ad..267c4451b9d7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -261,20 +261,20 @@ impl<'db> DefCollector<'db> { // Process other crate-level attributes. for attr in &*attrs { - if let Some(cfg) = attr.cfg() { - if self.cfg_options.check(&cfg) == Some(false) { - process = false; - break; - } + if let Some(cfg) = attr.cfg() + && self.cfg_options.check(&cfg) == Some(false) + { + process = false; + break; } let Some(attr_name) = attr.path.as_ident() else { continue }; match () { () if *attr_name == sym::recursion_limit => { - if let Some(limit) = attr.string_value() { - if let Ok(limit) = limit.as_str().parse() { - crate_data.recursion_limit = Some(limit); - } + if let Some(limit) = attr.string_value() + && let Ok(limit) = limit.as_str().parse() + { + crate_data.recursion_limit = Some(limit); } } () if *attr_name == sym::crate_type => { @@ -1188,56 +1188,44 @@ impl<'db> DefCollector<'db> { // Multiple globs may import the same item and they may override visibility from // previously resolved globs. Handle overrides here and leave the rest to // `ItemScope::push_res_with_import()`. - if let Some(def) = defs.types { - if let Some(prev_def) = prev_defs.types { - if def.def == prev_def.def - && self.from_glob_import.contains_type(module_id, name.clone()) - && def.vis != prev_def.vis - && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) - { - changed = true; - // This import is being handled here, don't pass it down to - // `ItemScope::push_res_with_import()`. - defs.types = None; - self.def_map.modules[module_id] - .scope - .update_visibility_types(name, def.vis); - } - } + if let Some(def) = defs.types + && let Some(prev_def) = prev_defs.types + && def.def == prev_def.def + && self.from_glob_import.contains_type(module_id, name.clone()) + && def.vis != prev_def.vis + && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) + { + changed = true; + // This import is being handled here, don't pass it down to + // `ItemScope::push_res_with_import()`. + defs.types = None; + self.def_map.modules[module_id].scope.update_visibility_types(name, def.vis); } - if let Some(def) = defs.values { - if let Some(prev_def) = prev_defs.values { - if def.def == prev_def.def - && self.from_glob_import.contains_value(module_id, name.clone()) - && def.vis != prev_def.vis - && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) - { - changed = true; - // See comment above. - defs.values = None; - self.def_map.modules[module_id] - .scope - .update_visibility_values(name, def.vis); - } - } + if let Some(def) = defs.values + && let Some(prev_def) = prev_defs.values + && def.def == prev_def.def + && self.from_glob_import.contains_value(module_id, name.clone()) + && def.vis != prev_def.vis + && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) + { + changed = true; + // See comment above. + defs.values = None; + self.def_map.modules[module_id].scope.update_visibility_values(name, def.vis); } - if let Some(def) = defs.macros { - if let Some(prev_def) = prev_defs.macros { - if def.def == prev_def.def - && self.from_glob_import.contains_macro(module_id, name.clone()) - && def.vis != prev_def.vis - && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) - { - changed = true; - // See comment above. - defs.macros = None; - self.def_map.modules[module_id] - .scope - .update_visibility_macros(name, def.vis); - } - } + if let Some(def) = defs.macros + && let Some(prev_def) = prev_defs.macros + && def.def == prev_def.def + && self.from_glob_import.contains_macro(module_id, name.clone()) + && def.vis != prev_def.vis + && def.vis.max(prev_def.vis, &self.def_map) == Some(def.vis) + { + changed = true; + // See comment above. + defs.macros = None; + self.def_map.modules[module_id].scope.update_visibility_macros(name, def.vis); } } @@ -1392,15 +1380,14 @@ impl<'db> DefCollector<'db> { Resolved::Yes }; - if let Some(ident) = path.as_ident() { - if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) { - if helpers.iter().any(|(it, ..)| it == ident) { - cov_mark::hit!(resolved_derive_helper); - // Resolved to derive helper. Collect the item's attributes again, - // starting after the derive helper. - return recollect_without(self); - } - } + if let Some(ident) = path.as_ident() + && let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) + && helpers.iter().any(|(it, ..)| it == ident) + { + cov_mark::hit!(resolved_derive_helper); + // Resolved to derive helper. Collect the item's attributes again, + // starting after the derive helper. + return recollect_without(self); } let def = match resolver_def_id(path) { @@ -1729,12 +1716,12 @@ impl ModCollector<'_, '_> { let mut process_mod_item = |item: ModItemId| { let attrs = self.item_tree.attrs(db, krate, item.ast_id()); - if let Some(cfg) = attrs.cfg() { - if !self.is_cfg_enabled(&cfg) { - let ast_id = item.ast_id().erase(); - self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg); - return; - } + if let Some(cfg) = attrs.cfg() + && !self.is_cfg_enabled(&cfg) + { + let ast_id = item.ast_id().erase(); + self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg); + return; } if let Err(()) = self.resolve_attributes(&attrs, item, container) { @@ -1871,14 +1858,13 @@ impl ModCollector<'_, '_> { if self.def_collector.def_map.block.is_none() && self.def_collector.is_proc_macro && self.module_id == DefMap::ROOT + && let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { - if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { - self.def_collector.export_proc_macro( - proc_macro, - InFile::new(self.file_id(), id), - fn_id, - ); - } + self.def_collector.export_proc_macro( + proc_macro, + InFile::new(self.file_id(), id), + fn_id, + ); } update_def(self.def_collector, fn_id.into(), &it.name, vis, false); @@ -2419,13 +2405,13 @@ impl ModCollector<'_, '_> { macro_id, &self.item_tree[mac.visibility], ); - if let Some(helpers) = helpers_opt { - if self.def_collector.def_map.block.is_none() { - Arc::get_mut(&mut self.def_collector.def_map.data) - .unwrap() - .exported_derives - .insert(macro_id.into(), helpers); - } + if let Some(helpers) = helpers_opt + && self.def_collector.def_map.block.is_none() + { + Arc::get_mut(&mut self.def_collector.def_map.data) + .unwrap() + .exported_derives + .insert(macro_id.into(), helpers); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 316ad5dae69d..a10990e6a8f9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -228,15 +228,15 @@ impl<'db> Resolver<'db> { ResolvePathResultPrefixInfo::default(), )); } - } else if let &GenericDefId::AdtId(adt) = def { - if *first_name == sym::Self_ { - return Some(( - TypeNs::AdtSelfType(adt), - remaining_idx(), - None, - ResolvePathResultPrefixInfo::default(), - )); - } + } else if let &GenericDefId::AdtId(adt) = def + && *first_name == sym::Self_ + { + return Some(( + TypeNs::AdtSelfType(adt), + remaining_idx(), + None, + ResolvePathResultPrefixInfo::default(), + )); } if let Some(id) = params.find_type_by_name(first_name, *def) { return Some(( @@ -401,13 +401,13 @@ impl<'db> Resolver<'db> { handle_macro_def_scope(db, &mut hygiene_id, &mut hygiene_info, macro_id) } Scope::GenericParams { params, def } => { - if let &GenericDefId::ImplId(impl_) = def { - if *first_name == sym::Self_ { - return Some(( - ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None), - ResolvePathResultPrefixInfo::default(), - )); - } + if let &GenericDefId::ImplId(impl_) = def + && *first_name == sym::Self_ + { + return Some(( + ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_), None), + ResolvePathResultPrefixInfo::default(), + )); } if let Some(id) = params.find_const_by_name(first_name, *def) { let val = ValueNs::GenericParam(id); @@ -436,14 +436,14 @@ impl<'db> Resolver<'db> { ResolvePathResultPrefixInfo::default(), )); } - } else if let &GenericDefId::AdtId(adt) = def { - if *first_name == sym::Self_ { - let ty = TypeNs::AdtSelfType(adt); - return Some(( - ResolveValueResult::Partial(ty, 1, None), - ResolvePathResultPrefixInfo::default(), - )); - } + } else if let &GenericDefId::AdtId(adt) = def + && *first_name == sym::Self_ + { + let ty = TypeNs::AdtSelfType(adt); + return Some(( + ResolveValueResult::Partial(ty, 1, None), + ResolvePathResultPrefixInfo::default(), + )); } if let Some(id) = params.find_type_by_name(first_name, *def) { let ty = TypeNs::GenericParam(id); @@ -469,13 +469,14 @@ impl<'db> Resolver<'db> { // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back // to resolving to the primitive type, to allow this to still work in the presence of // `use core::u16;`. - if path.kind == PathKind::Plain && n_segments > 1 { - if let Some(builtin) = BuiltinType::by_name(first_name) { - return Some(( - ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None), - ResolvePathResultPrefixInfo::default(), - )); - } + if path.kind == PathKind::Plain + && n_segments > 1 + && let Some(builtin) = BuiltinType::by_name(first_name) + { + return Some(( + ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1, None), + ResolvePathResultPrefixInfo::default(), + )); } None @@ -660,12 +661,11 @@ impl<'db> Resolver<'db> { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::GenericParams { def: GenericDefId::ImplId(impl_), .. } => { let impl_data = db.impl_signature(impl_); - if let Some(target_trait) = impl_data.target_trait { - if let Some(TypeNs::TraitId(trait_)) = self + if let Some(target_trait) = impl_data.target_trait + && let Some(TypeNs::TraitId(trait_)) = self .resolve_path_in_type_ns_fully(db, &impl_data.store[target_trait.path]) - { - traits.insert(trait_); - } + { + traits.insert(trait_); } } _ => (), @@ -918,17 +918,17 @@ fn handle_macro_def_scope( hygiene_info: &mut Option<(SyntaxContext, MacroDefId)>, macro_id: &MacroDefId, ) { - if let Some((parent_ctx, label_macro_id)) = hygiene_info { - if label_macro_id == macro_id { - // A macro is allowed to refer to variables from before its declaration. - // Therefore, if we got to the rib of its declaration, give up its hygiene - // and use its parent expansion. - *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db)); - *hygiene_info = parent_ctx.outer_expn(db).map(|expansion| { - let expansion = db.lookup_intern_macro_call(expansion.into()); - (parent_ctx.parent(db), expansion.def) - }); - } + if let Some((parent_ctx, label_macro_id)) = hygiene_info + && label_macro_id == macro_id + { + // A macro is allowed to refer to variables from before its declaration. + // Therefore, if we got to the rib of its declaration, give up its hygiene + // and use its parent expansion. + *hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(db)); + *hygiene_info = parent_ctx.outer_expn(db).map(|expansion| { + let expansion = db.lookup_intern_macro_call(expansion.into()); + (parent_ctx.parent(db), expansion.def) + }); } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 4a9af01091f2..58ab7f470c40 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -555,12 +555,11 @@ fn concat_expand( // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses // to ensure the right parsing order, so skip the parentheses here. Ideally we'd // implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623 - if let TtElement::Subtree(subtree, subtree_iter) = &t { - if let [tt::TokenTree::Leaf(tt)] = subtree_iter.remaining().flat_tokens() { - if subtree.delimiter.kind == tt::DelimiterKind::Parenthesis { - t = TtElement::Leaf(tt); - } - } + if let TtElement::Subtree(subtree, subtree_iter) = &t + && let [tt::TokenTree::Leaf(tt)] = subtree_iter.remaining().flat_tokens() + && subtree.delimiter.kind == tt::DelimiterKind::Parenthesis + { + t = TtElement::Leaf(tt); } match t { TtElement::Leaf(tt::Leaf::Literal(it)) if i % 2 == 0 => { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index c6ea4a3a33db..d5ebd6ee19f5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -334,10 +334,10 @@ where _ => Some(CfgExpr::Atom(CfgAtom::Flag(name))), }, }; - if let Some(NodeOrToken::Token(element)) = iter.peek() { - if element.kind() == syntax::T![,] { - iter.next(); - } + if let Some(NodeOrToken::Token(element)) = iter.peek() + && element.kind() == syntax::T![,] + { + iter.next(); } result } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 4a4a3e52aea4..fe77e1565987 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -280,8 +280,8 @@ pub(crate) fn fixup_syntax( } }, ast::RecordExprField(it) => { - if let Some(colon) = it.colon_token() { - if it.name_ref().is_some() && it.expr().is_none() { + if let Some(colon) = it.colon_token() + && it.name_ref().is_some() && it.expr().is_none() { append.insert(colon.into(), vec![ Leaf::Ident(Ident { sym: sym::__ra_fixup, @@ -290,11 +290,10 @@ pub(crate) fn fixup_syntax( }) ]); } - } }, ast::Path(it) => { - if let Some(colon) = it.coloncolon_token() { - if it.segment().is_none() { + if let Some(colon) = it.coloncolon_token() + && it.segment().is_none() { append.insert(colon.into(), vec![ Leaf::Ident(Ident { sym: sym::__ra_fixup, @@ -303,7 +302,6 @@ pub(crate) fn fixup_syntax( }) ]); } - } }, ast::ClosureExpr(it) => { if it.body().is_none() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index ac61b2200970..472ec83ffef5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -365,12 +365,11 @@ impl HirFileId { HirFileId::FileId(id) => break id, HirFileId::MacroFile(file) => { let loc = db.lookup_intern_macro_call(file); - if loc.def.is_include() { - if let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind { - if let Ok(it) = include_input_to_file_id(db, file, &eager.arg) { - break it; - } - } + if loc.def.is_include() + && let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind + && let Ok(it) = include_input_to_file_id(db, file, &eager.arg) + { + break it; } self = loc.kind.file_id(); } @@ -648,12 +647,11 @@ impl MacroCallLoc { db: &dyn ExpandDatabase, macro_call_id: MacroCallId, ) -> Option { - if self.def.is_include() { - if let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind { - if let Ok(it) = include_input_to_file_id(db, macro_call_id, &eager.arg) { - return Some(it); - } - } + if self.def.is_include() + && let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind + && let Ok(it) = include_input_to_file_id(db, macro_call_id, &eager.arg) + { + return Some(it); } None diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 9f1e3879e1ee..d84d978cdb7e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -273,16 +273,17 @@ fn convert_path( // Basically, even in rustc it is quite hacky: // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 // We follow what it did anyway :) - if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain { - if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - let syn_ctx = span_for_range(segment.syntax().text_range()); - if let Some(macro_call_id) = syn_ctx.outer_expn(db) { - if db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner { - mod_path.kind = match resolve_crate_root(db, syn_ctx) { - Some(crate_root) => PathKind::DollarCrate(crate_root), - None => PathKind::Crate, - } - } + if mod_path.segments.len() == 1 + && mod_path.kind == PathKind::Plain + && let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) + { + let syn_ctx = span_for_range(segment.syntax().text_range()); + if let Some(macro_call_id) = syn_ctx.outer_expn(db) + && db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner + { + mod_path.kind = match resolve_crate_root(db, syn_ctx) { + Some(crate_root) => PathKind::DollarCrate(crate_root), + None => PathKind::Crate, } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index cc8f7bf04a5c..26ca7fb9a15e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -197,10 +197,11 @@ pub(crate) fn deref_by_trait( // effectively bump the MSRV of rust-analyzer to 1.84 due to 1.83 and below lacking the // blanked impl on `Deref`. #[expect(clippy::overly_complex_bool_expr)] - if use_receiver_trait && false { - if let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate) { - return Some(receiver); - } + if use_receiver_trait + && false + && let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate) + { + return Some(receiver); } // Old rustc versions might not have `Receiver` trait. // Fallback to `Deref` if they don't diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 77d15a73af6f..8af8fb73f344 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -309,11 +309,11 @@ impl TyBuilder { if let Some(defaults) = defaults.get(self.vec.len()..) { for default_ty in defaults { // NOTE(skip_binders): we only check if the arg type is error type. - if let Some(x) = default_ty.skip_binders().ty(Interner) { - if x.is_unknown() { - self.vec.push(fallback().cast(Interner)); - continue; - } + if let Some(x) = default_ty.skip_binders().ty(Interner) + && x.is_unknown() + { + self.vec.push(fallback().cast(Interner)); + continue; } // Each default can only depend on the previous parameters. self.vec.push(default_ty.clone().substitute(Interner, &*self.vec).cast(Interner)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 26b635298a65..3ba7c93d4fb7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -83,34 +83,34 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { Arc::new(rust_ir::AdtRepr { c: false, packed: false, int: None }) } fn discriminant_type(&self, ty: chalk_ir::Ty) -> chalk_ir::Ty { - if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner) { - if let hir_def::AdtId::EnumId(e) = id.0 { - let enum_data = self.db.enum_signature(e); - let ty = enum_data.repr.unwrap_or_default().discr_type(); - return chalk_ir::TyKind::Scalar(match ty { - hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed { - true => chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize), - false => chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize), - }, - hir_def::layout::IntegerType::Fixed(size, is_signed) => match is_signed { - true => chalk_ir::Scalar::Int(match size { - hir_def::layout::Integer::I8 => chalk_ir::IntTy::I8, - hir_def::layout::Integer::I16 => chalk_ir::IntTy::I16, - hir_def::layout::Integer::I32 => chalk_ir::IntTy::I32, - hir_def::layout::Integer::I64 => chalk_ir::IntTy::I64, - hir_def::layout::Integer::I128 => chalk_ir::IntTy::I128, - }), - false => chalk_ir::Scalar::Uint(match size { - hir_def::layout::Integer::I8 => chalk_ir::UintTy::U8, - hir_def::layout::Integer::I16 => chalk_ir::UintTy::U16, - hir_def::layout::Integer::I32 => chalk_ir::UintTy::U32, - hir_def::layout::Integer::I64 => chalk_ir::UintTy::U64, - hir_def::layout::Integer::I128 => chalk_ir::UintTy::U128, - }), - }, - }) - .intern(Interner); - } + if let chalk_ir::TyKind::Adt(id, _) = ty.kind(Interner) + && let hir_def::AdtId::EnumId(e) = id.0 + { + let enum_data = self.db.enum_signature(e); + let ty = enum_data.repr.unwrap_or_default().discr_type(); + return chalk_ir::TyKind::Scalar(match ty { + hir_def::layout::IntegerType::Pointer(is_signed) => match is_signed { + true => chalk_ir::Scalar::Int(chalk_ir::IntTy::Isize), + false => chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize), + }, + hir_def::layout::IntegerType::Fixed(size, is_signed) => match is_signed { + true => chalk_ir::Scalar::Int(match size { + hir_def::layout::Integer::I8 => chalk_ir::IntTy::I8, + hir_def::layout::Integer::I16 => chalk_ir::IntTy::I16, + hir_def::layout::Integer::I32 => chalk_ir::IntTy::I32, + hir_def::layout::Integer::I64 => chalk_ir::IntTy::I64, + hir_def::layout::Integer::I128 => chalk_ir::IntTy::I128, + }), + false => chalk_ir::Scalar::Uint(match size { + hir_def::layout::Integer::I8 => chalk_ir::UintTy::U8, + hir_def::layout::Integer::I16 => chalk_ir::UintTy::U16, + hir_def::layout::Integer::I32 => chalk_ir::UintTy::U32, + hir_def::layout::Integer::I64 => chalk_ir::UintTy::U64, + hir_def::layout::Integer::I128 => chalk_ir::UintTy::U128, + }), + }, + }) + .intern(Interner); } chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U8)).intern(Interner) } @@ -142,10 +142,10 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { ) -> Option { if let TyKind::BoundVar(bv) = ty.kind(Interner) { let binders = binders.as_slice(Interner); - if bv.debruijn == DebruijnIndex::INNERMOST { - if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind { - return Some(tk); - } + if bv.debruijn == DebruijnIndex::INNERMOST + && let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind + { + return Some(tk); } } None diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index 14b9cd203f60..f30ec839a009 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -342,10 +342,10 @@ pub(crate) fn eval_to_const( return c; } } - if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) { - if let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None) { - return result; - } + if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr) + && let Ok((Ok(result), _)) = interpret_mir(db, Arc::new(mir_body), true, None) + { + return result; } unknown_const(infer[expr].clone()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 40fe3073cf2c..0815e62f87ee 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -657,10 +657,10 @@ impl<'a> DeclValidator<'a> { } fn is_trait_impl_container(&self, container_id: ItemContainerId) -> bool { - if let ItemContainerId::ImplId(impl_id) = container_id { - if self.db.impl_trait(impl_id).is_some() { - return true; - } + if let ItemContainerId::ImplId(impl_id) = container_id + && self.db.impl_trait(impl_id).is_some() + { + return true; } false } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index cc531f076dd1..b26bd2b8fa9c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -528,15 +528,15 @@ impl FilterMapNextChecker { return None; } - if *function_id == self.next_function_id? { - if let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id { - let is_dyn_trait = self - .prev_receiver_ty - .as_ref() - .is_some_and(|it| it.strip_references().dyn_trait().is_some()); - if *receiver_expr_id == prev_filter_map_expr_id && !is_dyn_trait { - return Some(()); - } + if *function_id == self.next_function_id? + && let Some(prev_filter_map_expr_id) = self.prev_filter_map_expr_id + { + let is_dyn_trait = self + .prev_receiver_ty + .as_ref() + .is_some_and(|it| it.strip_references().dyn_trait().is_some()); + if *receiver_expr_id == prev_filter_map_expr_id && !is_dyn_trait { + return Some(()); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index ca132fbdc454..e803b56a1ed8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -382,10 +382,10 @@ impl HirDisplay for Pat { let subpats = (0..num_fields).map(|i| { WriteWith(move |f| { let fid = LocalFieldId::from_raw((i as u32).into()); - if let Some(p) = subpatterns.get(i) { - if p.field == fid { - return p.pattern.hir_fmt(f); - } + if let Some(p) = subpatterns.get(i) + && p.field == fid + { + return p.pattern.hir_fmt(f); } if let Some(p) = subpatterns.iter().find(|p| p.field == fid) { p.pattern.hir_fmt(f) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index f6ad3c7aae2d..827585e50693 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -272,10 +272,10 @@ impl<'db> UnsafeVisitor<'db> { if let Some(func) = callee.as_fn_def(self.db) { self.check_call(current, func); } - if let TyKind::Function(fn_ptr) = callee.kind(Interner) { - if fn_ptr.sig.safety == chalk_ir::Safety::Unsafe { - self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall); - } + if let TyKind::Function(fn_ptr) = callee.kind(Interner) + && fn_ptr.sig.safety == chalk_ir::Safety::Unsafe + { + self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall); } } Expr::Path(path) => { @@ -346,12 +346,11 @@ impl<'db> UnsafeVisitor<'db> { Expr::Cast { .. } => self.inside_assignment = inside_assignment, Expr::Field { .. } => { self.inside_assignment = inside_assignment; - if !inside_assignment { - if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) = + if !inside_assignment + && let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) = self.infer.field_resolution(current) - { - self.on_unsafe_op(current.into(), UnsafetyReason::UnionField); - } + { + self.on_unsafe_op(current.into(), UnsafetyReason::UnionField); } } Expr::Unsafe { statements, .. } => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f0e31ebd020c..8f35a3c21455 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -608,48 +608,46 @@ impl HirDisplay for ProjectionTy { // if we are projection on a type parameter, check if the projection target has bounds // itself, if so, we render them directly as `impl Bound` instead of the less useful // `::Assoc` - if !f.display_kind.is_source_code() { - if let TyKind::Placeholder(idx) = self_ty.kind(Interner) { - if !f.bounds_formatting_ctx.contains(self) { - let db = f.db; - let id = from_placeholder_idx(db, *idx); - let generics = generics(db, id.parent); + if !f.display_kind.is_source_code() + && let TyKind::Placeholder(idx) = self_ty.kind(Interner) + && !f.bounds_formatting_ctx.contains(self) + { + let db = f.db; + let id = from_placeholder_idx(db, *idx); + let generics = generics(db, id.parent); - let substs = generics.placeholder_subst(db); - let bounds = db - .generic_predicates(id.parent) - .iter() - .map(|pred| pred.clone().substitute(Interner, &substs)) - .filter(|wc| { - let ty = match wc.skip_binders() { - WhereClause::Implemented(tr) => tr.self_type_parameter(Interner), - WhereClause::TypeOutlives(t) => t.ty.clone(), - // We shouldn't be here if these exist - WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => { - return false; - } - }; - let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else { - return false; - }; - proj == self - }) - .collect::>(); - if !bounds.is_empty() { - return f.format_bounds_with(self.clone(), |f| { - write_bounds_like_dyn_trait_with_prefix( - f, - "impl", - Either::Left( - &TyKind::Alias(AliasTy::Projection(self.clone())) - .intern(Interner), - ), - &bounds, - SizedByDefault::NotSized, - ) - }); - } - } + let substs = generics.placeholder_subst(db); + let bounds = db + .generic_predicates(id.parent) + .iter() + .map(|pred| pred.clone().substitute(Interner, &substs)) + .filter(|wc| { + let ty = match wc.skip_binders() { + WhereClause::Implemented(tr) => tr.self_type_parameter(Interner), + WhereClause::TypeOutlives(t) => t.ty.clone(), + // We shouldn't be here if these exist + WhereClause::AliasEq(_) | WhereClause::LifetimeOutlives(_) => { + return false; + } + }; + let TyKind::Alias(AliasTy::Projection(proj)) = ty.kind(Interner) else { + return false; + }; + proj == self + }) + .collect::>(); + if !bounds.is_empty() { + return f.format_bounds_with(self.clone(), |f| { + write_bounds_like_dyn_trait_with_prefix( + f, + "impl", + Either::Left( + &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner), + ), + &bounds, + SizedByDefault::NotSized, + ) + }); } } @@ -1860,18 +1858,13 @@ fn write_bounds_like_dyn_trait( write!(f, "{}", f.db.trait_signature(trait_).name.display(f.db, f.edition()))?; f.end_location_link(); if is_fn_trait { - if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) { - if let Some(args) = + if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) + && let Some(args) = params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple()) - { - write!(f, "(")?; - hir_fmt_generic_arguments( - f, - args.as_slice(Interner), - self_.ty(Interner), - )?; - write!(f, ")")?; - } + { + write!(f, "(")?; + hir_fmt_generic_arguments(f, args.as_slice(Interner), self_.ty(Interner))?; + write!(f, ")")?; } } else { let params = generic_args_sans_defaults( @@ -1879,13 +1872,13 @@ fn write_bounds_like_dyn_trait( Some(trait_.into()), trait_ref.substitution.as_slice(Interner), ); - if let [self_, params @ ..] = params { - if !params.is_empty() { - write!(f, "<")?; - hir_fmt_generic_arguments(f, params, self_.ty(Interner))?; - // there might be assoc type bindings, so we leave the angle brackets open - angle_open = true; - } + if let [self_, params @ ..] = params + && !params.is_empty() + { + write!(f, "<")?; + hir_fmt_generic_arguments(f, params, self_.ty(Interner))?; + // there might be assoc type bindings, so we leave the angle brackets open + angle_open = true; } } } @@ -2443,11 +2436,11 @@ impl HirDisplayWithExpressionStore for Path { generic_args.args[0].hir_fmt(f, store)?; } } - if let Some(ret) = generic_args.bindings[0].type_ref { - if !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty()) { - write!(f, " -> ")?; - ret.hir_fmt(f, store)?; - } + if let Some(ret) = generic_args.bindings[0].type_ref + && !matches!(&store[ret], TypeRef::Tuple(v) if v.is_empty()) + { + write!(f, " -> ")?; + ret.hir_fmt(f, store)?; } } hir_def::expr_store::path::GenericArgsParentheses::No => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 30949c83bfae..6294d683e6c0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -136,16 +136,15 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b let predicates = predicates.iter().map(|p| p.skip_binders().skip_binders().clone()); elaborate_clause_supertraits(db, predicates).any(|pred| match pred { WhereClause::Implemented(trait_ref) => { - if from_chalk_trait_id(trait_ref.trait_id) == sized { - if let TyKind::BoundVar(it) = + if from_chalk_trait_id(trait_ref.trait_id) == sized + && let TyKind::BoundVar(it) = *trait_ref.self_type_parameter(Interner).kind(Interner) - { - // Since `generic_predicates` is `Binder>`, the `DebrujinIndex` of - // self-parameter is `1` - return it - .index_if_bound_at(DebruijnIndex::ONE) - .is_some_and(|idx| idx == trait_self_param_idx); - } + { + // Since `generic_predicates` is `Binder>`, the `DebrujinIndex` of + // self-parameter is `1` + return it + .index_if_bound_at(DebruijnIndex::ONE) + .is_some_and(|idx| idx == trait_self_param_idx); } false } @@ -401,10 +400,10 @@ where cb(MethodViolationCode::ReferencesSelfOutput)?; } - if !func_data.is_async() { - if let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig) { - cb(mvc)?; - } + if !func_data.is_async() + && let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig) + { + cb(mvc)?; } let generic_params = db.generic_params(func.into()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 7c39afa0ef89..86345b23364d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -902,12 +902,12 @@ impl<'db> InferenceContext<'db> { return false; } - if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic { - if let Some(ty) = field_with_same_name { - *ty = table.resolve_completely(ty.clone()); - if ty.contains_unknown() { - *field_with_same_name = None; - } + if let UnresolvedMethodCall { field_with_same_name, .. } = diagnostic + && let Some(ty) = field_with_same_name + { + *ty = table.resolve_completely(ty.clone()); + if ty.contains_unknown() { + *field_with_same_name = None; } } } @@ -1010,12 +1010,12 @@ impl<'db> InferenceContext<'db> { param_tys.push(va_list_ty); } let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var())); - if let Some(self_param) = self.body.self_param { - if let Some(ty) = param_tys.next() { - let ty = self.insert_type_vars(ty); - let ty = self.normalize_associated_types_in(ty); - self.write_binding_ty(self_param, ty); - } + if let Some(self_param) = self.body.self_param + && let Some(ty) = param_tys.next() + { + let ty = self.insert_type_vars(ty); + let ty = self.normalize_associated_types_in(ty); + self.write_binding_ty(self_param, ty); } let mut tait_candidates = FxHashSet::default(); for (ty, pat) in param_tys.zip(&*self.body.params) { @@ -1199,20 +1199,19 @@ impl<'db> InferenceContext<'db> { ) -> std::ops::ControlFlow { let ty = self.table.resolve_ty_shallow(ty); - if let TyKind::OpaqueType(id, _) = ty.kind(Interner) { - if let ImplTraitId::TypeAliasImplTrait(alias_id, _) = + if let TyKind::OpaqueType(id, _) = ty.kind(Interner) + && let ImplTraitId::TypeAliasImplTrait(alias_id, _) = self.db.lookup_intern_impl_trait_id((*id).into()) - { - let loc = self.db.lookup_intern_type_alias(alias_id); - match loc.container { - ItemContainerId::ImplId(impl_id) => { - self.assocs.insert(*id, (impl_id, ty.clone())); - } - ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => { - self.non_assocs.insert(*id, ty.clone()); - } - _ => {} + { + let loc = self.db.lookup_intern_type_alias(alias_id); + match loc.container { + ItemContainerId::ImplId(impl_id) => { + self.assocs.insert(*id, (impl_id, ty.clone())); } + ItemContainerId::ModuleId(..) | ItemContainerId::ExternBlockId(..) => { + self.non_assocs.insert(*id, ty.clone()); + } + _ => {} } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 4e95eca3f940..f0a4167f8e25 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -233,26 +233,25 @@ impl CastCheck { F: FnMut(ExprId, Vec), { // Mutability order is opposite to rustc. `Mut < Not` - if m_expr <= m_cast { - if let TyKind::Array(ety, _) = t_expr.kind(Interner) { - // Coerce to a raw pointer so that we generate RawPtr in MIR. - let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner); - if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type, CoerceNever::Yes) - { - apply_adjustments(self.source_expr, adj); - } else { - never!( - "could not cast from reference to array to pointer to array ({:?} to {:?})", - self.expr_ty, - array_ptr_type - ); - } + if m_expr <= m_cast + && let TyKind::Array(ety, _) = t_expr.kind(Interner) + { + // Coerce to a raw pointer so that we generate RawPtr in MIR. + let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner); + if let Ok((adj, _)) = table.coerce(&self.expr_ty, &array_ptr_type, CoerceNever::Yes) { + apply_adjustments(self.source_expr, adj); + } else { + never!( + "could not cast from reference to array to pointer to array ({:?} to {:?})", + self.expr_ty, + array_ptr_type + ); + } - // This is a less strict condition than rustc's `demand_eqtype`, - // but false negative is better than false positive - if table.coerce(ety, t_cast, CoerceNever::Yes).is_ok() { - return Ok(()); - } + // This is a less strict condition than rustc's `demand_eqtype`, + // but false negative is better than false positive + if table.coerce(ety, t_cast, CoerceNever::Yes).is_ok() { + return Ok(()); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index c3029bf2b59a..8024c1a9a4e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -176,12 +176,12 @@ impl InferenceContext<'_> { } // Deduction based on the expected `dyn Fn` is done separately. - if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) { - if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) { - let expected_sig_ty = TyKind::Function(sig).intern(Interner); + if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) + && let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) + { + let expected_sig_ty = TyKind::Function(sig).intern(Interner); - self.unify(sig_ty, &expected_sig_ty); - } + self.unify(sig_ty, &expected_sig_ty); } } @@ -208,14 +208,13 @@ impl InferenceContext<'_> { alias: AliasTy::Projection(projection_ty), ty: projected_ty, }) = bound.skip_binders() - { - if let Some(sig) = self.deduce_sig_from_projection( + && let Some(sig) = self.deduce_sig_from_projection( closure_kind, projection_ty, projected_ty, - ) { - return Some(sig); - } + ) + { + return Some(sig); } None }); @@ -254,55 +253,44 @@ impl InferenceContext<'_> { let mut expected_kind = None; for clause in elaborate_clause_supertraits(self.db, clauses.rev()) { - if expected_sig.is_none() { - if let WhereClause::AliasEq(AliasEq { - alias: AliasTy::Projection(projection), - ty, - }) = &clause - { - let inferred_sig = - self.deduce_sig_from_projection(closure_kind, projection, ty); - // Make sure that we didn't infer a signature that mentions itself. - // This can happen when we elaborate certain supertrait bounds that - // mention projections containing the `Self` type. See rust-lang/rust#105401. - struct MentionsTy<'a> { - expected_ty: &'a Ty, + if expected_sig.is_none() + && let WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection), ty }) = + &clause + { + let inferred_sig = self.deduce_sig_from_projection(closure_kind, projection, ty); + // Make sure that we didn't infer a signature that mentions itself. + // This can happen when we elaborate certain supertrait bounds that + // mention projections containing the `Self` type. See rust-lang/rust#105401. + struct MentionsTy<'a> { + expected_ty: &'a Ty, + } + impl TypeVisitor for MentionsTy<'_> { + type BreakTy = (); + + fn interner(&self) -> Interner { + Interner } - impl TypeVisitor for MentionsTy<'_> { - type BreakTy = (); - fn interner(&self) -> Interner { - Interner - } - - fn as_dyn( - &mut self, - ) -> &mut dyn TypeVisitor - { - self - } - - fn visit_ty( - &mut self, - t: &Ty, - db: chalk_ir::DebruijnIndex, - ) -> ControlFlow<()> { - if t == self.expected_ty { - ControlFlow::Break(()) - } else { - t.super_visit_with(self, db) - } - } - } - if inferred_sig - .visit_with( - &mut MentionsTy { expected_ty }, - chalk_ir::DebruijnIndex::INNERMOST, - ) - .is_continue() + fn as_dyn( + &mut self, + ) -> &mut dyn TypeVisitor { - expected_sig = inferred_sig; + self } + + fn visit_ty(&mut self, t: &Ty, db: chalk_ir::DebruijnIndex) -> ControlFlow<()> { + if t == self.expected_ty { + ControlFlow::Break(()) + } else { + t.super_visit_with(self, db) + } + } + } + if inferred_sig + .visit_with(&mut MentionsTy { expected_ty }, chalk_ir::DebruijnIndex::INNERMOST) + .is_continue() + { + expected_sig = inferred_sig; } } @@ -617,11 +605,10 @@ impl HirPlace { if let CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow, }) = current_capture + && self.projections[len..].contains(&ProjectionElem::Deref) { - if self.projections[len..].contains(&ProjectionElem::Deref) { - current_capture = - CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }); - } + current_capture = + CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }); } current_capture } @@ -1076,12 +1063,11 @@ impl InferenceContext<'_> { Mutability::Mut => CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }), Mutability::Not => CaptureKind::ByRef(BorrowKind::Shared), }; - if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) { - if let Some(place) = + if let Some(place) = self.place_of_expr_without_adjust(tgt_expr) + && let Some(place) = apply_adjusts_to_place(&mut self.current_capture_span_stack, place, rest) - { - self.add_capture(place, capture_kind); - } + { + self.add_capture(place, capture_kind); } self.walk_expr_with_adjust(tgt_expr, rest); } @@ -1169,15 +1155,15 @@ impl InferenceContext<'_> { } } self.walk_expr(*expr); - if let Some(discr_place) = self.place_of_expr(*expr) { - if self.is_upvar(&discr_place) { - let mut capture_mode = None; - for arm in arms.iter() { - self.walk_pat(&mut capture_mode, arm.pat); - } - if let Some(c) = capture_mode { - self.push_capture(discr_place, c); - } + if let Some(discr_place) = self.place_of_expr(*expr) + && self.is_upvar(&discr_place) + { + let mut capture_mode = None; + for arm in arms.iter() { + self.walk_pat(&mut capture_mode, arm.pat); + } + if let Some(c) = capture_mode { + self.push_capture(discr_place, c); } } } @@ -1209,13 +1195,11 @@ impl InferenceContext<'_> { let mutability = 'b: { if let Some(deref_trait) = self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) - { - if let Some(deref_fn) = deref_trait + && let Some(deref_fn) = deref_trait .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::deref_mut)) - { - break 'b deref_fn == f; - } + { + break 'b deref_fn == f; } false }; @@ -1405,10 +1389,10 @@ impl InferenceContext<'_> { fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { let mut ty = None; - if let Some(it) = self.result.expr_adjustments.get(&e) { - if let Some(it) = it.last() { - ty = Some(it.target.clone()); - } + if let Some(it) = self.result.expr_adjustments.get(&e) + && let Some(it) = it.last() + { + ty = Some(it.target.clone()); } ty.unwrap_or_else(|| self.expr_ty(e)) } @@ -1793,10 +1777,10 @@ impl InferenceContext<'_> { } pub(super) fn add_current_closure_dependency(&mut self, dep: ClosureId) { - if let Some(c) = self.current_closure { - if !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep) { - self.closure_dependencies.entry(c).or_default().push(dep); - } + if let Some(c) = self.current_closure + && !dep_creates_cycle(&self.closure_dependencies, &mut FxHashSet::default(), c, dep) + { + self.closure_dependencies.entry(c).or_default().push(dep); } fn dep_creates_cycle( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 39bd90849fe8..761a2564aa79 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -164,14 +164,14 @@ impl CoerceMany { // - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335) // First try to coerce the new expression to the type of the previous ones, // but only if the new expression has no coercion already applied to it. - if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) { - if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) { - self.final_ty = Some(res); - if let Some(expr) = expr { - self.expressions.push(expr); - } - return; + if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) + && let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) + { + self.final_ty = Some(res); + if let Some(expr) = expr { + self.expressions.push(expr); } + return; } if let Ok((adjustments, res)) = @@ -322,18 +322,13 @@ impl InferenceTable<'_> { // If we are coercing into a TAIT, coerce into its proxy inference var, instead. let mut to_ty = to_ty; let _to; - if let Some(tait_table) = &self.tait_coercion_table { - if let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) { - if !matches!( - from_ty.kind(Interner), - TyKind::InferenceVar(..) | TyKind::OpaqueType(..) - ) { - if let Some(ty) = tait_table.get(opaque_ty_id) { - _to = ty.clone(); - to_ty = &_to; - } - } - } + if let Some(tait_table) = &self.tait_coercion_table + && let TyKind::OpaqueType(opaque_ty_id, _) = to_ty.kind(Interner) + && !matches!(from_ty.kind(Interner), TyKind::InferenceVar(..) | TyKind::OpaqueType(..)) + && let Some(ty) = tait_table.get(opaque_ty_id) + { + _to = ty.clone(); + to_ty = &_to; } // Consider coercing the subtype to a DST @@ -594,14 +589,13 @@ impl InferenceTable<'_> { F: FnOnce(Ty) -> Vec, G: FnOnce(Ty) -> Vec, { - if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner) { - if let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) = + if let TyKind::Function(to_fn_ptr) = to_ty.kind(Interner) + && let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) = (from_fn_ptr.sig.safety, to_fn_ptr.sig.safety) - { - let from_unsafe = - TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner); - return self.unify_and(&from_unsafe, to_ty, to_unsafe); - } + { + let from_unsafe = + TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(Interner); + return self.unify_and(&from_unsafe, to_ty, to_unsafe); } self.unify_and(&from_ty, to_ty, normal) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index d43c99fc2827..16fc2bfc0631 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -653,19 +653,18 @@ impl InferenceContext<'_> { // FIXME: Note down method resolution her match op { UnaryOp::Deref => { - if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) { - if let Some(deref_fn) = deref_trait + if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) + && let Some(deref_fn) = deref_trait .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::deref)) - { - // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that - // the mutability is not wrong, and will be fixed in `self.infer_mut`). - self.write_method_resolution( - tgt_expr, - deref_fn, - Substitution::empty(Interner), - ); - } + { + // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that + // the mutability is not wrong, and will be fixed in `self.infer_mut`). + self.write_method_resolution( + tgt_expr, + deref_fn, + Substitution::empty(Interner), + ); } if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) { self.resolve_ty_shallow(derefed) @@ -1387,28 +1386,28 @@ impl InferenceContext<'_> { let ret_ty = match method_ty.callable_sig(self.db) { Some(sig) => { let p_left = &sig.params()[0]; - if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) { - if let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner) { - self.write_expr_adj( - lhs, - Box::new([Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)), - target: p_left.clone(), - }]), - ); - } + if matches!(op, BinaryOp::CmpOp(..) | BinaryOp::Assignment { .. }) + && let TyKind::Ref(mtbl, lt, _) = p_left.kind(Interner) + { + self.write_expr_adj( + lhs, + Box::new([Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)), + target: p_left.clone(), + }]), + ); } let p_right = &sig.params()[1]; - if matches!(op, BinaryOp::CmpOp(..)) { - if let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner) { - self.write_expr_adj( - rhs, - Box::new([Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)), - target: p_right.clone(), - }]), - ); - } + if matches!(op, BinaryOp::CmpOp(..)) + && let TyKind::Ref(mtbl, lt, _) = p_right.kind(Interner) + { + self.write_expr_adj( + rhs, + Box::new([Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(lt.clone(), *mtbl)), + target: p_right.clone(), + }]), + ); } sig.ret().clone() } @@ -1664,14 +1663,12 @@ impl InferenceContext<'_> { Some((ty, field_id, adjustments, is_public)) => { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); self.result.field_resolutions.insert(tgt_expr, field_id); - if !is_public { - if let Either::Left(field) = field_id { - // FIXME: Merge this diagnostic into UnresolvedField? - self.push_diagnostic(InferenceDiagnostic::PrivateField { - expr: tgt_expr, - field, - }); - } + if !is_public && let Either::Left(field) = field_id { + // FIXME: Merge this diagnostic into UnresolvedField? + self.push_diagnostic(InferenceDiagnostic::PrivateField { + expr: tgt_expr, + field, + }); } ty } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index 3f7eba9dd18c..c798e9e050a1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -124,53 +124,41 @@ impl InferenceContext<'_> { self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) } &Expr::Index { base, index } => { - if mutability == Mutability::Mut { - if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { - if let Some(index_trait) = - LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate) - { - if let Some(index_fn) = index_trait - .trait_items(self.db) - .method_by_name(&Name::new_symbol_root(sym::index_mut)) - { - *f = index_fn; - let mut base_ty = None; - let base_adjustments = self - .result - .expr_adjustments - .get_mut(&base) - .and_then(|it| it.last_mut()); - if let Some(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), - target, - }) = base_adjustments - { - if let TyKind::Ref(_, _, ty) = target.kind(Interner) { - base_ty = Some(ty.clone()); - } - *mutability = Mutability::Mut; - } - - // Apply `IndexMut` obligation for non-assignee expr - if let Some(base_ty) = base_ty { - let index_ty = - if let Some(ty) = self.result.type_of_expr.get(index) { - ty.clone() - } else { - self.infer_expr( - index, - &Expectation::none(), - ExprIsRead::Yes, - ) - }; - let trait_ref = TyBuilder::trait_ref(self.db, index_trait) - .push(base_ty) - .fill(|_| index_ty.clone().cast(Interner)) - .build(); - self.push_obligation(trait_ref.cast(Interner)); - } - } + if mutability == Mutability::Mut + && let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) + && let Some(index_trait) = + LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate) + && let Some(index_fn) = index_trait + .trait_items(self.db) + .method_by_name(&Name::new_symbol_root(sym::index_mut)) + { + *f = index_fn; + let mut base_ty = None; + let base_adjustments = + self.result.expr_adjustments.get_mut(&base).and_then(|it| it.last_mut()); + if let Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), + target, + }) = base_adjustments + { + if let TyKind::Ref(_, _, ty) = target.kind(Interner) { + base_ty = Some(ty.clone()); } + *mutability = Mutability::Mut; + } + + // Apply `IndexMut` obligation for non-assignee expr + if let Some(base_ty) = base_ty { + let index_ty = if let Some(ty) = self.result.type_of_expr.get(index) { + ty.clone() + } else { + self.infer_expr(index, &Expectation::none(), ExprIsRead::Yes) + }; + let trait_ref = TyBuilder::trait_ref(self.db, index_trait) + .push(base_ty) + .fill(|_| index_ty.clone().cast(Interner)) + .build(); + self.push_obligation(trait_ref.cast(Interner)); } } self.infer_mut_expr(base, mutability); @@ -178,28 +166,23 @@ impl InferenceContext<'_> { } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { let mut mutability = mutability; - if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { - if mutability == Mutability::Mut { - if let Some(deref_trait) = - LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate) - { - let ty = self.result.type_of_expr.get(*expr); - let is_mut_ptr = ty.is_some_and(|ty| { - let ty = self.table.resolve_ty_shallow(ty); - matches!( - ty.kind(Interner), - chalk_ir::TyKind::Raw(Mutability::Mut, _) - ) - }); - if is_mut_ptr { - mutability = Mutability::Not; - } else if let Some(deref_fn) = deref_trait - .trait_items(self.db) - .method_by_name(&Name::new_symbol_root(sym::deref_mut)) - { - *f = deref_fn; - } - } + if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) + && mutability == Mutability::Mut + && let Some(deref_trait) = + LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate) + { + let ty = self.result.type_of_expr.get(*expr); + let is_mut_ptr = ty.is_some_and(|ty| { + let ty = self.table.resolve_ty_shallow(ty); + matches!(ty.kind(Interner), chalk_ir::TyKind::Raw(Mutability::Mut, _)) + }); + if is_mut_ptr { + mutability = Mutability::Not; + } else if let Some(deref_fn) = deref_trait + .trait_items(self.db) + .method_by_name(&Name::new_symbol_root(sym::deref_mut)) + { + *f = deref_fn; } } self.infer_mut_expr(*expr, mutability); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 18288b718f76..707bec0fce4c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -498,12 +498,12 @@ impl InferenceContext<'_> { // If `expected` is an infer ty, we try to equate it to an array if the given pattern // allows it. See issue #16609 - if self.pat_is_irrefutable(decl) && expected.is_ty_var() { - if let Some(resolved_array_ty) = + if self.pat_is_irrefutable(decl) + && expected.is_ty_var() + && let Some(resolved_array_ty) = self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice) - { - self.unify(&expected, &resolved_array_ty); - } + { + self.unify(&expected, &resolved_array_ty); } let expected = self.resolve_ty_shallow(&expected); @@ -539,17 +539,16 @@ impl InferenceContext<'_> { fn infer_lit_pat(&mut self, expr: ExprId, expected: &Ty) -> Ty { // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. - if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] { - if let Some((inner, ..)) = expected.as_reference() { - let inner = self.resolve_ty_shallow(inner); - if matches!(inner.kind(Interner), TyKind::Slice(_)) { - let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); - let slice_ty = TyKind::Slice(elem_ty).intern(Interner); - let ty = - TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty).intern(Interner); - self.write_expr_ty(expr, ty.clone()); - return ty; - } + if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] + && let Some((inner, ..)) = expected.as_reference() + { + let inner = self.resolve_ty_shallow(inner); + if matches!(inner.kind(Interner), TyKind::Slice(_)) { + let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); + let slice_ty = TyKind::Slice(elem_ty).intern(Interner); + let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty).intern(Interner); + self.write_expr_ty(expr, ty.clone()); + return ty; } } 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 d61e7de6672f..afee9606bd5f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -830,10 +830,10 @@ fn named_associated_type_shorthand_candidates( let data = t.hir_trait_id().trait_items(db); for (name, assoc_id) in &data.items { - if let AssocItemId::TypeAliasId(alias) = assoc_id { - if let Some(result) = cb(name, &t, *alias) { - return Some(result); - } + if let AssocItemId::TypeAliasId(alias) = assoc_id + && let Some(result) = cb(name, &t, *alias) + { + return Some(result); } } None diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 5c06234fa077..9519c38eeddf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -360,15 +360,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } } - if let Some(enum_segment) = enum_segment { - if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) - && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) - { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: (enum_segment + 1) as u32, - reason: GenericArgsProhibitedReason::EnumVariant, - }); - } + if let Some(enum_segment) = enum_segment + && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) + && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) + { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: (enum_segment + 1) as u32, + reason: GenericArgsProhibitedReason::EnumVariant, + }); } self.handle_type_ns_resolution(&resolution); @@ -417,15 +416,14 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { } } - if let Some(enum_segment) = enum_segment { - if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) - && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) - { - self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { - segment: (enum_segment + 1) as u32, - reason: GenericArgsProhibitedReason::EnumVariant, - }); - } + if let Some(enum_segment) = enum_segment + && segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) + && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) + { + self.on_diagnostic(PathLoweringDiagnostic::GenericArgsProhibited { + segment: (enum_segment + 1) as u32, + reason: GenericArgsProhibitedReason::EnumVariant, + }); } match &res { @@ -576,13 +574,12 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { // This simplifies the code a bit. let penultimate_idx = self.current_segment_idx.wrapping_sub(1); let penultimate = self.segments.get(penultimate_idx); - if let Some(penultimate) = penultimate { - if self.current_or_prev_segment.args_and_bindings.is_none() - && penultimate.args_and_bindings.is_some() - { - self.current_segment_idx = penultimate_idx; - self.current_or_prev_segment = penultimate; - } + if let Some(penultimate) = penultimate + && self.current_or_prev_segment.args_and_bindings.is_none() + && penultimate.args_and_bindings.is_some() + { + self.current_segment_idx = penultimate_idx; + self.current_or_prev_segment = penultimate; } var.lookup(self.ctx.db).parent.into() } @@ -607,37 +604,36 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { ) -> Substitution { let mut lifetime_elision = self.ctx.lifetime_elision.clone(); - if let Some(args) = self.current_or_prev_segment.args_and_bindings { - if args.parenthesized != GenericArgsParentheses::No { - let prohibit_parens = match def { - GenericDefId::TraitId(trait_) => { - // RTN is prohibited anyways if we got here. - let is_rtn = - args.parenthesized == GenericArgsParentheses::ReturnTypeNotation; - let is_fn_trait = self - .ctx - .db - .trait_signature(trait_) - .flags - .contains(TraitFlags::RUSTC_PAREN_SUGAR); - is_rtn || !is_fn_trait - } - _ => true, - }; - - if prohibit_parens { - let segment = self.current_segment_u32(); - self.on_diagnostic( - PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, - ); - - return TyBuilder::unknown_subst(self.ctx.db, def); + if let Some(args) = self.current_or_prev_segment.args_and_bindings + && args.parenthesized != GenericArgsParentheses::No + { + let prohibit_parens = match def { + GenericDefId::TraitId(trait_) => { + // RTN is prohibited anyways if we got here. + let is_rtn = args.parenthesized == GenericArgsParentheses::ReturnTypeNotation; + let is_fn_trait = self + .ctx + .db + .trait_signature(trait_) + .flags + .contains(TraitFlags::RUSTC_PAREN_SUGAR); + is_rtn || !is_fn_trait } + _ => true, + }; - // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. - lifetime_elision = - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; + if prohibit_parens { + let segment = self.current_segment_u32(); + self.on_diagnostic( + PathLoweringDiagnostic::ParenthesizedGenericArgsWithoutFnTrait { segment }, + ); + + return TyBuilder::unknown_subst(self.ctx.db, def); } + + // `Fn()`-style generics are treated like functions for the purpose of lifetime elision. + lifetime_elision = + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false }; } self.substs_from_args_and_bindings( @@ -753,18 +749,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { match param { GenericParamDataRef::LifetimeParamData(_) => error_lifetime().cast(Interner), GenericParamDataRef::TypeParamData(param) => { - if !infer_args && param.default.is_some() { - if let Some(default) = default() { - return default; - } + if !infer_args + && param.default.is_some() + && let Some(default) = default() + { + return default; } TyKind::Error.intern(Interner).cast(Interner) } GenericParamDataRef::ConstParamData(param) => { - if !infer_args && param.default.is_some() { - if let Some(default) = default() { - return default; - } + if !infer_args + && param.default.is_some() + && let Some(default) = default() + { + return default; } let GenericParamId::ConstParamId(const_id) = param_id else { unreachable!("non-const param ID for const param"); 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 a6150a9bc172..b22781e94701 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 @@ -581,15 +581,15 @@ impl ReceiverAdjustments { } if self.unsize_array { ty = 'it: { - if let TyKind::Ref(m, l, inner) = ty.kind(Interner) { - if let TyKind::Array(inner, _) = inner.kind(Interner) { - break 'it TyKind::Ref( - *m, - l.clone(), - TyKind::Slice(inner.clone()).intern(Interner), - ) - .intern(Interner); - } + if let TyKind::Ref(m, l, inner) = ty.kind(Interner) + && let TyKind::Array(inner, _) = inner.kind(Interner) + { + break 'it TyKind::Ref( + *m, + l.clone(), + TyKind::Slice(inner.clone()).intern(Interner), + ) + .intern(Interner); } // FIXME: report diagnostic if array unsizing happens without indirection. ty @@ -1549,11 +1549,11 @@ fn is_valid_impl_method_candidate( check_that!(receiver_ty.is_none()); check_that!(name.is_none_or(|n| n == item_name)); - if let Some(from_module) = visible_from_module { - if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) { - cov_mark::hit!(const_candidate_not_visible); - return IsValidCandidate::NotVisible; - } + if let Some(from_module) = visible_from_module + && !db.assoc_visibility(c.into()).is_visible_from(db, from_module) + { + cov_mark::hit!(const_candidate_not_visible); + return IsValidCandidate::NotVisible; } let self_ty_matches = table.run_in_snapshot(|table| { let expected_self_ty = @@ -1638,11 +1638,11 @@ fn is_valid_impl_fn_candidate( let db = table.db; let data = db.function_signature(fn_id); - if let Some(from_module) = visible_from_module { - if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) { - cov_mark::hit!(autoderef_candidate_not_visible); - return IsValidCandidate::NotVisible; - } + if let Some(from_module) = visible_from_module + && !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) + { + cov_mark::hit!(autoderef_candidate_not_visible); + return IsValidCandidate::NotVisible; } table.run_in_snapshot(|table| { let _p = tracing::info_span!("subst_for_def").entered(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index fb0c0dee095f..52df851c30d1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -559,10 +559,9 @@ fn mutability_of_locals( }, p, ) = value + && place_case(db, body, p) != ProjectionCase::Indirect { - if place_case(db, body, p) != ProjectionCase::Indirect { - push_mut_span(p.local, statement.span, &mut result); - } + push_mut_span(p.local, statement.span, &mut result); } } StatementKind::FakeRead(p) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 9a97bd6dbe29..dfb8ae704b99 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -1082,18 +1082,18 @@ impl Evaluator<'_> { let stack_size = { let mut stack_ptr = self.stack.len(); for (id, it) in body.locals.iter() { - if id == return_slot() { - if let Some(destination) = destination { - locals.ptr.insert(id, destination); - continue; - } + if id == return_slot() + && let Some(destination) = destination + { + locals.ptr.insert(id, destination); + continue; } let (size, align) = self.size_align_of_sized( &it.ty, &locals, "no unsized local in extending stack", )?; - while stack_ptr % align != 0 { + while !stack_ptr.is_multiple_of(align) { stack_ptr += 1; } let my_ptr = stack_ptr; @@ -1673,14 +1673,14 @@ impl Evaluator<'_> { if let Some(it) = goal(kind) { return Ok(it); } - if let TyKind::Adt(id, subst) = kind { - if let AdtId::StructId(struct_id) = id.0 { - let field_types = self.db.field_types(struct_id.into()); - if let Some(ty) = - field_types.iter().last().map(|it| it.1.clone().substitute(Interner, subst)) - { - return self.coerce_unsized_look_through_fields(&ty, goal); - } + if let TyKind::Adt(id, subst) = kind + && let AdtId::StructId(struct_id) = id.0 + { + let field_types = self.db.field_types(struct_id.into()); + if let Some(ty) = + field_types.iter().last().map(|it| it.1.clone().substitute(Interner, subst)) + { + return self.coerce_unsized_look_through_fields(&ty, goal); } } Err(MirEvalError::CoerceUnsizedError(ty.clone())) @@ -1778,17 +1778,15 @@ impl Evaluator<'_> { locals: &Locals, ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { let adt = it.adt_id(self.db); - if let DefWithBodyId::VariantId(f) = locals.body.owner { - if let VariantId::EnumVariantId(it) = it { - if let AdtId::EnumId(e) = adt { - if f.lookup(self.db).parent == e { - // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and - // infinite sized type errors) we use a dummy layout - let i = self.const_eval_discriminant(it)?; - return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); - } - } - } + if let DefWithBodyId::VariantId(f) = locals.body.owner + && let VariantId::EnumVariantId(it) = it + && let AdtId::EnumId(e) = adt + && f.lookup(self.db).parent == e + { + // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and + // infinite sized type errors) we use a dummy layout + let i = self.const_eval_discriminant(it)?; + return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); } let layout = self.layout_adt(adt, subst)?; Ok(match &layout.variants { @@ -1909,10 +1907,10 @@ impl Evaluator<'_> { let name = const_id.name(self.db); MirEvalError::ConstEvalError(name, Box::new(e)) })?; - if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value { - if let ConstScalar::Bytes(v, mm) = &c.interned { - break 'b (v, mm); - } + if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value + && let ConstScalar::Bytes(v, mm) = &c.interned + { + break 'b (v, mm); } not_supported!("unevaluatable constant"); } @@ -2055,14 +2053,13 @@ impl Evaluator<'_> { .is_sized() .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); } - if let DefWithBodyId::VariantId(f) = locals.body.owner { - if let Some((AdtId::EnumId(e), _)) = ty.as_adt() { - if f.lookup(self.db).parent == e { - // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and - // infinite sized type errors) we use a dummy size - return Ok(Some((16, 16))); - } - } + if let DefWithBodyId::VariantId(f) = locals.body.owner + && let Some((AdtId::EnumId(e), _)) = ty.as_adt() + && f.lookup(self.db).parent == e + { + // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and + // infinite sized type errors) we use a dummy size + return Ok(Some((16, 16))); } let layout = self.layout(ty); if self.assert_placeholder_ty_is_unused @@ -2103,7 +2100,7 @@ impl Evaluator<'_> { if !align.is_power_of_two() || align > 10000 { return Err(MirEvalError::UndefinedBehavior(format!("Alignment {align} is invalid"))); } - while self.heap.len() % align != 0 { + while !self.heap.len().is_multiple_of(align) { self.heap.push(0); } if size.checked_add(self.heap.len()).is_none_or(|x| x > self.memory_limit) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index e9665d5ae9cf..bb4c963a8ae1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -119,25 +119,25 @@ impl Evaluator<'_> { destination.write_from_bytes(self, &result)?; return Ok(true); } - if let ItemContainerId::TraitId(t) = def.lookup(self.db).container { - if self.db.lang_attr(t.into()) == Some(LangItem::Clone) { - let [self_ty] = generic_args.as_slice(Interner) else { - not_supported!("wrong generic arg count for clone"); - }; - let Some(self_ty) = self_ty.ty(Interner) else { - not_supported!("wrong generic arg kind for clone"); - }; - // Clone has special impls for tuples and function pointers - if matches!( - self_ty.kind(Interner), - TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..) - ) { - self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?; - return Ok(true); - } - // Return early to prevent caching clone as non special fn. - return Ok(false); + if let ItemContainerId::TraitId(t) = def.lookup(self.db).container + && self.db.lang_attr(t.into()) == Some(LangItem::Clone) + { + let [self_ty] = generic_args.as_slice(Interner) else { + not_supported!("wrong generic arg count for clone"); + }; + let Some(self_ty) = self_ty.ty(Interner) else { + not_supported!("wrong generic arg kind for clone"); + }; + // Clone has special impls for tuples and function pointers + if matches!( + self_ty.kind(Interner), + TyKind::Function(_) | TyKind::Tuple(..) | TyKind::Closure(..) + ) { + self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?; + return Ok(true); } + // Return early to prevent caching clone as non special fn. + return Ok(false); } self.not_special_fn_cache.borrow_mut().insert(def); Ok(false) @@ -1256,23 +1256,22 @@ impl Evaluator<'_> { let addr = tuple.interval.addr.offset(offset); args.push(IntervalAndTy::new(addr, field, self, locals)?); } - if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) { - if let Some(def) = target + if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) + && let Some(def) = target .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::call_once)) - { - self.exec_fn_trait( - def, - &args, - // FIXME: wrong for manual impls of `FnOnce` - Substitution::empty(Interner), - locals, - destination, - None, - span, - )?; - return Ok(true); - } + { + self.exec_fn_trait( + def, + &args, + // FIXME: wrong for manual impls of `FnOnce` + Substitution::empty(Interner), + locals, + destination, + None, + span, + )?; + return Ok(true); } not_supported!("FnOnce was not available for executing const_eval_select"); } @@ -1367,12 +1366,11 @@ impl Evaluator<'_> { break; } } - if signed { - if let Some((&l, &r)) = lhs.iter().zip(rhs).next_back() { - if l != r { - result = (l as i8).cmp(&(r as i8)); - } - } + if signed + && let Some((&l, &r)) = lhs.iter().zip(rhs).next_back() + && l != r + { + result = (l as i8).cmp(&(r as i8)); } if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) { let ty = self.db.ty(e.into()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index bc331a23d98e..f55477290453 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -114,12 +114,11 @@ impl Evaluator<'_> { break; } } - if is_signed { - if let Some((&l, &r)) = l.iter().zip(r).next_back() { - if l != r { - result = (l as i8).cmp(&(r as i8)); - } - } + if is_signed + && let Some((&l, &r)) = l.iter().zip(r).next_back() + && l != r + { + result = (l as i8).cmp(&(r as i8)); } let result = match result { Ordering::Less => ["lt", "le", "ne"].contains(&name), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 07d814727293..eb80e8706fa0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -320,11 +320,11 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id: ExprId, current: BasicBlockId, ) -> Result> { - if !self.has_adjustments(expr_id) { - if let Expr::Literal(l) = &self.body[expr_id] { - let ty = self.expr_ty_without_adjust(expr_id); - return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); - } + if !self.has_adjustments(expr_id) + && let Expr::Literal(l) = &self.body[expr_id] + { + let ty = self.expr_ty_without_adjust(expr_id); + return Ok(Some((self.lower_literal_to_operand(ty, l)?, current))); } let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else { return Ok(None); @@ -1039,18 +1039,18 @@ impl<'ctx> MirLowerCtx<'ctx> { && rhs_ty.is_scalar() && (lhs_ty == rhs_ty || builtin_inequal_impls) }; - if !is_builtin { - if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { - let func = Operand::from_fn(self.db, func_id, generic_args); - return self.lower_call_and_args( - func, - [*lhs, *rhs].into_iter(), - place, - current, - self.is_uninhabited(expr_id), - expr_id.into(), - ); - } + if !is_builtin + && let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) + { + let func = Operand::from_fn(self.db, func_id, generic_args); + return self.lower_call_and_args( + func, + [*lhs, *rhs].into_iter(), + place, + current, + self.is_uninhabited(expr_id), + expr_id.into(), + ); } if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op { // last adjustment is `&mut` which we don't want it. @@ -1596,10 +1596,10 @@ impl<'ctx> MirLowerCtx<'ctx> { fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { let mut ty = None; - if let Some(it) = self.infer.expr_adjustments.get(&e) { - if let Some(it) = it.last() { - ty = Some(it.target.clone()); - } + if let Some(it) = self.infer.expr_adjustments.get(&e) + && let Some(it) = it.last() + { + ty = Some(it.target.clone()); } ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) } @@ -1848,13 +1848,13 @@ impl<'ctx> MirLowerCtx<'ctx> { self.result.param_locals.extend(params.clone().map(|(it, ty)| { let local_id = self.result.locals.alloc(Local { ty }); self.drop_scopes.last_mut().unwrap().locals.push(local_id); - if let Pat::Bind { id, subpat: None } = self.body[it] { - if matches!( + if let Pat::Bind { id, subpat: None } = self.body[it] + && matches!( self.body[id].mode, BindingAnnotation::Unannotated | BindingAnnotation::Mutable - ) { - self.result.binding_locals.insert(id, local_id); - } + ) + { + self.result.binding_locals.insert(id, local_id); } local_id })); @@ -1887,10 +1887,10 @@ impl<'ctx> MirLowerCtx<'ctx> { .into_iter() .skip(base_param_count + self_binding.is_some() as usize); for ((param, _), local) in params.zip(local_params) { - if let Pat::Bind { id, .. } = self.body[param] { - if local == self.binding_local(id)? { - continue; - } + if let Pat::Bind { id, .. } = self.body[param] + && local == self.binding_local(id)? + { + continue; } let r = self.pattern_match(current, None, local.into(), param)?; if let Some(b) = r.1 { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index e074c2d558e8..42a14664626f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -189,17 +189,14 @@ impl MirLowerCtx<'_> { self.expr_ty_without_adjust(expr_id), expr_id.into(), 'b: { - if let Some((f, _)) = self.infer.method_resolution(expr_id) { - if let Some(deref_trait) = + if let Some((f, _)) = self.infer.method_resolution(expr_id) + && let Some(deref_trait) = self.resolve_lang_item(LangItem::DerefMut)?.as_trait() - { - if let Some(deref_fn) = deref_trait - .trait_items(self.db) - .method_by_name(&Name::new_symbol_root(sym::deref_mut)) - { - break 'b deref_fn == f; - } - } + && let Some(deref_fn) = deref_trait + .trait_items(self.db) + .method_by_name(&Name::new_symbol_root(sym::deref_mut)) + { + break 'b deref_fn == f; } false }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 3325226b1d36..0440d8502232 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -317,27 +317,26 @@ impl MirLowerCtx<'_> { (current, current_else) = self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } - if let &Some(slice) = slice { - if mode != MatchingMode::Check { - if let Pat::Bind { id, subpat: _ } = self.body[slice] { - let next_place = cond_place.project( - ProjectionElem::Subslice { - from: prefix.len() as u64, - to: suffix.len() as u64, - }, - &mut self.result.projection_store, - ); - let mode = self.infer.binding_modes[slice]; - (current, current_else) = self.pattern_match_binding( - id, - mode, - next_place, - (slice).into(), - current, - current_else, - )?; - } - } + if let &Some(slice) = slice + && mode != MatchingMode::Check + && let Pat::Bind { id, subpat: _ } = self.body[slice] + { + let next_place = cond_place.project( + ProjectionElem::Subslice { + from: prefix.len() as u64, + to: suffix.len() as u64, + }, + &mut self.result.projection_store, + ); + let mode = self.infer.binding_modes[slice]; + (current, current_else) = self.pattern_match_binding( + id, + mode, + next_place, + (slice).into(), + current, + current_else, + )?; } for (i, &pat) in suffix.iter().enumerate() { let next_place = cond_place.project( @@ -391,10 +390,10 @@ impl MirLowerCtx<'_> { return Ok((current, current_else)); } let (c, subst) = 'b: { - if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) { - if let AssocItemId::ConstId(c) = x.0 { - break 'b (c, x.1); - } + if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) + && let AssocItemId::ConstId(c) = x.0 + { + break 'b (c, x.1); } if let ResolveValueResult::ValueNs(ValueNs::ConstId(c), _) = pr { break 'b (c, Substitution::empty(Interner)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 7414b4fc6070..08b9d242e71d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -125,11 +125,10 @@ pub(crate) fn trait_solve_query( alias: AliasTy::Projection(projection_ty), .. }))) = &goal.value.goal.data(Interner) + && let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) { - if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(db).kind(Interner) { - // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible - return Some(Solution::Ambig(Guidance::Unknown)); - } + // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible + return Some(Solution::Ambig(Guidance::Unknown)); } // Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index d07c1aa33b40..209ec7926e82 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -333,13 +333,13 @@ impl FallibleTypeFolder for UnevaluatedConstEvaluatorFolder<'_> { constant: Const, _outer_binder: DebruijnIndex, ) -> Result { - if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value { - if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned { - if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) { - return Ok(eval); - } else { - return Ok(unknown_const(constant.data(Interner).ty.clone())); - } + if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value + && let ConstScalar::UnevaluatedConst(id, subst) = &c.interned + { + if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) { + return Ok(eval); + } else { + return Ok(unknown_const(constant.data(Interner).ty.clone())); } } Ok(constant) diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index c1e814ec223e..fca0162765ec 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -604,13 +604,13 @@ impl<'db> AnyDiagnostic<'db> { } } BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr } => { - if let Ok(source_ptr) = source_map.expr_syntax(if_expr) { - if let Some(ptr) = source_ptr.value.cast::() { - return Some( - RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) } - .into(), - ); - } + if let Ok(source_ptr) = source_map.expr_syntax(if_expr) + && let Some(ptr) = source_ptr.value.cast::() + { + return Some( + RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) } + .into(), + ); } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 4ddb04b24f7f..a323f97997c6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -1020,21 +1020,21 @@ fn emit_macro_def_diagnostics<'db>( m: Macro, ) { let id = db.macro_def(m.id); - if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) { - if let Some(e) = expander.mac.err() { - let Some(ast) = id.ast_id().left() else { - never!("declarative expander for non decl-macro: {:?}", e); - return; - }; - let krate = HasModule::krate(&m.id, db); - let edition = krate.data(db).edition; - emit_def_diagnostic_( - db, - acc, - &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, - edition, - ); - } + if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) + && let Some(e) = expander.mac.err() + { + let Some(ast) = id.ast_id().left() else { + never!("declarative expander for non decl-macro: {:?}", e); + return; + }; + let krate = HasModule::krate(&m.id, db); + let edition = krate.data(db).edition; + emit_def_diagnostic_( + db, + acc, + &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, + edition, + ); } } @@ -2564,10 +2564,10 @@ impl<'db> Param<'db> { Callee::Closure(closure, _) => { let c = db.lookup_intern_closure(closure.into()); let body = db.body(c.0); - if let Expr::Closure { args, .. } = &body[c.1] { - if let Pat::Bind { id, .. } = &body[args[self.idx]] { - return Some(Local { parent: c.0, binding_id: *id }); - } + if let Expr::Closure { args, .. } = &body[c.1] + && let Pat::Bind { id, .. } = &body[args[self.idx]] + { + return Some(Local { parent: c.0, binding_id: *id }); } None } @@ -2761,26 +2761,20 @@ impl EvaluatedConst { pub fn render_debug(&self, db: &dyn HirDatabase) -> Result { let data = self.const_.data(Interner); - if let TyKind::Scalar(s) = data.ty.kind(Interner) { - if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) { - if let hir_ty::ConstValue::Concrete(c) = &data.value { - if let hir_ty::ConstScalar::Bytes(b, _) = &c.interned { - let value = u128::from_le_bytes(mir::pad16(b, false)); - let value_signed = - i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); - let mut result = if let Scalar::Int(_) = s { - value_signed.to_string() - } else { - value.to_string() - }; - if value >= 10 { - format_to!(result, " ({value:#X})"); - return Ok(result); - } else { - return Ok(result); - } - } - } + if let TyKind::Scalar(s) = data.ty.kind(Interner) + && matches!(s, Scalar::Int(_) | Scalar::Uint(_)) + && let hir_ty::ConstValue::Concrete(c) = &data.value + && let hir_ty::ConstScalar::Bytes(b, _) = &c.interned + { + let value = u128::from_le_bytes(mir::pad16(b, false)); + let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); + let mut result = + if let Scalar::Int(_) = s { value_signed.to_string() } else { value.to_string() }; + if value >= 10 { + format_to!(result, " ({value:#X})"); + return Ok(result); + } else { + return Ok(result); } } mir::render_const_using_debug_impl(db, self.def, &self.const_) @@ -4421,10 +4415,10 @@ impl Impl { let impls = db.trait_impls_in_crate(id); all.extend(impls.for_trait(trait_.id).map(Self::from)) } - if let Some(block) = module.id.containing_block() { - if let Some(trait_impls) = db.trait_impls_in_block(block) { - all.extend(trait_impls.for_trait(trait_.id).map(Self::from)); - } + if let Some(block) = module.id.containing_block() + && let Some(trait_impls) = db.trait_impls_in_block(block) + { + all.extend(trait_impls.for_trait(trait_.id).map(Self::from)); } all } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index adba59236a40..d207305b4c61 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -933,19 +933,18 @@ impl<'db> SemanticsImpl<'db> { InFile::new(file.file_id, last), false, &mut |InFile { value: last, file_id: last_fid }, _ctx| { - if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { - if first_fid == last_fid { - if let Some(p) = first.parent() { - let range = first.text_range().cover(last.text_range()); - let node = find_root(&p) - .covering_element(range) - .ancestors() - .take_while(|it| it.text_range() == range) - .find_map(N::cast); - if let Some(node) = node { - res.push(node); - } - } + if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() + && first_fid == last_fid + && let Some(p) = first.parent() + { + let range = first.text_range().cover(last.text_range()); + let node = find_root(&p) + .covering_element(range) + .ancestors() + .take_while(|it| it.text_range() == range) + .find_map(N::cast); + if let Some(node) = node { + res.push(node); } } }, @@ -1391,10 +1390,10 @@ impl<'db> SemanticsImpl<'db> { } })() .is_none(); - if was_not_remapped { - if let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) { - return Some(b); - } + if was_not_remapped + && let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) + { + return Some(b); } } } @@ -2068,14 +2067,12 @@ impl<'db> SemanticsImpl<'db> { break false; } - if let Some(parent) = ast::Expr::cast(parent.clone()) { - if let Some(ExprOrPatId::ExprId(expr_id)) = + if let Some(parent) = ast::Expr::cast(parent.clone()) + && let Some(ExprOrPatId::ExprId(expr_id)) = source_map.node_expr(InFile { file_id, value: &parent }) - { - if let Expr::Unsafe { .. } = body[expr_id] { - break true; - } - } + && let Expr::Unsafe { .. } = body[expr_id] + { + break true; } let Some(parent_) = parent.parent() else { break false }; @@ -2354,32 +2351,30 @@ struct RenameConflictsVisitor<'a> { impl RenameConflictsVisitor<'_> { fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) { - if let Path::BarePath(path) = path { - if let Some(name) = path.as_ident() { - if *name.symbol() == self.new_name { - if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed( - self.db, - name, - path, - self.body.expr_or_pat_path_hygiene(node), - self.to_be_renamed, - ) { - self.conflicts.insert(conflicting); - } - } else if *name.symbol() == self.old_name { - if let Some(conflicting) = - self.resolver.rename_will_conflict_with_another_variable( - self.db, - name, - path, - self.body.expr_or_pat_path_hygiene(node), - &self.new_name, - self.to_be_renamed, - ) - { - self.conflicts.insert(conflicting); - } + if let Path::BarePath(path) = path + && let Some(name) = path.as_ident() + { + if *name.symbol() == self.new_name { + if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed( + self.db, + name, + path, + self.body.expr_or_pat_path_hygiene(node), + self.to_be_renamed, + ) { + self.conflicts.insert(conflicting); } + } else if *name.symbol() == self.old_name + && let Some(conflicting) = self.resolver.rename_will_conflict_with_another_variable( + self.db, + name, + path, + self.body.expr_or_pat_path_hygiene(node), + &self.new_name, + self.to_be_renamed, + ) + { + self.conflicts.insert(conflicting); } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 0b554a9d4e37..d25fb1d8cdb7 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -995,11 +995,11 @@ impl<'db> SourceAnalyzer<'db> { // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are // trying to resolve foo::bar. - if let Some(use_tree) = parent().and_then(ast::UseTree::cast) { - if use_tree.coloncolon_token().is_some() { - return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store) - .map(|it| (it, None)); - } + if let Some(use_tree) = parent().and_then(ast::UseTree::cast) + && use_tree.coloncolon_token().is_some() + { + return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &store) + .map(|it| (it, None)); } let meta_path = path @@ -1035,24 +1035,19 @@ impl<'db> SourceAnalyzer<'db> { // } // ``` Some(it) if matches!(it, PathResolution::Def(ModuleDef::BuiltinType(_))) => { - if let Some(mod_path) = hir_path.mod_path() { - if let Some(ModuleDefId::ModuleId(id)) = + if let Some(mod_path) = hir_path.mod_path() + && let Some(ModuleDefId::ModuleId(id)) = self.resolver.resolve_module_path_in_items(db, mod_path).take_types() + { + let parent_hir_name = parent_hir_path.segments().get(1).map(|it| it.name); + let module = crate::Module { id }; + if module + .scope(db, None) + .into_iter() + .any(|(name, _)| Some(&name) == parent_hir_name) { - let parent_hir_name = - parent_hir_path.segments().get(1).map(|it| it.name); - let module = crate::Module { id }; - if module - .scope(db, None) - .into_iter() - .any(|(name, _)| Some(&name) == parent_hir_name) - { - return Some(( - PathResolution::Def(ModuleDef::Module(module)), - None, - )); - }; - } + return Some((PathResolution::Def(ModuleDef::Module(module)), None)); + }; } Some((it, None)) } @@ -1282,22 +1277,22 @@ impl<'db> SourceAnalyzer<'db> { db: &'db dyn HirDatabase, macro_expr: InFile<&ast::MacroExpr>, ) -> bool { - if let Some((def, body, sm, Some(infer))) = self.body_() { - if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) { - let mut is_unsafe = false; - let mut walk_expr = |expr_id| { - unsafe_operations(db, infer, def, body, expr_id, &mut |inside_unsafe_block| { - is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No - }) - }; - match expanded_expr { - ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr), - ExprOrPatId::PatId(expanded_pat) => { - body.walk_exprs_in_pat(expanded_pat, &mut walk_expr) - } + if let Some((def, body, sm, Some(infer))) = self.body_() + && let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) + { + let mut is_unsafe = false; + let mut walk_expr = |expr_id| { + unsafe_operations(db, infer, def, body, expr_id, &mut |inside_unsafe_block| { + is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No + }) + }; + match expanded_expr { + ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr), + ExprOrPatId::PatId(expanded_pat) => { + body.walk_exprs_in_pat(expanded_pat, &mut walk_expr) } - return is_unsafe; } + return is_unsafe; } false } @@ -1575,12 +1570,11 @@ fn resolve_hir_path_( // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type // within the trait's associated types. - if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) { - if let Some(type_alias_id) = + if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) + && let Some(type_alias_id) = trait_id.trait_items(db).associated_type_by_name(unresolved.name) - { - return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); - } + { + return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); } let res = match ty { @@ -1726,12 +1720,11 @@ fn resolve_hir_path_qualifier( // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type // within the trait's associated types. - if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) { - if let Some(type_alias_id) = + if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) + && let Some(type_alias_id) = trait_id.trait_items(db).associated_type_by_name(unresolved.name) - { - return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); - } + { + return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); } let res = match ty { diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs index 4b354e640628..e4089218305c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs @@ -122,10 +122,10 @@ impl<'db> LookupTable<'db> { } // Collapse suggestions if there are many - if let Some(res) = &res { - if res.len() > self.many_threshold { - return Some(vec![Expr::Many(ty.clone())]); - } + if let Some(res) = &res + && res.len() > self.many_threshold + { + return Some(vec![Expr::Many(ty.clone())]); } res @@ -160,10 +160,10 @@ impl<'db> LookupTable<'db> { } // Collapse suggestions if there are many - if let Some(res) = &res { - if res.len() > self.many_threshold { - return Some(vec![Expr::Many(ty.clone())]); - } + if let Some(res) = &res + && res.len() > self.many_threshold + { + return Some(vec![Expr::Many(ty.clone())]); } res diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index 843831948adc..78f534d014b9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -336,10 +336,10 @@ impl<'db> Expr<'db> { if let Expr::Method { func, params, .. } = self { res.extend(params.iter().flat_map(|it| it.traits_used(db))); - if let Some(it) = func.as_assoc_item(db) { - if let Some(it) = it.container_or_implemented_trait(db) { - res.push(it); - } + if let Some(it) = func.as_assoc_item(db) + && let Some(it) = it.container_or_implemented_trait(db) + { + res.push(it); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs index dcdc7ea9cdce..27dbdcf2c4d5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_lifetime_to_type.rs @@ -82,10 +82,10 @@ fn fetch_borrowed_types(node: &ast::Adt) -> Option> { record_field_list .fields() .filter_map(|r_field| { - if let ast::Type::RefType(ref_type) = r_field.ty()? { - if ref_type.lifetime().is_none() { - return Some(ref_type); - } + if let ast::Type::RefType(ref_type) = r_field.ty()? + && ref_type.lifetime().is_none() + { + return Some(ref_type); } None @@ -102,10 +102,10 @@ fn find_ref_types_from_field_list(field_list: &ast::FieldList) -> Option record_list .fields() .filter_map(|f| { - if let ast::Type::RefType(ref_type) = f.ty()? { - if ref_type.lifetime().is_none() { - return Some(ref_type); - } + if let ast::Type::RefType(ref_type) = f.ty()? + && ref_type.lifetime().is_none() + { + return Some(ref_type); } None @@ -114,10 +114,10 @@ fn find_ref_types_from_field_list(field_list: &ast::FieldList) -> Option tuple_field_list .fields() .filter_map(|f| { - if let ast::Type::RefType(ref_type) = f.ty()? { - if ref_type.lifetime().is_none() { - return Some(ref_type); - } + if let ast::Type::RefType(ref_type) = f.ty()? + && ref_type.lifetime().is_none() + { + return Some(ref_type); } None diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index ab183ac70895..7f1e7ccb4487 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -201,14 +201,12 @@ fn add_missing_impl_members_inner( if let Some(cap) = ctx.config.snippet_cap { let mut placeholder = None; - if let DefaultMethods::No = mode { - if let Some(ast::AssocItem::Fn(func)) = &first_new_item { - if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) - && m.syntax().text() == "todo!()" - { - placeholder = Some(m); - } - } + if let DefaultMethods::No = mode + && let Some(ast::AssocItem::Fn(func)) = &first_new_item + && let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) + && m.syntax().text() == "todo!()" + { + placeholder = Some(m); } if let Some(macro_call) = placeholder { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs index 3b447d1f6d57..753a9e56c35a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -207,10 +207,10 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_> // negate all tail expressions in the closure body let tail_cb = &mut |e: &_| tail_cb_impl(&mut editor, &make, e); walk_expr(&closure_body, &mut |expr| { - if let ast::Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } + if let ast::Expr::ReturnExpr(ret_expr) = expr + && let Some(ret_expr_arg) = &ret_expr.expr() + { + for_each_tail_expr(ret_expr_arg, tail_cb); } }); for_each_tail_expr(&closure_body, tail_cb); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index d7b7e8d9cad0..9d5d3f223707 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -86,12 +86,11 @@ pub(crate) fn convert_if_to_bool_then(acc: &mut Assists, ctx: &AssistContext<'_> e @ ast::Expr::CallExpr(_) => Some(e.clone()), _ => None, }; - if let Some(ast::Expr::CallExpr(call)) = e { - if let Some(arg_list) = call.arg_list() { - if let Some(arg) = arg_list.args().next() { - editor.replace(call.syntax(), arg.syntax()); - } - } + if let Some(ast::Expr::CallExpr(call)) = e + && let Some(arg_list) = call.arg_list() + && let Some(arg) = arg_list.args().next() + { + editor.replace(call.syntax(), arg.syntax()); } }); let edit = editor.finish(); @@ -276,12 +275,12 @@ fn is_invalid_body( e @ ast::Expr::CallExpr(_) => Some(e.clone()), _ => None, }; - if let Some(ast::Expr::CallExpr(call)) = e { - if let Some(ast::Expr::PathExpr(p)) = call.expr() { - let res = p.path().and_then(|p| sema.resolve_path(&p)); - if let Some(hir::PathResolution::Def(hir::ModuleDef::Variant(v))) = res { - return invalid |= v != some_variant; - } + if let Some(ast::Expr::CallExpr(call)) = e + && let Some(ast::Expr::PathExpr(p)) = call.expr() + { + let res = p.path().and_then(|p| sema.resolve_path(&p)); + if let Some(hir::PathResolution::Def(hir::ModuleDef::Variant(v))) = res { + return invalid |= v != some_variant; } } invalid = true diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 43515de71e20..916bb67ebb40 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -101,21 +101,21 @@ pub(crate) fn convert_closure_to_fn(acc: &mut Assists, ctx: &AssistContext<'_>) // but we need to locate `AstPtr`s inside the body. let mut wrap_body_in_block = true; if let ast::Expr::BlockExpr(block) = &body { - if let Some(async_token) = block.async_token() { - if !is_async { - is_async = true; - ret_ty = ret_ty.future_output(ctx.db())?; - let token_idx = async_token.index(); - let whitespace_tokens_after_count = async_token - .siblings_with_tokens(Direction::Next) - .skip(1) - .take_while(|token| token.kind() == SyntaxKind::WHITESPACE) - .count(); - body.syntax().splice_children( - token_idx..token_idx + whitespace_tokens_after_count + 1, - Vec::new(), - ); - } + if let Some(async_token) = block.async_token() + && !is_async + { + is_async = true; + ret_ty = ret_ty.future_output(ctx.db())?; + let token_idx = async_token.index(); + let whitespace_tokens_after_count = async_token + .siblings_with_tokens(Direction::Next) + .skip(1) + .take_while(|token| token.kind() == SyntaxKind::WHITESPACE) + .count(); + body.syntax().splice_children( + token_idx..token_idx + whitespace_tokens_after_count + 1, + Vec::new(), + ); } if let Some(gen_token) = block.gen_token() { is_gen = true; @@ -513,10 +513,10 @@ fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Exp CaptureKind::MutableRef | CaptureKind::UniqueSharedRef => true, CaptureKind::Move => return place, }; - if let ast::Expr::PrefixExpr(expr) = &place { - if expr.op_kind() == Some(ast::UnaryOp::Deref) { - return expr.expr().expect("`display_place_source_code()` produced an invalid expr"); - } + if let ast::Expr::PrefixExpr(expr) = &place + && expr.op_kind() == Some(ast::UnaryOp::Deref) + { + return expr.expr().expect("`display_place_source_code()` produced an invalid expr"); } make::expr_ref(place, needs_mut) } @@ -642,11 +642,11 @@ fn peel_blocks_and_refs_and_parens(mut expr: ast::Expr) -> ast::Expr { expr = ast::Expr::cast(parent).unwrap(); continue; } - if let Some(stmt_list) = ast::StmtList::cast(parent) { - if let Some(block) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) { - expr = ast::Expr::BlockExpr(block); - continue; - } + if let Some(stmt_list) = ast::StmtList::cast(parent) + && let Some(block) = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast) + { + expr = ast::Expr::BlockExpr(block); + continue; } break; } @@ -662,12 +662,11 @@ fn expr_of_pat(pat: ast::Pat) -> Option { if let Some(let_stmt) = ast::LetStmt::cast(ancestor.clone()) { break 'find_expr let_stmt.initializer(); } - if ast::MatchArm::can_cast(ancestor.kind()) { - if let Some(match_) = + if ast::MatchArm::can_cast(ancestor.kind()) + && let Some(match_) = ancestor.parent().and_then(|it| it.parent()).and_then(ast::MatchExpr::cast) - { - break 'find_expr match_.expr(); - } + { + break 'find_expr match_.expr(); } if ast::ExprStmt::can_cast(ancestor.kind()) { break; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index db41927f1df2..a4742bc7bded 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -50,10 +50,10 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> let associated_items = impl_.assoc_item_list()?; let from_fn = associated_items.assoc_items().find_map(|item| { - if let ast::AssocItem::Fn(f) = item { - if f.name()?.text() == "from" { - return Some(f); - } + if let ast::AssocItem::Fn(f) = item + && f.name()?.text() == "from" + { + return Some(f); }; None })?; @@ -110,12 +110,11 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> )) .clone_for_update(); - if let Some(cap) = ctx.config.snippet_cap { - if let ast::AssocItem::TypeAlias(type_alias) = &error_type { - if let Some(ty) = type_alias.ty() { - builder.add_placeholder_snippet(cap, ty); - } - } + if let Some(cap) = ctx.config.snippet_cap + && let ast::AssocItem::TypeAlias(type_alias) = &error_type + && let Some(ty) = type_alias.ty() + { + builder.add_placeholder_snippet(cap, ty); } associated_items.add_item_at_start(error_type); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs index b80276a95fbf..3d9cde0e0a67 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -65,10 +65,10 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - }; let into_fn = impl_.assoc_item_list()?.assoc_items().find_map(|item| { - if let ast::AssocItem::Fn(f) = item { - if f.name()?.text() == "into" { - return Some(f); - } + if let ast::AssocItem::Fn(f) = item + && f.name()?.text() == "into" + { + return Some(f); }; None })?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index cca4cb9d8f77..247c1011589b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -265,10 +265,10 @@ fn replace_body_return_values(body: ast::Expr, struct_name: &str) { let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); walk_expr(&body, &mut |expr| { - if let ast::Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } + if let ast::Expr::ReturnExpr(ret_expr) = expr + && let Some(ret_expr_arg) = &ret_expr.expr() + { + for_each_tail_expr(ret_expr_arg, tail_cb); } }); for_each_tail_expr(&body, tail_cb); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index b27ebcaa4edf..3d78895477b3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -192,7 +192,7 @@ fn edit_struct_references( ).syntax().clone() ) }, - _ => return None, + _ => None, } } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs index e582aa814ae1..1af5db17f040 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -100,10 +100,10 @@ fn is_bool_literal_expr( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, ) -> Option { - if let ast::Expr::Literal(lit) = expr { - if let ast::LiteralKind::Bool(b) = lit.kind() { - return Some(ArmBodyExpression::Literal(b)); - } + if let ast::Expr::Literal(lit) = expr + && let ast::LiteralKind::Bool(b) = lit.kind() + { + return Some(ArmBodyExpression::Literal(b)); } if !sema.type_of_expr(expr)?.original.is_bool() { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs index efadde9e3648..9976e34e730c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs @@ -106,73 +106,73 @@ pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op }, ); - if let Some(let_stmt) = try_expr.syntax().parent().and_then(ast::LetStmt::cast) { - if let_stmt.let_else().is_none() { - let pat = let_stmt.pat()?; - acc.add( - AssistId::refactor_rewrite("desugar_try_expr_let_else"), - "Replace try expression with let else", - target, - |builder| { - let make = SyntaxFactory::with_mappings(); - let mut editor = builder.make_editor(let_stmt.syntax()); + if let Some(let_stmt) = try_expr.syntax().parent().and_then(ast::LetStmt::cast) + && let_stmt.let_else().is_none() + { + let pat = let_stmt.pat()?; + acc.add( + AssistId::refactor_rewrite("desugar_try_expr_let_else"), + "Replace try expression with let else", + target, + |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(let_stmt.syntax()); - let indent_level = IndentLevel::from_node(let_stmt.syntax()); - let new_let_stmt = make.let_else_stmt( - try_enum.happy_pattern(pat), - let_stmt.ty(), - expr, - make.block_expr( - iter::once( - make.expr_stmt( - make.expr_return(Some(match try_enum { - TryEnum::Option => make.expr_path(make.ident_path("None")), - TryEnum::Result => make - .expr_call( - make.expr_path(make.ident_path("Err")), - make.arg_list(iter::once( - match ctx.config.expr_fill_default { - ExprFillDefaultMode::Todo => make - .expr_macro( - make.ident_path("todo"), - make.token_tree( - syntax::SyntaxKind::L_PAREN, - [], - ), - ) - .into(), - ExprFillDefaultMode::Underscore => { - make.expr_underscore().into() - } - ExprFillDefaultMode::Default => make - .expr_macro( - make.ident_path("todo"), - make.token_tree( - syntax::SyntaxKind::L_PAREN, - [], - ), - ) - .into(), - }, - )), - ) - .into(), - })) - .indent(indent_level + 1) - .into(), - ) + let indent_level = IndentLevel::from_node(let_stmt.syntax()); + let new_let_stmt = make.let_else_stmt( + try_enum.happy_pattern(pat), + let_stmt.ty(), + expr, + make.block_expr( + iter::once( + make.expr_stmt( + make.expr_return(Some(match try_enum { + TryEnum::Option => make.expr_path(make.ident_path("None")), + TryEnum::Result => make + .expr_call( + make.expr_path(make.ident_path("Err")), + make.arg_list(iter::once( + match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make + .expr_macro( + make.ident_path("todo"), + make.token_tree( + syntax::SyntaxKind::L_PAREN, + [], + ), + ) + .into(), + ExprFillDefaultMode::Underscore => { + make.expr_underscore().into() + } + ExprFillDefaultMode::Default => make + .expr_macro( + make.ident_path("todo"), + make.token_tree( + syntax::SyntaxKind::L_PAREN, + [], + ), + ) + .into(), + }, + )), + ) + .into(), + })) + .indent(indent_level + 1) .into(), - ), - None, - ) - .indent(indent_level), - ); - editor.replace(let_stmt.syntax(), new_let_stmt.syntax()); - editor.add_mappings(make.finish_with_mappings()); - builder.add_file_edits(ctx.vfs_file_id(), editor); - }, - ); - } + ) + .into(), + ), + None, + ) + .indent(indent_level), + ); + editor.replace(let_stmt.syntax(), new_let_stmt.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, + ); } Some(()) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index 307414c79715..66552dd65f56 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -272,16 +272,16 @@ impl Refs { .clone() .into_iter() .filter(|r| { - if let Definition::Trait(tr) = r.def { - if tr.items(ctx.db()).into_iter().any(|ai| { + if let Definition::Trait(tr) = r.def + && tr.items(ctx.db()).into_iter().any(|ai| { if let AssocItem::Function(f) = ai { def_is_referenced_in(Definition::Function(f), ctx) } else { false } - }) { - return true; - } + }) + { + return true; } def_is_referenced_in(r.def, ctx) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 00cbef1c01c0..890b8dd64126 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -175,10 +175,10 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let fn_def = format_function(ctx, module, &fun, old_indent).clone_for_update(); - if let Some(cap) = ctx.config.snippet_cap { - if let Some(name) = fn_def.name() { - builder.add_tabstop_before(cap, name); - } + if let Some(cap) = ctx.config.snippet_cap + && let Some(name) = fn_def.name() + { + builder.add_tabstop_before(cap, name); } let fn_def = match fun.self_param_adt(ctx) { @@ -289,10 +289,10 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option { let func = sema.to_def(&fn_)?; let mut ret_ty = func.ret_type(sema.db); - if func.is_async(sema.db) { - if let Some(async_ret) = func.async_ret_type(sema.db) { + if func.is_async(sema.db) + && let Some(async_ret) = func.async_ret_type(sema.db) { ret_ty = async_ret; } - } (fn_.const_token().is_some(), fn_.body().map(ast::Expr::BlockExpr), Some(ret_ty)) }, ast::Static(statik) => { @@ -1172,19 +1171,19 @@ impl GenericParent { /// Search `parent`'s ancestors for items with potentially applicable generic parameters fn generic_parents(parent: &SyntaxNode) -> Vec { let mut list = Vec::new(); - if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast) { - if let ast::Item::Fn(ref fn_) = parent_item { - if let Some(parent_parent) = - parent_item.syntax().parent().and_then(|it| it.parent()).and_then(ast::Item::cast) - { - match parent_parent { - ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)), - ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)), - _ => (), - } + if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast) + && let ast::Item::Fn(ref fn_) = parent_item + { + if let Some(parent_parent) = + parent_item.syntax().parent().and_then(|it| it.parent()).and_then(ast::Item::cast) + { + match parent_parent { + ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)), + ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)), + _ => (), } - list.push(GenericParent::Fn(fn_.clone())); } + list.push(GenericParent::Fn(fn_.clone())); } list } @@ -1337,10 +1336,10 @@ fn locals_defined_in_body( // see https://github.com/rust-lang/rust-analyzer/pull/7535#discussion_r570048550 let mut res = FxIndexSet::default(); body.walk_pat(&mut |pat| { - if let ast::Pat::IdentPat(pat) = pat { - if let Some(local) = sema.to_def(&pat) { - res.insert(local); - } + if let ast::Pat::IdentPat(pat) = pat + && let Some(local) = sema.to_def(&pat) + { + res.insert(local); } }); res @@ -1445,11 +1444,11 @@ fn impl_type_name(impl_node: &ast::Impl) -> Option { fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) { let parent_match_arm = body.parent().and_then(ast::MatchArm::cast); - if let Some(parent_match_arm) = parent_match_arm { - if parent_match_arm.comma_token().is_none() { - let parent_match_arm = builder.make_mut(parent_match_arm); - ted::append_child_raw(parent_match_arm.syntax(), make::token(T![,])); - } + if let Some(parent_match_arm) = parent_match_arm + && parent_match_arm.comma_token().is_none() + { + let parent_match_arm = builder.make_mut(parent_match_arm); + ted::append_child_raw(parent_match_arm.syntax(), make::token(T![,])); } } @@ -2120,30 +2119,30 @@ fn update_external_control_flow(handler: &FlowHandler<'_>, syntax: &SyntaxNode) _ => {} }, WalkEvent::Leave(e) => { - if nested_scope.is_none() { - if let Some(expr) = ast::Expr::cast(e.clone()) { - match expr { - ast::Expr::ReturnExpr(return_expr) => { - let expr = return_expr.expr(); - if let Some(replacement) = make_rewritten_flow(handler, expr) { - ted::replace(return_expr.syntax(), replacement.syntax()) - } + if nested_scope.is_none() + && let Some(expr) = ast::Expr::cast(e.clone()) + { + match expr { + ast::Expr::ReturnExpr(return_expr) => { + let expr = return_expr.expr(); + if let Some(replacement) = make_rewritten_flow(handler, expr) { + ted::replace(return_expr.syntax(), replacement.syntax()) } - ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => { - let expr = break_expr.expr(); - if let Some(replacement) = make_rewritten_flow(handler, expr) { - ted::replace(break_expr.syntax(), replacement.syntax()) - } + } + ast::Expr::BreakExpr(break_expr) if nested_loop.is_none() => { + let expr = break_expr.expr(); + if let Some(replacement) = make_rewritten_flow(handler, expr) { + ted::replace(break_expr.syntax(), replacement.syntax()) } - ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => { - if let Some(replacement) = make_rewritten_flow(handler, None) { - ted::replace(continue_expr.syntax(), replacement.syntax()) - } - } - _ => { - // do nothing + } + ast::Expr::ContinueExpr(continue_expr) if nested_loop.is_none() => { + if let Some(replacement) = make_rewritten_flow(handler, None) { + ted::replace(continue_expr.syntax(), replacement.syntax()) } } + _ => { + // do nothing + } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index b82b7984d4a4..c6a6b97df824 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -69,13 +69,12 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti let mut impl_parent: Option = None; let mut impl_child_count: usize = 0; - if let Some(parent_assoc_list) = node.parent() { - if let Some(parent_impl) = parent_assoc_list.parent() { - if let Some(impl_) = ast::Impl::cast(parent_impl) { - impl_child_count = parent_assoc_list.children().count(); - impl_parent = Some(impl_); - } - } + if let Some(parent_assoc_list) = node.parent() + && let Some(parent_impl) = parent_assoc_list.parent() + && let Some(impl_) = ast::Impl::cast(parent_impl) + { + impl_child_count = parent_assoc_list.children().count(); + impl_parent = Some(impl_); } let mut curr_parent_module: Option = None; @@ -436,10 +435,10 @@ impl Module { } }) .for_each(|(node, def)| { - if node_set.insert(node.to_string()) { - if let Some(import) = self.process_def_in_sel(def, &node, &module, ctx) { - check_intersection_and_push(&mut imports_to_remove, import); - } + if node_set.insert(node.to_string()) + && let Some(import) = self.process_def_in_sel(def, &node, &module, ctx) + { + check_intersection_and_push(&mut imports_to_remove, import); } }) } @@ -542,15 +541,16 @@ impl Module { import_path_to_be_removed = Some(text_range); } - if def_in_mod && def_out_sel { - if let Some(first_path_in_use_tree) = use_tree_str.last() { - let first_path_in_use_tree_str = first_path_in_use_tree.to_string(); - if !first_path_in_use_tree_str.contains("super") - && !first_path_in_use_tree_str.contains("crate") - { - let super_path = make::ext::ident_path("super"); - use_tree_str.push(super_path); - } + if def_in_mod + && def_out_sel + && let Some(first_path_in_use_tree) = use_tree_str.last() + { + let first_path_in_use_tree_str = first_path_in_use_tree.to_string(); + if !first_path_in_use_tree_str.contains("super") + && !first_path_in_use_tree_str.contains("crate") + { + let super_path = make::ext::ident_path("super"); + use_tree_str.push(super_path); } } @@ -563,12 +563,11 @@ impl Module { if let Some(mut use_tree_paths) = use_tree_paths { use_tree_paths.reverse(); - if uses_exist_out_sel || !uses_exist_in_sel || !def_in_mod || !def_out_sel { - if let Some(first_path_in_use_tree) = use_tree_paths.first() { - if first_path_in_use_tree.to_string().contains("super") { - use_tree_paths.insert(0, make::ext::ident_path("super")); - } - } + if (uses_exist_out_sel || !uses_exist_in_sel || !def_in_mod || !def_out_sel) + && let Some(first_path_in_use_tree) = use_tree_paths.first() + && first_path_in_use_tree.to_string().contains("super") + { + use_tree_paths.insert(0, make::ext::ident_path("super")); } let is_item = matches!( @@ -691,11 +690,9 @@ fn check_def_in_mod_and_out_sel( _ => source.file_id.original_file(ctx.db()).file_id(ctx.db()) == curr_file_id, }; - if have_same_parent { - if let ModuleSource::Module(module_) = source.value { - let in_sel = !selection_range.contains_range(module_.syntax().text_range()); - return (have_same_parent, in_sel); - } + if have_same_parent && let ModuleSource::Module(module_) = source.value { + let in_sel = !selection_range.contains_range(module_.syntax().text_range()); + return (have_same_parent, in_sel); } return (have_same_parent, false); @@ -772,12 +769,12 @@ fn get_use_tree_paths_from_path( .filter(|x| x.to_string() != path.to_string()) .filter_map(ast::UseTree::cast) .find_map(|use_tree| { - if let Some(upper_tree_path) = use_tree.path() { - if upper_tree_path.to_string() != path.to_string() { - use_tree_str.push(upper_tree_path.clone()); - get_use_tree_paths_from_path(upper_tree_path, use_tree_str); - return Some(use_tree); - } + if let Some(upper_tree_path) = use_tree.path() + && upper_tree_path.to_string() != path.to_string() + { + use_tree_str.push(upper_tree_path.clone()); + get_use_tree_paths_from_path(upper_tree_path, use_tree_str); + return Some(use_tree); } None })?; @@ -786,11 +783,11 @@ fn get_use_tree_paths_from_path( } fn add_change_vis(vis: Option, node_or_token_opt: Option) { - if vis.is_none() { - if let Some(node_or_token) = node_or_token_opt { - let pub_crate_vis = make::visibility_pub_crate().clone_for_update(); - ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax()); - } + if vis.is_none() + && let Some(node_or_token) = node_or_token_opt + { + let pub_crate_vis = make::visibility_pub_crate().clone_for_update(); + ted::insert(ted::Position::before(node_or_token), pub_crate_vis.syntax()); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 9095b1825f5f..c56d0b3de5d6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -215,12 +215,12 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b ast::GenericParam::LifetimeParam(lt) if matches!(token.kind(), T![lifetime_ident]) => { - if let Some(lt) = lt.lifetime() { - if lt.text().as_str() == token.text() { - *tag = true; - tagged_one = true; - break; - } + if let Some(lt) = lt.lifetime() + && lt.text().as_str() == token.text() + { + *tag = true; + tagged_one = true; + break; } } param if matches!(token.kind(), T![ident]) => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index d843ac64567a..79f22381952a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -72,10 +72,10 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> let ty_alias = make::ty_alias("Type", generic_params, None, None, Some((ty, None))) .clone_for_update(); - if let Some(cap) = ctx.config.snippet_cap { - if let Some(name) = ty_alias.name() { - edit.add_annotation(name.syntax(), builder.make_tabstop_before(cap)); - } + if let Some(cap) = ctx.config.snippet_cap + && let Some(name) = ty_alias.name() + { + edit.add_annotation(name.syntax(), builder.make_tabstop_before(cap)); } let indent = IndentLevel::from_node(node); @@ -111,17 +111,17 @@ fn collect_used_generics<'gp>( match ty { ast::Type::PathType(ty) => { if let Some(path) = ty.path() { - if let Some(name_ref) = path.as_single_name_ref() { - if let Some(param) = known_generics.iter().find(|gp| { + if let Some(name_ref) = path.as_single_name_ref() + && let Some(param) = known_generics.iter().find(|gp| { match gp { ast::GenericParam::ConstParam(cp) => cp.name(), ast::GenericParam::TypeParam(tp) => tp.name(), _ => None, } .is_some_and(|n| n.text() == name_ref.text()) - }) { - generics.push(param); - } + }) + { + generics.push(param); } generics.extend( path.segments() @@ -160,20 +160,18 @@ fn collect_used_generics<'gp>( .and_then(|lt| known_generics.iter().find(find_lifetime(<.text()))), ), ast::Type::ArrayType(ar) => { - if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr()) { - if let Some(path) = p.path() { - if let Some(name_ref) = path.as_single_name_ref() { - if let Some(param) = known_generics.iter().find(|gp| { - if let ast::GenericParam::ConstParam(cp) = gp { - cp.name().is_some_and(|n| n.text() == name_ref.text()) - } else { - false - } - }) { - generics.push(param); - } + if let Some(ast::Expr::PathExpr(p)) = ar.const_arg().and_then(|x| x.expr()) + && let Some(path) = p.path() + && let Some(name_ref) = path.as_single_name_ref() + && let Some(param) = known_generics.iter().find(|gp| { + if let ast::GenericParam::ConstParam(cp) = gp { + cp.name().is_some_and(|n| n.text() == name_ref.text()) + } else { + false } - } + }) + { + generics.push(param); } } _ => (), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index db2d316d58ee..c9c1969b9e02 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -404,11 +404,10 @@ impl Anchor { } if let Some(expr) = node.parent().and_then(ast::StmtList::cast).and_then(|it| it.tail_expr()) + && expr.syntax() == &node { - if expr.syntax() == &node { - cov_mark::hit!(test_extract_var_last_expr); - return Some(Anchor::Before(node)); - } + cov_mark::hit!(test_extract_var_last_expr); + return Some(Anchor::Before(node)); } if let Some(parent) = node.parent() { @@ -427,10 +426,10 @@ impl Anchor { } if let Some(stmt) = ast::Stmt::cast(node.clone()) { - if let ast::Stmt::ExprStmt(stmt) = stmt { - if stmt.expr().as_ref() == Some(to_extract) { - return Some(Anchor::Replace(stmt)); - } + if let ast::Stmt::ExprStmt(stmt) = stmt + && stmt.expr().as_ref() == Some(to_extract) + { + return Some(Anchor::Replace(stmt)); } return Some(Anchor::Before(node)); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs index 68587f0cb5bc..77232dfebdfe 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -148,11 +148,11 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option) -> Option) ], ); - if let Some(cap) = ctx.config.snippet_cap { - if let Some(name) = ty_alias.name() { - edit.add_annotation(name.syntax(), builder.make_placeholder_snippet(cap)); - } + if let Some(cap) = ctx.config.snippet_cap + && let Some(name) = ty_alias.name() + { + edit.add_annotation(name.syntax(), builder.make_placeholder_snippet(cap)); } builder.add_file_edits(ctx.vfs_file_id(), edit); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 3290a70e1c69..613b32fcc165 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -70,10 +70,10 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let TargetInfo { target_module, adt_info, target, file } = fn_target_info(ctx, path, &call, fn_name)?; - if let Some(m) = target_module { - if !is_editable_crate(m.krate(), ctx.db()) { - return None; - } + if let Some(m) = target_module + && !is_editable_crate(m.krate(), ctx.db()) + { + return None; } let function_builder = diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 20ee9253d379..807b9194b2df 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -433,12 +433,11 @@ fn build_source_change( new_fn.indent(1.into()); // Insert a tabstop only for last method we generate - if i == record_fields_count - 1 { - if let Some(cap) = ctx.config.snippet_cap { - if let Some(name) = new_fn.name() { - builder.add_tabstop_before(cap, name); - } - } + if i == record_fields_count - 1 + && let Some(cap) = ctx.config.snippet_cap + && let Some(name) = new_fn.name() + { + builder.add_tabstop_before(cap, name); } assoc_item_list.add_item(new_fn.clone().into()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs index 31cadcf5ea86..fcb81d239ff3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs @@ -58,11 +58,11 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio let mut editor = edit.make_editor(nominal.syntax()); // Add a tabstop after the left curly brace - if let Some(cap) = ctx.config.snippet_cap { - if let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) { - let tabstop = edit.make_tabstop_after(cap); - editor.add_annotation(l_curly, tabstop); - } + if let Some(cap) = ctx.config.snippet_cap + && let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) + { + let tabstop = edit.make_tabstop_after(cap); + editor.add_annotation(l_curly, tabstop); } insert_impl(&mut editor, &impl_, &nominal); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index 92a4bd35b3e7..dc3dc73701f3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -175,18 +175,18 @@ fn remove_items_visibility(item: &ast::AssocItem) { } fn strip_body(item: &ast::AssocItem) { - if let ast::AssocItem::Fn(f) = item { - if let Some(body) = f.body() { - // In contrast to function bodies, we want to see no ws before a semicolon. - // So let's remove them if we see any. - if let Some(prev) = body.syntax().prev_sibling_or_token() { - if prev.kind() == SyntaxKind::WHITESPACE { - ted::remove(prev); - } - } - - ted::replace(body.syntax(), make::tokens::semicolon()); + if let ast::AssocItem::Fn(f) = item + && let Some(body) = f.body() + { + // In contrast to function bodies, we want to see no ws before a semicolon. + // So let's remove them if we see any. + if let Some(prev) = body.syntax().prev_sibling_or_token() + && prev.kind() == SyntaxKind::WHITESPACE + { + ted::remove(prev); } + + ted::replace(body.syntax(), make::tokens::semicolon()); }; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 1549b414dcc1..5367350052cb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -393,19 +393,17 @@ fn inline( // `FileReference` incorrect if let Some(imp) = sema.ancestors_with_macros(fn_body.syntax().clone()).find_map(ast::Impl::cast) + && !node.syntax().ancestors().any(|anc| &anc == imp.syntax()) + && let Some(t) = imp.self_ty() { - if !node.syntax().ancestors().any(|anc| &anc == imp.syntax()) { - if let Some(t) = imp.self_ty() { - while let Some(self_tok) = body - .syntax() - .descendants_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW) - { - let replace_with = t.clone_subtree().syntax().clone_for_update(); - ted::replace(self_tok, replace_with); - } - } + while let Some(self_tok) = body + .syntax() + .descendants_with_tokens() + .filter_map(NodeOrToken::into_token) + .find(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW) + { + let replace_with = t.clone_subtree().syntax().clone_for_update(); + ted::replace(self_tok, replace_with); } } @@ -415,10 +413,10 @@ fn inline( for stmt in fn_body.statements() { if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) { for has_token in let_stmt.syntax().children_with_tokens() { - if let Some(node) = has_token.as_node() { - if let Some(ident_pat) = ast::IdentPat::cast(node.to_owned()) { - func_let_vars.insert(ident_pat.syntax().text().to_string()); - } + if let Some(node) = has_token.as_node() + && let Some(ident_pat) = ast::IdentPat::cast(node.to_owned()) + { + func_let_vars.insert(ident_pat.syntax().text().to_string()); } } } @@ -534,16 +532,15 @@ fn inline( } } - if let Some(generic_arg_list) = generic_arg_list.clone() { - if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax())) - { - body.reindent_to(IndentLevel(0)); - if let Some(new_body) = ast::BlockExpr::cast( - PathTransform::function_call(target, source, function, generic_arg_list) - .apply(body.syntax()), - ) { - body = new_body; - } + if let Some(generic_arg_list) = generic_arg_list.clone() + && let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax())) + { + body.reindent_to(IndentLevel(0)); + if let Some(new_body) = ast::BlockExpr::cast( + PathTransform::function_call(target, source, function, generic_arg_list) + .apply(body.syntax()), + ) { + body = new_body; } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs index 0c1dc9eb9349..a645c8b90afc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs @@ -43,10 +43,10 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> let db = ctx.db(); let const_: ast::Const = ctx.find_node_at_offset()?; // Don't show the assist when the cursor is at the const's body. - if let Some(body) = const_.body() { - if body.syntax().text_range().contains(ctx.offset()) { - return None; - } + if let Some(body) = const_.body() + && body.syntax().text_range().contains(ctx.offset()) + { + return None; } let parent_fn = const_.syntax().ancestors().find_map(ast::Fn::cast)?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs index 1b0c31393537..21debf6745a6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs @@ -62,10 +62,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) -> return None; }; - if let Some(parent) = tgt.syntax().parent() { - if matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT) { - return None; - } + if let Some(parent) = tgt.syntax().parent() + && matches!(parent.kind(), syntax::SyntaxKind::BIN_EXPR | syntax::SyntaxKind::LET_STMT) + { + return None; } let target = tgt.syntax().text_range(); @@ -90,10 +90,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) -> let mut editor = SyntaxEditor::new(edit_tgt); for (stmt, rhs) in assignments { let mut stmt = stmt.syntax().clone(); - if let Some(parent) = stmt.parent() { - if ast::ExprStmt::cast(parent.clone()).is_some() { - stmt = parent.clone(); - } + if let Some(parent) = stmt.parent() + && ast::ExprStmt::cast(parent.clone()).is_some() + { + stmt = parent.clone(); } editor.replace(stmt, rhs.syntax()); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs index 94b49c5df091..2cbb24a64fd5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs @@ -80,15 +80,15 @@ pub(crate) fn make_usual_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> O // parse inside string to escape `"` let escaped = value.escape_default().to_string(); let suffix = string_suffix(token.text()).unwrap_or_default(); - if let Some(offsets) = token.quote_offsets() { - if token.text()[offsets.contents - token.syntax().text_range().start()] == escaped { - let end_quote = offsets.quotes.1; - let end_quote = - TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix)); - edit.replace(offsets.quotes.0, "\""); - edit.replace(end_quote, "\""); - return; - } + if let Some(offsets) = token.quote_offsets() + && token.text()[offsets.contents - token.syntax().text_range().start()] == escaped + { + let end_quote = offsets.quotes.1; + let end_quote = + TextRange::new(end_quote.start(), end_quote.end() - TextSize::of(suffix)); + edit.replace(offsets.quotes.0, "\""); + edit.replace(end_quote, "\""); + return; } edit.replace(token.syntax().text_range(), format!("\"{escaped}\"{suffix}")); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index fa005a411d36..9f742131e5cb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -102,10 +102,10 @@ pub(crate) fn replace_qualified_name_with_use( fn drop_generic_args(path: &ast::Path) -> ast::Path { let path = path.clone_for_update(); - if let Some(segment) = path.segment() { - if let Some(generic_args) = segment.generic_arg_list() { - ted::remove(generic_args.syntax()); - } + if let Some(segment) = path.segment() + && let Some(generic_args) = segment.generic_arg_list() + { + ted::remove(generic_args.syntax()); } path } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs index ac10a829bbf1..b9385775b476 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unnecessary_async.rs @@ -41,10 +41,10 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O return None; } // Do nothing if the method is a member of trait. - if let Some(impl_) = function.syntax().ancestors().nth(2).and_then(ast::Impl::cast) { - if impl_.trait_().is_some() { - return None; - } + if let Some(impl_) = function.syntax().ancestors().nth(2).and_then(ast::Impl::cast) + && impl_.trait_().is_some() + { + return None; } // Remove the `async` keyword plus whitespace after it, if any. diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs index cf38262fbf44..eea6c85e8df0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs @@ -72,20 +72,20 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> let mut exprs_to_unwrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); walk_expr(&body_expr, &mut |expr| { - if let ast::Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } + if let ast::Expr::ReturnExpr(ret_expr) = expr + && let Some(ret_expr_arg) = &ret_expr.expr() + { + for_each_tail_expr(ret_expr_arg, tail_cb); } }); for_each_tail_expr(&body_expr, tail_cb); let is_unit_type = is_unit_type(&happy_type); if is_unit_type { - if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { - if token.kind() == SyntaxKind::WHITESPACE { - editor.delete(token); - } + if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() + && token.kind() == SyntaxKind::WHITESPACE + { + editor.delete(token); } editor.delete(ret_type.syntax()); @@ -162,10 +162,10 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> } } - if let Some(cap) = ctx.config.snippet_cap { - if let Some(final_placeholder) = final_placeholder { - editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap)); - } + if let Some(cap) = ctx.config.snippet_cap + && let Some(final_placeholder) = final_placeholder + { + editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap)); } editor.add_mappings(make.finish_with_mappings()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs index ecfecbb04ff2..46f3e85e1234 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_tuple.rs @@ -47,10 +47,10 @@ pub(crate) fn unwrap_tuple(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option if tuple_pat.fields().count() != tuple_init.fields().count() { return None; } - if let Some(tys) = &tuple_ty { - if tuple_pat.fields().count() != tys.fields().count() { - return None; - } + if let Some(tys) = &tuple_ty + && tuple_pat.fields().count() != tys.fields().count() + { + return None; } let parent = let_kw.parent()?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs index d7189aa5dbbd..0f089c9b66eb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -101,24 +101,24 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let mut exprs_to_wrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); walk_expr(&body_expr, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { - if let Some(ret_expr_arg) = &ret_expr.expr() { - for_each_tail_expr(ret_expr_arg, tail_cb); - } + if let Expr::ReturnExpr(ret_expr) = expr + && let Some(ret_expr_arg) = &ret_expr.expr() + { + for_each_tail_expr(ret_expr_arg, tail_cb); } }); for_each_tail_expr(&body_expr, tail_cb); for ret_expr_arg in exprs_to_wrap { - if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg) { - if ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty) { - // The type is already correct, don't wrap it. - // We deliberately don't use `could_unify_with_deeply()`, because as long as the outer - // enum matches it's okay for us, as we don't trigger the assist if the return type - // is already `Option`/`Result`, so mismatched exact type is more likely a mistake - // than something intended. - continue; - } + if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg) + && ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty) + { + // The type is already correct, don't wrap it. + // We deliberately don't use `could_unify_with_deeply()`, because as long as the outer + // enum matches it's okay for us, as we don't trigger the assist if the return type + // is already `Option`/`Result`, so mismatched exact type is more likely a mistake + // than something intended. + continue; } let happy_wrapped = make.expr_call( @@ -147,13 +147,13 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ast::GenericArg::LifetimeArg(_) => false, _ => true, }); - if let Some(error_type_arg) = error_type_arg { - if let Some(cap) = ctx.config.snippet_cap { - editor.add_annotation( - error_type_arg.syntax(), - builder.make_placeholder_snippet(cap), - ); - } + if let Some(error_type_arg) = error_type_arg + && let Some(cap) = ctx.config.snippet_cap + { + editor.add_annotation( + error_type_arg.syntax(), + builder.make_placeholder_snippet(cap), + ); } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs index 5183566d136b..7d5740b748be 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs @@ -200,13 +200,12 @@ fn wrap_derive( ], ); - if let Some(snippet_cap) = ctx.config.snippet_cap { - if let Some(first_meta) = + if let Some(snippet_cap) = ctx.config.snippet_cap + && let Some(first_meta) = cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token()) - { - let tabstop = edit.make_tabstop_after(snippet_cap); - editor.add_annotation(first_meta, tabstop); - } + { + let tabstop = edit.make_tabstop_after(snippet_cap); + editor.add_annotation(first_meta, tabstop); } editor.add_mappings(make.finish_with_mappings()); @@ -256,13 +255,12 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) -> editor.replace(attr.syntax(), cfg_attr.syntax()); - if let Some(snippet_cap) = ctx.config.snippet_cap { - if let Some(first_meta) = + if let Some(snippet_cap) = ctx.config.snippet_cap + && let Some(first_meta) = cfg_attr.meta().and_then(|meta| meta.token_tree()).and_then(|tt| tt.l_paren_token()) - { - let tabstop = edit.make_tabstop_after(snippet_cap); - editor.add_annotation(first_meta, tabstop); - } + { + let tabstop = edit.make_tabstop_after(snippet_cap); + editor.add_annotation(first_meta, tabstop); } editor.add_mappings(make.finish_with_mappings()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 15c7a6a3fc26..77d471e5a748 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -131,10 +131,10 @@ pub fn filter_assoc_items( if ignore_items == IgnoreAssocItems::DocHiddenAttrPresent && assoc_item.attrs(sema.db).has_doc_hidden() { - if let hir::AssocItem::Function(f) = assoc_item { - if !f.has_body(sema.db) { - return true; - } + if let hir::AssocItem::Function(f) = assoc_item + && !f.has_body(sema.db) + { + return true; } return false; } @@ -514,10 +514,10 @@ pub(crate) fn find_struct_impl( if !(same_ty && not_trait_impl) { None } else { Some(impl_blk) } }); - if let Some(ref impl_blk) = block { - if has_any_fn(impl_blk, names) { - return None; - } + if let Some(ref impl_blk) = block + && has_any_fn(impl_blk, names) + { + return None; } Some(block) @@ -526,12 +526,11 @@ pub(crate) fn find_struct_impl( fn has_any_fn(imp: &ast::Impl, names: &[String]) -> bool { if let Some(il) = imp.assoc_item_list() { for item in il.assoc_items() { - if let ast::AssocItem::Fn(f) = item { - if let Some(name) = f.name() { - if names.iter().any(|n| n.eq_ignore_ascii_case(&name.text())) { - return true; - } - } + if let ast::AssocItem::Fn(f) = item + && let Some(name) = f.name() + && names.iter().any(|n| n.eq_ignore_ascii_case(&name.text())) + { + return true; } } } @@ -1021,12 +1020,12 @@ pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRa pub(crate) fn convert_param_list_to_arg_list(list: ast::ParamList) -> ast::ArgList { let mut args = vec![]; for param in list.params() { - if let Some(ast::Pat::IdentPat(pat)) = param.pat() { - if let Some(name) = pat.name() { - let name = name.to_string(); - let expr = make::expr_path(make::ext::ident_path(&name)); - args.push(expr); - } + if let Some(ast::Pat::IdentPat(pat)) = param.pat() + && let Some(name) = pat.name() + { + let name = name.to_string(); + let expr = make::expr_path(make::ext::ident_path(&name)); + args.push(expr); } } make::arg_list(args) @@ -1138,12 +1137,11 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo }; match expr { ast::Expr::CallExpr(call) => { - if let Some(ast::Expr::PathExpr(path_expr)) = call.expr() { - if let Some(PathResolution::Def(ModuleDef::Function(func))) = + if let Some(ast::Expr::PathExpr(path_expr)) = call.expr() + && let Some(PathResolution::Def(ModuleDef::Function(func))) = path_expr.path().and_then(|path| sema.resolve_path(&path)) - { - is_const &= func.is_const(sema.db); - } + { + is_const &= func.is_const(sema.db); } } ast::Expr::MethodCallExpr(call) => { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 65072d936f63..11d26228ba20 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -111,10 +111,11 @@ impl Completions { ctx: &CompletionContext<'_>, super_chain_len: Option, ) { - if let Some(len) = super_chain_len { - if len > 0 && len < ctx.depth_from_crate_root { - self.add_keyword(ctx, "super::"); - } + if let Some(len) = super_chain_len + && len > 0 + && len < ctx.depth_from_crate_root + { + self.add_keyword(ctx, "super::"); } } @@ -643,10 +644,10 @@ fn enum_variants_with_paths( let variants = enum_.variants(ctx.db); - if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { - if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { - variants.iter().for_each(|variant| process_variant(*variant)); - } + if let Some(impl_) = impl_.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) + && impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) + { + variants.iter().for_each(|variant| process_variant(*variant)); } for variant in variants { 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 5340d65a142d..f75123324f37 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 @@ -258,12 +258,11 @@ fn complete_methods( fn on_trait_method(&mut self, func: hir::Function) -> ControlFlow<()> { // This needs to come before the `seen_methods` test, so that if we see the same method twice, // once as inherent and once not, we will include it. - if let ItemContainer::Trait(trait_) = func.container(self.ctx.db) { - if self.ctx.exclude_traits.contains(&trait_) - || trait_.complete(self.ctx.db) == Complete::IgnoreMethods - { - return ControlFlow::Continue(()); - } + if let ItemContainer::Trait(trait_) = func.container(self.ctx.db) + && (self.ctx.exclude_traits.contains(&trait_) + || trait_.complete(self.ctx.db) == Complete::IgnoreMethods) + { + return ControlFlow::Continue(()); } if func.self_param(self.ctx.db).is_some() diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index 809e71cc119e..fb78386976d6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -128,10 +128,10 @@ fn params_from_stmt_list_scope( { let module = scope.module().into(); scope.process_all_names(&mut |name, def| { - if let hir::ScopeDef::Local(local) = def { - if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module, true) { - cb(name, ty); - } + if let hir::ScopeDef::Local(local) = def + && let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module, true) + { + cb(name, ty); } }); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index bcf8c0ec527a..cdd77e79b5cd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -228,24 +228,22 @@ fn add_function_impl_( .set_documentation(func.docs(ctx.db)) .set_relevance(CompletionRelevance { exact_name_match: true, ..Default::default() }); - if let Some(source) = ctx.sema.source(func) { - if let Some(transformed_fn) = + if let Some(source) = ctx.sema.source(func) + && let Some(transformed_fn) = get_transformed_fn(ctx, source.value, impl_def, async_sugaring) - { - let function_decl = - function_declaration(ctx, &transformed_fn, source.file_id.macro_file()); - match ctx.config.snippet_cap { - Some(cap) => { - let snippet = format!("{function_decl} {{\n $0\n}}"); - item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet)); - } - None => { - let header = format!("{function_decl} {{"); - item.text_edit(TextEdit::replace(replacement_range, header)); - } - }; - item.add_to(acc, ctx.db); - } + { + let function_decl = function_declaration(ctx, &transformed_fn, source.file_id.macro_file()); + match ctx.config.snippet_cap { + Some(cap) => { + let snippet = format!("{function_decl} {{\n $0\n}}"); + item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet)); + } + None => { + let header = format!("{function_decl} {{"); + item.text_edit(TextEdit::replace(replacement_range, header)); + } + }; + item.add_to(acc, ctx.db); } } @@ -447,36 +445,36 @@ fn add_const_impl( ) { let const_name = const_.name(ctx.db).map(|n| n.display_no_db(ctx.edition).to_smolstr()); - if let Some(const_name) = const_name { - if let Some(source) = ctx.sema.source(const_) { - let assoc_item = ast::AssocItem::Const(source.value); - if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { - let transformed_const = match transformed_item { - ast::AssocItem::Const(const_) => const_, - _ => unreachable!(), - }; + if let Some(const_name) = const_name + && let Some(source) = ctx.sema.source(const_) + { + let assoc_item = ast::AssocItem::Const(source.value); + if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { + let transformed_const = match transformed_item { + ast::AssocItem::Const(const_) => const_, + _ => unreachable!(), + }; - let label = - make_const_compl_syntax(ctx, &transformed_const, source.file_id.macro_file()); - let replacement = format!("{label} "); + let label = + make_const_compl_syntax(ctx, &transformed_const, source.file_id.macro_file()); + let replacement = format!("{label} "); - let mut item = - CompletionItem::new(SymbolKind::Const, replacement_range, label, ctx.edition); - item.lookup_by(format_smolstr!("const {const_name}")) - .set_documentation(const_.docs(ctx.db)) - .set_relevance(CompletionRelevance { - exact_name_match: true, - ..Default::default() - }); - match ctx.config.snippet_cap { - Some(cap) => item.snippet_edit( - cap, - TextEdit::replace(replacement_range, format!("{replacement}$0;")), - ), - None => item.text_edit(TextEdit::replace(replacement_range, replacement)), - }; - item.add_to(acc, ctx.db); - } + let mut item = + CompletionItem::new(SymbolKind::Const, replacement_range, label, ctx.edition); + item.lookup_by(format_smolstr!("const {const_name}")) + .set_documentation(const_.docs(ctx.db)) + .set_relevance(CompletionRelevance { + exact_name_match: true, + ..Default::default() + }); + match ctx.config.snippet_cap { + Some(cap) => item.snippet_edit( + cap, + TextEdit::replace(replacement_range, format!("{replacement}$0;")), + ), + None => item.text_edit(TextEdit::replace(replacement_range, replacement)), + }; + item.add_to(acc, ctx.db); } } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index 013747e4d0cc..333330004577 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -26,18 +26,17 @@ pub(crate) fn complete_mod( let mut current_module = ctx.module; // For `mod $0`, `ctx.module` is its parent, but for `mod f$0`, it's `mod f` itself, but we're // interested in its parent. - if ctx.original_token.kind() == SyntaxKind::IDENT { - if let Some(module) = + if ctx.original_token.kind() == SyntaxKind::IDENT + && let Some(module) = ctx.original_token.parent_ancestors().nth(1).and_then(ast::Module::cast) - { - match ctx.sema.to_def(&module) { - Some(module) if module == current_module => { - if let Some(parent) = current_module.parent(ctx.db) { - current_module = parent; - } + { + match ctx.sema.to_def(&module) { + Some(module) if module == current_module => { + if let Some(parent) = current_module.parent(ctx.db) { + current_module = parent; } - _ => {} } + _ => {} } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs index 62fae1cb2374..815ce5145dbe 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs @@ -64,18 +64,17 @@ pub(crate) fn complete_pattern( if let Some(hir::Adt::Enum(e)) = ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) + && (refutable || single_variant_enum(e)) { - if refutable || single_variant_enum(e) { - super::enum_variants_with_paths( - acc, - ctx, - e, - &pattern_ctx.impl_, - |acc, ctx, variant, path| { - acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path); - }, - ); - } + super::enum_variants_with_paths( + acc, + ctx, + e, + &pattern_ctx.impl_, + |acc, ctx, variant, path| { + acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path); + }, + ); } // FIXME: ideally, we should look at the type we are matching against and diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index d0023852acf9..0058611a6153 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -65,26 +65,19 @@ pub(crate) fn complete_postfix( let cfg = ctx.config.import_path_config(ctx.is_nightly); - if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() { - if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) { - if let Some(drop_fn) = ctx.famous_defs().core_mem_drop() { - if let Some(path) = - ctx.module.find_path(ctx.db, ItemInNs::Values(drop_fn.into()), cfg) - { - cov_mark::hit!(postfix_drop_completion); - let mut item = postfix_snippet( - "drop", - "fn drop(&mut self)", - &format!( - "{path}($0{receiver_text})", - path = path.display(ctx.db, ctx.edition) - ), - ); - item.set_documentation(drop_fn.docs(ctx.db)); - item.add_to(acc, ctx.db); - } - } - } + if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() + && receiver_ty.impls_trait(ctx.db, drop_trait, &[]) + && let Some(drop_fn) = ctx.famous_defs().core_mem_drop() + && let Some(path) = ctx.module.find_path(ctx.db, ItemInNs::Values(drop_fn.into()), cfg) + { + cov_mark::hit!(postfix_drop_completion); + let mut item = postfix_snippet( + "drop", + "fn drop(&mut self)", + &format!("{path}($0{receiver_text})", path = path.display(ctx.db, ctx.edition)), + ); + item.set_documentation(drop_fn.docs(ctx.db)); + item.add_to(acc, ctx.db); } postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc, ctx.db); @@ -117,56 +110,50 @@ pub(crate) fn complete_postfix( let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); let mut is_in_cond = false; - if let Some(parent) = dot_receiver_including_refs.syntax().parent() { - if let Some(second_ancestor) = parent.parent() { - let sec_ancestor_kind = second_ancestor.kind(); - if let Some(expr) = >::cast(second_ancestor) { - is_in_cond = match expr { - Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent), - Either::Right(it) => { - it.condition().is_some_and(|cond| *cond.syntax() == parent) - } - } + if let Some(parent) = dot_receiver_including_refs.syntax().parent() + && let Some(second_ancestor) = parent.parent() + { + let sec_ancestor_kind = second_ancestor.kind(); + if let Some(expr) = >::cast(second_ancestor) { + is_in_cond = match expr { + Either::Left(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent), + Either::Right(it) => it.condition().is_some_and(|cond| *cond.syntax() == parent), } - match &try_enum { - Some(try_enum) if is_in_cond => match try_enum { - TryEnum::Result => { - postfix_snippet( - "let", - "let Ok(_)", - &format!("let Ok($0) = {receiver_text}"), - ) - .add_to(acc, ctx.db); - postfix_snippet( - "letm", - "let Ok(mut _)", - &format!("let Ok(mut $0) = {receiver_text}"), - ) - .add_to(acc, ctx.db); - } - TryEnum::Option => { - postfix_snippet( - "let", - "let Some(_)", - &format!("let Some($0) = {receiver_text}"), - ) - .add_to(acc, ctx.db); - postfix_snippet( - "letm", - "let Some(mut _)", - &format!("let Some(mut $0) = {receiver_text}"), - ) - .add_to(acc, ctx.db); - } - }, - _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => { - postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) - .add_to(acc, ctx.db); - postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) + } + match &try_enum { + Some(try_enum) if is_in_cond => match try_enum { + TryEnum::Result => { + postfix_snippet("let", "let Ok(_)", &format!("let Ok($0) = {receiver_text}")) .add_to(acc, ctx.db); + postfix_snippet( + "letm", + "let Ok(mut _)", + &format!("let Ok(mut $0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); } - _ => (), + TryEnum::Option => { + postfix_snippet( + "let", + "let Some(_)", + &format!("let Some($0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); + postfix_snippet( + "letm", + "let Some(mut _)", + &format!("let Some(mut $0) = {receiver_text}"), + ) + .add_to(acc, ctx.db); + } + }, + _ if matches!(sec_ancestor_kind, STMT_LIST | EXPR_STMT) => { + postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) + .add_to(acc, ctx.db); + postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) + .add_to(acc, ctx.db); } + _ => (), } } @@ -258,25 +245,25 @@ pub(crate) fn complete_postfix( ) .add_to(acc, ctx.db); postfix_snippet("not", "!expr", &format!("!{receiver_text}")).add_to(acc, ctx.db); - } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() { - if receiver_ty.impls_trait(ctx.db, trait_, &[]) { - postfix_snippet( - "for", - "for ele in expr {}", - &format!("for ele in {receiver_text} {{\n $0\n}}"), - ) - .add_to(acc, ctx.db); - } + } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() + && receiver_ty.impls_trait(ctx.db, trait_, &[]) + { + postfix_snippet( + "for", + "for ele in expr {}", + &format!("for ele in {receiver_text} {{\n $0\n}}"), + ) + .add_to(acc, ctx.db); } } let mut block_should_be_wrapped = true; if dot_receiver.syntax().kind() == BLOCK_EXPR { block_should_be_wrapped = false; - if let Some(parent) = dot_receiver.syntax().parent() { - if matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) { - block_should_be_wrapped = true; - } + if let Some(parent) = dot_receiver.syntax().parent() + && matches!(parent.kind(), IF_EXPR | WHILE_EXPR | LOOP_EXPR | FOR_EXPR) + { + block_should_be_wrapped = true; } }; { @@ -292,10 +279,10 @@ pub(crate) fn complete_postfix( postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db); } - if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() { - if let Some(literal_text) = ast::String::cast(literal.token()) { - add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text); - } + if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() + && let Some(literal_text) = ast::String::cast(literal.token()) + { + add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text); } postfix_snippet( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs index d2ab193ec3df..f39b64164932 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs @@ -54,12 +54,10 @@ pub(crate) fn complete_use_path( for (name, def) in module_scope { if let (Some(attrs), Some(defining_crate)) = (def.attrs(ctx.db), def.krate(ctx.db)) + && (!ctx.check_stability(Some(&attrs)) + || ctx.is_doc_hidden(&attrs, defining_crate)) { - if !ctx.check_stability(Some(&attrs)) - || ctx.is_doc_hidden(&attrs, defining_crate) - { - continue; - } + continue; } let is_name_already_imported = already_imported_names.contains(name.as_str()); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs index 38761f77a2c5..28d906d91ce5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs @@ -20,11 +20,11 @@ pub(crate) fn complete_vis_path( // Try completing next child module of the path that is still a parent of the current module let next_towards_current = ctx.module.path_to_root(ctx.db).into_iter().take_while(|it| it != module).last(); - if let Some(next) = next_towards_current { - if let Some(name) = next.name(ctx.db) { - cov_mark::hit!(visibility_qualified); - acc.add_module(ctx, path_ctx, next, name, vec![]); - } + if let Some(next) = next_towards_current + && let Some(name) = next.name(ctx.db) + { + cov_mark::hit!(visibility_qualified); + acc.add_module(ctx, path_ctx, next, name, vec![]); } acc.add_super_keyword(ctx, *super_chain_len); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index ea5fb39338b2..2eabf99fc697 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -287,24 +287,22 @@ fn expand( &spec_attr, fake_ident_token.clone(), ), - ) { - if let Some((fake_mapped_token, _)) = - fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank) - { - return Some(ExpansionResult { - original_file: original_file.value, - speculative_file, - original_offset, - speculative_offset: fake_ident_token.text_range().start(), - fake_ident_token, - derive_ctx: Some(( - actual_expansion, - fake_expansion, - fake_mapped_token.text_range().start(), - orig_attr, - )), - }); - } + ) && let Some((fake_mapped_token, _)) = + fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank) + { + return Some(ExpansionResult { + original_file: original_file.value, + speculative_file, + original_offset, + speculative_offset: fake_ident_token.text_range().start(), + fake_ident_token, + derive_ctx: Some(( + actual_expansion, + fake_expansion, + fake_mapped_token.text_range().start(), + orig_attr, + )), + }); } if let Some(spec_adt) = @@ -535,14 +533,13 @@ fn analyze<'db>( NameRefKind::Path(PathCompletionCtx { kind: PathKind::Expr { .. }, path, .. }, ..), .. } = &nameref_ctx + && is_in_token_of_for_loop(path) { - if is_in_token_of_for_loop(path) { - // for pat $0 - // there is nothing to complete here except `in` keyword - // don't bother populating the context - // Ideally this special casing wouldn't be needed, but the parser recovers - return None; - } + // for pat $0 + // there is nothing to complete here except `in` keyword + // don't bother populating the context + // Ideally this special casing wouldn't be needed, but the parser recovers + return None; } qual_ctx = qualifier_ctx; @@ -951,29 +948,26 @@ fn classify_name_ref<'db>( let inbetween_body_and_decl_check = |node: SyntaxNode| { if let Some(NodeOrToken::Node(n)) = syntax::algo::non_trivia_sibling(node.into(), syntax::Direction::Prev) + && let Some(item) = ast::Item::cast(n) { - if let Some(item) = ast::Item::cast(n) { - let is_inbetween = match &item { - ast::Item::Const(it) => it.body().is_none() && it.semicolon_token().is_none(), - ast::Item::Enum(it) => it.variant_list().is_none(), - ast::Item::ExternBlock(it) => it.extern_item_list().is_none(), - ast::Item::Fn(it) => it.body().is_none() && it.semicolon_token().is_none(), - ast::Item::Impl(it) => it.assoc_item_list().is_none(), - ast::Item::Module(it) => { - it.item_list().is_none() && it.semicolon_token().is_none() - } - ast::Item::Static(it) => it.body().is_none(), - ast::Item::Struct(it) => { - it.field_list().is_none() && it.semicolon_token().is_none() - } - ast::Item::Trait(it) => it.assoc_item_list().is_none(), - ast::Item::TypeAlias(it) => it.ty().is_none() && it.semicolon_token().is_none(), - ast::Item::Union(it) => it.record_field_list().is_none(), - _ => false, - }; - if is_inbetween { - return Some(item); + let is_inbetween = match &item { + ast::Item::Const(it) => it.body().is_none() && it.semicolon_token().is_none(), + ast::Item::Enum(it) => it.variant_list().is_none(), + ast::Item::ExternBlock(it) => it.extern_item_list().is_none(), + ast::Item::Fn(it) => it.body().is_none() && it.semicolon_token().is_none(), + ast::Item::Impl(it) => it.assoc_item_list().is_none(), + ast::Item::Module(it) => it.item_list().is_none() && it.semicolon_token().is_none(), + ast::Item::Static(it) => it.body().is_none(), + ast::Item::Struct(it) => { + it.field_list().is_none() && it.semicolon_token().is_none() } + ast::Item::Trait(it) => it.assoc_item_list().is_none(), + ast::Item::TypeAlias(it) => it.ty().is_none() && it.semicolon_token().is_none(), + ast::Item::Union(it) => it.record_field_list().is_none(), + _ => false, + }; + if is_inbetween { + return Some(item); } } None @@ -1502,10 +1496,10 @@ fn classify_name_ref<'db>( } }; } - } else if let Some(segment) = path.segment() { - if segment.coloncolon_token().is_some() { - path_ctx.qualified = Qualified::Absolute; - } + } else if let Some(segment) = path.segment() + && segment.coloncolon_token().is_some() + { + path_ctx.qualified = Qualified::Absolute; } let mut qualifier_ctx = QualifierCtx::default(); @@ -1530,38 +1524,30 @@ fn classify_name_ref<'db>( if let Some(top) = top_node { if let Some(NodeOrToken::Node(error_node)) = syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev) + && error_node.kind() == SyntaxKind::ERROR { - if error_node.kind() == SyntaxKind::ERROR { - for token in - error_node.children_with_tokens().filter_map(NodeOrToken::into_token) - { - match token.kind() { - SyntaxKind::UNSAFE_KW => qualifier_ctx.unsafe_tok = Some(token), - SyntaxKind::ASYNC_KW => qualifier_ctx.async_tok = Some(token), - SyntaxKind::SAFE_KW => qualifier_ctx.safe_tok = Some(token), - _ => {} - } + for token in error_node.children_with_tokens().filter_map(NodeOrToken::into_token) { + match token.kind() { + SyntaxKind::UNSAFE_KW => qualifier_ctx.unsafe_tok = Some(token), + SyntaxKind::ASYNC_KW => qualifier_ctx.async_tok = Some(token), + SyntaxKind::SAFE_KW => qualifier_ctx.safe_tok = Some(token), + _ => {} } - qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast); } + qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast); } - if let PathKind::Item { .. } = path_ctx.kind { - if qualifier_ctx.none() { - if let Some(t) = top.first_token() { - if let Some(prev) = t - .prev_token() - .and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev)) - { - if ![T![;], T!['}'], T!['{']].contains(&prev.kind()) { - // This was inferred to be an item position path, but it seems - // to be part of some other broken node which leaked into an item - // list - return None; - } - } - } - } + if let PathKind::Item { .. } = path_ctx.kind + && qualifier_ctx.none() + && let Some(t) = top.first_token() + && let Some(prev) = + t.prev_token().and_then(|t| syntax::algo::skip_trivia_token(t, Direction::Prev)) + && ![T![;], T!['}'], T!['{']].contains(&prev.kind()) + { + // This was inferred to be an item position path, but it seems + // to be part of some other broken node which leaked into an item + // list + return None; } } } 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 dcaac3997b27..f27cd0781665 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -636,10 +636,10 @@ impl Builder { } pub(crate) fn set_detail(&mut self, detail: Option>) -> &mut Builder { self.detail = detail.map(Into::into); - if let Some(detail) = &self.detail { - if never!(detail.contains('\n'), "multiline detail:\n{}", detail) { - self.detail = Some(detail.split('\n').next().unwrap().to_owned()); - } + if let Some(detail) = &self.detail + && never!(detail.contains('\n'), "multiline detail:\n{}", detail) + { + self.detail = Some(detail.split('\n').next().unwrap().to_owned()); } self } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 1fdd4cdb1c6b..a70a1138d2f4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -208,9 +208,9 @@ pub fn completions( // when the user types a bare `_` (that is it does not belong to an identifier) // the user might just wanted to type a `_` for type inference or pattern discarding // so try to suppress completions in those cases - if trigger_character == Some('_') && ctx.original_token.kind() == syntax::SyntaxKind::UNDERSCORE - { - if let CompletionAnalysis::NameRef(NameRefContext { + if trigger_character == Some('_') + && ctx.original_token.kind() == syntax::SyntaxKind::UNDERSCORE + && let CompletionAnalysis::NameRef(NameRefContext { kind: NameRefKind::Path( path_ctx @ PathCompletionCtx { @@ -220,11 +220,9 @@ pub fn completions( ), .. }) = analysis - { - if path_ctx.is_trivial_path() { - return None; - } - } + && path_ctx.is_trivial_path() + { + return None; } { 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 c6b8af3c79a2..3d7a4067c2cd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -164,19 +164,18 @@ pub(crate) fn render_field( let expected_fn_type = ctx.completion.expected_type.as_ref().is_some_and(|ty| ty.is_fn() || ty.is_closure()); - if !expected_fn_type { - if let Some(receiver) = &dot_access.receiver { - if let Some(receiver) = ctx.completion.sema.original_ast_node(receiver.clone()) { - builder.insert(receiver.syntax().text_range().start(), "(".to_owned()); - builder.insert(ctx.source_range().end(), ")".to_owned()); + if !expected_fn_type + && let Some(receiver) = &dot_access.receiver + && let Some(receiver) = ctx.completion.sema.original_ast_node(receiver.clone()) + { + builder.insert(receiver.syntax().text_range().start(), "(".to_owned()); + builder.insert(ctx.source_range().end(), ")".to_owned()); - let is_parens_needed = - !matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); + let is_parens_needed = + !matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); - if is_parens_needed { - builder.insert(ctx.source_range().end(), "()".to_owned()); - } - } + if is_parens_needed { + builder.insert(ctx.source_range().end(), "()".to_owned()); } } @@ -184,12 +183,11 @@ pub(crate) fn render_field( } else { item.insert_text(field_with_receiver(receiver.as_deref(), &escaped_name)); } - if let Some(receiver) = &dot_access.receiver { - if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) { - if let Some(ref_mode) = compute_ref_match(ctx.completion, ty) { - item.ref_match(ref_mode, original.syntax().text_range().start()); - } - } + if let Some(receiver) = &dot_access.receiver + && let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) + && let Some(ref_mode) = compute_ref_match(ctx.completion, ty) + { + item.ref_match(ref_mode, original.syntax().text_range().start()); } item.doc_aliases(ctx.doc_aliases); item.build(db) @@ -437,26 +435,21 @@ fn render_resolution_path( path_ctx, PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. } ) && config.callable.is_some(); - if type_path_no_ty_args { - if let Some(cap) = cap { - let has_non_default_type_params = match resolution { - ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db), - ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => { - it.has_non_default_type_params(db) - } - _ => false, - }; - - if has_non_default_type_params { - cov_mark::hit!(inserts_angle_brackets_for_generics); - item.lookup_by(name.clone()) - .label(SmolStr::from_iter([&name, "<…>"])) - .trigger_call_info() - .insert_snippet( - cap, - format!("{}<$0>", local_name.display(db, completion.edition)), - ); + if type_path_no_ty_args && let Some(cap) = cap { + let has_non_default_type_params = match resolution { + ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db), + ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => { + it.has_non_default_type_params(db) } + _ => false, + }; + + if has_non_default_type_params { + cov_mark::hit!(inserts_angle_brackets_for_generics); + item.lookup_by(name.clone()) + .label(SmolStr::from_iter([&name, "<…>"])) + .trigger_call_info() + .insert_snippet(cap, format!("{}<$0>", local_name.display(db, completion.edition))); } } @@ -634,23 +627,24 @@ fn compute_ref_match( if expected_type.could_unify_with(ctx.db, completion_ty) { return None; } - if let Some(expected_without_ref) = &expected_without_ref { - if completion_ty.autoderef(ctx.db).any(|ty| ty == *expected_without_ref) { - cov_mark::hit!(suggest_ref); - let mutability = if expected_type.is_mutable_reference() { - hir::Mutability::Mut - } else { - hir::Mutability::Shared - }; - return Some(CompletionItemRefMode::Reference(mutability)); - } + if let Some(expected_without_ref) = &expected_without_ref + && completion_ty.autoderef(ctx.db).any(|ty| ty == *expected_without_ref) + { + cov_mark::hit!(suggest_ref); + let mutability = if expected_type.is_mutable_reference() { + hir::Mutability::Mut + } else { + hir::Mutability::Shared + }; + return Some(CompletionItemRefMode::Reference(mutability)); } - if let Some(completion_without_ref) = completion_without_ref { - if completion_without_ref == *expected_type && completion_without_ref.is_copy(ctx.db) { - cov_mark::hit!(suggest_deref); - return Some(CompletionItemRefMode::Dereference); - } + if let Some(completion_without_ref) = completion_without_ref + && completion_without_ref == *expected_type + && completion_without_ref.is_copy(ctx.db) + { + cov_mark::hit!(suggest_deref); + return Some(CompletionItemRefMode::Dereference); } None @@ -664,10 +658,10 @@ fn path_ref_match( ) { if let Some(original_path) = &path_ctx.original_path { // At least one char was typed by the user already, in that case look for the original path - if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) { - if let Some(ref_mode) = compute_ref_match(completion, ty) { - item.ref_match(ref_mode, original_path.syntax().text_range().start()); - } + if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) + && let Some(ref_mode) = compute_ref_match(completion, ty) + { + item.ref_match(ref_mode, original_path.syntax().text_range().start()); } } else { // completion requested on an empty identifier, there is no path here yet. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs index f11b3023679a..707a8aed4fb9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs @@ -25,10 +25,10 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option .detail(detail) .set_relevance(ctx.completion_relevance()); - if let Some(actm) = const_.as_assoc_item(db) { - if let Some(trt) = actm.container_or_implemented_trait(db) { - item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); - } + if let Some(actm) = const_.as_assoc_item(db) + && let Some(trt) = actm.container_or_implemented_trait(db) + { + item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); } item.insert_text(escaped_name); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 7669aec8f535..c466019f991f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -132,10 +132,10 @@ fn render( super::path_ref_match(completion, path_ctx, &ret_type, &mut item); } FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { - if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { - if let Some(ref_mode) = compute_ref_match(completion, &ret_type) { - item.ref_match(ref_mode, original_expr.syntax().text_range().start()); - } + if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) + && let Some(ref_mode) = compute_ref_match(completion, &ret_type) + { + item.ref_match(ref_mode, original_expr.syntax().text_range().start()); } } _ => (), @@ -169,12 +169,10 @@ fn render( item.add_import(import_to_add); } None => { - if let Some(actm) = assoc_item { - if let Some(trt) = actm.container_or_implemented_trait(db) { - item.trait_name( - trt.name(db).display_no_db(ctx.completion.edition).to_smolstr(), - ); - } + if let Some(actm) = assoc_item + && let Some(trt) = actm.container_or_implemented_trait(db) + { + item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); } } } @@ -378,15 +376,13 @@ fn params<'db>( ctx.config.callable.as_ref()?; // Don't add parentheses if the expected type is a function reference with the same signature. - if let Some(expected) = ctx.expected_type.as_ref().filter(|e| e.is_fn()) { - if let Some(expected) = expected.as_callable(ctx.db) { - if let Some(completed) = func.ty(ctx.db).as_callable(ctx.db) { - if expected.sig() == completed.sig() { - cov_mark::hit!(no_call_parens_if_fn_ptr_needed); - return None; - } - } - } + if let Some(expected) = ctx.expected_type.as_ref().filter(|e| e.is_fn()) + && let Some(expected) = expected.as_callable(ctx.db) + && let Some(completed) = func.ty(ctx.db).as_callable(ctx.db) + && expected.sig() == completed.sig() + { + cov_mark::hit!(no_call_parens_if_fn_ptr_needed); + return None; } let self_param = if has_dot_receiver || matches!(func_kind, FuncKind::Method(_, Some(_))) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs index d57feee4fa65..3fc0f369e5ad 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs @@ -51,10 +51,10 @@ fn render( .detail(detail) .set_relevance(ctx.completion_relevance()); - if let Some(actm) = type_alias.as_assoc_item(db) { - if let Some(trt) = actm.container_or_implemented_trait(db) { - item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); - } + if let Some(actm) = type_alias.as_assoc_item(db) + && let Some(trt) = actm.container_or_implemented_trait(db) + { + item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); } item.insert_text(escaped_name); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index a4a140ec57aa..2a4fcf6a2e5f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -610,18 +610,16 @@ impl<'db> NameClass<'db> { let local = sema.to_def(&ident_pat)?; let pat_parent = ident_pat.syntax().parent(); - if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) { - if record_pat_field.name_ref().is_none() { - if let Some((field, _, adt_subst)) = - sema.resolve_record_pat_field_with_subst(&record_pat_field) - { - return Some(NameClass::PatFieldShorthand { - local_def: local, - field_ref: field, - adt_subst, - }); - } - } + if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) + && record_pat_field.name_ref().is_none() + && let Some((field, _, adt_subst)) = + sema.resolve_record_pat_field_with_subst(&record_pat_field) + { + return Some(NameClass::PatFieldShorthand { + local_def: local, + field_ref: field, + adt_subst, + }); } Some(NameClass::Definition(Definition::Local(local))) } @@ -755,30 +753,27 @@ impl<'db> NameRefClass<'db> { let parent = name_ref.syntax().parent()?; - if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { - if let Some((field, local, _, adt_subst)) = + if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) + && let Some((field, local, _, adt_subst)) = sema.resolve_record_field_with_substitution(&record_field) - { - let res = match local { - None => NameRefClass::Definition(Definition::Field(field), Some(adt_subst)), - Some(local) => NameRefClass::FieldShorthand { - field_ref: field, - local_ref: local, - adt_subst, - }, - }; - return Some(res); - } + { + let res = match local { + None => NameRefClass::Definition(Definition::Field(field), Some(adt_subst)), + Some(local) => { + NameRefClass::FieldShorthand { field_ref: field, local_ref: local, adt_subst } + } + }; + return Some(res); } if let Some(path) = ast::PathSegment::cast(parent.clone()).map(|it| it.parent_path()) { - if path.parent_path().is_none() { - if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - // Only use this to resolve to macro calls for last segments as qualifiers resolve - // to modules below. - if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { - return Some(NameRefClass::Definition(Definition::Macro(macro_def), None)); - } + if path.parent_path().is_none() + && let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) + { + // Only use this to resolve to macro calls for last segments as qualifiers resolve + // to modules below. + if let Some(macro_def) = sema.resolve_macro_call(¯o_call) { + return Some(NameRefClass::Definition(Definition::Macro(macro_def), None)); } } return sema @@ -820,8 +815,8 @@ impl<'db> NameRefClass<'db> { // ^^^^^ let containing_path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; let resolved = sema.resolve_path(&containing_path)?; - if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { - if let Some(ty) = tr + if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved + && let Some(ty) = tr .items_with_supertraits(sema.db) .iter() .filter_map(|&assoc| match assoc { @@ -833,7 +828,6 @@ impl<'db> NameRefClass<'db> { // No substitution, this can only occur in type position. return Some(NameRefClass::Definition(Definition::TypeAlias(ty), None)); } - } None }, ast::UseBoundGenericArgs(_) => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs index 340429037e67..1e54058dd16c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs @@ -70,11 +70,11 @@ pub fn visit_file_defs( }; let mut defs: VecDeque<_> = module.declarations(db).into(); while let Some(def) = defs.pop_front() { - if let ModuleDef::Module(submodule) = def { - if submodule.is_inline(db) { - defs.extend(submodule.declarations(db)); - submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into())); - } + if let ModuleDef::Module(submodule) = def + && submodule.is_inline(db) + { + defs.extend(submodule.declarations(db)); + submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into())); } cb(def.into()); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs index 813f38380f69..08cd8f28608c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs @@ -97,12 +97,11 @@ impl ImportScope { .map(ImportScopeKind::Module) .map(|kind| ImportScope { kind, required_cfgs }); } else if let Some(has_attrs) = ast::AnyHasAttrs::cast(syntax) { - if block.is_none() { - if let Some(b) = ast::BlockExpr::cast(has_attrs.syntax().clone()) { - if let Some(b) = sema.original_ast_node(b) { - block = b.stmt_list(); - } - } + if block.is_none() + && let Some(b) = ast::BlockExpr::cast(has_attrs.syntax().clone()) + && let Some(b) = sema.original_ast_node(b) + { + block = b.stmt_list(); } if has_attrs .attrs() @@ -349,26 +348,24 @@ fn guess_granularity_from_scope(scope: &ImportScope) -> ImportGranularityGuess { seen_one_style_groups.push((curr_vis.clone(), curr_attrs.clone())); } else if eq_visibility(prev_vis, curr_vis.clone()) && eq_attrs(prev_attrs, curr_attrs.clone()) + && let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) + && let Some((prev_prefix, _)) = common_prefix(&prev_path, &curr_path) { - if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) { - if let Some((prev_prefix, _)) = common_prefix(&prev_path, &curr_path) { - if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() { - let prefix_c = prev_prefix.qualifiers().count(); - let curr_c = curr_path.qualifiers().count() - prefix_c; - let prev_c = prev_path.qualifiers().count() - prefix_c; - if curr_c == 1 && prev_c == 1 { - // Same prefix, only differing in the last segment and no use tree lists so this has to be of item style. - break ImportGranularityGuess::Item; - } else { - // Same prefix and no use tree list but differs in more than one segment at the end. This might be module style still. - res = ImportGranularityGuess::ModuleOrItem; - } - } else { - // Same prefix with item tree lists, has to be module style as it - // can't be crate style since the trees wouldn't share a prefix then. - break ImportGranularityGuess::Module; - } + if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() { + let prefix_c = prev_prefix.qualifiers().count(); + let curr_c = curr_path.qualifiers().count() - prefix_c; + let prev_c = prev_path.qualifiers().count() - prefix_c; + if curr_c == 1 && prev_c == 1 { + // Same prefix, only differing in the last segment and no use tree lists so this has to be of item style. + break ImportGranularityGuess::Item; + } else { + // Same prefix and no use tree list but differs in more than one segment at the end. This might be module style still. + res = ImportGranularityGuess::ModuleOrItem; } + } else { + // Same prefix with item tree lists, has to be module style as it + // can't be crate style since the trees wouldn't share a prefix then. + break ImportGranularityGuess::Module; } } prev = curr; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index b7432d89c7b7..5d88afec5095 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -193,13 +193,12 @@ impl<'a> PathTransform<'a> { } } (Either::Right(k), None) => { - if let Some(default) = k.default(db) { - if let Some(default) = + if let Some(default) = k.default(db) + && let Some(default) = &default.display_source_code(db, source_module.into(), false).ok() - { - type_substs.insert(k, make::ty(default).clone_for_update()); - defaulted_params.push(Either::Left(k)); - } + { + type_substs.insert(k, make::ty(default).clone_for_update()); + defaulted_params.push(Either::Left(k)); } } (Either::Left(k), Some(TypeOrConst::Either(v))) => { @@ -221,11 +220,10 @@ impl<'a> PathTransform<'a> { (Either::Left(k), None) => { if let Some(default) = k.default(db, target_module.krate().to_display_target(db)) + && let Some(default) = default.expr() { - if let Some(default) = default.expr() { - const_substs.insert(k, default.syntax().clone_for_update()); - defaulted_params.push(Either::Right(k)); - } + const_substs.insert(k, default.syntax().clone_for_update()); + defaulted_params.push(Either::Right(k)); } } _ => (), // ignore mismatching params @@ -427,14 +425,14 @@ impl Ctx<'_> { } } hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => { - if let hir::ModuleDef::Trait(_) = def { - if matches!(path.segment()?.kind()?, ast::PathSegmentKind::Type { .. }) { - // `speculative_resolve` resolves segments like `` into `Trait`, but just the trait name should - // not be used as the replacement of the original - // segment. - return None; - } + if let hir::ModuleDef::Trait(_) = def + && matches!(path.segment()?.kind()?, ast::PathSegmentKind::Type { .. }) + { + // `speculative_resolve` resolves segments like `` into `Trait`, but just the trait name should + // not be used as the replacement of the original + // segment. + return None; } let cfg = ImportPathConfig { @@ -446,19 +444,17 @@ impl Ctx<'_> { let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?; let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update(); let mut res_editor = SyntaxEditor::new(res.syntax().clone_subtree()); - if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) { - if let Some(segment) = res.segment() { - if let Some(old) = segment.generic_arg_list() { - res_editor.replace( - old.syntax(), - args.clone_subtree().syntax().clone_for_update(), - ) - } else { - res_editor.insert( - syntax_editor::Position::last_child_of(segment.syntax()), - args.clone_subtree().syntax().clone_for_update(), - ); - } + if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) + && let Some(segment) = res.segment() + { + if let Some(old) = segment.generic_arg_list() { + res_editor + .replace(old.syntax(), args.clone_subtree().syntax().clone_for_update()) + } else { + res_editor.insert( + syntax_editor::Position::last_child_of(segment.syntax()), + args.clone_subtree().syntax().clone_for_update(), + ); } } let res = res_editor.finish().new_root().clone(); @@ -485,27 +481,27 @@ impl Ctx<'_> { .ok()?; let ast_ty = make::ty(ty_str).clone_for_update(); - if let Some(adt) = ty.as_adt() { - if let ast::Type::PathType(path_ty) = &ast_ty { - let cfg = ImportPathConfig { - prefer_no_std: false, - prefer_prelude: true, - prefer_absolute: false, - allow_unstable: true, - }; - let found_path = self.target_module.find_path( - self.source_scope.db, - ModuleDef::from(adt), - cfg, - )?; + if let Some(adt) = ty.as_adt() + && let ast::Type::PathType(path_ty) = &ast_ty + { + let cfg = ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + allow_unstable: true, + }; + let found_path = self.target_module.find_path( + self.source_scope.db, + ModuleDef::from(adt), + cfg, + )?; - if let Some(qual) = - mod_path_to_ast(&found_path, self.target_edition).qualifier() - { - let res = make::path_concat(qual, path_ty.path()?).clone_for_update(); - editor.replace(path.syntax(), res.syntax()); - return Some(()); - } + if let Some(qual) = + mod_path_to_ast(&found_path, self.target_edition).qualifier() + { + let res = make::path_concat(qual, path_ty.path()?).clone_for_update(); + editor.replace(path.syntax(), res.syntax()); + return Some(()); } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 4e737e27f050..424b27a398b2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -442,17 +442,17 @@ fn source_edit_from_name( name: &ast::Name, new_name: &dyn Display, ) -> bool { - if ast::RecordPatField::for_field_name(name).is_some() { - if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { - cov_mark::hit!(rename_record_pat_field_name_split); - // Foo { ref mut field } -> Foo { new_name: ref mut field } - // ^ insert `new_name: ` + if ast::RecordPatField::for_field_name(name).is_some() + && let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) + { + cov_mark::hit!(rename_record_pat_field_name_split); + // Foo { ref mut field } -> Foo { new_name: ref mut field } + // ^ insert `new_name: ` - // FIXME: instead of splitting the shorthand, recursively trigger a rename of the - // other name https://github.com/rust-lang/rust-analyzer/issues/6547 - edit.insert(ident_pat.syntax().text_range().start(), format!("{new_name}: ")); - return true; - } + // FIXME: instead of splitting the shorthand, recursively trigger a rename of the + // other name https://github.com/rust-lang/rust-analyzer/issues/6547 + edit.insert(ident_pat.syntax().text_range().start(), format!("{new_name}: ")); + return true; } false diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 9cf0bcf91901..4dd64229d274 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -295,10 +295,10 @@ impl Definition { } // def is crate root - if let &Definition::Module(module) = self { - if module.is_crate_root() { - return SearchScope::reverse_dependencies(db, module.krate()); - } + if let &Definition::Module(module) = self + && module.is_crate_root() + { + return SearchScope::reverse_dependencies(db, module.krate()); } let module = match self.module(db) { @@ -683,51 +683,47 @@ impl<'a> FindUsages<'a> { } } else if let Some(alias) = usage.ancestors().find_map(ast::TypeAlias::cast) + && let Some(name) = alias.name() + && seen + .insert(InFileWrapper::new(file_id, name.syntax().text_range())) { - if let Some(name) = alias.name() { - if seen.insert(InFileWrapper::new( - file_id, - name.syntax().text_range(), - )) { - if let Some(def) = is_alias(&alias) { - cov_mark::hit!(container_type_alias); - insert_type_alias( - sema.db, - &mut to_process, - name.text().as_str(), - def.into(), - ); - } else { - cov_mark::hit!(same_name_different_def_type_alias); - } - } + if let Some(def) = is_alias(&alias) { + cov_mark::hit!(container_type_alias); + insert_type_alias( + sema.db, + &mut to_process, + name.text().as_str(), + def.into(), + ); + } else { + cov_mark::hit!(same_name_different_def_type_alias); } } // We need to account for `Self`. It can only refer to our type inside an impl. let impl_ = 'impl_: { for ancestor in usage.ancestors() { - if let Some(parent) = ancestor.parent() { - if let Some(parent) = ast::Impl::cast(parent) { - // Only if the GENERIC_PARAM_LIST is directly under impl, otherwise it may be in the self ty. - if matches!( - ancestor.kind(), - SyntaxKind::ASSOC_ITEM_LIST - | SyntaxKind::WHERE_CLAUSE - | SyntaxKind::GENERIC_PARAM_LIST - ) { - break; - } - if parent - .trait_() - .is_some_and(|trait_| *trait_.syntax() == ancestor) - { - break; - } - - // Otherwise, found an impl where its self ty may be our type. - break 'impl_ Some(parent); + if let Some(parent) = ancestor.parent() + && let Some(parent) = ast::Impl::cast(parent) + { + // Only if the GENERIC_PARAM_LIST is directly under impl, otherwise it may be in the self ty. + if matches!( + ancestor.kind(), + SyntaxKind::ASSOC_ITEM_LIST + | SyntaxKind::WHERE_CLAUSE + | SyntaxKind::GENERIC_PARAM_LIST + ) { + break; } + if parent + .trait_() + .is_some_and(|trait_| *trait_.syntax() == ancestor) + { + break; + } + + // Otherwise, found an impl where its self ty may be our type. + break 'impl_ Some(parent); } } None @@ -1356,11 +1352,10 @@ impl ReferenceCategory { if matches!(expr.op_kind()?, ast::BinaryOp::Assignment { .. }) { // If the variable or field ends on the LHS's end then it's a Write // (covers fields and locals). FIXME: This is not terribly accurate. - if let Some(lhs) = expr.lhs() { - if lhs.syntax().text_range().end() == r.syntax().text_range().end() { + if let Some(lhs) = expr.lhs() + && lhs.syntax().text_range().end() == r.syntax().text_range().end() { return Some(ReferenceCategory::WRITE) } - } } Some(ReferenceCategory::READ) }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index c15cade84a50..9c4e6f5cbf82 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -252,10 +252,10 @@ impl SymbolIndex { let mut last_batch_start = 0; for idx in 0..symbols.len() { - if let Some(next_symbol) = symbols.get(idx + 1) { - if cmp(&symbols[last_batch_start], next_symbol) == Ordering::Equal { - continue; - } + if let Some(next_symbol) = symbols.get(idx + 1) + && cmp(&symbols[last_batch_start], next_symbol) == Ordering::Equal + { + continue; } let start = last_batch_start; @@ -371,10 +371,10 @@ impl Query { if self.exclude_imports && symbol.is_import { continue; } - if self.mode.check(&self.query, self.case_sensitive, symbol_name) { - if let Some(b) = cb(symbol).break_value() { - return Some(b); - } + if self.mode.check(&self.query, self.case_sensitive, symbol_name) + && let Some(b) = cb(symbol).break_value() + { + return Some(b); } } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs index 7e8c921d9ed3..1d4d8decf541 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs @@ -230,11 +230,11 @@ pub fn lex_format_specifiers( skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback); } continue; - } else if let '}' = first_char { - if let Some((_, '}')) = chars.peek() { - // Escaped format specifier, `}}` - read_escaped_format_specifier(&mut chars, &mut callback); - } + } else if let '}' = first_char + && let Some((_, '}')) = chars.peek() + { + // Escaped format specifier, `}}` + read_escaped_format_specifier(&mut chars, &mut callback); } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs index bdff64dd0812..cefd8fd49676 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -79,14 +79,13 @@ pub fn preorder_expr_with_ctx_checker( continue; } }; - if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) { - if let_stmt.initializer().map(|it| it.syntax() != &node).unwrap_or(true) - && let_stmt.let_else().map(|it| it.syntax() != &node).unwrap_or(true) - { - // skipping potential const pat expressions in let statements - preorder.skip_subtree(); - continue; - } + if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) + && let_stmt.initializer().map(|it| it.syntax() != &node).unwrap_or(true) + && let_stmt.let_else().map(|it| it.syntax() != &node).unwrap_or(true) + { + // skipping potential const pat expressions in let statements + preorder.skip_subtree(); + continue; } match ast::Stmt::cast(node.clone()) { @@ -306,10 +305,10 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { Some(ast::BlockModifier::AsyncGen(_)) => (), None => (), } - if let Some(stmt_list) = b.stmt_list() { - if let Some(e) = stmt_list.tail_expr() { - for_each_tail_expr(&e, cb); - } + if let Some(stmt_list) = b.stmt_list() + && let Some(e) = stmt_list.tail_expr() + { + for_each_tail_expr(&e, cb); } } ast::Expr::IfExpr(if_) => { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs index f63cd92694b3..a91d436afcfb 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs @@ -16,17 +16,17 @@ pub fn use_trivial_constructor( ) -> Option { match ty.as_adt() { Some(hir::Adt::Enum(x)) => { - if let &[variant] = &*x.variants(db) { - if variant.kind(db) == hir::StructKind::Unit { - let path = make::path_qualified( - path, - make::path_segment(make::name_ref( - &variant.name(db).display_no_db(edition).to_smolstr(), - )), - ); + if let &[variant] = &*x.variants(db) + && variant.kind(db) == hir::StructKind::Unit + { + let path = make::path_qualified( + path, + make::path_segment(make::name_ref( + &variant.name(db).display_no_db(edition).to_smolstr(), + )), + ); - return Some(make::expr_path(path)); - } + return Some(make::expr_path(path)); } } Some(hir::Adt::Struct(x)) if x.kind(db) == StructKind::Unit => { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index bf7dddacd8c5..742d614bc567 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -148,37 +148,27 @@ pub(crate) fn json_in_items( allow_unstable: true, }; - if !scope_has("Serialize") { - if let Some(PathResolution::Def(it)) = serialize_resolved { - if let Some(it) = current_module.find_use_path( - sema.db, - it, - config.insert_use.prefix_kind, - cfg, - ) { - insert_use( - &scope, - mod_path_to_ast(&it, edition), - &config.insert_use, - ); - } - } + if !scope_has("Serialize") + && let Some(PathResolution::Def(it)) = serialize_resolved + && let Some(it) = current_module.find_use_path( + sema.db, + it, + config.insert_use.prefix_kind, + cfg, + ) + { + insert_use(&scope, mod_path_to_ast(&it, edition), &config.insert_use); } - if !scope_has("Deserialize") { - if let Some(PathResolution::Def(it)) = deserialize_resolved { - if let Some(it) = current_module.find_use_path( - sema.db, - it, - config.insert_use.prefix_kind, - cfg, - ) { - insert_use( - &scope, - mod_path_to_ast(&it, edition), - &config.insert_use, - ); - } - } + if !scope_has("Deserialize") + && let Some(PathResolution::Def(it)) = deserialize_resolved + && let Some(it) = current_module.find_use_path( + sema.db, + it, + config.insert_use.prefix_kind, + cfg, + ) + { + insert_use(&scope, mod_path_to_ast(&it, edition), &config.insert_use); } let mut sc = scb.finish(); sc.insert_source_edit(vfs_file_id, edit.finish()); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 7da799e0d490..893bfca6a129 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -227,12 +227,11 @@ fn get_default_constructor( // Look for a ::new() associated function let has_new_func = ty .iterate_assoc_items(ctx.sema.db, krate, |assoc_item| { - if let AssocItem::Function(func) = assoc_item { - if func.name(ctx.sema.db) == sym::new - && func.assoc_fn_params(ctx.sema.db).is_empty() - { - return Some(()); - } + if let AssocItem::Function(func) = assoc_item + && func.name(ctx.sema.db) == sym::new + && func.assoc_fn_params(ctx.sema.db).is_empty() + { + return Some(()); } None diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 8831efa31172..6e30bf92dbaa 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -12,14 +12,14 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option let root = ctx.sema.db.parse_or_expand(d.span.file_id); let node = d.span.value.to_node(&root); let mut span = d.span; - if let Some(parent) = node.parent() { - if ast::BinExpr::can_cast(parent.kind()) { - // In case of an assignment, the diagnostic is provided on the variable name. - // We want to expand it to include the whole assignment, but only when this - // is an ordinary assignment, not a destructuring assignment. So, the direct - // parent is an assignment expression. - span = d.span.with_value(SyntaxNodePtr::new(&parent)); - } + if let Some(parent) = node.parent() + && ast::BinExpr::can_cast(parent.kind()) + { + // In case of an assignment, the diagnostic is provided on the variable name. + // We want to expand it to include the whole assignment, but only when this + // is an ordinary assignment, not a destructuring assignment. So, the direct + // parent is an assignment expression. + span = d.span.with_value(SyntaxNodePtr::new(&parent)); }; let fixes = (|| { @@ -73,10 +73,10 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Op let ast = source.syntax(); let Some(mut_token) = token(ast, T![mut]) else { continue }; edit_builder.delete(mut_token.text_range()); - if let Some(token) = mut_token.next_token() { - if token.kind() == SyntaxKind::WHITESPACE { - edit_builder.delete(token.text_range()); - } + if let Some(token) = mut_token.next_token() + && token.kind() == SyntaxKind::WHITESPACE + { + edit_builder.delete(token.text_range()); } } let edit = edit_builder.finish(); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs index d96c658d7b04..3a6e480f55ed 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -231,13 +231,13 @@ fn make_fixes( // If there's an existing `mod m;` statement matching the new one, don't emit a fix (it's // probably `#[cfg]`d out). for item in items.clone() { - if let ast::Item::Module(m) = item { - if let Some(name) = m.name() { - if m.item_list().is_none() && name.to_string() == new_mod_name { - cov_mark::hit!(unlinked_file_skip_fix_when_mod_already_exists); - return None; - } - } + if let ast::Item::Module(m) = item + && let Some(name) = m.name() + && m.item_list().is_none() + && name.to_string() == new_mod_name + { + cov_mark::hit!(unlinked_file_skip_fix_when_mod_already_exists); + return None; } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 72bd66d1c8bb..a1db92641f5e 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -568,10 +568,10 @@ fn handle_diag_from_macros( diag.fixes = None; // All Clippy lints report in macros, see https://github.com/rust-lang/rust-clippy/blob/903293b199364/declare_clippy_lint/src/lib.rs#L172. - if let DiagnosticCode::RustcLint(lint) = diag.code { - if !LINTS_TO_REPORT_IN_EXTERNAL_MACROS.contains(lint) { - return false; - } + if let DiagnosticCode::RustcLint(lint) = diag.code + && !LINTS_TO_REPORT_IN_EXTERNAL_MACROS.contains(lint) + { + return false; }; } true @@ -760,35 +760,35 @@ fn cfg_attr_lint_attrs( } while let Some(value) = iter.next() { - if let Some(token) = value.as_token() { - if token.kind() == SyntaxKind::IDENT { - let severity = match token.text() { - "allow" | "expect" => Some(Severity::Allow), - "warn" => Some(Severity::Warning), - "forbid" | "deny" => Some(Severity::Error), - "cfg_attr" => { - if let Some(NodeOrToken::Node(value)) = iter.next() { - cfg_attr_lint_attrs(sema, &value, lint_attrs); - } - None - } - _ => None, - }; - if let Some(severity) = severity { - let lints = iter.next(); - if let Some(NodeOrToken::Node(lints)) = lints { - lint_attrs.push((severity, lints)); + if let Some(token) = value.as_token() + && token.kind() == SyntaxKind::IDENT + { + let severity = match token.text() { + "allow" | "expect" => Some(Severity::Allow), + "warn" => Some(Severity::Warning), + "forbid" | "deny" => Some(Severity::Error), + "cfg_attr" => { + if let Some(NodeOrToken::Node(value)) = iter.next() { + cfg_attr_lint_attrs(sema, &value, lint_attrs); } + None + } + _ => None, + }; + if let Some(severity) = severity { + let lints = iter.next(); + if let Some(NodeOrToken::Node(lints)) = lints { + lint_attrs.push((severity, lints)); } } } } - if prev_len != lint_attrs.len() { - if let Some(false) | None = sema.check_cfg_attr(value) { - // Discard the attributes when the condition is false. - lint_attrs.truncate(prev_len); - } + if prev_len != lint_attrs.len() + && let Some(false) | None = sema.check_cfg_attr(value) + { + // Discard the attributes when the condition is false. + lint_attrs.truncate(prev_len); } } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index e4b20f3f1aad..138af22089eb 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -283,17 +283,16 @@ impl<'db> MatchFinder<'db> { node: node.clone(), }); } - } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) { - if let Some(expanded) = self.sema.expand_macro_call(¯o_call) { - if let Some(tt) = macro_call.token_tree() { - self.output_debug_for_nodes_at_range( - &expanded.value, - range, - &Some(self.sema.original_range(tt.syntax())), - out, - ); - } - } + } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) + && let Some(expanded) = self.sema.expand_macro_call(¯o_call) + && let Some(tt) = macro_call.token_tree() + { + self.output_debug_for_nodes_at_range( + &expanded.value, + range, + &Some(self.sema.original_range(tt.syntax())), + out, + ); } self.output_debug_for_nodes_at_range(&node, range, restrict_range, out); } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index b350315ba548..f21132c297ee 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -156,12 +156,11 @@ impl<'db, 'sema> Matcher<'db, 'sema> { /// processing a macro expansion and we want to fail the match if we're working with a node that /// didn't originate from the token tree of the macro call. fn validate_range(&self, range: &FileRange) -> Result<(), MatchFailed> { - if let Some(restrict_range) = &self.restrict_range { - if restrict_range.file_id != range.file_id - || !restrict_range.range.contains_range(range.range) - { - fail_match!("Node originated from a macro"); - } + if let Some(restrict_range) = &self.restrict_range + && (restrict_range.file_id != range.file_id + || !restrict_range.range.contains_range(range.range)) + { + fail_match!("Node originated from a macro"); } Ok(()) } @@ -404,30 +403,27 @@ impl<'db, 'sema> Matcher<'db, 'sema> { // Build a map keyed by field name. let mut fields_by_name: FxHashMap = FxHashMap::default(); for child in code.children() { - if let Some(record) = ast::RecordExprField::cast(child.clone()) { - if let Some(name) = record.field_name() { - fields_by_name.insert(name.text().into(), child.clone()); - } + if let Some(record) = ast::RecordExprField::cast(child.clone()) + && let Some(name) = record.field_name() + { + fields_by_name.insert(name.text().into(), child.clone()); } } for p in pattern.children_with_tokens() { - if let SyntaxElement::Node(p) = p { - if let Some(name_element) = p.first_child_or_token() { - if self.get_placeholder(&name_element).is_some() { - // If the pattern is using placeholders for field names then order - // independence doesn't make sense. Fall back to regular ordered - // matching. - return self.attempt_match_node_children(phase, pattern, code); - } - if let Some(ident) = only_ident(name_element) { - let code_record = fields_by_name.remove(ident.text()).ok_or_else(|| { - match_error!( - "Placeholder has record field '{}', but code doesn't", - ident - ) - })?; - self.attempt_match_node(phase, &p, &code_record)?; - } + if let SyntaxElement::Node(p) = p + && let Some(name_element) = p.first_child_or_token() + { + if self.get_placeholder(&name_element).is_some() { + // If the pattern is using placeholders for field names then order + // independence doesn't make sense. Fall back to regular ordered + // matching. + return self.attempt_match_node_children(phase, pattern, code); + } + if let Some(ident) = only_ident(name_element) { + let code_record = fields_by_name.remove(ident.text()).ok_or_else(|| { + match_error!("Placeholder has record field '{}', but code doesn't", ident) + })?; + self.attempt_match_node(phase, &p, &code_record)?; } } } @@ -476,14 +472,13 @@ impl<'db, 'sema> Matcher<'db, 'sema> { } } SyntaxElement::Node(n) => { - if let Some(first_token) = n.first_token() { - if Some(first_token.text()) == next_pattern_token.as_deref() { - if let Some(SyntaxElement::Node(p)) = pattern.next() { - // We have a subtree that starts with the next token in our pattern. - self.attempt_match_token_tree(phase, &p, n)?; - break; - } - } + if let Some(first_token) = n.first_token() + && Some(first_token.text()) == next_pattern_token.as_deref() + && let Some(SyntaxElement::Node(p)) = pattern.next() + { + // We have a subtree that starts with the next token in our pattern. + self.attempt_match_token_tree(phase, &p, n)?; + break; } } }; @@ -562,23 +557,22 @@ impl<'db, 'sema> Matcher<'db, 'sema> { let deref_count = self.check_expr_type(pattern_type, expr)?; let pattern_receiver = pattern_args.next(); self.attempt_match_opt(phase, pattern_receiver.clone(), code.receiver())?; - if let Phase::Second(match_out) = phase { - if let Some(placeholder_value) = pattern_receiver + if let Phase::Second(match_out) = phase + && let Some(placeholder_value) = pattern_receiver .and_then(|n| self.get_placeholder_for_node(n.syntax())) .and_then(|placeholder| { match_out.placeholder_values.get_mut(&placeholder.ident) }) - { - placeholder_value.autoderef_count = deref_count; - placeholder_value.autoref_kind = self - .sema - .resolve_method_call_as_callable(code) - .and_then(|callable| { - let (self_param, _) = callable.receiver_param(self.sema.db)?; - Some(self.sema.source(self_param)?.value.kind()) - }) - .unwrap_or(ast::SelfParamKind::Owned); - } + { + placeholder_value.autoderef_count = deref_count; + placeholder_value.autoref_kind = self + .sema + .resolve_method_call_as_callable(code) + .and_then(|callable| { + let (self_param, _) = callable.receiver_param(self.sema.db)?; + Some(self.sema.source(self_param)?.value.kind()) + }) + .unwrap_or(ast::SelfParamKind::Owned); } } } else { @@ -698,12 +692,11 @@ impl Phase<'_> { } fn record_ignored_comments(&mut self, token: &SyntaxToken) { - if token.kind() == SyntaxKind::COMMENT { - if let Phase::Second(match_out) = self { - if let Some(comment) = ast::Comment::cast(token.clone()) { - match_out.ignored_comments.push(comment); - } - } + if token.kind() == SyntaxKind::COMMENT + && let Phase::Second(match_out) = self + && let Some(comment) = ast::Comment::cast(token.clone()) + { + match_out.ignored_comments.push(comment); } } } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs index 752edd6535a6..16287a439c35 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs @@ -112,12 +112,12 @@ impl<'db> ReplacementRenderer<'_, 'db> { self.out.push_str(&mod_path.display(self.db, self.edition).to_string()); // Emit everything except for the segment's name-ref, since we already effectively // emitted that as part of `mod_path`. - if let Some(path) = ast::Path::cast(node.clone()) { - if let Some(segment) = path.segment() { - for node_or_token in segment.syntax().children_with_tokens() { - if node_or_token.kind() != SyntaxKind::NAME_REF { - self.render_node_or_token(&node_or_token); - } + if let Some(path) = ast::Path::cast(node.clone()) + && let Some(segment) = path.segment() + { + for node_or_token in segment.syntax().children_with_tokens() { + if node_or_token.kind() != SyntaxKind::NAME_REF { + self.render_node_or_token(&node_or_token); } } } @@ -242,15 +242,15 @@ fn token_is_method_call_receiver(token: &SyntaxToken) -> bool { } fn parse_as_kind(code: &str, kind: SyntaxKind) -> Option { - if ast::Expr::can_cast(kind) { - if let Ok(expr) = fragments::expr(code) { - return Some(expr); - } + if ast::Expr::can_cast(kind) + && let Ok(expr) = fragments::expr(code) + { + return Some(expr); } - if ast::Item::can_cast(kind) { - if let Ok(item) = fragments::item(code) { - return Some(item); - } + if ast::Item::can_cast(kind) + && let Ok(item) = fragments::item(code) + { + return Some(item); } None } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs index 8f28a1cd3a62..a4e2cfbaee27 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs @@ -83,21 +83,17 @@ impl<'db> Resolver<'_, 'db> { let ufcs_function_calls = resolved_paths .iter() .filter_map(|(path_node, resolved)| { - if let Some(grandparent) = path_node.parent().and_then(|parent| parent.parent()) { - if let Some(call_expr) = ast::CallExpr::cast(grandparent.clone()) { - if let hir::PathResolution::Def(hir::ModuleDef::Function(function)) = - resolved.resolution - { - if function.as_assoc_item(self.resolution_scope.scope.db).is_some() { - let qualifier_type = - self.resolution_scope.qualifier_type(path_node); - return Some(( - grandparent, - UfcsCallInfo { call_expr, function, qualifier_type }, - )); - } - } - } + if let Some(grandparent) = path_node.parent().and_then(|parent| parent.parent()) + && let Some(call_expr) = ast::CallExpr::cast(grandparent.clone()) + && let hir::PathResolution::Def(hir::ModuleDef::Function(function)) = + resolved.resolution + && function.as_assoc_item(self.resolution_scope.scope.db).is_some() + { + let qualifier_type = self.resolution_scope.qualifier_type(path_node); + return Some(( + grandparent, + UfcsCallInfo { call_expr, function, qualifier_type }, + )); } None }) @@ -153,12 +149,11 @@ impl<'db> Resolver<'_, 'db> { /// Returns whether `path` contains a placeholder, but ignores any placeholders within type /// arguments. fn path_contains_placeholder(&self, path: &ast::Path) -> bool { - if let Some(segment) = path.segment() { - if let Some(name_ref) = segment.name_ref() { - if self.placeholders_by_stand_in.contains_key(name_ref.text().as_str()) { - return true; - } - } + if let Some(segment) = path.segment() + && let Some(name_ref) = segment.name_ref() + && self.placeholders_by_stand_in.contains_key(name_ref.text().as_str()) + { + return true; } if let Some(qualifier) = path.qualifier() { return self.path_contains_placeholder(&qualifier); @@ -252,14 +247,12 @@ impl<'db> ResolutionScope<'db> { fn qualifier_type(&self, path: &SyntaxNode) -> Option> { use syntax::ast::AstNode; - if let Some(path) = ast::Path::cast(path.clone()) { - if let Some(qualifier) = path.qualifier() { - if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) = - self.resolve_path(&qualifier) - { - return Some(adt.ty(self.scope.db)); - } - } + if let Some(path) = ast::Path::cast(path.clone()) + && let Some(qualifier) = path.qualifier() + && let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) = + self.resolve_path(&qualifier) + { + return Some(adt.ty(self.scope.db)); } None } @@ -299,11 +292,11 @@ fn pick_node_for_resolution(node: SyntaxNode) -> SyntaxNode { /// Returns whether `path` or any of its qualifiers contains type arguments. fn path_contains_type_arguments(path: Option) -> bool { if let Some(path) = path { - if let Some(segment) = path.segment() { - if segment.generic_arg_list().is_some() { - cov_mark::hit!(type_arguments_within_path); - return true; - } + if let Some(segment) = path.segment() + && segment.generic_arg_list().is_some() + { + cov_mark::hit!(type_arguments_within_path); + return true; } return path_contains_type_arguments(path.qualifier()); } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index 99a98fb2a713..72f857ceda90 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -187,16 +187,15 @@ impl<'db> MatchFinder<'db> { self.try_add_match(rule, code, restrict_range, matches_out); // If we've got a macro call, we already tried matching it pre-expansion, which is the only // way to match the whole macro, now try expanding it and matching the expansion. - if let Some(macro_call) = ast::MacroCall::cast(code.clone()) { - if let Some(expanded) = self.sema.expand_macro_call(¯o_call) { - if let Some(tt) = macro_call.token_tree() { - // When matching within a macro expansion, we only want to allow matches of - // nodes that originated entirely from within the token tree of the macro call. - // i.e. we don't want to match something that came from the macro itself. - if let Some(range) = self.sema.original_range_opt(tt.syntax()) { - self.slow_scan_node(&expanded.value, rule, &Some(range), matches_out); - } - } + if let Some(macro_call) = ast::MacroCall::cast(code.clone()) + && let Some(expanded) = self.sema.expand_macro_call(¯o_call) + && let Some(tt) = macro_call.token_tree() + { + // When matching within a macro expansion, we only want to allow matches of + // nodes that originated entirely from within the token tree of the macro call. + // i.e. we don't want to match something that came from the macro itself. + if let Some(range) = self.sema.original_range_opt(tt.syntax()) { + self.slow_scan_node(&expanded.value, rule, &Some(range), matches_out); } } for child in code.children() { @@ -241,10 +240,10 @@ impl<'db> MatchFinder<'db> { /// Returns whether we support matching within `node` and all of its ancestors. fn is_search_permitted_ancestors(node: &SyntaxNode) -> bool { - if let Some(parent) = node.parent() { - if !is_search_permitted_ancestors(&parent) { - return false; - } + if let Some(parent) = node.parent() + && !is_search_permitted_ancestors(&parent) + { + return false; } is_search_permitted(node) } diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs index 05196ac98c03..dec1889926da 100644 --- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs +++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs @@ -159,10 +159,10 @@ pub(crate) fn annotations( node.value.syntax().text_range(), Some(name), ); - if res.call_site.0.file_id == source_file_id { - if let Some(name_range) = res.call_site.1 { - return Some((res.call_site.0.range, Some(name_range))); - } + if res.call_site.0.file_id == source_file_id + && let Some(name_range) = res.call_site.1 + { + return Some((res.call_site.0.range, Some(name_range))); } }; // otherwise try upmapping the entire node out of attributes diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index f31886b96976..ad84eacfb3e8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -96,14 +96,14 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< let (name, expanded, kind) = loop { let node = anc.next()?; - if let Some(item) = ast::Item::cast(node.clone()) { - if let Some(def) = sema.resolve_attr_macro_call(&item) { - break ( - def.name(db).display(db, file_id.edition(db)).to_string(), - expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?, - SyntaxKind::MACRO_ITEMS, - ); - } + if let Some(item) = ast::Item::cast(node.clone()) + && let Some(def) = sema.resolve_attr_macro_call(&item) + { + break ( + def.name(db).display(db, file_id.edition(db)).to_string(), + expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?, + SyntaxKind::MACRO_ITEMS, + ); } if let Some(mac) = ast::MacroCall::cast(node) { let mut name = mac.path()?.segment()?.name_ref()?.to_string(); 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 a374f9752fcf..2926384c4078 100644 --- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs +++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs @@ -81,10 +81,10 @@ fn try_extend_selection( if token.text_range() != range { return Some(token.text_range()); } - if let Some(comment) = ast::Comment::cast(token.clone()) { - if let Some(range) = extend_comments(comment) { - return Some(range); - } + if let Some(comment) = ast::Comment::cast(token.clone()) + && let Some(range) = extend_comments(comment) + { + return Some(range); } token.parent()? } @@ -92,12 +92,11 @@ fn try_extend_selection( }; // if we are in single token_tree, we maybe live in macro or attr - if node.kind() == TOKEN_TREE { - if let Some(macro_call) = node.ancestors().find_map(ast::MacroCall::cast) { - if let Some(range) = extend_tokens_from_range(sema, macro_call, range) { - return Some(range); - } - } + if node.kind() == TOKEN_TREE + && let Some(macro_call) = node.ancestors().find_map(ast::MacroCall::cast) + && let Some(range) = extend_tokens_from_range(sema, macro_call, range) + { + return Some(range); } if node.text_range() != range { @@ -106,10 +105,10 @@ fn try_extend_selection( let node = shallowest_node(&node); - if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) { - if let Some(range) = extend_list_item(&node) { - return Some(range); - } + if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) + && let Some(range) = extend_list_item(&node) + { + return Some(range); } node.parent().map(|it| it.text_range()) @@ -221,19 +220,20 @@ fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextSize) -> TextRange let prefix = TextRange::new(ws.text_range().start(), offset) - ws.text_range().start(); let ws_suffix = &ws_text[suffix]; let ws_prefix = &ws_text[prefix]; - if ws_text.contains('\n') && !ws_suffix.contains('\n') { - if let Some(node) = ws.next_sibling_or_token() { - let start = match ws_prefix.rfind('\n') { - Some(idx) => ws.text_range().start() + TextSize::from((idx + 1) as u32), - None => node.text_range().start(), - }; - let end = if root.text().char_at(node.text_range().end()) == Some('\n') { - node.text_range().end() + TextSize::of('\n') - } else { - node.text_range().end() - }; - return TextRange::new(start, end); - } + if ws_text.contains('\n') + && !ws_suffix.contains('\n') + && let Some(node) = ws.next_sibling_or_token() + { + let start = match ws_prefix.rfind('\n') { + Some(idx) => ws.text_range().start() + TextSize::from((idx + 1) as u32), + None => node.text_range().start(), + }; + let end = if root.text().char_at(node.text_range().end()) == Some('\n') { + node.text_range().end() + TextSize::of('\n') + } else { + node.text_range().end() + }; + return TextRange::new(start, end); } ws.text_range() } diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs index 1901bcc797e7..ac64413effeb 100755 --- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs +++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs @@ -61,30 +61,29 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { }; if is_multiline { // for the func with multiline param list - if matches!(element.kind(), FN) { - if let NodeOrToken::Node(node) = &element { - if let Some(fn_node) = ast::Fn::cast(node.clone()) { - if !fn_node - .param_list() - .map(|param_list| param_list.syntax().text().contains_char('\n')) - .unwrap_or(false) - { - continue; - } + if matches!(element.kind(), FN) + && let NodeOrToken::Node(node) = &element + && let Some(fn_node) = ast::Fn::cast(node.clone()) + { + if !fn_node + .param_list() + .map(|param_list| param_list.syntax().text().contains_char('\n')) + .unwrap_or(false) + { + continue; + } - if fn_node.body().is_some() { - // Get the actual start of the function (excluding doc comments) - let fn_start = fn_node - .fn_token() - .map(|token| token.text_range().start()) - .unwrap_or(node.text_range().start()); - res.push(Fold { - range: TextRange::new(fn_start, node.text_range().end()), - kind: FoldKind::Function, - }); - continue; - } - } + if fn_node.body().is_some() { + // Get the actual start of the function (excluding doc comments) + let fn_start = fn_node + .fn_token() + .map(|token| token.text_range().start()) + .unwrap_or(node.text_range().start()); + res.push(Fold { + range: TextRange::new(fn_start, node.text_range().end()), + kind: FoldKind::Function, + }); + continue; } } res.push(Fold { range: element.text_range(), kind }); @@ -120,14 +119,13 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { match_ast! { match node { ast::Module(module) => { - if module.item_list().is_none() { - if let Some(range) = contiguous_range_for_item_group( + if module.item_list().is_none() + && let Some(range) = contiguous_range_for_item_group( module, &mut visited_nodes, ) { res.push(Fold { range, kind: FoldKind::Modules }) } - } }, ast::Use(use_) => { if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) { @@ -212,11 +210,11 @@ where for element in first.syntax().siblings_with_tokens(Direction::Next) { let node = match element { NodeOrToken::Token(token) => { - if let Some(ws) = ast::Whitespace::cast(token) { - if !ws.spans_multiple_lines() { - // Ignore whitespace without blank lines - continue; - } + if let Some(ws) = ast::Whitespace::cast(token) + && !ws.spans_multiple_lines() + { + // Ignore whitespace without blank lines + continue; } // There is a blank line or another token, which means that the // group ends here @@ -270,21 +268,21 @@ fn contiguous_range_for_comment( for element in first.syntax().siblings_with_tokens(Direction::Next) { match element { NodeOrToken::Token(token) => { - if let Some(ws) = ast::Whitespace::cast(token.clone()) { - if !ws.spans_multiple_lines() { - // Ignore whitespace without blank lines - continue; - } + if let Some(ws) = ast::Whitespace::cast(token.clone()) + && !ws.spans_multiple_lines() + { + // Ignore whitespace without blank lines + continue; } - if let Some(c) = ast::Comment::cast(token) { - if c.kind() == group_kind { - let text = c.text().trim_start(); - // regions are not real comments - if !(text.starts_with(REGION_START) || text.starts_with(REGION_END)) { - visited.insert(c.clone()); - last = c; - continue; - } + if let Some(c) = ast::Comment::cast(token) + && c.kind() == group_kind + { + let text = c.text().trim_start(); + // regions are not real comments + if !(text.starts_with(REGION_START) || text.starts_with(REGION_END)) { + visited.insert(c.clone()); + last = c; + continue; } } // The comment group ends because either: diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 29fc68bb50f1..84e41277390f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -94,18 +94,17 @@ pub(crate) fn goto_definition( let parent = token.value.parent()?; let token_file_id = token.file_id; - if let Some(token) = ast::String::cast(token.value.clone()) { - if let Some(x) = + if let Some(token) = ast::String::cast(token.value.clone()) + && let Some(x) = try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id) - { - return Some(vec![x]); - } + { + return Some(vec![x]); } - if ast::TokenTree::can_cast(parent.kind()) { - if let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value) { - return Some(vec![x]); - } + if ast::TokenTree::can_cast(parent.kind()) + && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value) + { + return Some(vec![x]); } Some( @@ -245,12 +244,11 @@ fn try_lookup_macro_def_in_macro_use( let krate = extern_crate.resolved_crate(sema.db)?; for mod_def in krate.root_module().declarations(sema.db) { - if let ModuleDef::Macro(mac) = mod_def { - if mac.name(sema.db).as_str() == token.text() { - if let Some(nav) = mac.try_to_nav(sema.db) { - return Some(nav.call_site); - } - } + if let ModuleDef::Macro(mac) = mod_def + && mac.name(sema.db).as_str() == token.text() + && let Some(nav) = mac.try_to_nav(sema.db) + { + return Some(nav.call_site); } } 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 356bd69aa44e..9960e79a5380 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -722,20 +722,19 @@ impl<'a> WalkExpandedExprCtx<'a> { self.depth += 1; } - if let ast::Expr::MacroExpr(expr) = expr { - if let Some(expanded) = + if let ast::Expr::MacroExpr(expr) = expr + && let Some(expanded) = expr.macro_call().and_then(|call| self.sema.expand_macro_call(&call)) - { - match_ast! { - match (expanded.value) { - ast::MacroStmts(it) => { - self.handle_expanded(it, cb); - }, - ast::Expr(it) => { - self.walk(&it, cb); - }, - _ => {} - } + { + match_ast! { + match (expanded.value) { + ast::MacroStmts(it) => { + self.handle_expanded(it, cb); + }, + ast::Expr(it) => { + self.walk(&it, cb); + }, + _ => {} } } } @@ -755,10 +754,10 @@ impl<'a> WalkExpandedExprCtx<'a> { } for stmt in expanded.statements() { - if let ast::Stmt::ExprStmt(stmt) = stmt { - if let Some(expr) = stmt.expr() { - self.walk(&expr, cb); - } + if let ast::Stmt::ExprStmt(stmt) = stmt + && let Some(expr) = stmt.expr() + { + self.walk(&expr, cb); } } } @@ -806,12 +805,12 @@ pub(crate) fn highlight_unsafe_points( push_to_highlights(unsafe_token_file_id, Some(unsafe_token.text_range())); // highlight unsafe operations - if let Some(block) = block_expr { - if let Some(body) = sema.body_for(InFile::new(unsafe_token_file_id, block.syntax())) { - let unsafe_ops = sema.get_unsafe_ops(body); - for unsafe_op in unsafe_ops { - push_to_highlights(unsafe_op.file_id, Some(unsafe_op.value.text_range())); - } + if let Some(block) = block_expr + && let Some(body) = sema.body_for(InFile::new(unsafe_token_file_id, block.syntax())) + { + let unsafe_ops = sema.get_unsafe_ops(body); + for unsafe_op in unsafe_ops { + push_to_highlights(unsafe_op.file_id, Some(unsafe_op.value.text_range())); } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index e4d6279759ed..44c98a43f694 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -244,17 +244,15 @@ fn hover_offset( let node = token.parent()?; // special case macro calls, we wanna render the invoked arm index - if let Some(name) = ast::NameRef::cast(node.clone()) { - if let Some(path_seg) = + if let Some(name) = ast::NameRef::cast(node.clone()) + && let Some(path_seg) = name.syntax().parent().and_then(ast::PathSegment::cast) - { - if let Some(macro_call) = path_seg + && let Some(macro_call) = path_seg .parent_path() .syntax() .parent() .and_then(ast::MacroCall::cast) - { - if let Some(macro_) = sema.resolve_macro_call(¯o_call) { + && let Some(macro_) = sema.resolve_macro_call(¯o_call) { break 'a vec![( (Definition::Macro(macro_), None), sema.resolve_macro_call_arm(¯o_call), @@ -262,9 +260,6 @@ fn hover_offset( node, )]; } - } - } - } match IdentClass::classify_node(sema, &node)? { // It's better for us to fall back to the keyword hover here, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 670210d4998d..51b5900e8155 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -95,23 +95,25 @@ pub(super) fn try_expr( if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts { let famous_defs = FamousDefs(sema, sema.scope(try_expr.syntax())?.krate()); // special case for two options, there is no value in showing them - if let Some(option_enum) = famous_defs.core_option_Option() { - if inner == option_enum && body == option_enum { - cov_mark::hit!(hover_try_expr_opt_opt); - return None; - } + if let Some(option_enum) = famous_defs.core_option_Option() + && inner == option_enum + && body == option_enum + { + cov_mark::hit!(hover_try_expr_opt_opt); + return None; } // special case two results to show the error variants only - if let Some(result_enum) = famous_defs.core_result_Result() { - if inner == result_enum && body == result_enum { - let error_type_args = - inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1)); - if let Some((inner, body)) = error_type_args { - inner_ty = inner; - body_ty = body; - "Try Error".clone_into(&mut s); - } + if let Some(result_enum) = famous_defs.core_result_Result() + && inner == result_enum + && body == result_enum + { + let error_type_args = + inner_ty.type_arguments().nth(1).zip(body_ty.type_arguments().nth(1)); + if let Some((inner, body)) = error_type_args { + inner_ty = inner; + body_ty = body; + "Try Error".clone_into(&mut s); } } } @@ -1132,10 +1134,10 @@ fn markup( ) -> (Markup, Option) { let mut buf = String::new(); - if let Some(mod_path) = mod_path { - if !mod_path.is_empty() { - format_to!(buf, "```rust\n{}\n```\n\n", mod_path); - } + if let Some(mod_path) = mod_path + && !mod_path.is_empty() + { + format_to!(buf, "```rust\n{}\n```\n\n", mod_path); } format_to!(buf, "```rust\n{}\n```", rust); @@ -1217,55 +1219,55 @@ fn render_memory_layout( format_to!(label, ", "); } - if let Some(render) = config.offset { - if let Some(offset) = offset(&layout) { - format_to!(label, "offset = "); - match render { - MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{offset}"), - MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{offset:#X}"), - MemoryLayoutHoverRenderKind::Both if offset >= 10 => { - format_to!(label, "{offset} ({offset:#X})") - } - MemoryLayoutHoverRenderKind::Both => { - format_to!(label, "{offset}") - } + if let Some(render) = config.offset + && let Some(offset) = offset(&layout) + { + format_to!(label, "offset = "); + match render { + MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{offset}"), + MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{offset:#X}"), + MemoryLayoutHoverRenderKind::Both if offset >= 10 => { + format_to!(label, "{offset} ({offset:#X})") + } + MemoryLayoutHoverRenderKind::Both => { + format_to!(label, "{offset}") } - format_to!(label, ", "); } + format_to!(label, ", "); } - if let Some(render) = config.padding { - if let Some((padding_name, padding)) = padding(&layout) { - format_to!(label, "{padding_name} = "); - match render { - MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{padding}"), - MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{padding:#X}"), - MemoryLayoutHoverRenderKind::Both if padding >= 10 => { - format_to!(label, "{padding} ({padding:#X})") - } - MemoryLayoutHoverRenderKind::Both => { - format_to!(label, "{padding}") - } + if let Some(render) = config.padding + && let Some((padding_name, padding)) = padding(&layout) + { + format_to!(label, "{padding_name} = "); + match render { + MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{padding}"), + MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{padding:#X}"), + MemoryLayoutHoverRenderKind::Both if padding >= 10 => { + format_to!(label, "{padding} ({padding:#X})") + } + MemoryLayoutHoverRenderKind::Both => { + format_to!(label, "{padding}") } - format_to!(label, ", "); } + format_to!(label, ", "); } - if config.niches { - if let Some(niches) = layout.niches() { - if niches > 1024 { - if niches.is_power_of_two() { - format_to!(label, "niches = 2{}, ", pwr2_to_exponent(niches)); - } else if is_pwr2plus1(niches) { - format_to!(label, "niches = 2{} + 1, ", pwr2_to_exponent(niches - 1)); - } else if is_pwr2minus1(niches) { - format_to!(label, "niches = 2{} - 1, ", pwr2_to_exponent(niches + 1)); - } else { - format_to!(label, "niches = a lot, "); - } + if config.niches + && let Some(niches) = layout.niches() + { + if niches > 1024 { + if niches.is_power_of_two() { + format_to!(label, "niches = 2{}, ", pwr2_to_exponent(niches)); + } else if is_pwr2plus1(niches) { + format_to!(label, "niches = 2{} + 1, ", pwr2_to_exponent(niches - 1)); + } else if is_pwr2minus1(niches) { + format_to!(label, "niches = 2{} - 1, ", pwr2_to_exponent(niches + 1)); } else { - format_to!(label, "niches = {niches}, "); + format_to!(label, "niches = a lot, "); } + } else { + format_to!(label, "niches = {niches}, "); } } label.pop(); // ' ' diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 671fddb43630..7a8514c47af9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -576,13 +576,13 @@ impl InlayHintLabel { } pub fn append_part(&mut self, part: InlayHintLabelPart) { - if part.linked_location.is_none() && part.tooltip.is_none() { - if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) = + if part.linked_location.is_none() + && part.tooltip.is_none() + && let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) = self.parts.last_mut() - { - text.push_str(&part.text); - return; - } + { + text.push_str(&part.text); + return; } self.parts.push(part); } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 49b43fc37f24..4d020bac3aad 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -39,10 +39,10 @@ pub(super) fn hints( if let ast::Expr::ParenExpr(_) = expr { return None; } - if let ast::Expr::BlockExpr(b) = expr { - if !b.is_standalone() { - return None; - } + if let ast::Expr::BlockExpr(b) = expr + && !b.is_standalone() + { + return None; } let descended = sema.descend_node_into_attributes(expr.clone()).pop(); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 729349365e6c..922e9598aa01 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -41,13 +41,11 @@ pub(super) fn hints( Some(it.colon_token()) }, ast::LetStmt(it) => { - if config.hide_closure_initialization_hints { - if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() { - if closure_has_block_body(&closure) { + if config.hide_closure_initialization_hints + && let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() + && closure_has_block_body(&closure) { return None; } - } - } if it.ty().is_some() { return None; } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index ff157fa171b5..a8bb652fda22 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -51,12 +51,11 @@ pub(super) fn hints( if ty.is_unknown() { return None; } - if matches!(expr, ast::Expr::PathExpr(_)) { - if let Some(hir::Adt::Struct(st)) = ty.as_adt() { - if st.fields(sema.db).is_empty() { - return None; - } - } + if matches!(expr, ast::Expr::PathExpr(_)) + && let Some(hir::Adt::Struct(st)) = ty.as_adt() + && st.fields(sema.db).is_empty() + { + return None; } let label = label_of_ty(famous_defs, config, &ty, display_target)?; acc.push(InlayHint { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index 05253b679489..e80c9dc9d473 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -120,11 +120,11 @@ pub(super) fn hints( }; if let Some(mut next) = closing_token.next_token() { - if next.kind() == T![;] { - if let Some(tok) = next.next_token() { - closing_token = next; - next = tok; - } + if next.kind() == T![;] + && let Some(tok) = next.next_token() + { + closing_token = next; + next = tok; } if !(next.kind() == SyntaxKind::WHITESPACE && next.text().contains('\n')) { // Only display the hint if the `}` is the last token on the line diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs index 9e600b5455be..fef1cb83c119 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs @@ -55,11 +55,9 @@ pub(super) fn hints( // Insert braces if necessary let insert_braces = |builder: &mut TextEditBuilder| { - if !has_block_body { - if let Some(range) = closure.body().map(|b| b.syntax().text_range()) { - builder.insert(range.start(), "{ ".to_owned()); - builder.insert(range.end(), " }".to_owned()); - } + if !has_block_body && let Some(range) = closure.body().map(|b| b.syntax().text_range()) { + builder.insert(range.start(), "{ ".to_owned()); + builder.insert(range.end(), " }".to_owned()); } }; diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs index 88152bf3e388..491018a4dda8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -81,10 +81,10 @@ fn item_hint( text_edit: Some(config.lazy_text_edit(|| { let mut builder = TextEdit::builder(); builder.insert(token.text_range().start(), "unsafe ".to_owned()); - if extern_block.unsafe_token().is_none() { - if let Some(abi) = extern_block.abi() { - builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned()); - } + if extern_block.unsafe_token().is_none() + && let Some(abi) = extern_block.abi() + { + builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned()); } builder.finish() })), diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs index 6e1b3bdbdf03..1fddb6fbe01d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs @@ -33,10 +33,10 @@ pub(crate) fn hints( let mut args = generic_arg_list.generic_args().peekable(); let start_with_lifetime = matches!(args.peek()?, ast::GenericArg::LifetimeArg(_)); let params = generic_def.params(sema.db).into_iter().filter(|p| { - if let hir::GenericParam::TypeParam(it) = p { - if it.is_implicit(sema.db) { - return false; - } + if let hir::GenericParam::TypeParam(it) = p + && it.is_implicit(sema.db) + { + return false; } if !start_with_lifetime { return !matches!(p, hir::GenericParam::LifetimeParam(_)); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs index 7212efd954e8..bddce904dfde 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs @@ -22,30 +22,31 @@ pub(super) fn hints( return None; } - if let Either::Right(it) = &statik_or_const { - if ast::AssocItemList::can_cast( + if let Either::Right(it) = &statik_or_const + && ast::AssocItemList::can_cast( it.syntax().parent().map_or(SyntaxKind::EOF, |it| it.kind()), - ) { - return None; - } + ) + { + return None; } - if let Some(ast::Type::RefType(ty)) = statik_or_const.either(|it| it.ty(), |it| it.ty()) { - if ty.lifetime().is_none() { - let t = ty.amp_token()?; - acc.push(InlayHint { - range: t.text_range(), - kind: InlayKind::Lifetime, - label: "'static".into(), - text_edit: Some(config.lazy_text_edit(|| { - TextEdit::insert(t.text_range().start(), "'static ".into()) - })), - position: InlayHintPosition::After, - pad_left: false, - pad_right: true, - resolve_parent: None, - }); - } + if let Some(ast::Type::RefType(ty)) = statik_or_const.either(|it| it.ty(), |it| it.ty()) + && ty.lifetime().is_none() + { + let t = ty.amp_token()?; + acc.push(InlayHint { + range: t.text_range(), + kind: InlayKind::Lifetime, + label: "'static".into(), + text_edit: Some( + config + .lazy_text_edit(|| TextEdit::insert(t.text_range().start(), "'static ".into())), + ), + position: InlayHintPosition::After, + pad_left: false, + pad_right: true, + resolve_parent: None, + }); } Some(()) diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs index 49fec0a793c3..a89c53e00b3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -324,35 +324,35 @@ fn hints_( // apply hints // apply output if required - if let (Some(output_lt), Some(r)) = (&output, ret_type) { - if let Some(ty) = r.ty() { - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(ty) if ty.lifetime().is_none() => { - if let Some(amp) = ty.amp_token() { - is_trivial = false; - acc.push(mk_lt_hint(amp, output_lt.to_string())); - } - false + if let (Some(output_lt), Some(r)) = (&output, ret_type) + && let Some(ty) = r.ty() + { + walk_ty(&ty, &mut |ty| match ty { + ast::Type::RefType(ty) if ty.lifetime().is_none() => { + if let Some(amp) = ty.amp_token() { + is_trivial = false; + acc.push(mk_lt_hint(amp, output_lt.to_string())); } - ast::Type::FnPtrType(_) => { + false + } + ast::Type::FnPtrType(_) => { + is_trivial = false; + true + } + ast::Type::PathType(t) => { + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() + { is_trivial = false; true + } else { + false } - ast::Type::PathType(t) => { - if t.path() - .and_then(|it| it.segment()) - .and_then(|it| it.parenthesized_arg_list()) - .is_some() - { - is_trivial = false; - true - } else { - false - } - } - _ => false, - }) - } + } + _ => false, + }) } if config.lifetime_elision_hints == LifetimeElisionHints::SkipTrivial && is_trivial { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index 5174228466c0..ec0a4c46c7fe 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -135,10 +135,10 @@ fn should_hide_param_name_hint( } if unary_function { - if let Some(function_name) = function_name { - if is_param_name_suffix_of_fn_name(param_name, function_name) { - return true; - } + if let Some(function_name) = function_name + && is_param_name_suffix_of_fn_name(param_name, function_name) + { + return true; } if is_obvious_param(param_name) { return true; diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs index 0188c105faa7..a946559c3545 100644 --- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs +++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs @@ -144,15 +144,15 @@ fn remove_newline( } } - if config.join_else_if { - if let (Some(prev), Some(_next)) = (as_if_expr(&prev), as_if_expr(&next)) { - match prev.else_token() { - Some(_) => cov_mark::hit!(join_two_ifs_with_existing_else), - None => { - cov_mark::hit!(join_two_ifs); - edit.replace(token.text_range(), " else ".to_owned()); - return; - } + if config.join_else_if + && let (Some(prev), Some(_next)) = (as_if_expr(&prev), as_if_expr(&next)) + { + match prev.else_token() { + Some(_) => cov_mark::hit!(join_two_ifs_with_existing_else), + None => { + cov_mark::hit!(join_two_ifs); + edit.replace(token.text_range(), " else ".to_owned()); + return; } } } @@ -213,10 +213,10 @@ fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Op let mut buf = expr.syntax().text().to_string(); // Match block needs to have a comma after the block - if let Some(match_arm) = block_expr.syntax().parent().and_then(ast::MatchArm::cast) { - if match_arm.comma_token().is_none() { - buf.push(','); - } + if let Some(match_arm) = block_expr.syntax().parent().and_then(ast::MatchArm::cast) + && match_arm.comma_token().is_none() + { + buf.push(','); } edit.replace(block_range, buf); diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs index 50219cee57db..96d829d1260b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs +++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs @@ -29,14 +29,13 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec(source_file.syntax(), position.offset); // If cursor is literally on `mod foo`, go to the grandpa. - if let Some(m) = &module { - if !m + if let Some(m) = &module + && !m .item_list() .is_some_and(|it| it.syntax().text_range().contains_inclusive(position.offset)) - { - cov_mark::hit!(test_resolve_parent_module_on_module_decl); - module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); - } + { + cov_mark::hit!(test_resolve_parent_module_on_module_decl); + module = m.syntax().ancestors().skip(1).find_map(ast::Module::cast); } match module { diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 6c1d142c3b05..634edaa5edaf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -494,10 +494,10 @@ mod tests { ) { let ra_fixture_after = &trim_indent(ra_fixture_after); let (analysis, position) = fixture::position(ra_fixture_before); - if !ra_fixture_after.starts_with("error: ") { - if let Err(err) = analysis.prepare_rename(position).unwrap() { - panic!("Prepare rename to '{new_name}' was failed: {err}") - } + if !ra_fixture_after.starts_with("error: ") + && let Err(err) = analysis.prepare_rename(position).unwrap() + { + panic!("Prepare rename to '{new_name}' was failed: {err}") } let rename_result = analysis .rename(position, new_name) diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 9d1a5bae96fb..83e5c5ab1dfe 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -514,20 +514,19 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { .flat_map(|it| it.name(db)) .for_each(|name| format_to!(path, "{}::", name.display(db, edition))); // This probably belongs to canonical_path? - if let Some(assoc_item) = def.as_assoc_item(db) { - if let Some(ty) = assoc_item.implementing_ty(db) { - if let Some(adt) = ty.as_adt() { - let name = adt.name(db); - let mut ty_args = ty.generic_parameters(db, display_target).peekable(); - format_to!(path, "{}", name.display(db, edition)); - if ty_args.peek().is_some() { - format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); - } - format_to!(path, "::{}", def_name.display(db, edition)); - path.retain(|c| c != ' '); - return Some(path); - } + if let Some(assoc_item) = def.as_assoc_item(db) + && let Some(ty) = assoc_item.implementing_ty(db) + && let Some(adt) = ty.as_adt() + { + let name = adt.name(db); + let mut ty_args = ty.generic_parameters(db, display_target).peekable(); + format_to!(path, "{}", name.display(db, edition)); + if ty_args.peek().is_some() { + format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); } + format_to!(path, "::{}", def_name.display(db, edition)); + path.retain(|c| c != ' '); + return Some(path); } format_to!(path, "{}", def_name.display(db, edition)); Some(path) @@ -697,14 +696,13 @@ impl UpdateTest { continue; }; for item in items { - if let hir::ItemInNs::Macros(makro) = item { - if Definition::Macro(makro) + if let hir::ItemInNs::Macros(makro) = item + && Definition::Macro(makro) .usages(sema) .in_scope(&search_scope) .at_least_one() - { - return true; - } + { + return true; } } } diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index e30a3ebefb98..382573b68011 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -146,12 +146,11 @@ pub(crate) fn signature_help( // Stop at multi-line expressions, since the signature of the outer call is not very // helpful inside them. - if let Some(expr) = ast::Expr::cast(node.clone()) { - if !matches!(expr, ast::Expr::RecordExpr(..)) - && expr.syntax().text().contains_char('\n') - { - break; - } + if let Some(expr) = ast::Expr::cast(node.clone()) + && !matches!(expr, ast::Expr::RecordExpr(..)) + && expr.syntax().text().contains_char('\n') + { + break; } } @@ -366,10 +365,10 @@ fn signature_help_for_generics( res.signature.push('<'); let mut buf = String::new(); for param in params { - if let hir::GenericParam::TypeParam(ty) = param { - if ty.is_implicit(db) { - continue; - } + if let hir::GenericParam::TypeParam(ty) = param + && ty.is_implicit(db) + { + continue; } buf.clear(); diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index efee39c13db9..694ac22e1993 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -133,10 +133,10 @@ fn get_definitions( ) -> Option> { for token in sema.descend_into_macros_exact(token) { let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); - if let Some(defs) = def { - if !defs.is_empty() { - return Some(defs); - } + if let Some(defs) = def + && !defs.is_empty() + { + return Some(defs); } } None diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 87db0cd7dc53..8bde8fd97006 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -306,12 +306,12 @@ fn highlight_name_ref( }; let mut h = match name_class { NameRefClass::Definition(def, _) => { - if let Definition::Local(local) = &def { - if let Some(bindings_shadow_count) = bindings_shadow_count { - let name = local.name(sema.db); - let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); - *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) - } + if let Definition::Local(local) = &def + && let Some(bindings_shadow_count) = bindings_shadow_count + { + let name = local.name(sema.db); + let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); + *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) }; let mut h = highlight_def(sema, krate, def, edition, true); @@ -437,21 +437,21 @@ fn highlight_name( edition: Edition, ) -> Highlight { let name_kind = NameClass::classify(sema, &name); - if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind { - if let Some(bindings_shadow_count) = bindings_shadow_count { - let name = local.name(sema.db); - let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); - *shadow_count += 1; - *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) - } + if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind + && let Some(bindings_shadow_count) = bindings_shadow_count + { + let name = local.name(sema.db); + let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); + *shadow_count += 1; + *binding_hash = Some(calc_binding_hash(&name, *shadow_count)) }; match name_kind { Some(NameClass::Definition(def)) => { let mut h = highlight_def(sema, krate, def, edition, false) | HlMod::Definition; - if let Definition::Trait(trait_) = &def { - if trait_.is_unsafe(sema.db) { - h |= HlMod::Unsafe; - } + if let Definition::Trait(trait_) = &def + && trait_.is_unsafe(sema.db) + { + h |= HlMod::Unsafe; } h } @@ -743,10 +743,9 @@ fn highlight_method_call( hir::Access::Owned => { if let Some(receiver_ty) = method_call.receiver().and_then(|it| sema.type_of_expr(&it)) + && !receiver_ty.adjusted().is_copy(sema.db) { - if !receiver_ty.adjusted().is_copy(sema.db) { - h |= HlMod::Consuming - } + h |= HlMod::Consuming } } } diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 98f415a522cb..ad838a6550ec 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -475,10 +475,10 @@ fn load_crate_graph_into_db( } let changes = vfs.take_changes(); for (_, file) in changes { - if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change { - if let Ok(text) = String::from_utf8(v) { - analysis_change.change_file(file.file_id, Some(text)) - } + if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change + && let Ok(text) = String::from_utf8(v) + { + analysis_change.change_file(file.file_id, Some(text)) } } let source_roots = source_root_config.partition(vfs); diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 04ac85ad43dd..b185556b5c7b 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -185,24 +185,22 @@ fn invocation_fixtures( for it in tokens.iter() { collect_from_op(it, builder, seed); } - if i + 1 != cnt { - if let Some(sep) = separator { - match &**sep { - Separator::Literal(it) => { - builder.push(tt::Leaf::Literal(it.clone())) + if i + 1 != cnt + && let Some(sep) = separator + { + match &**sep { + Separator::Literal(it) => builder.push(tt::Leaf::Literal(it.clone())), + Separator::Ident(it) => builder.push(tt::Leaf::Ident(it.clone())), + Separator::Puncts(puncts) => { + for it in puncts { + builder.push(tt::Leaf::Punct(*it)) } - Separator::Ident(it) => builder.push(tt::Leaf::Ident(it.clone())), - Separator::Puncts(puncts) => { - for it in puncts { - builder.push(tt::Leaf::Punct(*it)) - } - } - Separator::Lifetime(punct, ident) => { - builder.push(tt::Leaf::Punct(*punct)); - builder.push(tt::Leaf::Ident(ident.clone())); - } - }; - } + } + Separator::Lifetime(punct, ident) => { + builder.push(tt::Leaf::Punct(*punct)); + builder.push(tt::Leaf::Ident(ident.clone())); + } + }; } } } diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs index a8d5965d480c..189efcd15c2f 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs @@ -475,12 +475,12 @@ fn match_loop_inner<'t>( }) } OpDelimited::Op(Op::Subtree { tokens, delimiter }) => { - if let Ok((subtree, _)) = src.clone().expect_subtree() { - if subtree.delimiter.kind == delimiter.kind { - item.stack.push(item.dot); - item.dot = tokens.iter_delimited_with(*delimiter); - cur_items.push(item); - } + if let Ok((subtree, _)) = src.clone().expect_subtree() + && subtree.delimiter.kind == delimiter.kind + { + item.stack.push(item.dot); + item.dot = tokens.iter_delimited_with(*delimiter); + cur_items.push(item); } } OpDelimited::Op(Op::Var { kind, name, .. }) => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 2b4151e3b752..41fd72d8d5a2 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -77,38 +77,38 @@ pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) { return; } - if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) { - if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) { - // test no_semi_after_block - // fn foo() { - // if true {} - // loop {} - // match () {} - // while true {} - // for _ in () {} - // {} - // {} - // macro_rules! test { - // () => {} - // } - // test!{} - // } - let m = cm.precede(p); - match semicolon { - Semicolon::Required => { - if blocklike.is_block() { - p.eat(T![;]); - } else { - p.expect(T![;]); - } - } - Semicolon::Optional => { + if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) + && !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) + { + // test no_semi_after_block + // fn foo() { + // if true {} + // loop {} + // match () {} + // while true {} + // for _ in () {} + // {} + // {} + // macro_rules! test { + // () => {} + // } + // test!{} + // } + let m = cm.precede(p); + match semicolon { + Semicolon::Required => { + if blocklike.is_block() { p.eat(T![;]); + } else { + p.expect(T![;]); } - Semicolon::Forbidden => (), } - m.complete(p, EXPR_STMT); + Semicolon::Optional => { + p.eat(T![;]); + } + Semicolon::Forbidden => (), } + m.complete(p, EXPR_STMT); } } @@ -134,14 +134,11 @@ pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) { if p.at(T![else]) { // test_err let_else_right_curly_brace // fn func() { let Some(_) = {Some(1)} else { panic!("h") };} - if let Some(expr) = expr_after_eq { - if let Some(token) = expr.last_token(p) { - if token == T!['}'] { - p.error( - "right curly brace `}` before `else` in a `let...else` statement not allowed" - ) - } - } + if let Some(expr) = expr_after_eq + && let Some(token) = expr.last_token(p) + && token == T!['}'] + { + p.error("right curly brace `}` before `else` in a `let...else` statement not allowed") } // test let_else diff --git a/src/tools/rust-analyzer/crates/parser/src/input.rs b/src/tools/rust-analyzer/crates/parser/src/input.rs index 4490956f9704..331bc58dd052 100644 --- a/src/tools/rust-analyzer/crates/parser/src/input.rs +++ b/src/tools/rust-analyzer/crates/parser/src/input.rs @@ -61,7 +61,7 @@ impl Input { #[inline] fn push_impl(&mut self, kind: SyntaxKind, contextual_kind: SyntaxKind) { let idx = self.len(); - if idx % (bits::BITS as usize) == 0 { + if idx.is_multiple_of(bits::BITS as usize) { self.joint.push(0); } self.kind.push(kind); diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs index e2baec890c3a..d5e513933f7a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs +++ b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs @@ -252,10 +252,10 @@ fn n_attached_trivias<'a>( WHITESPACE if text.contains("\n\n") => { // we check whether the next token is a doc-comment // and skip the whitespace in this case - if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) { - if is_outer(peek_text) { - continue; - } + if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) + && is_outer(peek_text) + { + continue; } break; } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs index ec4b6b2a4ac3..277cc0b269d7 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs @@ -278,15 +278,15 @@ pub(crate) fn query_group_impl( return Err(syn::Error::new(signature.span(), "Queries must have a return type")); }; - if let syn::Type::Path(ref ty_path) = *return_ty { - if matches!(query_kind, QueryKind::Input) { - let field = InputStructField { - name: method_name.to_token_stream(), - ty: ty_path.path.to_token_stream(), - }; + if let syn::Type::Path(ref ty_path) = *return_ty + && matches!(query_kind, QueryKind::Input) + { + let field = InputStructField { + name: method_name.to_token_stream(), + ty: ty_path.path.to_token_stream(), + }; - input_struct_fields.push(field); - } + input_struct_fields.push(field); } if let Some(block) = &mut method.default { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index 4dba97c8ec49..ab045e0bf9ff 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -122,12 +122,12 @@ fn setup_logging(log_file_flag: Option) -> anyhow::Result<()> { // directory which we set to the project workspace. // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/general-environment-variables // https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize - if let Ok(path) = env::current_exe() { - if let Some(path) = path.parent() { - // SAFETY: This is safe because this is single-threaded. - unsafe { - env::set_var("_NT_SYMBOL_PATH", path); - } + if let Ok(path) = env::current_exe() + && let Some(path) = path.parent() + { + // SAFETY: This is safe because this is single-threaded. + unsafe { + env::set_var("_NT_SYMBOL_PATH", path); } } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 4f75d14834c6..97886844a9f9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -136,34 +136,30 @@ impl flags::AnalysisStats { for source_root_id in source_roots { let source_root = db.source_root(source_root_id).source_root(db); for file_id in source_root.iter() { - if let Some(p) = source_root.path_for_file(&file_id) { - if let Some((_, Some("rs"))) = p.name_and_extension() { - // measure workspace/project code - if !source_root.is_library || self.with_deps { - let length = db.file_text(file_id).text(db).lines().count(); - let item_stats = db - .file_item_tree( - EditionedFileId::current_edition(db, file_id).into(), - ) - .item_tree_stats() - .into(); + if let Some(p) = source_root.path_for_file(&file_id) + && let Some((_, Some("rs"))) = p.name_and_extension() + { + // measure workspace/project code + if !source_root.is_library || self.with_deps { + let length = db.file_text(file_id).text(db).lines().count(); + let item_stats = db + .file_item_tree(EditionedFileId::current_edition(db, file_id).into()) + .item_tree_stats() + .into(); - workspace_loc += length; - workspace_item_trees += 1; - workspace_item_stats += item_stats; - } else { - let length = db.file_text(file_id).text(db).lines().count(); - let item_stats = db - .file_item_tree( - EditionedFileId::current_edition(db, file_id).into(), - ) - .item_tree_stats() - .into(); + workspace_loc += length; + workspace_item_trees += 1; + workspace_item_stats += item_stats; + } else { + let length = db.file_text(file_id).text(db).lines().count(); + let item_stats = db + .file_item_tree(EditionedFileId::current_edition(db, file_id).into()) + .item_tree_stats() + .into(); - dep_loc += length; - dep_item_trees += 1; - dep_item_stats += item_stats; - } + dep_loc += length; + dep_item_trees += 1; + dep_item_stats += item_stats; } } } @@ -560,29 +556,35 @@ impl flags::AnalysisStats { std::fs::write(path, txt).unwrap(); let res = ws.run_build_scripts(&cargo_config, &|_| ()).unwrap(); - if let Some(err) = res.error() { - if err.contains("error: could not compile") { - if let Some(mut err_idx) = err.find("error[E") { - err_idx += 7; - let err_code = &err[err_idx..err_idx + 4]; - match err_code { - "0282" | "0283" => continue, // Byproduct of testing method - "0277" | "0308" if generated.contains(&todo) => continue, // See https://github.com/rust-lang/rust/issues/69882 - // FIXME: In some rare cases `AssocItem::container_or_implemented_trait` returns `None` for trait methods. - // Generated code is valid in case traits are imported - "0599" if err.contains("the following trait is implemented but not in scope") => continue, - _ => (), + if let Some(err) = res.error() + && err.contains("error: could not compile") + { + if let Some(mut err_idx) = err.find("error[E") { + err_idx += 7; + let err_code = &err[err_idx..err_idx + 4]; + match err_code { + "0282" | "0283" => continue, // Byproduct of testing method + "0277" | "0308" if generated.contains(&todo) => continue, // See https://github.com/rust-lang/rust/issues/69882 + // FIXME: In some rare cases `AssocItem::container_or_implemented_trait` returns `None` for trait methods. + // Generated code is valid in case traits are imported + "0599" + if err.contains( + "the following trait is implemented but not in scope", + ) => + { + continue; } - bar.println(err); - bar.println(generated); - acc.error_codes - .entry(err_code.to_owned()) - .and_modify(|n| *n += 1) - .or_insert(1); - } else { - acc.syntax_errors += 1; - bar.println(format!("Syntax error: \n{err}")); + _ => (), } + bar.println(err); + bar.println(generated); + acc.error_codes + .entry(err_code.to_owned()) + .and_modify(|n| *n += 1) + .or_insert(1); + } else { + acc.syntax_errors += 1; + bar.println(format!("Syntax error: \n{err}")); } } } @@ -731,12 +733,11 @@ impl flags::AnalysisStats { let name = body_id.name(db).unwrap_or_else(Name::missing); let module = body_id.module(db); let display_target = module.krate().to_display_target(db); - if let Some(only_name) = self.only.as_deref() { - if name.display(db, Edition::LATEST).to_string() != only_name - && full_name(db, body_id, module) != only_name - { - continue; - } + if let Some(only_name) = self.only.as_deref() + && name.display(db, Edition::LATEST).to_string() != only_name + && full_name(db, body_id, module) != only_name + { + continue; } let msg = move || { if verbosity.is_verbose() { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs index 1b9b870a7c74..028311388c56 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs @@ -83,11 +83,11 @@ impl<'a> ProgressReport<'a> { output.extend(text.chars().skip(common_prefix_length)); // If the new text is shorter than the old one: delete overlapping characters - if let Some(overlap_count) = self.text.len().checked_sub(text.len()) { - if overlap_count > 0 { - output += &" ".repeat(overlap_count); - output += &"\x08".repeat(overlap_count); - } + if let Some(overlap_count) = self.text.len().checked_sub(text.len()) + && overlap_count > 0 + { + output += &" ".repeat(overlap_count); + output += &"\x08".repeat(overlap_count); } let _ = io::stdout().write(output.as_bytes()); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 30ac93fb6f83..36ae98b321b8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -305,10 +305,10 @@ impl flags::RustcTests { for i in walk_dir { let i = i?; let p = i.into_path(); - if let Some(f) = &self.filter { - if !p.as_os_str().to_string_lossy().contains(f) { - continue; - } + if let Some(f) = &self.filter + && !p.as_os_str().to_string_lossy().contains(f) + { + continue; } if p.extension().is_none_or(|x| x != "rs") { continue; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index a8bcce196c4e..70d04485ca08 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -3904,17 +3904,16 @@ mod tests { for idx in url_offsets { let link = &schema[idx..]; // matching on whitespace to ignore normal links - if let Some(link_end) = link.find([' ', '[']) { - if link.chars().nth(link_end) == Some('[') { - if let Some(link_text_end) = link.find(']') { - let link_text = link[link_end..(link_text_end + 1)].to_string(); + if let Some(link_end) = link.find([' ', '[']) + && link.chars().nth(link_end) == Some('[') + && let Some(link_text_end) = link.find(']') + { + let link_text = link[link_end..(link_text_end + 1)].to_string(); - schema.replace_range((idx + link_end)..(idx + link_text_end + 1), ""); - schema.insert(idx, '('); - schema.insert(idx + link_end + 1, ')'); - schema.insert_str(idx, &link_text); - } - } + schema.replace_range((idx + link_end)..(idx + link_text_end + 1), ""); + schema.insert(idx, '('); + schema.insert(idx + link_end + 1, ')'); + schema.insert_str(idx, &link_text); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs index 95857dd8f3b4..389bb7848c01 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs @@ -73,19 +73,19 @@ pub(super) fn patch_json_for_outdated_configs(json: &mut Value) { } // completion.snippets -> completion.snippets.custom; - if let Some(Value::Object(obj)) = copy.pointer("/completion/snippets").cloned() { - if obj.len() != 1 || obj.get("custom").is_none() { - merge( - json, - json! {{ - "completion": { - "snippets": { - "custom": obj - }, + if let Some(Value::Object(obj)) = copy.pointer("/completion/snippets").cloned() + && (obj.len() != 1 || obj.get("custom").is_none()) + { + merge( + json, + json! {{ + "completion": { + "snippets": { + "custom": obj }, - }}, - ); - } + }, + }}, + ); } // callInfo_full -> signatureInfo_detail, signatureInfo_documentation_enable diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs index 79d8f678de4d..3f64628de860 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -298,10 +298,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp( let mut source = String::from("rustc"); let mut code = rd.code.as_ref().map(|c| c.code.clone()); - if let Some(code_val) = &code { - if config.check_ignore.contains(code_val) { - return Vec::new(); - } + if let Some(code_val) = &code + && config.check_ignore.contains(code_val) + { + return Vec::new(); } if let Some(code_val) = &code { @@ -373,10 +373,8 @@ pub(crate) fn map_rust_diagnostic_to_lsp( let primary_location = primary_location(config, workspace_root, primary_span, snap); let message = { let mut message = message.clone(); - if needs_primary_span_label { - if let Some(primary_span_label) = &primary_span.label { - format_to!(message, "\n{}", primary_span_label); - } + if needs_primary_span_label && let Some(primary_span_label) = &primary_span.label { + format_to!(message, "\n{}", primary_span_label); } message }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 512ce0b9de35..e4e0bcdc1cd0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -492,12 +492,11 @@ impl FlycheckActor { FlycheckConfig::CargoCommand { command, options, ansi_color_output } => { let mut cmd = toolchain::command(Tool::Cargo.path(), &*self.root, &options.extra_env); - if let Some(sysroot_root) = &self.sysroot_root { - if !options.extra_env.contains_key("RUSTUP_TOOLCHAIN") - && std::env::var_os("RUSTUP_TOOLCHAIN").is_none() - { - cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); - } + if let Some(sysroot_root) = &self.sysroot_root + && !options.extra_env.contains_key("RUSTUP_TOOLCHAIN") + && std::env::var_os("RUSTUP_TOOLCHAIN").is_none() + { + cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); } cmd.arg(command); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 62a28a1a685d..3171bdd36178 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -591,10 +591,10 @@ impl GlobalState { pub(crate) fn respond(&mut self, response: lsp_server::Response) { if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) { - if let Some(err) = &response.error { - if err.message.starts_with("server panicked") { - self.poke_rust_analyzer_developer(format!("{}, check the log", err.message)); - } + if let Some(err) = &response.error + && err.message.starts_with("server panicked") + { + self.poke_rust_analyzer_developer(format!("{}, check the log", err.message)); } let duration = start.elapsed(); @@ -663,18 +663,18 @@ impl GlobalState { pub(crate) fn check_workspaces_msrv(&self) -> impl Iterator + '_ { self.workspaces.iter().filter_map(|ws| { - if let Some(toolchain) = &ws.toolchain { - if *toolchain < crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION { - return Some(format!( - "Workspace `{}` is using an outdated toolchain version `{}` but \ + if let Some(toolchain) = &ws.toolchain + && *toolchain < crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION + { + return Some(format!( + "Workspace `{}` is using an outdated toolchain version `{}` but \ rust-analyzer only supports `{}` and higher.\n\ Consider using the rust-analyzer rustup component for your toolchain or upgrade your toolchain to a supported version.\n\n", - ws.manifest_or_root(), - toolchain, - crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION, - )); - } + ws.manifest_or_root(), + toolchain, + crate::MINIMUM_SUPPORTED_TOOLCHAIN_VERSION, + )); } None }) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index aea116e647db..b25245dd884a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -433,10 +433,10 @@ impl NotificationDispatcher<'_> { } pub(crate) fn finish(&mut self) { - if let Some(not) = &self.not { - if !not.method.starts_with("$/") { - tracing::error!("unhandled notification: {:?}", not); - } + if let Some(not) = &self.not + && !not.method.starts_with("$/") + { + tracing::error!("unhandled notification: {:?}", not); } } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 200e972e4289..e193ff77743d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -39,14 +39,12 @@ pub(crate) fn handle_work_done_progress_cancel( state: &mut GlobalState, params: WorkDoneProgressCancelParams, ) -> anyhow::Result<()> { - if let lsp_types::NumberOrString::String(s) = ¶ms.token { - if let Some(id) = s.strip_prefix("rust-analyzer/flycheck/") { - if let Ok(id) = id.parse::() { - if let Some(flycheck) = state.flycheck.get(id as usize) { - flycheck.cancel(); - } - } - } + if let lsp_types::NumberOrString::String(s) = ¶ms.token + && let Some(id) = s.strip_prefix("rust-analyzer/flycheck/") + && let Ok(id) = id.parse::() + && let Some(flycheck) = state.flycheck.get(id as usize) + { + flycheck.cancel(); } // Just ignore this. It is OK to continue sending progress @@ -76,12 +74,12 @@ pub(crate) fn handle_did_open_text_document( tracing::error!("duplicate DidOpenTextDocument: {}", path); } - if let Some(abs_path) = path.as_path() { - if state.config.excluded().any(|excluded| abs_path.starts_with(&excluded)) { - tracing::trace!("opened excluded file {abs_path}"); - state.vfs.write().0.insert_excluded_file(path); - return Ok(()); - } + if let Some(abs_path) = path.as_path() + && state.config.excluded().any(|excluded| abs_path.starts_with(&excluded)) + { + tracing::trace!("opened excluded file {abs_path}"); + state.vfs.write().0.insert_excluded_file(path); + return Ok(()); } let contents = params.text_document.text.into_bytes(); @@ -449,12 +447,11 @@ pub(crate) fn handle_run_flycheck( params: RunFlycheckParams, ) -> anyhow::Result<()> { let _p = tracing::info_span!("handle_run_flycheck").entered(); - if let Some(text_document) = params.text_document { - if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) { - if run_flycheck(state, vfs_path) { - return Ok(()); - } - } + if let Some(text_document) = params.text_document + && let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) + && run_flycheck(state, vfs_path) + { + return Ok(()); } // No specific flycheck was triggered, so let's trigger all of them. if state.config.flycheck_workspace(None) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index a76a65220d3b..25c0aac405e7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -973,14 +973,13 @@ pub(crate) fn handle_runnables( res.push(runnable); } - if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args { - if let Some(TargetSpec::Cargo(CargoTargetSpec { + if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args + && let Some(TargetSpec::Cargo(CargoTargetSpec { sysroot_root: Some(sysroot_root), .. })) = &target_spec - { - r.environment.insert("RUSTC_TOOLCHAIN".to_owned(), sysroot_root.to_string()); - } + { + r.environment.insert("RUSTC_TOOLCHAIN".to_owned(), sysroot_root.to_string()); }; res.push(runnable); @@ -1034,25 +1033,25 @@ pub(crate) fn handle_runnables( } Some(TargetSpec::ProjectJson(_)) => {} None => { - if !snap.config.linked_or_discovered_projects().is_empty() { - if let Some(path) = snap.file_id_to_file_path(file_id).parent() { - let mut cargo_args = vec!["check".to_owned(), "--workspace".to_owned()]; - cargo_args.extend(config.cargo_extra_args.iter().cloned()); - res.push(lsp_ext::Runnable { - label: "cargo check --workspace".to_owned(), - location: None, - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { - workspace_root: None, - cwd: path.as_path().unwrap().to_path_buf().into(), - override_cargo: config.override_cargo, - cargo_args, - executable_args: Vec::new(), - environment: Default::default(), - }), - }); - }; - } + if !snap.config.linked_or_discovered_projects().is_empty() + && let Some(path) = snap.file_id_to_file_path(file_id).parent() + { + let mut cargo_args = vec!["check".to_owned(), "--workspace".to_owned()]; + cargo_args.extend(config.cargo_extra_args.iter().cloned()); + res.push(lsp_ext::Runnable { + label: "cargo check --workspace".to_owned(), + location: None, + kind: lsp_ext::RunnableKind::Cargo, + args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { + workspace_root: None, + cwd: path.as_path().unwrap().to_path_buf().into(), + override_cargo: config.override_cargo, + cargo_args, + executable_args: Vec::new(), + environment: Default::default(), + }), + }); + }; } } Ok(res) @@ -1557,12 +1556,12 @@ pub(crate) fn handle_code_action_resolve( code_action.edit = ca.edit; code_action.command = ca.command; - if let Some(edit) = code_action.edit.as_ref() { - if let Some(changes) = edit.document_changes.as_ref() { - for change in changes { - if let lsp_ext::SnippetDocumentChangeOperation::Op(res_op) = change { - resource_ops_supported(&snap.config, resolve_resource_op(res_op))? - } + if let Some(edit) = code_action.edit.as_ref() + && let Some(changes) = edit.document_changes.as_ref() + { + for change in changes { + if let lsp_ext::SnippetDocumentChangeOperation::Op(res_op) = change { + resource_ops_supported(&snap.config, resolve_resource_op(res_op))? } } } @@ -1958,12 +1957,11 @@ pub(crate) fn handle_semantic_tokens_full_delta( if let Some(cached_tokens @ lsp_types::SemanticTokens { result_id: Some(prev_id), .. }) = &cached_tokens + && *prev_id == params.previous_result_id { - if *prev_id == params.previous_result_id { - let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens); - snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens); - return Ok(Some(delta.into())); - } + let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens); + snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens); + return Ok(Some(delta.into())); } // Clone first to keep the lock short @@ -2122,24 +2120,25 @@ fn show_impl_command_link( snap: &GlobalStateSnapshot, position: &FilePosition, ) -> Option { - if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference { - if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { - let uri = to_proto::url(snap, position.file_id); - let line_index = snap.file_line_index(position.file_id).ok()?; - let position = to_proto::position(&line_index, position.offset); - let locations: Vec<_> = nav_data - .info - .into_iter() - .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok()) - .collect(); - let title = to_proto::implementation_title(locations.len()); - let command = to_proto::command::show_references(title, &uri, position, locations); + if snap.config.hover_actions().implementations + && snap.config.client_commands().show_reference + && let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) + { + let uri = to_proto::url(snap, position.file_id); + let line_index = snap.file_line_index(position.file_id).ok()?; + let position = to_proto::position(&line_index, position.offset); + let locations: Vec<_> = nav_data + .info + .into_iter() + .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok()) + .collect(); + let title = to_proto::implementation_title(locations.len()); + let command = to_proto::command::show_references(title, &uri, position, locations); - return Some(lsp_ext::CommandLinkGroup { - commands: vec![to_command_link(command, "Go to implementations".into())], - ..Default::default() - }); - } + return Some(lsp_ext::CommandLinkGroup { + commands: vec![to_command_link(command, "Go to implementations".into())], + ..Default::default() + }); } None } @@ -2148,28 +2147,29 @@ fn show_ref_command_link( snap: &GlobalStateSnapshot, position: &FilePosition, ) -> Option { - if snap.config.hover_actions().references && snap.config.client_commands().show_reference { - if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { - let uri = to_proto::url(snap, position.file_id); - let line_index = snap.file_line_index(position.file_id).ok()?; - let position = to_proto::position(&line_index, position.offset); - let locations: Vec<_> = ref_search_res - .into_iter() - .flat_map(|res| res.references) - .flat_map(|(file_id, ranges)| { - ranges.into_iter().map(move |(range, _)| FileRange { file_id, range }) - }) - .unique() - .filter_map(|range| to_proto::location(snap, range).ok()) - .collect(); - let title = to_proto::reference_title(locations.len()); - let command = to_proto::command::show_references(title, &uri, position, locations); + if snap.config.hover_actions().references + && snap.config.client_commands().show_reference + && let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) + { + let uri = to_proto::url(snap, position.file_id); + let line_index = snap.file_line_index(position.file_id).ok()?; + let position = to_proto::position(&line_index, position.offset); + let locations: Vec<_> = ref_search_res + .into_iter() + .flat_map(|res| res.references) + .flat_map(|(file_id, ranges)| { + ranges.into_iter().map(move |(range, _)| FileRange { file_id, range }) + }) + .unique() + .filter_map(|range| to_proto::location(snap, range).ok()) + .collect(); + let title = to_proto::reference_title(locations.len()); + let command = to_proto::command::show_references(title, &uri, position, locations); - return Some(lsp_ext::CommandLinkGroup { - commands: vec![to_command_link(command, "Go to references".into())], - ..Default::default() - }); - } + return Some(lsp_ext::CommandLinkGroup { + commands: vec![to_command_link(command, "Go to references".into())], + ..Default::default() + }); } None } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 00cf890510d4..61c758d5e86e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -501,14 +501,12 @@ impl GlobalState { } } - if self.config.cargo_autoreload_config(None) - || self.config.discover_workspace_config().is_some() - { - if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) = + if (self.config.cargo_autoreload_config(None) + || self.config.discover_workspace_config().is_some()) + && let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) = self.fetch_workspaces_queue.should_start_op() - { - self.fetch_workspaces(cause, path, force_crate_graph_reload); - } + { + self.fetch_workspaces(cause, path, force_crate_graph_reload); } if !self.fetch_workspaces_queue.op_in_progress() { @@ -765,33 +763,33 @@ impl GlobalState { self.report_progress("Fetching", state, msg, None, None); } Task::DiscoverLinkedProjects(arg) => { - if let Some(cfg) = self.config.discover_workspace_config() { - if !self.discover_workspace_queue.op_in_progress() { - // the clone is unfortunately necessary to avoid a borrowck error when - // `self.report_progress` is called later - let title = &cfg.progress_label.clone(); - let command = cfg.command.clone(); - let discover = DiscoverCommand::new(self.discover_sender.clone(), command); + if let Some(cfg) = self.config.discover_workspace_config() + && !self.discover_workspace_queue.op_in_progress() + { + // the clone is unfortunately necessary to avoid a borrowck error when + // `self.report_progress` is called later + let title = &cfg.progress_label.clone(); + let command = cfg.command.clone(); + let discover = DiscoverCommand::new(self.discover_sender.clone(), command); - self.report_progress(title, Progress::Begin, None, None, None); - self.discover_workspace_queue - .request_op("Discovering workspace".to_owned(), ()); - let _ = self.discover_workspace_queue.should_start_op(); + self.report_progress(title, Progress::Begin, None, None, None); + self.discover_workspace_queue + .request_op("Discovering workspace".to_owned(), ()); + let _ = self.discover_workspace_queue.should_start_op(); - let arg = match arg { - DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it), - DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it), - }; + let arg = match arg { + DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it), + DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it), + }; - let handle = discover.spawn( - arg, - &std::env::current_dir() - .expect("Failed to get cwd during project discovery"), - ); - self.discover_handle = Some(handle.unwrap_or_else(|e| { - panic!("Failed to spawn project discovery command: {e}") - })); - } + let handle = discover.spawn( + arg, + &std::env::current_dir() + .expect("Failed to get cwd during project discovery"), + ); + self.discover_handle = Some(handle.unwrap_or_else(|e| { + panic!("Failed to spawn project discovery command: {e}") + })); } } Task::FetchBuildData(progress) => { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index e798aa6a8a60..aa38aa72d44e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -306,13 +306,13 @@ impl GlobalState { _ => None, }); - if let Some(build) = build { - if is_quiescent { - let path = AbsPathBuf::try_from(build.build_file) - .expect("Unable to convert to an AbsPath"); - let arg = DiscoverProjectParam::Buildfile(path); - sender.send(Task::DiscoverLinkedProjects(arg)).unwrap(); - } + if let Some(build) = build + && is_quiescent + { + let path = AbsPathBuf::try_from(build.build_file) + .expect("Unable to convert to an AbsPath"); + let arg = DiscoverProjectParam::Buildfile(path); + sender.send(Task::DiscoverLinkedProjects(arg)).unwrap(); } } diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs index f58201793da2..bb09933536e7 100644 --- a/src/tools/rust-analyzer/crates/span/src/map.rs +++ b/src/tools/rust-analyzer/crates/span/src/map.rs @@ -41,13 +41,13 @@ where /// Pushes a new span onto the [`SpanMap`]. pub fn push(&mut self, offset: TextSize, span: SpanData) { - if cfg!(debug_assertions) { - if let Some(&(last_offset, _)) = self.spans.last() { - assert!( - last_offset < offset, - "last_offset({last_offset:?}) must be smaller than offset({offset:?})" - ); - } + if cfg!(debug_assertions) + && let Some(&(last_offset, _)) = self.spans.last() + { + assert!( + last_offset < offset, + "last_offset({last_offset:?}) must be smaller than offset({offset:?})" + ); } self.spans.push((offset, span)); } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index d59229952f52..bdff671802c2 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -768,17 +768,17 @@ where } fn bump(&mut self) -> Option<(Self::Token, TextRange)> { - if let Some((punct, offset)) = self.punct_offset.clone() { - if usize::from(offset) + 1 < punct.text().len() { - let offset = offset + TextSize::of('.'); - let range = punct.text_range(); - self.punct_offset = Some((punct.clone(), offset)); - let range = TextRange::at(range.start() + offset, TextSize::of('.')); - return Some(( - SynToken::Punct { token: punct, offset: u32::from(offset) as usize }, - range, - )); - } + if let Some((punct, offset)) = self.punct_offset.clone() + && usize::from(offset) + 1 < punct.text().len() + { + let offset = offset + TextSize::of('.'); + let range = punct.text_range(); + self.punct_offset = Some((punct.clone(), offset)); + let range = TextRange::at(range.start() + offset, TextSize::of('.')); + return Some(( + SynToken::Punct { token: punct, offset: u32::from(offset) as usize }, + range, + )); } if let Some(leaf) = self.current_leaves.pop() { diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs index 0a5c8df0d0ae..2f932e045832 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/prettify_macro_expansion.rs @@ -61,10 +61,11 @@ pub fn prettify_macro_expansion( } _ => continue, }; - if token.kind() == SyntaxKind::IDENT && token.text() == "$crate" { - if let Some(replacement) = dollar_crate_replacement(&token) { - dollar_crate_replacements.push((token.clone(), replacement)); - } + if token.kind() == SyntaxKind::IDENT + && token.text() == "$crate" + && let Some(replacement) = dollar_crate_replacement(&token) + { + dollar_crate_replacements.push((token.clone(), replacement)); } let tok = &token; diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs index 8871bf56a5df..c8dc3131b59c 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs @@ -34,14 +34,11 @@ fn check_punct_spacing(fixture: &str) { while !cursor.eof() { while let Some(token_tree) = cursor.token_tree() { if let tt::TokenTree::Leaf(Leaf::Punct(Punct { - spacing, - span: Span { range, .. }, - .. + spacing, span: Span { range, .. }, .. })) = token_tree + && let Some(expected) = annotations.remove(range) { - if let Some(expected) = annotations.remove(range) { - assert_eq!(expected, *spacing); - } + assert_eq!(expected, *spacing); } cursor.bump(); } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs index 021dc6595f9b..c0ff8e1db2c2 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs @@ -21,17 +21,17 @@ pub fn to_parser_input( let tt = current.token_tree(); // Check if it is lifetime - if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tt { - if punct.char == '\'' { - current.bump(); - match current.token_tree() { - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(_ident))) => { - res.push(LIFETIME_IDENT); - current.bump(); - continue; - } - _ => panic!("Next token must be ident"), + if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tt + && punct.char == '\'' + { + current.bump(); + match current.token_tree() { + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(_ident))) => { + res.push(LIFETIME_IDENT); + current.bump(); + continue; } + _ => panic!("Next token must be ident"), } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index d97fdec524fb..9b30642fe4b0 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -89,11 +89,11 @@ impl IndentLevel { _ => None, }); for token in tokens { - if let Some(ws) = ast::Whitespace::cast(token) { - if ws.text().contains('\n') { - let new_ws = make::tokens::whitespace(&format!("{}{self}", ws.syntax())); - ted::replace(ws.syntax(), &new_ws); - } + if let Some(ws) = ast::Whitespace::cast(token) + && ws.text().contains('\n') + { + let new_ws = make::tokens::whitespace(&format!("{}{self}", ws.syntax())); + ted::replace(ws.syntax(), &new_ws); } } } @@ -122,13 +122,13 @@ impl IndentLevel { _ => None, }); for token in tokens { - if let Some(ws) = ast::Whitespace::cast(token) { - if ws.text().contains('\n') { - let new_ws = make::tokens::whitespace( - &ws.syntax().text().replace(&format!("\n{self}"), "\n"), - ); - ted::replace(ws.syntax(), &new_ws); - } + if let Some(ws) = ast::Whitespace::cast(token) + && ws.text().contains('\n') + { + let new_ws = make::tokens::whitespace( + &ws.syntax().text().replace(&format!("\n{self}"), "\n"), + ); + ted::replace(ws.syntax(), &new_ws); } } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 28b543ea7064..f01ac081c8bd 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -383,10 +383,10 @@ impl ast::GenericParamList { impl ast::WhereClause { pub fn add_predicate(&self, predicate: ast::WherePred) { - if let Some(pred) = self.predicates().last() { - if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) { - ted::append_child_raw(self.syntax(), make::token(T![,])); - } + if let Some(pred) = self.predicates().last() + && !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) + { + ted::append_child_raw(self.syntax(), make::token(T![,])); } ted::append_child(self.syntax(), predicate.syntax()); } @@ -744,10 +744,10 @@ impl ast::LetStmt { } if let Some(existing_ty) = self.ty() { - if let Some(sibling) = existing_ty.syntax().prev_sibling_or_token() { - if sibling.kind() == SyntaxKind::WHITESPACE { - ted::remove(sibling); - } + if let Some(sibling) = existing_ty.syntax().prev_sibling_or_token() + && sibling.kind() == SyntaxKind::WHITESPACE + { + ted::remove(sibling); } ted::remove(existing_ty.syntax()); @@ -823,19 +823,18 @@ impl ast::RecordExprField { return; } // this is a shorthand - if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() { - if let Some(path) = path_expr.path() { - if let Some(name_ref) = path.as_single_name_ref() { - path_expr.syntax().detach(); - let children = vec![ - name_ref.syntax().clone().into(), - ast::make::token(T![:]).into(), - ast::make::tokens::single_space().into(), - expr.syntax().clone().into(), - ]; - ted::insert_all_raw(Position::last_child_of(self.syntax()), children); - } - } + if let Some(ast::Expr::PathExpr(path_expr)) = self.expr() + && let Some(path) = path_expr.path() + && let Some(name_ref) = path.as_single_name_ref() + { + path_expr.syntax().detach(); + let children = vec![ + name_ref.syntax().clone().into(), + ast::make::token(T![:]).into(), + ast::make::tokens::single_space().into(), + expr.syntax().clone().into(), + ]; + ted::insert_all_raw(Position::last_child_of(self.syntax()), children); } } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 00750bff0ba2..1364adb187fc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -276,19 +276,19 @@ impl Expr { } // Not every expression can be followed by `else` in the `let-else` - if let Some(ast::Stmt::LetStmt(e)) = stmt { - if e.let_else().is_some() { - match self { - BinExpr(e) - if e.op_kind() - .map(|op| matches!(op, BinaryOp::LogicOp(_))) - .unwrap_or(false) => - { - return true; - } - _ if self.clone().trailing_brace().is_some() => return true, - _ => {} + if let Some(ast::Stmt::LetStmt(e)) = stmt + && e.let_else().is_some() + { + match self { + BinExpr(e) + if e.op_kind() + .map(|op| matches!(op, BinaryOp::LogicOp(_))) + .unwrap_or(false) => + { + return true; } + _ if self.clone().trailing_brace().is_some() => return true, + _ => {} } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 5107754b1825..124ac5c072c9 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -626,10 +626,10 @@ mod tests { if let Some(ret_ty) = parent_fn.ret_type() { editor.delete(ret_ty.syntax().clone()); - if let Some(SyntaxElement::Token(token)) = ret_ty.syntax().next_sibling_or_token() { - if token.kind().is_trivia() { - editor.delete(token); - } + if let Some(SyntaxElement::Token(token)) = ret_ty.syntax().next_sibling_or_token() + && token.kind().is_trivia() + { + editor.delete(token); } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ted.rs b/src/tools/rust-analyzer/crates/syntax/src/ted.rs index 6fcbdd006c24..5c286479c4e3 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ted.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ted.rs @@ -90,15 +90,15 @@ pub fn insert_raw(position: Position, elem: impl Element) { insert_all_raw(position, vec![elem.syntax_element()]); } pub fn insert_all(position: Position, mut elements: Vec) { - if let Some(first) = elements.first() { - if let Some(ws) = ws_before(&position, first) { - elements.insert(0, ws.into()); - } + if let Some(first) = elements.first() + && let Some(ws) = ws_before(&position, first) + { + elements.insert(0, ws.into()); } - if let Some(last) = elements.last() { - if let Some(ws) = ws_after(&position, last) { - elements.push(ws.into()); - } + if let Some(last) = elements.last() + && let Some(ws) = ws_after(&position, last) + { + elements.push(ws.into()); } insert_all_raw(position, elements); } @@ -165,20 +165,22 @@ fn ws_before(position: &Position, new: &SyntaxElement) -> Option { PositionRepr::After(it) => it, }; - if prev.kind() == T!['{'] && new.kind() == SyntaxKind::USE { - if let Some(item_list) = prev.parent().and_then(ast::ItemList::cast) { - let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into()); - indent.0 += 1; - return Some(make::tokens::whitespace(&format!("\n{indent}"))); - } + if prev.kind() == T!['{'] + && new.kind() == SyntaxKind::USE + && let Some(item_list) = prev.parent().and_then(ast::ItemList::cast) + { + let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into()); + indent.0 += 1; + return Some(make::tokens::whitespace(&format!("\n{indent}"))); } - if prev.kind() == T!['{'] && ast::Stmt::can_cast(new.kind()) { - if let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast) { - let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into()); - indent.0 += 1; - return Some(make::tokens::whitespace(&format!("\n{indent}"))); - } + if prev.kind() == T!['{'] + && ast::Stmt::can_cast(new.kind()) + && let Some(stmt_list) = prev.parent().and_then(ast::StmtList::cast) + { + let mut indent = IndentLevel::from_element(&stmt_list.syntax().clone().into()); + indent.0 += 1; + return Some(make::tokens::whitespace(&format!("\n{indent}"))); } ws_between(prev, new) diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 4180f9cd1855..485140be8f69 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -142,50 +142,50 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { match literal.kind() { ast::LiteralKind::String(s) => { - if !s.is_raw() { - if let Some(without_quotes) = unquote(text, 1, '"') { - unescape_str(without_quotes, |range, char| { - if let Err(err) = char { - push_err(1, range.start, err); - } - }); - } + if !s.is_raw() + && let Some(without_quotes) = unquote(text, 1, '"') + { + unescape_str(without_quotes, |range, char| { + if let Err(err) = char { + push_err(1, range.start, err); + } + }); } } ast::LiteralKind::ByteString(s) => { - if !s.is_raw() { - if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_byte_str(without_quotes, |range, char| { - if let Err(err) = char { - push_err(1, range.start, err); - } - }); - } + if !s.is_raw() + && let Some(without_quotes) = unquote(text, 2, '"') + { + unescape_byte_str(without_quotes, |range, char| { + if let Err(err) = char { + push_err(1, range.start, err); + } + }); } } ast::LiteralKind::CString(s) => { - if !s.is_raw() { - if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_c_str(without_quotes, |range, char| { - if let Err(err) = char { - push_err(1, range.start, err); - } - }); - } + if !s.is_raw() + && let Some(without_quotes) = unquote(text, 2, '"') + { + unescape_c_str(without_quotes, |range, char| { + if let Err(err) = char { + push_err(1, range.start, err); + } + }); } } ast::LiteralKind::Char(_) => { - if let Some(without_quotes) = unquote(text, 1, '\'') { - if let Err(err) = unescape_char(without_quotes) { - push_err(1, 0, err); - } + if let Some(without_quotes) = unquote(text, 1, '\'') + && let Err(err) = unescape_char(without_quotes) + { + push_err(1, 0, err); } } ast::LiteralKind::Byte(_) => { - if let Some(without_quotes) = unquote(text, 2, '\'') { - if let Err(err) = unescape_byte(without_quotes) { - push_err(2, 0, err); - } + if let Some(without_quotes) = unquote(text, 2, '\'') + && let Err(err) = unescape_byte(without_quotes) + { + push_err(2, 0, err); } } ast::LiteralKind::IntNumber(_) @@ -224,14 +224,14 @@ pub(crate) fn validate_block_structure(root: &SyntaxNode) { } fn validate_numeric_name(name_ref: Option, errors: &mut Vec) { - if let Some(int_token) = int_token(name_ref) { - if int_token.text().chars().any(|c| !c.is_ascii_digit()) { - errors.push(SyntaxError::new( - "Tuple (struct) field access is only allowed through \ + if let Some(int_token) = int_token(name_ref) + && int_token.text().chars().any(|c| !c.is_ascii_digit()) + { + errors.push(SyntaxError::new( + "Tuple (struct) field access is only allowed through \ decimal integers with no underscores or suffix", - int_token.text_range(), - )); - } + int_token.text_range(), + )); } fn int_token(name_ref: Option) -> Option { @@ -285,13 +285,13 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec Option { diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 8937e53175ab..4413d2f222c1 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -955,12 +955,12 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander { _: String, ) -> Result { for tt in subtree.token_trees().flat_tokens() { - if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt { - if ident.sym == sym::cfg || ident.sym == sym::cfg_attr { - return Err(ProcMacroExpansionError::Panic( - "cfg or cfg_attr found in DisallowCfgProcMacroExpander".to_owned(), - )); - } + if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt + && (ident.sym == sym::cfg || ident.sym == sym::cfg_attr) + { + return Err(ProcMacroExpansionError::Panic( + "cfg or cfg_attr found in DisallowCfgProcMacroExpander".to_owned(), + )); } } Ok(subtree.clone()) diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 44123385c8cc..243a27b83b0d 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -357,10 +357,10 @@ impl<'a, S: Copy> TokenTreesView<'a, S> { } pub fn try_into_subtree(self) -> Option> { - if let Some(TokenTree::Subtree(subtree)) = self.0.first() { - if subtree.usize_len() == (self.0.len() - 1) { - return Some(SubtreeView::new(self.0)); - } + if let Some(TokenTree::Subtree(subtree)) = self.0.first() + && subtree.usize_len() == (self.0.len() - 1) + { + return Some(SubtreeView::new(self.0)); } None } @@ -1028,10 +1028,10 @@ pub fn pretty(mut tkns: &[TokenTree]) -> String { tkns = rest; last = [last, tokentree_to_text(tkn, &mut tkns)].join(if last_to_joint { "" } else { " " }); last_to_joint = false; - if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn { - if punct.spacing == Spacing::Joint { - last_to_joint = true; - } + if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn + && punct.spacing == Spacing::Joint + { + last_to_joint = true; } } last diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index a03337dbc51e..c6393cc6922a 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -194,52 +194,49 @@ impl NotifyActor { } }, Event::NotifyEvent(event) => { - if let Some(event) = log_notify_error(event) { - if let EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) = + if let Some(event) = log_notify_error(event) + && let EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) = event.kind - { - let files = event - .paths - .into_iter() - .filter_map(|path| { - Some( - AbsPathBuf::try_from( - Utf8PathBuf::from_path_buf(path).ok()?, - ) + { + let files = event + .paths + .into_iter() + .filter_map(|path| { + Some( + AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).ok()?) .expect("path is absolute"), - ) - }) - .filter_map(|path| -> Option<(AbsPathBuf, Option>)> { - let meta = fs::metadata(&path).ok()?; - if meta.file_type().is_dir() - && self - .watched_dir_entries - .iter() - .any(|dir| dir.contains_dir(&path)) - { - self.watch(path.as_ref()); - return None; - } + ) + }) + .filter_map(|path| -> Option<(AbsPathBuf, Option>)> { + let meta = fs::metadata(&path).ok()?; + if meta.file_type().is_dir() + && self + .watched_dir_entries + .iter() + .any(|dir| dir.contains_dir(&path)) + { + self.watch(path.as_ref()); + return None; + } - if !meta.file_type().is_file() { - return None; - } + if !meta.file_type().is_file() { + return None; + } - if !(self.watched_file_entries.contains(&path) - || self - .watched_dir_entries - .iter() - .any(|dir| dir.contains_file(&path))) - { - return None; - } + if !(self.watched_file_entries.contains(&path) + || self + .watched_dir_entries + .iter() + .any(|dir| dir.contains_file(&path))) + { + return None; + } - let contents = read(&path); - Some((path, contents)) - }) - .collect(); - self.send(loader::Message::Changed { files }); - } + let contents = read(&path); + Some((path, contents)) + }) + .collect(); + self.send(loader::Message::Changed { files }); } } } diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs index 19ca62e8a329..bc7eb88f3a84 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen.rs @@ -173,11 +173,11 @@ fn add_preamble(cg: CodegenType, mut text: String) -> String { #[allow(clippy::print_stderr)] fn ensure_file_contents(cg: CodegenType, file: &Path, contents: &str, check: bool) -> bool { let contents = normalize_newlines(contents); - if let Ok(old_contents) = fs::read_to_string(file) { - if normalize_newlines(&old_contents) == contents { - // File is already up to date. - return false; - } + if let Ok(old_contents) = fs::read_to_string(file) + && normalize_newlines(&old_contents) == contents + { + // File is already up to date. + return false; } let display_path = file.strip_prefix(project_root()).unwrap_or(file); diff --git a/src/tools/rust-analyzer/xtask/src/publish/notes.rs b/src/tools/rust-analyzer/xtask/src/publish/notes.rs index 93592d4986f8..8d36fcb61b44 100644 --- a/src/tools/rust-analyzer/xtask/src/publish/notes.rs +++ b/src/tools/rust-analyzer/xtask/src/publish/notes.rs @@ -72,13 +72,13 @@ impl<'a, 'b, R: BufRead> Converter<'a, 'b, R> { } fn process_document_title(&mut self) -> anyhow::Result<()> { - if let Some(Ok(line)) = self.iter.next() { - if let Some((level, title)) = get_title(&line) { - let title = process_inline_macros(title)?; - if level == 1 { - self.write_title(level, &title); - return Ok(()); - } + if let Some(Ok(line)) = self.iter.next() + && let Some((level, title)) = get_title(&line) + { + let title = process_inline_macros(title)?; + if level == 1 { + self.write_title(level, &title); + return Ok(()); } } bail!("document title not found") @@ -141,39 +141,39 @@ impl<'a, 'b, R: BufRead> Converter<'a, 'b, R> { } fn process_source_code_block(&mut self, level: usize) -> anyhow::Result<()> { - if let Some(Ok(line)) = self.iter.next() { - if let Some(styles) = line.strip_prefix("[source").and_then(|s| s.strip_suffix(']')) { - let mut styles = styles.split(','); - if !styles.next().unwrap().is_empty() { - bail!("not a source code block"); - } - let language = styles.next(); - return self.process_listing_block(language, level); + if let Some(Ok(line)) = self.iter.next() + && let Some(styles) = line.strip_prefix("[source").and_then(|s| s.strip_suffix(']')) + { + let mut styles = styles.split(','); + if !styles.next().unwrap().is_empty() { + bail!("not a source code block"); } + let language = styles.next(); + return self.process_listing_block(language, level); } bail!("not a source code block") } fn process_listing_block(&mut self, style: Option<&str>, level: usize) -> anyhow::Result<()> { - if let Some(Ok(line)) = self.iter.next() { - if line == LISTING_DELIMITER { - self.write_indent(level); - self.output.push_str("```"); - if let Some(style) = style { - self.output.push_str(style); - } - self.output.push('\n'); - while let Some(line) = self.iter.next() { - let line = line?; - if line == LISTING_DELIMITER { - self.write_line("```", level); - return Ok(()); - } else { - self.write_line(&line, level); - } - } - bail!("listing block is not terminated") + if let Some(Ok(line)) = self.iter.next() + && line == LISTING_DELIMITER + { + self.write_indent(level); + self.output.push_str("```"); + if let Some(style) = style { + self.output.push_str(style); } + self.output.push('\n'); + while let Some(line) = self.iter.next() { + let line = line?; + if line == LISTING_DELIMITER { + self.write_line("```", level); + return Ok(()); + } else { + self.write_line(&line, level); + } + } + bail!("listing block is not terminated") } bail!("not a listing block") } @@ -200,49 +200,48 @@ impl<'a, 'b, R: BufRead> Converter<'a, 'b, R> { } fn process_image_block(&mut self, caption: Option<&str>, level: usize) -> anyhow::Result<()> { - if let Some(Ok(line)) = self.iter.next() { - if let Some((url, attrs)) = parse_media_block(&line, IMAGE_BLOCK_PREFIX) { - let alt = if let Some(stripped) = - attrs.strip_prefix('"').and_then(|s| s.strip_suffix('"')) - { + if let Some(Ok(line)) = self.iter.next() + && let Some((url, attrs)) = parse_media_block(&line, IMAGE_BLOCK_PREFIX) + { + let alt = + if let Some(stripped) = attrs.strip_prefix('"').and_then(|s| s.strip_suffix('"')) { stripped } else { attrs }; - if let Some(caption) = caption { - self.write_caption_line(caption, level); - } - self.write_indent(level); - self.output.push_str("!["); - self.output.push_str(alt); - self.output.push_str("]("); - self.output.push_str(url); - self.output.push_str(")\n"); - return Ok(()); + if let Some(caption) = caption { + self.write_caption_line(caption, level); } + self.write_indent(level); + self.output.push_str("!["); + self.output.push_str(alt); + self.output.push_str("]("); + self.output.push_str(url); + self.output.push_str(")\n"); + return Ok(()); } bail!("not a image block") } fn process_video_block(&mut self, caption: Option<&str>, level: usize) -> anyhow::Result<()> { - if let Some(Ok(line)) = self.iter.next() { - if let Some((url, attrs)) = parse_media_block(&line, VIDEO_BLOCK_PREFIX) { - let html_attrs = match attrs { - "options=loop" => "controls loop", - r#"options="autoplay,loop""# => "autoplay controls loop", - _ => bail!("unsupported video syntax"), - }; - if let Some(caption) = caption { - self.write_caption_line(caption, level); - } - self.write_indent(level); - self.output.push_str(r#"\n"); - return Ok(()); + if let Some(Ok(line)) = self.iter.next() + && let Some((url, attrs)) = parse_media_block(&line, VIDEO_BLOCK_PREFIX) + { + let html_attrs = match attrs { + "options=loop" => "controls loop", + r#"options="autoplay,loop""# => "autoplay controls loop", + _ => bail!("unsupported video syntax"), + }; + if let Some(caption) = caption { + self.write_caption_line(caption, level); } + self.write_indent(level); + self.output.push_str(r#"\n"); + return Ok(()); } bail!("not a video block") } @@ -371,12 +370,11 @@ fn strip_prefix_symbol(line: &str, symbol: char) -> Option<(usize, &str)> { } fn parse_media_block<'a>(line: &'a str, prefix: &str) -> Option<(&'a str, &'a str)> { - if let Some(line) = line.strip_prefix(prefix) { - if let Some((url, rest)) = line.split_once('[') { - if let Some(attrs) = rest.strip_suffix(']') { - return Some((url, attrs)); - } - } + if let Some(line) = line.strip_prefix(prefix) + && let Some((url, rest)) = line.split_once('[') + && let Some(attrs) = rest.strip_suffix(']') + { + return Some((url, attrs)); } None } From 94cc5bb9620cdee942b8b79e7026f622fcc695a0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Jul 2025 14:29:28 +1000 Subject: [PATCH 111/242] Streamline const folding/visiting. Type folders can only modify a few "types of interest": `Binder`, `Ty`, `Predicate`, `Clauses`, `Region`, `Const`. Likewise for type visitors, but they can also visit errors (via `ErrorGuaranteed`). Currently the impls of `try_super_fold_with`, `super_fold_with`, and `super_visit_with` do more than they need to -- they fold/visit values that cannot contain any types of interest. This commit removes those unnecessary fold/visit operations, which makes these impls more similar to the impls for `Ty`. It also removes the now-unnecessary derived impls for the no-longer-visited types. --- .../rustc_middle/src/ty/structural_impls.rs | 46 ++++++++----------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a5fdce93e4b2..10e499d9c758 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -232,6 +232,7 @@ TrivialLiftImpls! { crate::mir::Promoted, crate::mir::interpret::AllocId, crate::mir::interpret::Scalar, + crate::ty::ParamConst, rustc_abi::ExternAbi, rustc_abi::Size, rustc_hir::Safety, @@ -271,10 +272,6 @@ TrivialTypeTraversalImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::BoundRegion, - crate::ty::BoundVar, - crate::ty::InferConst, - crate::ty::Placeholder, - crate::ty::Placeholder, crate::ty::UserTypeAnnotationIndex, crate::ty::ValTree<'tcx>, crate::ty::abstract_const::NotConstEvaluatable, @@ -302,9 +299,8 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start - crate::ty::ParamConst, crate::ty::ParamTy, - crate::ty::Placeholder, + crate::ty::PlaceholderType, crate::ty::instance::ReifyReason, rustc_hir::def_id::DefId, // tidy-alphabetical-end @@ -673,30 +669,30 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { folder: &mut F, ) -> Result { let kind = match self.kind() { - ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), - ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), - ConstKind::Bound(d, b) => { - ConstKind::Bound(d.try_fold_with(folder)?, b.try_fold_with(folder)?) - } - ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), - ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => return Ok(self), }; if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) } } fn super_fold_with>>(self, folder: &mut F) -> Self { let kind = match self.kind() { - ConstKind::Param(p) => ConstKind::Param(p.fold_with(folder)), - ConstKind::Infer(i) => ConstKind::Infer(i.fold_with(folder)), - ConstKind::Bound(d, b) => ConstKind::Bound(d.fold_with(folder), b.fold_with(folder)), - ConstKind::Placeholder(p) => ConstKind::Placeholder(p.fold_with(folder)), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)), ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)), - ConstKind::Error(e) => ConstKind::Error(e.fold_with(folder)), ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) + | ConstKind::Error(_) => return self, }; if kind != self.kind() { folder.cx().mk_ct_from_kind(kind) } else { self } } @@ -705,17 +701,15 @@ impl<'tcx> TypeSuperFoldable> for ty::Const<'tcx> { impl<'tcx> TypeSuperVisitable> for ty::Const<'tcx> { fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { match self.kind() { - ConstKind::Param(p) => p.visit_with(visitor), - ConstKind::Infer(i) => i.visit_with(visitor), - ConstKind::Bound(d, b) => { - try_visit!(d.visit_with(visitor)); - b.visit_with(visitor) - } - ConstKind::Placeholder(p) => p.visit_with(visitor), ConstKind::Unevaluated(uv) => uv.visit_with(visitor), ConstKind::Value(v) => v.visit_with(visitor), - ConstKind::Error(e) => e.visit_with(visitor), ConstKind::Expr(e) => e.visit_with(visitor), + ConstKind::Error(e) => e.visit_with(visitor), + + ConstKind::Param(_) + | ConstKind::Infer(_) + | ConstKind::Bound(..) + | ConstKind::Placeholder(_) => V::Result::output(), } } } From 507dec4dc321c868ad876c0b7302c66088b7cc7c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Jul 2025 14:21:00 +1000 Subject: [PATCH 112/242] Make const bound handling more like types/regions. Currently there is `Ty` and `BoundTy`, and `Region` and `BoundRegion`, and `Const` and... `BoundVar`. An annoying inconsistency. This commit repurposes the existing `BoundConst`, which was barely used, so it's the partner to `Const`. Unlike `BoundTy`/`BoundRegion` it lacks a `kind` field but it's still nice to have because it makes the const code more similar to the ty/region code everywhere. The commit also removes `impl From for BoundTy`, which has a single use and doesn't seem worth it. These changes fix the "FIXME: We really should have a separate `BoundConst` for consts". --- .../src/type_check/relate_tys.rs | 4 ++-- .../src/check/compare_impl_item.rs | 2 +- .../src/collect/item_bounds.rs | 10 ++++---- .../src/hir_ty_lowering/bounds.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 8 ++++--- .../src/infer/canonical/canonicalizer.rs | 6 +++-- .../src/infer/canonical/instantiate.rs | 4 ++-- .../src/infer/canonical/query_response.rs | 6 ++--- compiler/rustc_infer/src/infer/mod.rs | 4 ++-- .../src/infer/relate/higher_ranked.rs | 4 ++-- compiler/rustc_middle/src/ty/consts.rs | 14 +++++++---- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/fold.rs | 24 ++++++++++++------- compiler/rustc_middle/src/ty/mod.rs | 23 ++++++++++++------ compiler/rustc_middle/src/ty/sty.rs | 6 ----- .../rustc_middle/src/ty/typeck_results.rs | 6 ++--- .../src/traits/coherence.rs | 5 +++- .../rustc_trait_selection/src/traits/mod.rs | 5 +++- .../rustc_trait_selection/src/traits/util.rs | 4 ++-- compiler/rustc_type_ir/src/inherent.rs | 2 +- compiler/rustc_type_ir/src/lib.rs | 10 -------- 21 files changed, 82 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index e023300f1c28..bb72d1d52f37 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -187,7 +187,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar| { + consts: &mut |_bound_const: ty::BoundConst| { unreachable!("we only replace regions in nll_relate, not consts") }, }; @@ -226,7 +226,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar| { + consts: &mut |_bound_const: ty::BoundConst| { unreachable!("we only replace regions in nll_relate, not consts") }, }; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e24426f9fedc..13d690054ce6 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2498,7 +2498,7 @@ fn param_env_with_gat_bounds<'tcx>( ty::Const::new_bound( tcx, ty::INNERMOST, - ty::BoundVar::from_usize(bound_vars.len() - 1), + ty::BoundConst { var: ty::BoundVar::from_usize(bound_vars.len() - 1) }, ) .into() } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 548ba343aaee..ba54fa8cc0db 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -189,7 +189,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>( } ty::GenericArgKind::Const(ct) => { if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() { - mapping.insert(bv, tcx.mk_param_from_def(param)) + mapping.insert(bv.var, tcx.mk_param_from_def(param)) } else { return None; } @@ -307,16 +307,16 @@ impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { return ct; } - if let ty::ConstKind::Bound(binder, old_var) = ct.kind() + if let ty::ConstKind::Bound(binder, old_bound) = ct.kind() && self.binder == binder { - let mapped = if let Some(mapped) = self.mapping.get(&old_var) { + let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) { mapped.expect_const() } else { let var = ty::BoundVar::from_usize(self.still_bound_vars.len()); self.still_bound_vars.push(ty::BoundVariableKind::Const); - let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, var); - self.mapping.insert(old_var, mapped.into()); + let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst { var }); + self.mapping.insert(old_bound.var, mapped.into()); mapped }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 7760642d8fb0..386e1091ac4e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1077,7 +1077,7 @@ impl<'tcx> TypeVisitor> for GenericParamAndBoundVarCollector<'_, 't ty::ConstKind::Param(param) => { self.params.insert(param.index); } - ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => { + ty::ConstKind::Bound(db, _) if db >= self.depth => { let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var"); return ControlFlow::Break(guar); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d76879983586..d93f3c5f5085 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2107,9 +2107,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let name = tcx.item_name(param_def_id); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) - } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => ty::Const::new_bound( + tcx, + debruijn, + ty::BoundConst { var: ty::BoundVar::from_u32(index) }, + ), Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id), } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 060447ba7206..a4c6d078125d 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -752,7 +752,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ) -> Ty<'tcx> { debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))); let var = self.canonical_var(var_kind, ty_var.into()); - Ty::new_bound(self.tcx, self.binder_index, var.into()) + let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon }; + Ty::new_bound(self.tcx, self.binder_index, bt) } /// Given a type variable `const_var` of the given kind, first check @@ -768,6 +769,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var)) ); let var = self.canonical_var(var_kind, ct_var.into()); - ty::Const::new_bound(self.tcx, self.binder_index, var) + let bc = ty::BoundConst { var }; + ty::Const::new_bound(self.tcx, self.binder_index, bc) } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index 2385c68ef6bb..cc052fbd85c1 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -133,7 +133,7 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { - self.var_values[bound_const.as_usize()].expect_const() + self.var_values[bound_const.var.as_usize()].expect_const() } _ => ct.super_fold_with(self), } @@ -217,7 +217,7 @@ fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize { if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind() && debruijn == self.current_index { - self.max_var = self.max_var.max(bound_const.as_usize()); + self.max_var = self.max_var.max(bound_const.var.as_usize()); } else if ct.has_vars_bound_at_or_above(self.current_index) { ct.super_visit_with(self); } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 6be53c948c84..73b1ca6c6913 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -433,12 +433,12 @@ impl<'tcx> InferCtxt<'tcx> { } GenericArgKind::Lifetime(result_value) => { // e.g., here `result_value` might be `'?1` in the example above... - if let ty::ReBound(debruijn, br) = result_value.kind() { + if let ty::ReBound(debruijn, b) = result_value.kind() { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.var] = Some(*original_value); + opt_values[b.var] = Some(*original_value); } } GenericArgKind::Const(result_value) => { @@ -447,7 +447,7 @@ impl<'tcx> InferCtxt<'tcx> { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - opt_values[b] = Some(*original_value); + opt_values[b.var] = Some(*original_value); } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2d269e320b64..41297e8ffca1 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1208,8 +1208,8 @@ impl<'tcx> InferCtxt<'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { self.args[bt.var.index()].expect_ty() } - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { - self.args[bv.index()].expect_const() + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> { + self.args[bc.var.index()].expect_const() } } let delegate = ToFreshVars { args }; diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 2143f72a3b0a..16fe591b29bb 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -45,10 +45,10 @@ impl<'tcx> InferCtxt<'tcx> { ty::PlaceholderType { universe: next_universe, bound: bound_ty }, ) }, - consts: &mut |bound_var: ty::BoundVar| { + consts: &mut |bound_const: ty::BoundConst| { ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { universe: next_universe, bound: bound_var }, + ty::PlaceholderConst { universe: next_universe, bound: bound_const }, ) }, }; diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index fd1aa4042bcf..614b6471f188 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -93,9 +93,9 @@ impl<'tcx> Const<'tcx> { pub fn new_bound( tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, - var: ty::BoundVar, + bound_const: ty::BoundConst, ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Bound(debruijn, var)) + Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const)) } #[inline] @@ -168,12 +168,16 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_var(tcx, vid) } - fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { - Const::new_bound(interner, debruijn, var) + fn new_bound( + interner: TyCtxt<'tcx>, + debruijn: ty::DebruijnIndex, + bound_const: ty::BoundConst, + ) -> Self { + Const::new_bound(interner, debruijn, bound_const) } fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { - Const::new_bound(tcx, debruijn, var) + Const::new_bound(tcx, debruijn, ty::BoundConst { var }) } fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6f21160d1f66..466b3f191c06 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -152,7 +152,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type PlaceholderConst = ty::PlaceholderConst; type ParamConst = ty::ParamConst; - type BoundConst = ty::BoundVar; + type BoundConst = ty::BoundConst; type ValueConst = ty::Value<'tcx>; type ExprConst = ty::Expr<'tcx>; type ValTree = ty::ValTree<'tcx>; diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b2057fa36d7f..7d56ec1635f8 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId; use rustc_type_ir::data_structures::DelayedMap; use crate::ty::{ - self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + self, Binder, BoundConst, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -60,7 +60,7 @@ where pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>; + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx>; } /// A simple delegate taking 3 mutable functions. The used functions must @@ -69,7 +69,7 @@ pub trait BoundVarReplacerDelegate<'tcx> { pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), - pub consts: &'a mut (dyn FnMut(ty::BoundVar) -> ty::Const<'tcx> + 'a), + pub consts: &'a mut (dyn FnMut(ty::BoundConst) -> ty::Const<'tcx> + 'a), } impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { @@ -79,8 +79,8 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { (self.types)(bt) } - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { - (self.consts)(bv) + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> { + (self.consts)(bc) } } @@ -300,7 +300,13 @@ impl<'tcx> TyCtxt<'tcx> { ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, ) }, - consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), + consts: &mut |c| { + ty::Const::new_bound( + self, + ty::INNERMOST, + ty::BoundConst { var: shift_bv(c.var) }, + ) + }, }, ) } @@ -343,12 +349,12 @@ impl<'tcx> TyCtxt<'tcx> { .expect_ty(); Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind }) } - fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { - let entry = self.map.entry(bv); + fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> { + let entry = self.map.entry(bc.var); let index = entry.index(); let var = ty::BoundVar::from_usize(index); let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); - ty::Const::new_bound(self.tcx, ty::INNERMOST, var) + ty::Const::new_bound(self.tcx, ty::INNERMOST, BoundConst { var }) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bb70c61cd141..fab020547ad3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -968,34 +968,43 @@ impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for Placeholde #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TyEncodable, TyDecodable)] -pub struct BoundConst<'tcx> { +pub struct BoundConst { pub var: BoundVar, - pub ty: Ty<'tcx>, } -pub type PlaceholderConst = Placeholder; +impl<'tcx> rustc_type_ir::inherent::BoundVarLike> for BoundConst { + fn var(self) -> BoundVar { + self.var + } + + fn assert_eq(self, _var: ty::BoundVariableKind) { + unreachable!() + } +} + +pub type PlaceholderConst = Placeholder; impl<'tcx> rustc_type_ir::inherent::PlaceholderLike> for PlaceholderConst { - type Bound = BoundVar; + type Bound = BoundConst; fn universe(self) -> UniverseIndex { self.universe } fn var(self) -> BoundVar { - self.bound + self.bound.var } fn with_updated_universe(self, ui: UniverseIndex) -> Self { Placeholder { universe: ui, ..self } } - fn new(ui: UniverseIndex, bound: BoundVar) -> Self { + fn new(ui: UniverseIndex, bound: BoundConst) -> Self { Placeholder { universe: ui, bound } } fn new_anon(ui: UniverseIndex, var: BoundVar) -> Self { - Placeholder { universe: ui, bound: var } + Placeholder { universe: ui, bound: BoundConst { var } } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 4569596cfbe8..ea84ea3af428 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -403,12 +403,6 @@ pub enum BoundTyKind { Param(DefId), } -impl From for BoundTy { - fn from(var: BoundVar) -> Self { - BoundTy { var, kind: BoundTyKind::Anon } - } -} - /// Constructors for `Ty` impl<'tcx> Ty<'tcx> { /// Avoid using this in favour of more specific `new_*` methods, where possible. diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 88583407d25d..6b187c5325a9 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -789,10 +789,10 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { }, GenericArgKind::Lifetime(r) => match r.kind() { - ty::ReBound(debruijn, br) => { + ty::ReBound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - cvar == br.var + cvar == b.var } _ => false, }, @@ -801,7 +801,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { ty::ConstKind::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); - cvar == b + cvar == b.var } _ => false, }, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 07e78da37b3b..d8aedf5c2bf3 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -535,7 +535,10 @@ fn plug_infer_with_placeholders<'tcx>( ct, ty::Const::new_placeholder( self.infcx.tcx, - ty::Placeholder { universe: self.universe, bound: self.next_var() }, + ty::Placeholder { + universe: self.universe, + bound: ty::BoundConst { var: self.next_var() }, + }, ), ) else { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9b5e59ce0fdb..08315dbd21fb 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -706,7 +706,10 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( self.idx += 1; ty::Const::new_placeholder( self.tcx, - ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, bound: idx }, + ty::PlaceholderConst { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundConst { var: idx }, + }, ) } else { c.super_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c3d60ec45c46..83c0969762f4 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -222,7 +222,7 @@ pub struct PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap, mapped_types: FxIndexMap, - mapped_consts: FxIndexMap, + mapped_consts: FxIndexMap, universe_indices: &'a [Option], current_index: ty::DebruijnIndex, } @@ -232,7 +232,7 @@ impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, mapped_regions: FxIndexMap, mapped_types: FxIndexMap, - mapped_consts: FxIndexMap, + mapped_consts: FxIndexMap, universe_indices: &'a [Option], value: T, ) -> T { diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 0e307e15d5b4..1a6c99ce7dec 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -251,7 +251,7 @@ pub trait Const>: fn new_var(interner: I, var: ty::ConstVid) -> Self; - fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, bound_const: I::BoundConst) -> Self; fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a483c18813b0..5c9cac5b21b1 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -387,16 +387,6 @@ rustc_index::newtype_index! { pub struct BoundVar {} } -impl inherent::BoundVarLike for BoundVar { - fn var(self) -> BoundVar { - self - } - - fn assert_eq(self, _var: I::BoundVarKind) { - unreachable!("FIXME: We really should have a separate `BoundConst` for consts") - } -} - /// Represents the various closure traits in the language. This /// will determine the type of the environment (`self`, in the /// desugaring) argument that the closure expects. From 64be8bb599d3efa12235e266177c828ad97373e6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Jul 2025 19:04:03 +1000 Subject: [PATCH 113/242] Check consts in `ValidateBoundVars`. Alongside the existing type and region checking. --- compiler/rustc_middle/src/ty/mod.rs | 4 ++-- compiler/rustc_type_ir/src/binder.rs | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fab020547ad3..342f59874661 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -977,8 +977,8 @@ impl<'tcx> rustc_type_ir::inherent::BoundVarLike> for BoundConst { self.var } - fn assert_eq(self, _var: ty::BoundVariableKind) { - unreachable!() + fn assert_eq(self, var: ty::BoundVariableKind) { + var.expect_const() } } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index a7b915c48455..fb0dfe95b738 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -274,8 +274,9 @@ impl Binder { pub struct ValidateBoundVars { bound_vars: I::BoundVarKinds, binder_index: ty::DebruijnIndex, - // We may encounter the same variable at different levels of binding, so - // this can't just be `Ty` + // We only cache types because any complex const will have to step through + // a type at some point anyways. We may encounter the same variable at + // different levels of binding, so this can't just be `Ty`. visited: SsoHashSet<(ty::DebruijnIndex, I::Ty)>, } @@ -319,6 +320,24 @@ impl TypeVisitor for ValidateBoundVars { t.super_visit_with(self) } + fn visit_const(&mut self, c: I::Const) -> Self::Result { + if c.outer_exclusive_binder() < self.binder_index { + return ControlFlow::Break(()); + } + match c.kind() { + ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.binder_index => { + let idx = bound_const.var().as_usize(); + if self.bound_vars.len() <= idx { + panic!("Not enough bound vars: {:?} not found in {:?}", c, self.bound_vars); + } + bound_const.assert_eq(self.bound_vars.get(idx).unwrap()); + } + _ => {} + }; + + c.super_visit_with(self) + } + fn visit_region(&mut self, r: I::Region) -> Self::Result { match r.kind() { ty::ReBound(index, br) if index == self.binder_index => { From 75a1f47750fb34031f00cc2ee2b0d385426bec94 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 25 Jul 2025 19:52:08 +1000 Subject: [PATCH 114/242] Avoid vacuous `Constraint::{VarSubVar,RegSubReg}` constraints. If the two regions are the same, we can skip it. This is a small perf win. --- compiler/rustc_infer/src/infer/region_constraints/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index a1744b4df80f..4747c203c807 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -471,7 +471,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { // all regions are subregions of static, so we can ignore this } (ReVar(sub_id), ReVar(sup_id)) => { - self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); + if sub_id != sup_id { + self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); + } } (_, ReVar(sup_id)) => { self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin); @@ -480,7 +482,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin); } _ => { - self.add_constraint(Constraint::RegSubReg(sub, sup), origin); + if sub != sup { + self.add_constraint(Constraint::RegSubReg(sub, sup), origin); + } } } } From 066a973312066b792c5de4b41b92dcb437f22bac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 25 Jul 2025 20:34:36 +1000 Subject: [PATCH 115/242] Overhaul `Constraint`. This commit changes it to store a `Region` instead of a `RegionVid` for the `Var` cases: - We avoid having to call `Region::new_var` to re-create `Region`s from `RegionVid`s in a few places, avoiding the interning process, giving a small perf win. (At the cost of the type allowing some invalid combinations of values.) - All the cases now store two `Region`s, so the commit also separates the `ConstraintKind` (a new type) from the `sub` and `sup` arguments in `Constraint`. --- .../src/diagnostics/bound_region_errors.rs | 39 ++- .../src/infer/canonical/query_response.rs | 25 +- .../src/infer/lexical_region_resolve/mod.rs | 230 +++++++++--------- .../rustc_infer/src/infer/outlives/mod.rs | 8 +- .../infer/region_constraints/leak_check.rs | 29 +-- .../src/infer/region_constraints/mod.rs | 46 ++-- .../src/solve/delegate.rs | 1 - .../src/traits/auto_trait.rs | 44 ++-- .../src/traits/query/type_op/custom.rs | 1 - .../rustc_traits/src/coroutine_witnesses.rs | 1 - src/librustdoc/clean/auto_trait.rs | 40 +-- 11 files changed, 225 insertions(+), 239 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 0de4bd67f0ce..6ccded01e886 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; -use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; +use rustc_infer::infer::region_constraints::{Constraint, ConstraintKind, RegionConstraintData}; use rustc_infer::infer::{ InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _, }; @@ -454,25 +454,24 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound, _ => a_region == b_region, }; - let mut check = - |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint { - Constraint::RegSubReg(sub, sup) - if ((exact && sup == placeholder_region) - || (!exact && regions_the_same(sup, placeholder_region))) - && sup != sub => - { - Some((sub, cause.clone())) - } - Constraint::VarSubReg(vid, sup) - if (exact - && sup == placeholder_region - && !universe_of_region(vid).can_name(placeholder_universe)) - || (!exact && regions_the_same(sup, placeholder_region)) => - { - Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) - } - _ => None, - }; + let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind { + ConstraintKind::RegSubReg + if ((exact && c.sup == placeholder_region) + || (!exact && regions_the_same(c.sup, placeholder_region))) + && c.sup != c.sub => + { + Some((c.sub, cause.clone())) + } + ConstraintKind::VarSubReg + if (exact + && c.sup == placeholder_region + && !universe_of_region(c.sub.as_var()).can_name(placeholder_universe)) + || (!exact && regions_the_same(c.sup, placeholder_region)) => + { + Some((c.sub, cause.clone())) + } + _ => None, + }; let mut find_culprit = |exact_match: bool| { region_constraints diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 6be53c948c84..d92f4c2444b6 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -21,7 +21,7 @@ use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryRegionConstraints, QueryResponse, }; -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; +use crate::infer::region_constraints::RegionConstraintData; use crate::infer::{ DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint, }; @@ -105,8 +105,6 @@ impl<'tcx> InferCtxt<'tcx> { where T: Debug + TypeFoldable>, { - let tcx = self.tcx; - // Select everything, returning errors. let errors = fulfill_cx.select_all_or_error(self); @@ -120,7 +118,6 @@ impl<'tcx> InferCtxt<'tcx> { debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { make_query_region_constraints( - tcx, region_obligations, region_constraints, region_assumptions, @@ -587,7 +584,6 @@ impl<'tcx> InferCtxt<'tcx> { /// Given the region obligations and constraints scraped from the infcx, /// creates query region constraints. pub fn make_query_region_constraints<'tcx>( - tcx: TyCtxt<'tcx>, outlives_obligations: Vec>, region_constraints: &RegionConstraintData<'tcx>, assumptions: Vec>, @@ -600,22 +596,9 @@ pub fn make_query_region_constraints<'tcx>( let outlives: Vec<_> = constraints .iter() - .map(|(k, origin)| { - let constraint = match *k { - // Swap regions because we are going from sub (<=) to outlives - // (>=). - Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( - ty::Region::new_var(tcx, v2).into(), - ty::Region::new_var(tcx, v1), - ), - Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), ty::Region::new_var(tcx, v1)) - } - Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(ty::Region::new_var(tcx, v2).into(), r1) - } - Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), - }; + .map(|(c, origin)| { + // Swap regions because we are going from sub (<=) to outlives (>=). + let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub); (constraint, origin.to_constraint_category()) }) .chain(outlives_obligations.into_iter().map(|obl| { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 2185886901e5..3adcfb427278 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -19,7 +19,7 @@ use tracing::{debug, instrument}; use super::outlives::test_type_match; use crate::infer::region_constraints::{ - Constraint, GenericKind, RegionConstraintData, VarInfos, VerifyBound, + Constraint, ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound, }; use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin}; @@ -187,91 +187,96 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values); // Tracks the changed region vids. let mut changes = Vec::new(); - for (constraint, _) in &self.data.constraints { - match *constraint { - Constraint::RegSubVar(a_region, b_vid) => { - let b_data = var_values.value_mut(b_vid); + for (c, _) in &self.data.constraints { + match c.kind { + ConstraintKind::RegSubVar => { + let sup_vid = c.sup.as_var(); + let sup_data = var_values.value_mut(sup_vid); - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); + if self.expand_node(c.sub, sup_vid, sup_data) { + changes.push(sup_vid); } } - Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { - VarValue::ErrorValue => continue, - VarValue::Empty(a_universe) => { - let b_data = var_values.value_mut(b_vid); + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); + match *var_values.value(sub_vid) { + VarValue::ErrorValue => continue, + VarValue::Empty(sub_universe) => { + let sup_data = var_values.value_mut(sup_vid); - let changed = match *b_data { - VarValue::Empty(b_universe) => { - // Empty regions are ordered according to the universe - // they are associated with. - let ui = a_universe.min(b_universe); + let changed = match *sup_data { + VarValue::Empty(sup_universe) => { + // Empty regions are ordered according to the universe + // they are associated with. + let ui = sub_universe.min(sup_universe); - debug!( - "Expanding value of {:?} \ + debug!( + "Expanding value of {:?} \ from empty lifetime with universe {:?} \ to empty lifetime with universe {:?}", - b_vid, b_universe, ui - ); + sup_vid, sup_universe, ui + ); - *b_data = VarValue::Empty(ui); - true - } - VarValue::Value(cur_region) => { - match cur_region.kind() { - // If this empty region is from a universe that can name the - // placeholder universe, then the LUB is the Placeholder region - // (which is the cur_region). Otherwise, the LUB is the Static - // lifetime. - RePlaceholder(placeholder) - if !a_universe.can_name(placeholder.universe) => - { - let lub = self.tcx().lifetimes.re_static; - debug!( - "Expanding value of {:?} from {:?} to {:?}", - b_vid, cur_region, lub - ); + *sup_data = VarValue::Empty(ui); + true + } + VarValue::Value(cur_region) => { + match cur_region.kind() { + // If this empty region is from a universe that can name + // the placeholder universe, then the LUB is the + // Placeholder region (which is the cur_region). Otherwise, + // the LUB is the Static lifetime. + RePlaceholder(placeholder) + if !sub_universe.can_name(placeholder.universe) => + { + let lub = self.tcx().lifetimes.re_static; + debug!( + "Expanding value of {:?} from {:?} to {:?}", + sup_vid, cur_region, lub + ); - *b_data = VarValue::Value(lub); - true + *sup_data = VarValue::Value(lub); + true + } + + _ => false, } + } - _ => false, + VarValue::ErrorValue => false, + }; + + if changed { + changes.push(sup_vid); + } + match sup_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[sub_vid].push((sub_vid, sup_vid)); + constraints[sup_vid].push((sub_vid, sup_vid)); } } - - VarValue::ErrorValue => false, - }; - - if changed { - changes.push(b_vid); } - match b_data { - VarValue::Value(Region(Interned(ReStatic, _))) - | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); + VarValue::Value(sub_region) => { + let sup_data = var_values.value_mut(sup_vid); + + if self.expand_node(sub_region, sup_vid, sup_data) { + changes.push(sup_vid); + } + match sup_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[sub_vid].push((sub_vid, sup_vid)); + constraints[sup_vid].push((sub_vid, sup_vid)); + } } } } - VarValue::Value(a_region) => { - let b_data = var_values.value_mut(b_vid); - - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); - } - match b_data { - VarValue::Value(Region(Interned(ReStatic, _))) - | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); - } - } - } - }, - Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => { + } + ConstraintKind::RegSubReg | ConstraintKind::VarSubReg => { // These constraints are checked after expansion // is done, in `collect_errors`. continue; @@ -528,49 +533,48 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { var_data: &mut LexicalRegionResolutions<'tcx>, errors: &mut Vec>, ) { - for (constraint, origin) in &self.data.constraints { - debug!(?constraint, ?origin); - match *constraint { - Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => { + for (c, origin) in &self.data.constraints { + debug!(?c, ?origin); + match c.kind { + ConstraintKind::RegSubVar | ConstraintKind::VarSubVar => { // Expansion will ensure that these constraints hold. Ignore. } - Constraint::RegSubReg(sub, sup) => { - if self.sub_concrete_regions(sub, sup) { + ConstraintKind::RegSubReg => { + if self.sub_concrete_regions(c.sub, c.sup) { continue; } debug!( - "region error at {:?}: \ - cannot verify that {:?} <= {:?}", - origin, sub, sup + "region error at {:?}: cannot verify that {:?} <= {:?}", + origin, c.sub, c.sup ); errors.push(RegionResolutionError::ConcreteFailure( (*origin).clone(), - sub, - sup, + c.sub, + c.sup, )); } - Constraint::VarSubReg(a_vid, b_region) => { - let a_data = var_data.value_mut(a_vid); - debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region); + ConstraintKind::VarSubReg => { + let sub_vid = c.sub.as_var(); + let sub_data = var_data.value_mut(sub_vid); + debug!("contraction: {:?} == {:?}, {:?}", sub_vid, sub_data, c.sup); - let VarValue::Value(a_region) = *a_data else { + let VarValue::Value(sub_region) = *sub_data else { continue; }; // Do not report these errors immediately: // instead, set the variable value to error and // collect them later. - if !self.sub_concrete_regions(a_region, b_region) { + if !self.sub_concrete_regions(sub_region, c.sup) { debug!( - "region error at {:?}: \ - cannot verify that {:?}={:?} <= {:?}", - origin, a_vid, a_region, b_region + "region error at {:?}: cannot verify that {:?}={:?} <= {:?}", + origin, sub_vid, sub_region, c.sup ); - *a_data = VarValue::ErrorValue; + *sub_data = VarValue::ErrorValue; } } } @@ -682,18 +686,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let dummy_source = graph.add_node(()); let dummy_sink = graph.add_node(()); - for (constraint, _) in &self.data.constraints { - match *constraint { - Constraint::VarSubVar(a_id, b_id) => { - graph.add_edge(NodeIndex(a_id.index()), NodeIndex(b_id.index()), *constraint); + for (c, _) in &self.data.constraints { + match c.kind { + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); + graph.add_edge(NodeIndex(sub_vid.index()), NodeIndex(sup_vid.index()), *c); } - Constraint::RegSubVar(_, b_id) => { - graph.add_edge(dummy_source, NodeIndex(b_id.index()), *constraint); + ConstraintKind::RegSubVar => { + graph.add_edge(dummy_source, NodeIndex(c.sup.as_var().index()), *c); } - Constraint::VarSubReg(a_id, _) => { - graph.add_edge(NodeIndex(a_id.index()), dummy_sink, *constraint); + ConstraintKind::VarSubReg => { + graph.add_edge(NodeIndex(c.sub.as_var().index()), dummy_sink, *c); } - Constraint::RegSubReg(..) => { + ConstraintKind::RegSubReg => { // this would be an edge from `dummy_source` to // `dummy_sink`; just ignore it. } @@ -878,26 +884,30 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let source_node_index = NodeIndex(source_vid.index()); for (_, edge) in graph.adjacent_edges(source_node_index, dir) { - match edge.data { - Constraint::VarSubVar(from_vid, to_vid) => { + let get_origin = + || this.constraints.iter().find(|(c, _)| *c == edge.data).unwrap().1.clone(); + + match edge.data.kind { + ConstraintKind::VarSubVar => { + let from_vid = edge.data.sub.as_var(); + let to_vid = edge.data.sup.as_var(); let opp_vid = if from_vid == source_vid { to_vid } else { from_vid }; if state.set.insert(opp_vid) { state.stack.push(opp_vid); } } - Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => { - let origin = this - .constraints - .iter() - .find(|(c, _)| *c == edge.data) - .unwrap() - .1 - .clone(); - state.result.push(RegionAndOrigin { region, origin }); + ConstraintKind::RegSubVar => { + let origin = get_origin(); + state.result.push(RegionAndOrigin { region: edge.data.sub, origin }); } - Constraint::RegSubReg(..) => panic!( + ConstraintKind::VarSubReg => { + let origin = get_origin(); + state.result.push(RegionAndOrigin { region: edge.data.sup, origin }); + } + + ConstraintKind::RegSubReg => panic!( "cannot reach reg-sub-reg edge in region inference \ post-processing" ), diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 19911bfbd48b..c992cda8aaed 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -10,7 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; -use crate::infer::region_constraints::Constraint; +use crate::infer::region_constraints::ConstraintKind; pub mod env; pub mod for_liveness; @@ -70,10 +70,10 @@ impl<'tcx> InferCtxt<'tcx> { // Filter out any region-region outlives assumptions that are implied by // coroutine well-formedness. if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions { - storage.data.constraints.retain(|(constraint, _)| match *constraint { - Constraint::RegSubReg(r1, r2) => !outlives_env + storage.data.constraints.retain(|(c, _)| match c.kind { + ConstraintKind::RegSubReg => !outlives_env .higher_ranked_assumptions() - .contains(&ty::OutlivesPredicate(r2.into(), r1)), + .contains(&ty::OutlivesPredicate(c.sup.into(), c.sub)), _ => true, }); } diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index e332b6d0447a..4d76bc2e17a1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -83,7 +83,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { return Ok(()); } - let mini_graph = MiniGraph::new(tcx, &self, only_consider_snapshot); + let mini_graph = MiniGraph::new(&self, only_consider_snapshot); let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self); leak_check.assign_placeholder_values()?; @@ -359,7 +359,6 @@ struct MiniGraph<'tcx> { impl<'tcx> MiniGraph<'tcx> { fn new( - tcx: TyCtxt<'tcx>, region_constraints: &RegionConstraintCollector<'_, 'tcx>, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> Self { @@ -368,7 +367,6 @@ impl<'tcx> MiniGraph<'tcx> { // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter. Self::iterate_region_constraints( - tcx, region_constraints, only_consider_snapshot, |target, source| { @@ -384,33 +382,18 @@ impl<'tcx> MiniGraph<'tcx> { /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1` fn iterate_region_constraints( - tcx: TyCtxt<'tcx>, region_constraints: &RegionConstraintCollector<'_, 'tcx>, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>), ) { - let mut each_constraint = |constraint| match constraint { - &Constraint::VarSubVar(a, b) => { - each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b)); - } - &Constraint::RegSubVar(a, b) => { - each_edge(a, ty::Region::new_var(tcx, b)); - } - &Constraint::VarSubReg(a, b) => { - each_edge(ty::Region::new_var(tcx, a), b); - } - &Constraint::RegSubReg(a, b) => { - each_edge(a, b); - } - }; - if let Some(snapshot) = only_consider_snapshot { for undo_entry in region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot) { match undo_entry { &AddConstraint(i) => { - each_constraint(®ion_constraints.data().constraints[i].0); + let c = region_constraints.data().constraints[i].0; + each_edge(c.sub, c.sup); } &AddVerify(i) => span_bug!( region_constraints.data().verifys[i].origin.span(), @@ -420,11 +403,7 @@ impl<'tcx> MiniGraph<'tcx> { } } } else { - region_constraints - .data() - .constraints - .iter() - .for_each(|(constraint, _)| each_constraint(constraint)); + region_constraints.data().constraints.iter().for_each(|(c, _)| each_edge(c.sub, c.sup)) } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 4747c203c807..85f5e55a8e1e 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -80,31 +80,37 @@ pub struct RegionConstraintData<'tcx> { /// Represents a constraint that influences the inference process. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub enum Constraint<'tcx> { +pub enum ConstraintKind { /// A region variable is a subregion of another. - VarSubVar(RegionVid, RegionVid), + VarSubVar, /// A concrete region is a subregion of region variable. - RegSubVar(Region<'tcx>, RegionVid), + RegSubVar, /// A region variable is a subregion of a concrete region. This does not /// directly affect inference, but instead is checked after /// inference is complete. - VarSubReg(RegionVid, Region<'tcx>), + VarSubReg, /// A constraint where neither side is a variable. This does not /// directly affect inference, but instead is checked after /// inference is complete. - RegSubReg(Region<'tcx>, Region<'tcx>), + RegSubReg, +} + +/// Represents a constraint that influences the inference process. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub struct Constraint<'tcx> { + pub kind: ConstraintKind, + // If `kind` is `VarSubVar` or `VarSubReg`, this must be a `ReVar`. + pub sub: Region<'tcx>, + // If `kind` is `VarSubVar` or `RegSubVar`, this must be a `ReVar`. + pub sup: Region<'tcx>, } impl Constraint<'_> { pub fn involves_placeholders(&self) -> bool { - match self { - Constraint::VarSubVar(_, _) => false, - Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(), - Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(), - } + self.sub.is_placeholder() || self.sup.is_placeholder() } } @@ -472,18 +478,22 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } (ReVar(sub_id), ReVar(sup_id)) => { if sub_id != sup_id { - self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); + self.add_constraint( + Constraint { kind: ConstraintKind::VarSubVar, sub, sup }, + origin, + ); } } - (_, ReVar(sup_id)) => { - self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin); - } - (ReVar(sub_id), _) => { - self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin); - } + (_, ReVar(_)) => self + .add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin), + (ReVar(_), _) => self + .add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin), _ => { if sub != sup { - self.add_constraint(Constraint::RegSubReg(sub, sup), origin); + self.add_constraint( + Constraint { kind: ConstraintKind::RegSubReg, sub, sup }, + origin, + ) } } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 7426504e1393..96c6e5893734 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -205,7 +205,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned(); let region_constraints = self.0.with_region_constraints(|region_constraints| { make_query_region_constraints( - self.tcx, region_obligations, region_constraints, region_assumptions, diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 759db1d18c01..c63cc0e17ab9 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -13,7 +13,7 @@ use tracing::debug; use super::*; use crate::errors::UnableToConstructConstantValue; -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; +use crate::infer::region_constraints::{ConstraintKind, RegionConstraintData}; use crate::regions::OutlivesEnvironmentBuildExt; use crate::traits::project::ProjectAndUnifyResult; @@ -452,37 +452,41 @@ impl<'tcx> AutoTraitFinder<'tcx> { let mut vid_map = FxIndexMap::, RegionDeps<'cx>>::default(); let mut finished_map = FxIndexMap::default(); - for (constraint, _) in ®ions.constraints { - match constraint { - &Constraint::VarSubVar(r1, r2) => { + for (c, _) in ®ions.constraints { + match c.kind { + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); { - let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(r2)); + let deps1 = vid_map.entry(RegionTarget::RegionVid(sub_vid)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(sup_vid)); } - let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default(); - deps2.smaller.insert(RegionTarget::RegionVid(r1)); + let deps2 = vid_map.entry(RegionTarget::RegionVid(sup_vid)).or_default(); + deps2.smaller.insert(RegionTarget::RegionVid(sub_vid)); } - &Constraint::RegSubVar(region, vid) => { + ConstraintKind::RegSubVar => { + let sup_vid = c.sup.as_var(); { - let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(vid)); + let deps1 = vid_map.entry(RegionTarget::Region(c.sub)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(sup_vid)); } - let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default(); - deps2.smaller.insert(RegionTarget::Region(region)); + let deps2 = vid_map.entry(RegionTarget::RegionVid(sup_vid)).or_default(); + deps2.smaller.insert(RegionTarget::Region(c.sub)); } - &Constraint::VarSubReg(vid, region) => { - finished_map.insert(vid, region); + ConstraintKind::VarSubReg => { + let sub_vid = c.sub.as_var(); + finished_map.insert(sub_vid, c.sup); } - &Constraint::RegSubReg(r1, r2) => { + ConstraintKind::RegSubReg => { { - let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default(); - deps1.larger.insert(RegionTarget::Region(r2)); + let deps1 = vid_map.entry(RegionTarget::Region(c.sub)).or_default(); + deps1.larger.insert(RegionTarget::Region(c.sup)); } - let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default(); - deps2.smaller.insert(RegionTarget::Region(r1)); + let deps2 = vid_map.entry(RegionTarget::Region(c.sup)).or_default(); + deps2.smaller.insert(RegionTarget::Region(c.sub)); } } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index f027ba1c5cbf..0ca2d2162288 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -108,7 +108,6 @@ where let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( - infcx.tcx, region_obligations, ®ion_constraint_data, region_assumptions, diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 87d17f3e131a..8a2a0832ddb7 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -70,7 +70,6 @@ fn compute_assumptions<'tcx>( let region_constraints = infcx.take_and_reset_region_constraints(); let outlives = make_query_region_constraints( - tcx, region_obligations, ®ion_constraints, region_assumptions, diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index a91ea55bcae6..e6ac0270f783 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_hir as hir; -use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; +use rustc_infer::infer::region_constraints::{ConstraintKind, RegionConstraintData}; use rustc_middle::bug; use rustc_middle::ty::{self, Region, Ty, fold_regions}; use rustc_span::def_id::DefId; @@ -233,31 +233,35 @@ fn clean_region_outlives_constraints<'tcx>( // Each `RegionTarget` (a `RegionVid` or a `Region`) maps to its smaller and larger regions. // Note that "larger" regions correspond to sub regions in the surface language. // E.g., in `'a: 'b`, `'a` is the larger region. - for (constraint, _) in ®ions.constraints { - match *constraint { - Constraint::VarSubVar(vid1, vid2) => { - let deps1 = map.entry(RegionTarget::RegionVid(vid1)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(vid2)); + for (c, _) in ®ions.constraints { + match c.kind { + ConstraintKind::VarSubVar => { + let sub_vid = c.sub.as_var(); + let sup_vid = c.sup.as_var(); + let deps1 = map.entry(RegionTarget::RegionVid(sub_vid)).or_default(); + deps1.larger.insert(RegionTarget::RegionVid(sup_vid)); - let deps2 = map.entry(RegionTarget::RegionVid(vid2)).or_default(); - deps2.smaller.insert(RegionTarget::RegionVid(vid1)); + let deps2 = map.entry(RegionTarget::RegionVid(sup_vid)).or_default(); + deps2.smaller.insert(RegionTarget::RegionVid(sub_vid)); } - Constraint::RegSubVar(region, vid) => { - let deps = map.entry(RegionTarget::RegionVid(vid)).or_default(); - deps.smaller.insert(RegionTarget::Region(region)); + ConstraintKind::RegSubVar => { + let sup_vid = c.sup.as_var(); + let deps = map.entry(RegionTarget::RegionVid(sup_vid)).or_default(); + deps.smaller.insert(RegionTarget::Region(c.sub)); } - Constraint::VarSubReg(vid, region) => { - let deps = map.entry(RegionTarget::RegionVid(vid)).or_default(); - deps.larger.insert(RegionTarget::Region(region)); + ConstraintKind::VarSubReg => { + let sub_vid = c.sub.as_var(); + let deps = map.entry(RegionTarget::RegionVid(sub_vid)).or_default(); + deps.larger.insert(RegionTarget::Region(c.sup)); } - Constraint::RegSubReg(r1, r2) => { + ConstraintKind::RegSubReg => { // The constraint is already in the form that we want, so we're done with it // The desired order is [larger, smaller], so flip them. - if early_bound_region_name(r1) != early_bound_region_name(r2) { + if early_bound_region_name(c.sub) != early_bound_region_name(c.sup) { outlives_predicates - .entry(early_bound_region_name(r2).expect("no region_name found")) + .entry(early_bound_region_name(c.sup).expect("no region_name found")) .or_default() - .push(r1); + .push(c.sub); } } } From f638ebcfcea887eff5f3f05b1b2a455176a3d49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 31 Jul 2025 11:00:40 +0200 Subject: [PATCH 116/242] remove rustc_attr_data_structures --- src/attributes.rs | 4 ++-- src/callee.rs | 2 +- src/lib.rs | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/attributes.rs b/src/attributes.rs index 7a1ae6ca9c8b..04b43bb8bb7c 100644 --- a/src/attributes.rs +++ b/src/attributes.rs @@ -2,8 +2,8 @@ use gccjit::FnAttribute; use gccjit::Function; #[cfg(feature = "master")] -use rustc_attr_data_structures::InlineAttr; -use rustc_attr_data_structures::InstructionSetAttr; +use rustc_hir::attrs::InlineAttr; +use rustc_hir::attrs::InstructionSetAttr; #[cfg(feature = "master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; #[cfg(feature = "master")] diff --git a/src/callee.rs b/src/callee.rs index e7ca95af594c..8487a85bd035 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -106,7 +106,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() || tcx.codegen_instance_attrs(instance.def).inline - == rustc_attr_data_structures::InlineAttr::Never) + == rustc_hir::attrs::InlineAttr::Never) { // When not sharing generics, all instances are in the same // crate and have hidden visibility. diff --git a/src/lib.rs b/src/lib.rs index a31206825007..613315f77a6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,6 @@ extern crate tracing; extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; -extern crate rustc_attr_data_structures; extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; From 26c03e206a7c45f5767d5f2eb521d9961a4aeaf5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 28 Jul 2025 09:34:44 +0000 Subject: [PATCH 117/242] dont assemble shadowed impl candidates --- .../src/solve/assembly/mod.rs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index b2d401463485..b75da23cdaca 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -21,7 +21,7 @@ use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, - MaybeCause, NoSolution, ParamEnvSource, QueryResult, + MaybeCause, NoSolution, ParamEnvSource, QueryResult, has_no_inference_or_external_constraints, }; enum AliasBoundKind { @@ -395,9 +395,30 @@ where match assemble_from { AssembleCandidatesFrom::All => { - self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); - self.assemble_object_bound_candidates(goal, &mut candidates); + // For performance we only assemble impls if there are no candidates + // which would shadow them. This is necessary to avoid hangs in rayon, + // see trait-system-refactor-initiative#109 for more details. + // + // We always assemble builtin impls as trivial builtin impls have a higher + // priority than where-clauses. + // + // We only do this if any such candidate applies without any constraints + // as we may want to weaken inference guidance in the future and don't want + // to worry about causing major performance regressions when doing so. + // See trait-system-refactor-initiative#226 for some ideas here. + if TypingMode::Coherence == self.typing_mode() + || !candidates.iter().any(|c| { + matches!( + c.source, + CandidateSource::ParamEnv(ParamEnvSource::NonGlobal) + | CandidateSource::AliasBound + ) && has_no_inference_or_external_constraints(c.result) + }) + { + self.assemble_impl_candidates(goal, &mut candidates); + self.assemble_object_bound_candidates(goal, &mut candidates); + } } AssembleCandidatesFrom::EnvAndBounds => {} } From a78f92be9bd29b8d4d31ca97d2f5ba0bf818df08 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 31 Jul 2025 14:36:22 +0200 Subject: [PATCH 118/242] add tests --- .../traits/next-solver/cycles/rayon-hang-1.rs | 32 ++++++++++++ .../traits/next-solver/cycles/rayon-hang-2.rs | 49 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/ui/traits/next-solver/cycles/rayon-hang-1.rs create mode 100644 tests/ui/traits/next-solver/cycles/rayon-hang-2.rs diff --git a/tests/ui/traits/next-solver/cycles/rayon-hang-1.rs b/tests/ui/traits/next-solver/cycles/rayon-hang-1.rs new file mode 100644 index 000000000000..61e1f1b200f6 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/rayon-hang-1.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#109. + +trait ParallelIterator: Sized { + type Item; +} +trait IntoParallelIterator { + type Iter: ParallelIterator; + type Item; +} +impl IntoParallelIterator for T { + type Iter = T; + type Item = T::Item; +} + +macro_rules! multizip_impls { + ($($T:ident),+) => { + fn foo<$( $T, )+>() where + $( + $T: IntoParallelIterator, + $T::Iter: ParallelIterator, + )+ + ($( $T, )+): IntoParallelIterator, + {} + } +} + +multizip_impls! { A, B, C, D, E, F, G, H, I, J, K, L } + +fn main() {} diff --git a/tests/ui/traits/next-solver/cycles/rayon-hang-2.rs b/tests/ui/traits/next-solver/cycles/rayon-hang-2.rs new file mode 100644 index 000000000000..bb5d8335dd62 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/rayon-hang-2.rs @@ -0,0 +1,49 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#109. +// Unlike `rayon-hang-1.rs` the cycles in this test are not +// unproductive, which causes the `AliasRelate` goal when trying +// to apply where-clauses to only error in the second iteration. +// +// This makes the exponential blowup to be significantly harder +// to avoid. + +trait ParallelIterator: Sized { + type Item; +} + +trait IntoParallelIteratorIndir { + type Iter: ParallelIterator; + type Item; +} +impl IntoParallelIteratorIndir for I +where + Box: IntoParallelIterator, +{ + type Iter = as IntoParallelIterator>::Iter; + type Item = as IntoParallelIterator>::Item; +} +trait IntoParallelIterator { + type Iter: ParallelIterator; + type Item; +} +impl IntoParallelIterator for T { + type Iter = T; + type Item = T::Item; +} + +macro_rules! multizip_impls { + ($($T:ident),+) => { + fn foo<'a, $( $T, )+>() where + $( + $T: IntoParallelIteratorIndir, + $T::Iter: ParallelIterator, + )+ + {} + } +} + +multizip_impls! { A, B, C, D, E, F, G, H, I, J, K, L } + +fn main() {} From 42c520d631ef2eb3cb44b8490b8330b6651bd22f Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Thu, 31 Jul 2025 10:03:06 -0400 Subject: [PATCH 119/242] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 9b296973b425..840b83a10fb0 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 9b296973b425ffb159e12cf3cd56580fd5c85382 +Subproject commit 840b83a10fb0e039a83f4d70ad032892c287570a From cde0374d9301090c9b6b93bb033c07b04b55ab73 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 31 Jul 2025 19:17:51 +0300 Subject: [PATCH 120/242] resolve: Clarify extern prelude insertion for `extern crate` items --- Cargo.lock | 1 + compiler/rustc_resolve/Cargo.toml | 1 + .../rustc_resolve/src/build_reduced_graph.rs | 42 +++++++++++-------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1076f05ef12..e0f3a9d1ff1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4552,6 +4552,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "bitflags", + "indexmap", "itertools", "pulldown-cmark", "rustc_arena", diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 1238ce0125a1..19854502cc30 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +indexmap = "2.4.0" itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7912345ec56a..a665dd978990 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -968,7 +968,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); - if parent == self.r.graph_root { + if ident.name != kw::Underscore && parent == self.r.graph_root { let ident = ident.normalize_to_macros_2_0(); if let Some(entry) = self.r.extern_prelude.get(&ident) && expansion != LocalExpnId::ROOT @@ -984,23 +984,29 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { // more details: https://github.com/rust-lang/rust/pull/111761 return; } - let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry { - binding: Cell::new(None), - introduced_by_item: true, - }); - if orig_name.is_some() { - entry.introduced_by_item = true; - } - // Binding from `extern crate` item in source code can replace - // a binding from `--extern` on command line here. - if !entry.is_import() { - entry.binding.set(Some(imported_binding)); - } else if ident.name != kw::Underscore { - self.r.dcx().span_delayed_bug( - item.span, - format!("it had been define the external module '{ident}' multiple times"), - ); - } + + use indexmap::map::Entry; + match self.r.extern_prelude.entry(ident) { + Entry::Occupied(mut occupied) => { + let entry = occupied.get_mut(); + if let Some(old_binding) = entry.binding.get() + && old_binding.is_import() + { + let msg = format!("extern crate `{ident}` already in extern prelude"); + self.r.tcx.dcx().span_delayed_bug(item.span, msg); + } else { + // Binding from `extern crate` item in source code can replace + // a binding from `--extern` on command line here. + entry.binding.set(Some(imported_binding)); + entry.introduced_by_item = orig_name.is_some(); + } + entry + } + Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { + binding: Cell::new(Some(imported_binding)), + introduced_by_item: true, + }), + }; } self.r.define_binding_local(parent, ident, TypeNS, imported_binding); } From a4a5bf5a71bd0c3fb52a28f81d88ce1755b3bc30 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 24 Jul 2025 17:22:54 +0500 Subject: [PATCH 121/242] comments --- .../deref-chain-method-calls-13264.rs} | 2 + ...lts.rs => blocks-without-results-11709.rs} | 2 + .../moved-value-in-thread-loop-12041.rs} | 2 + .../moved-value-in-thread-loop-12041.stderr} | 2 +- ....rs => refcell-borrow-comparison-12033.rs} | 2 + .../string-literal-match-patterns-11869.rs} | 2 + ...d-twice.rs => fnonce-moved-twice-12127.rs} | 2 + .../fnonce-moved-twice-12127.stderr} | 6 +-- ...ind.rs => moved-upvar-mut-rebind-11958.rs} | 2 + .../moved-upvar-mut-rebind-11958.stderr} | 4 +- .../any-trait-object-debug-12744.rs} | 2 + ...r.rs => hashset-connected-border-12860.rs} | 2 + .../vec-macro-in-static-array.rs | 2 + .../vec-macro-in-static-array.stderr} | 2 +- tests/ui/extern/format-message-windows-ffi.rs | 39 --------------- tests/ui/extern/windows-tcb-trash-13259.rs | 49 +++++++++++++++++++ ...rs => anonymous-parameters-trait-13105.rs} | 2 + ...clone.rs => bytes-iterator-clone-12677.rs} | 2 + ...=> iterator-trait-lifetime-error-13058.rs} | 2 + ...terator-trait-lifetime-error-13058.stderr} | 2 +- .../lifetime-inference-destructuring-arg.rs} | 2 + .../matcher-trait-equality-13323.rs} | 2 + ...struct-lifetime-field-assignment-13405.rs} | 2 + .../unsafe-transmute-in-find-11740.rs} | 2 + ...tch.rs => option-result-mismatch-11844.rs} | 2 + .../option-result-mismatch-11844.stderr} | 2 +- ...ption-result-type-param-mismatch-13466.rs} | 2 + ...n-result-type-param-mismatch-13466.stderr} | 4 +- ...s => overeager-sub-match-pruning-13027.rs} | 2 + ...error.rs => slice-move-out-error-12567.rs} | 2 + .../slice-move-out-error-12567.stderr} | 4 +- ....rs => struct-reference-patterns-12285.rs} | 2 + .../encode-symbol-ice-12920.rs} | 2 + .../privacy/private-unit-struct-assignment.rs | 2 + .../private-unit-struct-assignment.stderr} | 6 +-- .../use-in-impl-scope-12729.rs} | 2 + .../reference-clone-nonclone-11820.rs} | 2 + ... => enum-with-static-str-variant-13214.rs} | 2 + ...> default-method-lifetime-params-13204.rs} | 2 + ...pl.rs => fnonce-repro-trait-impl-13434.rs} | 2 + ...nference.rs => partial-type-hint-12909.rs} | 2 + .../function-in-pattern-error-12863.rs} | 2 + .../function-in-pattern-error-12863.stderr} | 2 +- .../isize-usize-mismatch-error.rs | 2 + .../isize-usize-mismatch-error.stderr} | 8 +-- .../unit-type-add-error-11771.rs} | 2 + .../unit-type-add-error-11771.stderr} | 4 +- .../unwrap-or-panic-input-13202.rs} | 2 + 48 files changed, 140 insertions(+), 62 deletions(-) rename tests/ui/{traits/deref-chain-method-calls.rs => autoref-autoderef/deref-chain-method-calls-13264.rs} (93%) rename tests/ui/block-result/{blocks-without-results.rs => blocks-without-results-11709.rs} (91%) rename tests/ui/{threads/moved-value-in-thread-loop.rs => borrowck/moved-value-in-thread-loop-12041.rs} (78%) rename tests/ui/{issues/issue-12041.stderr => borrowck/moved-value-in-thread-loop-12041.stderr} (87%) rename tests/ui/borrowck/{refcell-borrow-comparison.rs => refcell-borrow-comparison-12033.rs} (61%) rename tests/ui/{match/string-literal-match-patterns.rs => borrowck/string-literal-match-patterns-11869.rs} (75%) rename tests/ui/closures/{fnonce-moved-twice.rs => fnonce-moved-twice-12127.rs} (82%) rename tests/ui/{issues/issue-12127.stderr => closures/fnonce-moved-twice-12127.stderr} (62%) rename tests/ui/closures/{moved-upvar-mut-rebind.rs => moved-upvar-mut-rebind-11958.rs} (78%) rename tests/ui/{issues/issue-11958.stderr => closures/moved-upvar-mut-rebind-11958.stderr} (84%) rename tests/ui/{traits/any-trait-object-debug.rs => coercion/any-trait-object-debug-12744.rs} (62%) rename tests/ui/collections/{hashset-connected-border.rs => hashset-connected-border-12860.rs} (95%) rename tests/ui/{issues/issue-13446.stderr => const-generics/vec-macro-in-static-array.stderr} (90%) delete mode 100644 tests/ui/extern/format-message-windows-ffi.rs create mode 100644 tests/ui/extern/windows-tcb-trash-13259.rs rename tests/ui/fn/{anonymous-parameters-trait.rs => anonymous-parameters-trait-13105.rs} (61%) rename tests/ui/iterators/{bytes-iterator-clone.rs => bytes-iterator-clone-12677.rs} (71%) rename tests/ui/lifetimes/{iterator-trait-lifetime-error.rs => iterator-trait-lifetime-error-13058.rs} (90%) rename tests/ui/{issues/issue-13058.stderr => lifetimes/iterator-trait-lifetime-error-13058.stderr} (90%) rename tests/ui/{iterators/phf-map-entries-iterator.rs => lifetimes/lifetime-inference-destructuring-arg.rs} (88%) rename tests/ui/{traits/matcher-trait-equality.rs => lifetimes/matcher-trait-equality-13323.rs} (93%) rename tests/ui/lifetimes/{struct-lifetime-field-assignment.rs => struct-lifetime-field-assignment-13405.rs} (79%) rename tests/ui/{unsafe/unsafe-transmute-in-find.rs => lifetimes/unsafe-transmute-in-find-11740.rs} (87%) rename tests/ui/match/{option-result-mismatch.rs => option-result-mismatch-11844.rs} (69%) rename tests/ui/{issues/issue-11844.stderr => match/option-result-mismatch-11844.stderr} (90%) rename tests/ui/match/{option-result-type-param-mismatch.rs => option-result-type-param-mismatch-13466.rs} (91%) rename tests/ui/{issues/issue-13466.stderr => match/option-result-type-param-mismatch-13466.stderr} (87%) rename tests/ui/match/{guard-literal-range-shadow.rs => overeager-sub-match-pruning-13027.rs} (97%) rename tests/ui/match/{slice-move-out-error.rs => slice-move-out-error-12567.rs} (85%) rename tests/ui/{issues/issue-12567.stderr => match/slice-move-out-error-12567.stderr} (94%) rename tests/ui/match/{struct-reference-patterns.rs => struct-reference-patterns-12285.rs} (73%) rename tests/ui/{panics/explicit-panic-unreachable.rs => parser/encode-symbol-ice-12920.rs} (63%) rename tests/ui/{issues/issue-13407.stderr => privacy/private-unit-struct-assignment.stderr} (79%) rename tests/ui/{imports/use-in-impl-scope.rs => privacy/use-in-impl-scope-12729.rs} (68%) rename tests/ui/{traits/reference-clone-noclone.rs => resolve/reference-clone-nonclone-11820.rs} (73%) rename tests/ui/statics/{enum-with-static-str-variant.rs => enum-with-static-str-variant-13214.rs} (81%) rename tests/ui/traits/{default-method-lifetime-params.rs => default-method-lifetime-params-13204.rs} (88%) rename tests/ui/traits/{fnonce-repro-trait-impl.rs => fnonce-repro-trait-impl-13434.rs} (84%) rename tests/ui/type-inference/{type-collect-inference.rs => partial-type-hint-12909.rs} (86%) rename tests/ui/{match/function-in-pattern-error.rs => typeck/function-in-pattern-error-12863.rs} (71%) rename tests/ui/{issues/issue-12863.stderr => typeck/function-in-pattern-error-12863.stderr} (85%) rename tests/ui/{type-inference => typeck}/isize-usize-mismatch-error.rs (80%) rename tests/ui/{issues/issue-13359.stderr => typeck/isize-usize-mismatch-error.stderr} (85%) rename tests/ui/{type-inference/unit-type-add-error.rs => typeck/unit-type-add-error-11771.rs} (63%) rename tests/ui/{issues/issue-11771.stderr => typeck/unit-type-add-error-11771.stderr} (93%) rename tests/ui/{panics/unwrap-or-panic-input.rs => typeck/unwrap-or-panic-input-13202.rs} (65%) diff --git a/tests/ui/traits/deref-chain-method-calls.rs b/tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs similarity index 93% rename from tests/ui/traits/deref-chain-method-calls.rs rename to tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs index bf4ec388c4fd..f471c1c7eefc 100644 --- a/tests/ui/traits/deref-chain-method-calls.rs +++ b/tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13264 + //@ run-pass #![allow(non_camel_case_types)] #![allow(non_snake_case)] diff --git a/tests/ui/block-result/blocks-without-results.rs b/tests/ui/block-result/blocks-without-results-11709.rs similarity index 91% rename from tests/ui/block-result/blocks-without-results.rs rename to tests/ui/block-result/blocks-without-results-11709.rs index 8a11074eca8e..97ea6f9e19ed 100644 --- a/tests/ui/block-result/blocks-without-results.rs +++ b/tests/ui/block-result/blocks-without-results-11709.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11709 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/threads/moved-value-in-thread-loop.rs b/tests/ui/borrowck/moved-value-in-thread-loop-12041.rs similarity index 78% rename from tests/ui/threads/moved-value-in-thread-loop.rs rename to tests/ui/borrowck/moved-value-in-thread-loop-12041.rs index 091e8fe8b2a6..98f9cdbdef79 100644 --- a/tests/ui/threads/moved-value-in-thread-loop.rs +++ b/tests/ui/borrowck/moved-value-in-thread-loop-12041.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12041 + use std::sync::mpsc::channel; use std::thread; diff --git a/tests/ui/issues/issue-12041.stderr b/tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr similarity index 87% rename from tests/ui/issues/issue-12041.stderr rename to tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr index f2c10b833836..627dd193dade 100644 --- a/tests/ui/issues/issue-12041.stderr +++ b/tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `tx` - --> $DIR/issue-12041.rs:8:22 + --> $DIR/moved-value-in-thread-loop-12041.rs:10:22 | LL | let tx = tx; | ^^ value moved here, in previous iteration of loop diff --git a/tests/ui/borrowck/refcell-borrow-comparison.rs b/tests/ui/borrowck/refcell-borrow-comparison-12033.rs similarity index 61% rename from tests/ui/borrowck/refcell-borrow-comparison.rs rename to tests/ui/borrowck/refcell-borrow-comparison-12033.rs index 0bf6490bafed..de22cedd5b94 100644 --- a/tests/ui/borrowck/refcell-borrow-comparison.rs +++ b/tests/ui/borrowck/refcell-borrow-comparison-12033.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12033 + //@ run-pass use std::cell::RefCell; diff --git a/tests/ui/match/string-literal-match-patterns.rs b/tests/ui/borrowck/string-literal-match-patterns-11869.rs similarity index 75% rename from tests/ui/match/string-literal-match-patterns.rs rename to tests/ui/borrowck/string-literal-match-patterns-11869.rs index dd752227bbec..4c159e457cf1 100644 --- a/tests/ui/match/string-literal-match-patterns.rs +++ b/tests/ui/borrowck/string-literal-match-patterns-11869.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11869 + //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/closures/fnonce-moved-twice.rs b/tests/ui/closures/fnonce-moved-twice-12127.rs similarity index 82% rename from tests/ui/closures/fnonce-moved-twice.rs rename to tests/ui/closures/fnonce-moved-twice-12127.rs index 199d542e816f..369ddcafaabd 100644 --- a/tests/ui/closures/fnonce-moved-twice.rs +++ b/tests/ui/closures/fnonce-moved-twice-12127.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12127 + #![feature(unboxed_closures, tuple_trait)] fn to_fn_once>(f: F) -> F { f } diff --git a/tests/ui/issues/issue-12127.stderr b/tests/ui/closures/fnonce-moved-twice-12127.stderr similarity index 62% rename from tests/ui/issues/issue-12127.stderr rename to tests/ui/closures/fnonce-moved-twice-12127.stderr index 2a6233547ee8..c2e12827527b 100644 --- a/tests/ui/issues/issue-12127.stderr +++ b/tests/ui/closures/fnonce-moved-twice-12127.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `f` - --> $DIR/issue-12127.rs:11:9 + --> $DIR/fnonce-moved-twice-12127.rs:13:9 | LL | f(); | --- `f` moved due to this call @@ -7,11 +7,11 @@ LL | f(); | ^ value used here after move | note: this value implements `FnOnce`, which causes it to be moved when called - --> $DIR/issue-12127.rs:10:9 + --> $DIR/fnonce-moved-twice-12127.rs:12:9 | LL | f(); | ^ - = note: move occurs because `f` has type `{closure@$DIR/issue-12127.rs:8:24: 8:30}`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `{closure@$DIR/fnonce-moved-twice-12127.rs:10:24: 10:30}`, which does not implement the `Copy` trait error: aborting due to 1 previous error diff --git a/tests/ui/closures/moved-upvar-mut-rebind.rs b/tests/ui/closures/moved-upvar-mut-rebind-11958.rs similarity index 78% rename from tests/ui/closures/moved-upvar-mut-rebind.rs rename to tests/ui/closures/moved-upvar-mut-rebind-11958.rs index 9185c5158af6..701dc1a2cefd 100644 --- a/tests/ui/closures/moved-upvar-mut-rebind.rs +++ b/tests/ui/closures/moved-upvar-mut-rebind-11958.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11958 + //@ run-pass // We shouldn't need to rebind a moved upvar as mut if it's already diff --git a/tests/ui/issues/issue-11958.stderr b/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr similarity index 84% rename from tests/ui/issues/issue-11958.stderr rename to tests/ui/closures/moved-upvar-mut-rebind-11958.stderr index 5dca4c2f01d5..b12bbcad9258 100644 --- a/tests/ui/issues/issue-11958.stderr +++ b/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr @@ -1,5 +1,5 @@ warning: value assigned to `x` is never read - --> $DIR/issue-11958.rs:8:36 + --> $DIR/moved-upvar-mut-rebind-11958.rs:10:36 | LL | let _thunk = Box::new(move|| { x = 2; }); | ^ @@ -8,7 +8,7 @@ LL | let _thunk = Box::new(move|| { x = 2; }); = note: `#[warn(unused_assignments)]` on by default warning: unused variable: `x` - --> $DIR/issue-11958.rs:8:36 + --> $DIR/moved-upvar-mut-rebind-11958.rs:10:36 | LL | let _thunk = Box::new(move|| { x = 2; }); | ^ diff --git a/tests/ui/traits/any-trait-object-debug.rs b/tests/ui/coercion/any-trait-object-debug-12744.rs similarity index 62% rename from tests/ui/traits/any-trait-object-debug.rs rename to tests/ui/coercion/any-trait-object-debug-12744.rs index eaf92d413d57..4d981c077ee2 100644 --- a/tests/ui/traits/any-trait-object-debug.rs +++ b/tests/ui/coercion/any-trait-object-debug-12744.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12744 + //@ run-pass fn main() { fn test() -> Box { Box::new(1) } diff --git a/tests/ui/collections/hashset-connected-border.rs b/tests/ui/collections/hashset-connected-border-12860.rs similarity index 95% rename from tests/ui/collections/hashset-connected-border.rs rename to tests/ui/collections/hashset-connected-border-12860.rs index 255f66707937..40185bef7c8d 100644 --- a/tests/ui/collections/hashset-connected-border.rs +++ b/tests/ui/collections/hashset-connected-border-12860.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12860 + //@ run-pass use std::collections::HashSet; diff --git a/tests/ui/const-generics/vec-macro-in-static-array.rs b/tests/ui/const-generics/vec-macro-in-static-array.rs index 9f1fc42774fb..7a81836e2556 100644 --- a/tests/ui/const-generics/vec-macro-in-static-array.rs +++ b/tests/ui/const-generics/vec-macro-in-static-array.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13446 + // Used to cause ICE static VEC: [u32; 256] = vec![]; diff --git a/tests/ui/issues/issue-13446.stderr b/tests/ui/const-generics/vec-macro-in-static-array.stderr similarity index 90% rename from tests/ui/issues/issue-13446.stderr rename to tests/ui/const-generics/vec-macro-in-static-array.stderr index 28c459e6e62c..de21f2274f3a 100644 --- a/tests/ui/issues/issue-13446.stderr +++ b/tests/ui/const-generics/vec-macro-in-static-array.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-13446.rs:3:26 + --> $DIR/vec-macro-in-static-array.rs:5:26 | LL | static VEC: [u32; 256] = vec![]; | ^^^^^^ expected `[u32; 256]`, found `Vec<_>` diff --git a/tests/ui/extern/format-message-windows-ffi.rs b/tests/ui/extern/format-message-windows-ffi.rs deleted file mode 100644 index 381e3f152590..000000000000 --- a/tests/ui/extern/format-message-windows-ffi.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ run-pass - -#[cfg(windows)] -mod imp { - type LPVOID = *mut u8; - type DWORD = u32; - type LPWSTR = *mut u16; - - extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const u8) - -> DWORD; - } - - pub fn test() { - let mut buf: [u16; 50] = [0; 50]; - let ret = unsafe { - FormatMessageW(0x1000, core::ptr::null_mut(), 1, 0x400, - buf.as_mut_ptr(), buf.len() as u32, core::ptr::null()) - }; - // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented - // stacks taking control of pvArbitrary - assert!(ret != 0); - } -} - -#[cfg(not(windows))] -mod imp { - pub fn test() { } -} - -fn main() { - imp::test() -} diff --git a/tests/ui/extern/windows-tcb-trash-13259.rs b/tests/ui/extern/windows-tcb-trash-13259.rs new file mode 100644 index 000000000000..0852e31251ac --- /dev/null +++ b/tests/ui/extern/windows-tcb-trash-13259.rs @@ -0,0 +1,49 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13259 + +//@ run-pass + +#[cfg(windows)] +mod imp { + type LPVOID = *mut u8; + type DWORD = u32; + type LPWSTR = *mut u16; + + extern "system" { + fn FormatMessageW( + flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const u8, + ) -> DWORD; + } + + pub fn test() { + let mut buf: [u16; 50] = [0; 50]; + let ret = unsafe { + FormatMessageW( + 0x1000, + core::ptr::null_mut(), + 1, + 0x400, + buf.as_mut_ptr(), + buf.len() as u32, + core::ptr::null(), + ) + }; + // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented + // stacks taking control of pvArbitrary + assert!(ret != 0); + } +} + +#[cfg(not(windows))] +mod imp { + pub fn test() {} +} + +fn main() { + imp::test() +} diff --git a/tests/ui/fn/anonymous-parameters-trait.rs b/tests/ui/fn/anonymous-parameters-trait-13105.rs similarity index 61% rename from tests/ui/fn/anonymous-parameters-trait.rs rename to tests/ui/fn/anonymous-parameters-trait-13105.rs index d119aa9c788d..171dab15fe71 100644 --- a/tests/ui/fn/anonymous-parameters-trait.rs +++ b/tests/ui/fn/anonymous-parameters-trait-13105.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13105 + //@ edition: 2015 //@ check-pass diff --git a/tests/ui/iterators/bytes-iterator-clone.rs b/tests/ui/iterators/bytes-iterator-clone-12677.rs similarity index 71% rename from tests/ui/iterators/bytes-iterator-clone.rs rename to tests/ui/iterators/bytes-iterator-clone-12677.rs index dbc2dbc85276..cfbb85a3ecba 100644 --- a/tests/ui/iterators/bytes-iterator-clone.rs +++ b/tests/ui/iterators/bytes-iterator-clone-12677.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12677 + //@ run-pass fn main() { diff --git a/tests/ui/lifetimes/iterator-trait-lifetime-error.rs b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs similarity index 90% rename from tests/ui/lifetimes/iterator-trait-lifetime-error.rs rename to tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs index a5806feb720d..6cfe440b43d7 100644 --- a/tests/ui/lifetimes/iterator-trait-lifetime-error.rs +++ b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13058 + use std::ops::Range; trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } diff --git a/tests/ui/issues/issue-13058.stderr b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr similarity index 90% rename from tests/ui/issues/issue-13058.stderr rename to tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr index 4f4108fa1825..e6564e36b215 100644 --- a/tests/ui/issues/issue-13058.stderr +++ b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr @@ -1,5 +1,5 @@ error[E0621]: explicit lifetime required in the type of `cont` - --> $DIR/issue-13058.rs:14:21 + --> $DIR/iterator-trait-lifetime-error-13058.rs:16:21 | LL | let cont_iter = cont.iter(); | ^^^^^^^^^^^ lifetime `'r` required diff --git a/tests/ui/iterators/phf-map-entries-iterator.rs b/tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs similarity index 88% rename from tests/ui/iterators/phf-map-entries-iterator.rs rename to tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs index 5f733e859488..7a019a71d75c 100644 --- a/tests/ui/iterators/phf-map-entries-iterator.rs +++ b/tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13167 + //@ check-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) diff --git a/tests/ui/traits/matcher-trait-equality.rs b/tests/ui/lifetimes/matcher-trait-equality-13323.rs similarity index 93% rename from tests/ui/traits/matcher-trait-equality.rs rename to tests/ui/lifetimes/matcher-trait-equality-13323.rs index 8f334404f9ab..efd56294b398 100644 --- a/tests/ui/traits/matcher-trait-equality.rs +++ b/tests/ui/lifetimes/matcher-trait-equality-13323.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13323 + //@ run-pass struct StrWrap { diff --git a/tests/ui/lifetimes/struct-lifetime-field-assignment.rs b/tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs similarity index 79% rename from tests/ui/lifetimes/struct-lifetime-field-assignment.rs rename to tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs index 80b298d2f37a..9482d89681b5 100644 --- a/tests/ui/lifetimes/struct-lifetime-field-assignment.rs +++ b/tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13405 + //@ check-pass #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/unsafe/unsafe-transmute-in-find.rs b/tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs similarity index 87% rename from tests/ui/unsafe/unsafe-transmute-in-find.rs rename to tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs index c6099c2a0c04..eeecd2e9e404 100644 --- a/tests/ui/unsafe/unsafe-transmute-in-find.rs +++ b/tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11740 + //@ check-pass struct Attr { diff --git a/tests/ui/match/option-result-mismatch.rs b/tests/ui/match/option-result-mismatch-11844.rs similarity index 69% rename from tests/ui/match/option-result-mismatch.rs rename to tests/ui/match/option-result-mismatch-11844.rs index f974a4702960..24a2004134df 100644 --- a/tests/ui/match/option-result-mismatch.rs +++ b/tests/ui/match/option-result-mismatch-11844.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11844 + fn main() { let a = Some(Box::new(1)); match a { diff --git a/tests/ui/issues/issue-11844.stderr b/tests/ui/match/option-result-mismatch-11844.stderr similarity index 90% rename from tests/ui/issues/issue-11844.stderr rename to tests/ui/match/option-result-mismatch-11844.stderr index 9ff66eaef498..8a84b7b8a486 100644 --- a/tests/ui/issues/issue-11844.stderr +++ b/tests/ui/match/option-result-mismatch-11844.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-11844.rs:4:9 + --> $DIR/option-result-mismatch-11844.rs:6:9 | LL | match a { | - this expression has type `Option>` diff --git a/tests/ui/match/option-result-type-param-mismatch.rs b/tests/ui/match/option-result-type-param-mismatch-13466.rs similarity index 91% rename from tests/ui/match/option-result-type-param-mismatch.rs rename to tests/ui/match/option-result-type-param-mismatch-13466.rs index 78ce4c1d2f60..05dbdfdee0e3 100644 --- a/tests/ui/match/option-result-type-param-mismatch.rs +++ b/tests/ui/match/option-result-type-param-mismatch-13466.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13466 + // Regression test for #13466 //@ dont-require-annotations: NOTE diff --git a/tests/ui/issues/issue-13466.stderr b/tests/ui/match/option-result-type-param-mismatch-13466.stderr similarity index 87% rename from tests/ui/issues/issue-13466.stderr rename to tests/ui/match/option-result-type-param-mismatch-13466.stderr index 68a555a16260..b0cf1591f5ee 100644 --- a/tests/ui/issues/issue-13466.stderr +++ b/tests/ui/match/option-result-type-param-mismatch-13466.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-13466.rs:10:9 + --> $DIR/option-result-type-param-mismatch-13466.rs:12:9 | LL | let _x: usize = match Some(1) { | ------- this expression has type `Option<{integer}>` @@ -10,7 +10,7 @@ LL | Ok(u) => u, found enum `Result<_, _>` error[E0308]: mismatched types - --> $DIR/issue-13466.rs:16:9 + --> $DIR/option-result-type-param-mismatch-13466.rs:18:9 | LL | let _x: usize = match Some(1) { | ------- this expression has type `Option<{integer}>` diff --git a/tests/ui/match/guard-literal-range-shadow.rs b/tests/ui/match/overeager-sub-match-pruning-13027.rs similarity index 97% rename from tests/ui/match/guard-literal-range-shadow.rs rename to tests/ui/match/overeager-sub-match-pruning-13027.rs index fbd1d75067b5..c4feb697f7d1 100644 --- a/tests/ui/match/guard-literal-range-shadow.rs +++ b/tests/ui/match/overeager-sub-match-pruning-13027.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13027 + //@ run-pass // Tests that match expression handles overlapped literal and range diff --git a/tests/ui/match/slice-move-out-error.rs b/tests/ui/match/slice-move-out-error-12567.rs similarity index 85% rename from tests/ui/match/slice-move-out-error.rs rename to tests/ui/match/slice-move-out-error-12567.rs index 1b2a37de4753..3f9bf9c76cf3 100644 --- a/tests/ui/match/slice-move-out-error.rs +++ b/tests/ui/match/slice-move-out-error-12567.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12567 + fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { match (l1, l2) { //~^ ERROR: cannot move out of type `[T]`, a non-copy slice diff --git a/tests/ui/issues/issue-12567.stderr b/tests/ui/match/slice-move-out-error-12567.stderr similarity index 94% rename from tests/ui/issues/issue-12567.stderr rename to tests/ui/match/slice-move-out-error-12567.stderr index 0b19299ece3e..ab5377d47013 100644 --- a/tests/ui/issues/issue-12567.stderr +++ b/tests/ui/match/slice-move-out-error-12567.stderr @@ -1,5 +1,5 @@ error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:2:11 + --> $DIR/slice-move-out-error-12567.rs:4:11 | LL | match (l1, l2) { | ^^^^^^^^ cannot move out of here @@ -23,7 +23,7 @@ LL + (&[hd1, ..], [hd2, ..]) | error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:2:11 + --> $DIR/slice-move-out-error-12567.rs:4:11 | LL | match (l1, l2) { | ^^^^^^^^ cannot move out of here diff --git a/tests/ui/match/struct-reference-patterns.rs b/tests/ui/match/struct-reference-patterns-12285.rs similarity index 73% rename from tests/ui/match/struct-reference-patterns.rs rename to tests/ui/match/struct-reference-patterns-12285.rs index fe199147128b..246e230b0de7 100644 --- a/tests/ui/match/struct-reference-patterns.rs +++ b/tests/ui/match/struct-reference-patterns-12285.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12285 + //@ run-pass struct S; diff --git a/tests/ui/panics/explicit-panic-unreachable.rs b/tests/ui/parser/encode-symbol-ice-12920.rs similarity index 63% rename from tests/ui/panics/explicit-panic-unreachable.rs rename to tests/ui/parser/encode-symbol-ice-12920.rs index f3b1b643c45a..87389c0ffb42 100644 --- a/tests/ui/panics/explicit-panic-unreachable.rs +++ b/tests/ui/parser/encode-symbol-ice-12920.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12920 + //@ run-fail //@ error-pattern:explicit panic //@ needs-subprocess diff --git a/tests/ui/privacy/private-unit-struct-assignment.rs b/tests/ui/privacy/private-unit-struct-assignment.rs index 7794be37b850..b8e1c4ecb188 100644 --- a/tests/ui/privacy/private-unit-struct-assignment.rs +++ b/tests/ui/privacy/private-unit-struct-assignment.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13407 + mod A { struct C; } diff --git a/tests/ui/issues/issue-13407.stderr b/tests/ui/privacy/private-unit-struct-assignment.stderr similarity index 79% rename from tests/ui/issues/issue-13407.stderr rename to tests/ui/privacy/private-unit-struct-assignment.stderr index ac2eb6581fe2..8c36a08846d8 100644 --- a/tests/ui/issues/issue-13407.stderr +++ b/tests/ui/privacy/private-unit-struct-assignment.stderr @@ -1,17 +1,17 @@ error[E0603]: unit struct `C` is private - --> $DIR/issue-13407.rs:6:8 + --> $DIR/private-unit-struct-assignment.rs:8:8 | LL | A::C = 1; | ^ private unit struct | note: the unit struct `C` is defined here - --> $DIR/issue-13407.rs:2:5 + --> $DIR/private-unit-struct-assignment.rs:4:5 | LL | struct C; | ^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/issue-13407.rs:6:5 + --> $DIR/private-unit-struct-assignment.rs:8:5 | LL | struct C; | -------- unit struct defined here diff --git a/tests/ui/imports/use-in-impl-scope.rs b/tests/ui/privacy/use-in-impl-scope-12729.rs similarity index 68% rename from tests/ui/imports/use-in-impl-scope.rs rename to tests/ui/privacy/use-in-impl-scope-12729.rs index 4d45846bc608..58fe042beece 100644 --- a/tests/ui/imports/use-in-impl-scope.rs +++ b/tests/ui/privacy/use-in-impl-scope-12729.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12729 + //@ edition: 2015 //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/traits/reference-clone-noclone.rs b/tests/ui/resolve/reference-clone-nonclone-11820.rs similarity index 73% rename from tests/ui/traits/reference-clone-noclone.rs rename to tests/ui/resolve/reference-clone-nonclone-11820.rs index ada844f8ee12..74dad96da94e 100644 --- a/tests/ui/traits/reference-clone-noclone.rs +++ b/tests/ui/resolve/reference-clone-nonclone-11820.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11820 + //@ run-pass #![allow(noop_method_call)] diff --git a/tests/ui/statics/enum-with-static-str-variant.rs b/tests/ui/statics/enum-with-static-str-variant-13214.rs similarity index 81% rename from tests/ui/statics/enum-with-static-str-variant.rs rename to tests/ui/statics/enum-with-static-str-variant-13214.rs index 8140ec943a01..1db37da632de 100644 --- a/tests/ui/statics/enum-with-static-str-variant.rs +++ b/tests/ui/statics/enum-with-static-str-variant-13214.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13214 + //@ build-pass #![allow(dead_code)] // defining static with struct that contains enum diff --git a/tests/ui/traits/default-method-lifetime-params.rs b/tests/ui/traits/default-method-lifetime-params-13204.rs similarity index 88% rename from tests/ui/traits/default-method-lifetime-params.rs rename to tests/ui/traits/default-method-lifetime-params-13204.rs index 01362f6fe61d..cdf34ab773c1 100644 --- a/tests/ui/traits/default-method-lifetime-params.rs +++ b/tests/ui/traits/default-method-lifetime-params-13204.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13204 + //@ run-pass #![allow(unused_mut)] // Test that when instantiating trait default methods, typeck handles diff --git a/tests/ui/traits/fnonce-repro-trait-impl.rs b/tests/ui/traits/fnonce-repro-trait-impl-13434.rs similarity index 84% rename from tests/ui/traits/fnonce-repro-trait-impl.rs rename to tests/ui/traits/fnonce-repro-trait-impl-13434.rs index caf7b6323933..61d5a1d74aee 100644 --- a/tests/ui/traits/fnonce-repro-trait-impl.rs +++ b/tests/ui/traits/fnonce-repro-trait-impl-13434.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13434 + //@ run-pass #[derive(Debug)] struct MyStruct; diff --git a/tests/ui/type-inference/type-collect-inference.rs b/tests/ui/type-inference/partial-type-hint-12909.rs similarity index 86% rename from tests/ui/type-inference/type-collect-inference.rs rename to tests/ui/type-inference/partial-type-hint-12909.rs index f2c33806aae8..d7017f451e32 100644 --- a/tests/ui/type-inference/type-collect-inference.rs +++ b/tests/ui/type-inference/partial-type-hint-12909.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12909 + //@ run-pass #![allow(unused_variables)] diff --git a/tests/ui/match/function-in-pattern-error.rs b/tests/ui/typeck/function-in-pattern-error-12863.rs similarity index 71% rename from tests/ui/match/function-in-pattern-error.rs rename to tests/ui/typeck/function-in-pattern-error-12863.rs index 1ac1c3d818e5..d2fa25556584 100644 --- a/tests/ui/match/function-in-pattern-error.rs +++ b/tests/ui/typeck/function-in-pattern-error-12863.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12863 + mod foo { pub fn bar() {} } fn main() { diff --git a/tests/ui/issues/issue-12863.stderr b/tests/ui/typeck/function-in-pattern-error-12863.stderr similarity index 85% rename from tests/ui/issues/issue-12863.stderr rename to tests/ui/typeck/function-in-pattern-error-12863.stderr index 95d4a704e72d..f28874b5d485 100644 --- a/tests/ui/issues/issue-12863.stderr +++ b/tests/ui/typeck/function-in-pattern-error-12863.stderr @@ -1,5 +1,5 @@ error[E0532]: expected unit struct, unit variant or constant, found function `foo::bar` - --> $DIR/issue-12863.rs:5:9 + --> $DIR/function-in-pattern-error-12863.rs:7:9 | LL | foo::bar => {} | ^^^^^^^^ not a unit struct, unit variant or constant diff --git a/tests/ui/type-inference/isize-usize-mismatch-error.rs b/tests/ui/typeck/isize-usize-mismatch-error.rs similarity index 80% rename from tests/ui/type-inference/isize-usize-mismatch-error.rs rename to tests/ui/typeck/isize-usize-mismatch-error.rs index 5d31d7f861c6..2fb5cf489c03 100644 --- a/tests/ui/type-inference/isize-usize-mismatch-error.rs +++ b/tests/ui/typeck/isize-usize-mismatch-error.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13359 + //@ dont-require-annotations: NOTE fn foo(_s: i16) { } diff --git a/tests/ui/issues/issue-13359.stderr b/tests/ui/typeck/isize-usize-mismatch-error.stderr similarity index 85% rename from tests/ui/issues/issue-13359.stderr rename to tests/ui/typeck/isize-usize-mismatch-error.stderr index 91f5de8e8f3a..d5724665a03c 100644 --- a/tests/ui/issues/issue-13359.stderr +++ b/tests/ui/typeck/isize-usize-mismatch-error.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-13359.rs:8:9 + --> $DIR/isize-usize-mismatch-error.rs:10:9 | LL | foo(1*(1 as isize)); | --- ^^^^^^^^^^^^^^ expected `i16`, found `isize` @@ -7,7 +7,7 @@ LL | foo(1*(1 as isize)); | arguments to this function are incorrect | note: function defined here - --> $DIR/issue-13359.rs:3:4 + --> $DIR/isize-usize-mismatch-error.rs:5:4 | LL | fn foo(_s: i16) { } | ^^^ ------- @@ -17,7 +17,7 @@ LL | foo((1*(1 as isize)).try_into().unwrap()); | + +++++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/issue-13359.rs:12:9 + --> $DIR/isize-usize-mismatch-error.rs:14:9 | LL | bar(1*(1 as usize)); | --- ^^^^^^^^^^^^^^ expected `u32`, found `usize` @@ -25,7 +25,7 @@ LL | bar(1*(1 as usize)); | arguments to this function are incorrect | note: function defined here - --> $DIR/issue-13359.rs:5:4 + --> $DIR/isize-usize-mismatch-error.rs:7:4 | LL | fn bar(_s: u32) { } | ^^^ ------- diff --git a/tests/ui/type-inference/unit-type-add-error.rs b/tests/ui/typeck/unit-type-add-error-11771.rs similarity index 63% rename from tests/ui/type-inference/unit-type-add-error.rs rename to tests/ui/typeck/unit-type-add-error-11771.rs index c69cd1e79e37..d009f50f4b92 100644 --- a/tests/ui/type-inference/unit-type-add-error.rs +++ b/tests/ui/typeck/unit-type-add-error-11771.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11771 + fn main() { let x = (); 1 + diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/typeck/unit-type-add-error-11771.stderr similarity index 93% rename from tests/ui/issues/issue-11771.stderr rename to tests/ui/typeck/unit-type-add-error-11771.stderr index 5603dc18b635..155cc0935245 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/typeck/unit-type-add-error-11771.stderr @@ -1,5 +1,5 @@ error[E0277]: cannot add `()` to `{integer}` - --> $DIR/issue-11771.rs:3:7 + --> $DIR/unit-type-add-error-11771.rs:5:7 | LL | 1 + | ^ no implementation for `{integer} + ()` @@ -17,7 +17,7 @@ LL | 1 + and 56 others error[E0277]: cannot add `()` to `{integer}` - --> $DIR/issue-11771.rs:8:7 + --> $DIR/unit-type-add-error-11771.rs:10:7 | LL | 1 + | ^ no implementation for `{integer} + ()` diff --git a/tests/ui/panics/unwrap-or-panic-input.rs b/tests/ui/typeck/unwrap-or-panic-input-13202.rs similarity index 65% rename from tests/ui/panics/unwrap-or-panic-input.rs rename to tests/ui/typeck/unwrap-or-panic-input-13202.rs index 99ffba3fba51..29833a727c55 100644 --- a/tests/ui/panics/unwrap-or-panic-input.rs +++ b/tests/ui/typeck/unwrap-or-panic-input-13202.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13202 + //@ run-fail //@ error-pattern:bad input //@ needs-subprocess From 2f7a2fa00fd06f9a1dcd51891b11a255cbf9d32b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 31 Jul 2025 19:33:12 +0300 Subject: [PATCH 122/242] resolve: Do not add erroneous names to extern prelude --- compiler/rustc_resolve/src/lib.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a70ae4fd57a0..17ca2ef7743d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1487,13 +1487,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxIndexMap> = tcx + let mut extern_prelude: FxIndexMap<_, _> = tcx .sess .opts .externs .iter() - .filter(|(_, entry)| entry.add_prelude) - .map(|(name, _)| (Ident::from_str(name), Default::default())) + .filter_map(|(name, entry)| { + // Make sure `self`, `super`, `_` etc do not get into extern prelude. + // FIXME: reject `--extern self` and similar in option parsing instead. + if entry.add_prelude + && let name = Symbol::intern(name) + && name.can_be_raw() + { + Some((Ident::with_dummy_span(name), Default::default())) + } else { + None + } + }) .collect(); if !attr::contains_name(attrs, sym::no_core) { @@ -2168,11 +2178,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option> { - if ident.is_path_segment_keyword() { - // Make sure `self`, `super` etc produce an error when passed to here. - return None; - } - let norm_ident = ident.normalize_to_macros_2_0(); let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| { Some(if let Some(binding) = entry.binding.get() { From 73096965fbac485a83033516cf61645889700a71 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 31 Jul 2025 19:51:51 +0300 Subject: [PATCH 123/242] resolve: Avoid double table lookup in `extern_prelude_get` Do not write dummy bindings to extern prelude. Use more precise `Used::Scope` while recording use and remove now redundant `introduced_by_item` check. --- compiler/rustc_resolve/src/lib.rs | 51 ++++++++++++++++++------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 17ca2ef7743d..bdac1b4675a0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2178,35 +2178,42 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option> { - let norm_ident = ident.normalize_to_macros_2_0(); - let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| { - Some(if let Some(binding) = entry.binding.get() { + let mut record_use = None; + let entry = self.extern_prelude.get(&ident.normalize_to_macros_2_0()); + let binding = entry.and_then(|entry| match entry.binding.get() { + Some(binding) if binding.is_import() => { if finalize { - if !entry.is_import() { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); - } else if entry.introduced_by_item { - self.record_use(ident, binding, Used::Other); - } + record_use = Some(binding); } - binding - } else { + Some(binding) + } + Some(binding) => { + if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + } + Some(binding) + } + None => { let crate_id = if finalize { - let Some(crate_id) = - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - else { - return Some(self.dummy_binding); - }; - crate_id + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)? + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) }; - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) - }) + match crate_id { + Some(crate_id) => { + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); + let binding = + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); + entry.binding.set(Some(binding)); + Some(binding) + } + None => finalize.then_some(self.dummy_binding), + } + } }); - if let Some(entry) = self.extern_prelude.get(&norm_ident) { - entry.binding.set(binding); + if let Some(binding) = record_use { + self.record_use(ident, binding, Used::Scope); } binding From d525e79157e32abc510714dd32628c9c155f2997 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 18:17:15 +0000 Subject: [PATCH 124/242] Stall coroutines based off of ty::Coroutine, not ty::CoroutineWitness --- .../src/solve/trait_goals.rs | 11 +- .../src/solve/fulfill.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 60 +++--- .../src/traits/select/mod.rs | 2 +- compiler/rustc_type_ir/src/flags.rs | 11 +- tests/ui/async-await/issue-70818.rs | 1 + tests/ui/async-await/issue-70818.stderr | 23 ++- tests/ui/async-await/issue-86507.stderr | 2 +- tests/ui/coroutine/clone-impl-async.rs | 6 +- tests/ui/coroutine/clone-impl-async.stderr | 180 ++++++++---------- tests/ui/coroutine/clone-impl-static.stderr | 12 +- tests/ui/coroutine/clone-impl.rs | 1 + tests/ui/coroutine/clone-impl.stderr | 88 ++++----- tests/ui/coroutine/ref-upvar-not-send.stderr | 14 +- .../ui/impl-trait/issues/issue-55872-3.stderr | 15 +- 15 files changed, 218 insertions(+), 210 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 650b85d99d2c..31991565b0dc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -229,7 +229,7 @@ where } // We need to make sure to stall any coroutines we are inferring to avoid query cycles. - if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) { return cand; } @@ -294,7 +294,7 @@ where } // We need to make sure to stall any coroutines we are inferring to avoid query cycles. - if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) { return cand; } @@ -1432,11 +1432,8 @@ where self.merge_trait_candidates(candidates) } - fn try_stall_coroutine_witness( - &mut self, - self_ty: I::Ty, - ) -> Option, NoSolution>> { - if let ty::CoroutineWitness(def_id, _) = self_ty.kind() { + fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option, NoSolution>> { + if let ty::Coroutine(def_id, _) = self_ty.kind() { match self.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 01bdae7435d7..3f628d806620 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -355,7 +355,7 @@ impl<'tcx> TypeVisitor> for StalledOnCoroutines<'tcx> { return ControlFlow::Continue(()); } - if let ty::CoroutineWitness(def_id, _) = *ty.kind() + if let ty::Coroutine(def_id, _) = *ty.kind() && def_id.as_local().is_some_and(|def_id| self.stalled_coroutines.contains(&def_id)) { ControlFlow::Break(()) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2c7089507a89..af6dafb30629 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -794,18 +794,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The auto impl might apply; we don't know. candidates.ambiguous = true; } - ty::Coroutine(coroutine_def_id, _) - if self.tcx().is_lang_item(def_id, LangItem::Unpin) => - { - match self.tcx().coroutine_movability(coroutine_def_id) { - hir::Movability::Static => { - // Immovable coroutines are never `Unpin`, so - // suppress the normal auto-impl candidate for it. + ty::Coroutine(coroutine_def_id, _) => { + if self.tcx().is_lang_item(def_id, LangItem::Unpin) { + match self.tcx().coroutine_movability(coroutine_def_id) { + hir::Movability::Static => { + // Immovable coroutines are never `Unpin`, so + // suppress the normal auto-impl candidate for it. + } + hir::Movability::Movable => { + // Movable coroutines are always `Unpin`, so add an + // unconditional builtin candidate with no sub-obligations. + candidates.vec.push(BuiltinCandidate); + } } - hir::Movability::Movable => { - // Movable coroutines are always `Unpin`, so add an - // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate); + } else { + if self.should_stall_coroutine(coroutine_def_id) { + candidates.ambiguous = true; + } else { + // Coroutines implement all other auto traits normally. + candidates.vec.push(AutoImplCandidate); } } } @@ -842,12 +849,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::CoroutineWitness(def_id, _) => { - if self.should_stall_coroutine_witness(def_id) { - candidates.ambiguous = true; - } else { - candidates.vec.push(AutoImplCandidate); - } + ty::CoroutineWitness(..) => { + candidates.vec.push(AutoImplCandidate); } ty::Bool @@ -866,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::FnPtr(..) | ty::Closure(..) | ty::CoroutineClosure(..) - | ty::Coroutine(..) | ty::Never | ty::Tuple(_) | ty::UnsafeBinder(_) => { @@ -1153,6 +1155,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Ref(_, _, hir::Mutability::Mut) => {} ty::Coroutine(coroutine_def_id, args) => { + if self.should_stall_coroutine(coroutine_def_id) { + candidates.ambiguous = true; + return; + } + match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => {} hir::Movability::Movable => { @@ -1194,12 +1201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::CoroutineWitness(coroutine_def_id, _) => { - if self.should_stall_coroutine_witness(coroutine_def_id) { - candidates.ambiguous = true; - } else { - candidates.vec.push(SizedCandidate); - } + ty::CoroutineWitness(..) => { + candidates.vec.push(SizedCandidate); } // Fallback to whatever user-defined impls or param-env clauses exist in this case. @@ -1238,7 +1241,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(..) | ty::Char | ty::Ref(..) - | ty::Coroutine(..) | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1247,14 +1249,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(SizedCandidate); } - ty::CoroutineWitness(coroutine_def_id, _) => { - if self.should_stall_coroutine_witness(coroutine_def_id) { + ty::Coroutine(coroutine_def_id, _) => { + if self.should_stall_coroutine(coroutine_def_id) { candidates.ambiguous = true; } else { candidates.vec.push(SizedCandidate); } } + ty::CoroutineWitness(..) => { + candidates.vec.push(SizedCandidate); + } + // Conditionally `Sized`. ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { candidates.vec.push(SizedCandidate); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d7c3543cb3fd..e893add81c8f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2841,7 +2841,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } - fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool { + fn should_stall_coroutine(&self, def_id: DefId) -> bool { match self.infcx.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index d7b9e0ca340a..23b7f55fbbe5 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -131,10 +131,7 @@ bitflags::bitflags! { /// Does this have any binders with bound vars (e.g. that need to be anonymized)? const HAS_BINDER_VARS = 1 << 23; - /// Does this type have any coroutine witnesses in it? - // FIXME: This should probably be changed to track whether the type has any - // *coroutines* in it, though this will happen if we remove coroutine witnesses - // altogether. + /// Does this type have any coroutines in it? const HAS_TY_CORO = 1 << 24; } } @@ -246,11 +243,13 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_TY_PARAM); } - ty::Closure(_, args) | ty::Coroutine(_, args) | ty::CoroutineClosure(_, args) => { + ty::Closure(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) => { self.add_args(args.as_slice()); } - ty::CoroutineWitness(_, args) => { + ty::Coroutine(_, args) => { self.add_flags(TypeFlags::HAS_TY_CORO); self.add_args(args.as_slice()); } diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs index bc181de8d925..c11332fe7d84 100644 --- a/tests/ui/async-await/issue-70818.rs +++ b/tests/ui/async-await/issue-70818.rs @@ -4,6 +4,7 @@ use std::future::Future; fn foo(ty: T, ty1: U) -> impl Future + Send { //~^ ERROR future cannot be sent between threads safely async { (ty, ty1) } + //~^ ERROR future cannot be sent between threads safely } fn main() {} diff --git a/tests/ui/async-await/issue-70818.stderr b/tests/ui/async-await/issue-70818.stderr index 8de6a825042b..07fd20cdd77e 100644 --- a/tests/ui/async-await/issue-70818.stderr +++ b/tests/ui/async-await/issue-70818.stderr @@ -1,3 +1,24 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:6:5 + | +LL | async { (ty, ty1) } + | ^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> $DIR/issue-70818.rs:6:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` +note: required by a bound in an opaque type + --> $DIR/issue-70818.rs:4:69 + | +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | ^^^^ +help: consider restricting type parameter `U` with trait `Send` + | +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | +++++++++++++++++++ + error: future cannot be sent between threads safely --> $DIR/issue-70818.rs:4:38 | @@ -14,5 +35,5 @@ help: consider restricting type parameter `U` with trait `Send` LL | fn foo(ty: T, ty1: U) -> impl Future + Send { | +++++++++++++++++++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-86507.stderr b/tests/ui/async-await/issue-86507.stderr index 6385a8c975e3..c71801dcfc85 100644 --- a/tests/ui/async-await/issue-86507.stderr +++ b/tests/ui/async-await/issue-86507.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `Pin>` to `Pin + Send + 'async_trait)>>` + = note: required for the cast from `Pin>` to `Pin + Send>>` help: consider further restricting type parameter `T` with trait `Sync` | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/coroutine/clone-impl-async.rs b/tests/ui/coroutine/clone-impl-async.rs index 2794b167aa20..4e2b26d02957 100644 --- a/tests/ui/coroutine/clone-impl-async.rs +++ b/tests/ui/coroutine/clone-impl-async.rs @@ -9,7 +9,7 @@ use std::future::ready; struct NonClone; -fn main() { +fn local() { let inner_non_clone = async { let non_clone = NonClone; let () = ready(()).await; @@ -34,7 +34,9 @@ fn main() { //~^ ERROR : Copy` is not satisfied check_clone(&maybe_copy_clone); //~^ ERROR : Clone` is not satisfied +} +fn non_local() { let inner_non_clone_fn = the_inner_non_clone_fn(); check_copy(&inner_non_clone_fn); //~^ ERROR : Copy` is not satisfied @@ -69,3 +71,5 @@ async fn the_maybe_copy_clone_fn() {} fn check_copy(_x: &T) {} fn check_clone(_x: &T) {} + +fn main() {} diff --git a/tests/ui/coroutine/clone-impl-async.stderr b/tests/ui/coroutine/clone-impl-async.stderr index 62bcce2fbcbe..319a5ed3d8d3 100644 --- a/tests/ui/coroutine/clone-impl-async.stderr +++ b/tests/ui/coroutine/clone-impl-async.stderr @@ -1,89 +1,5 @@ -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:18:16 - | -LL | check_copy(&inner_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:20:17 - | -LL | check_clone(&inner_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 - | -LL | fn check_clone(_x: &T) {} - | ^^^^^ required by this bound in `check_clone` - -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:27:16 - | -LL | check_copy(&outer_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:29:17 - | -LL | check_clone(&outer_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 - | -LL | fn check_clone(_x: &T) {} - | ^^^^^ required by this bound in `check_clone` - -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:33:16 - | -LL | check_copy(&maybe_copy_clone); - | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:35:17 - | -LL | check_clone(&maybe_copy_clone); - | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 - | -LL | fn check_clone(_x: &T) {} - | ^^^^^ required by this bound in `check_clone` - error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:39:16 + --> $DIR/clone-impl-async.rs:41:16 | LL | check_copy(&inner_non_clone_fn); | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` @@ -91,13 +7,13 @@ LL | check_copy(&inner_non_clone_fn); | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` error[E0277]: the trait bound `impl Future: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:41:17 + --> $DIR/clone-impl-async.rs:43:17 | LL | check_clone(&inner_non_clone_fn); | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` @@ -105,13 +21,13 @@ LL | check_clone(&inner_non_clone_fn); | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:45:16 + --> $DIR/clone-impl-async.rs:47:16 | LL | check_copy(&outer_non_clone_fn); | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` @@ -119,13 +35,13 @@ LL | check_copy(&outer_non_clone_fn); | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` error[E0277]: the trait bound `impl Future: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:47:17 + --> $DIR/clone-impl-async.rs:49:17 | LL | check_clone(&outer_non_clone_fn); | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` @@ -133,13 +49,13 @@ LL | check_clone(&outer_non_clone_fn); | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:51:16 + --> $DIR/clone-impl-async.rs:53:16 | LL | check_copy(&maybe_copy_clone_fn); | ---------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` @@ -147,13 +63,13 @@ LL | check_copy(&maybe_copy_clone_fn); | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` error[E0277]: the trait bound `impl Future: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:53:17 + --> $DIR/clone-impl-async.rs:55:17 | LL | check_clone(&maybe_copy_clone_fn); | ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` @@ -161,7 +77,79 @@ LL | check_clone(&maybe_copy_clone_fn); | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:18:5 + | +LL | check_copy(&inner_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:20:5 + | +LL | check_clone(&inner_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:73:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:27:5 + | +LL | check_copy(&outer_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:29:5 + | +LL | check_clone(&outer_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:73:19 + | +LL | fn check_clone(_x: &T) {} + | ^^^^^ required by this bound in `check_clone` + +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:33:5 + | +LL | check_copy(&maybe_copy_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` + | +note: required by a bound in `check_copy` + --> $DIR/clone-impl-async.rs:72:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:35:5 + | +LL | check_clone(&maybe_copy_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` + | +note: required by a bound in `check_clone` + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` diff --git a/tests/ui/coroutine/clone-impl-static.stderr b/tests/ui/coroutine/clone-impl-static.stderr index 9fb71fd5fd01..4df6b9759c3f 100644 --- a/tests/ui/coroutine/clone-impl-static.stderr +++ b/tests/ui/coroutine/clone-impl-static.stderr @@ -1,10 +1,8 @@ error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}: Copy` is not satisfied - --> $DIR/clone-impl-static.rs:14:16 + --> $DIR/clone-impl-static.rs:14:5 | LL | check_copy(&generator); - | ---------- ^^^^^^^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` | note: required by a bound in `check_copy` --> $DIR/clone-impl-static.rs:20:18 @@ -13,12 +11,10 @@ LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}: Clone` is not satisfied - --> $DIR/clone-impl-static.rs:16:17 + --> $DIR/clone-impl-static.rs:16:5 | LL | check_clone(&generator); - | ----------- ^^^^^^^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` | note: required by a bound in `check_clone` --> $DIR/clone-impl-static.rs:21:19 diff --git a/tests/ui/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs index e528f031d526..9e04e256fc11 100644 --- a/tests/ui/coroutine/clone-impl.rs +++ b/tests/ui/coroutine/clone-impl.rs @@ -42,6 +42,7 @@ fn test3_upvars() { let clonable_0: Vec = Vec::new(); let gen_clone_0 = #[coroutine] move || { + yield; drop(clonable_0); }; check_copy(&gen_clone_0); diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index 714e5aa3d9e3..f316902a42d0 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -1,59 +1,81 @@ error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` - --> $DIR/clone-impl.rs:47:16 + --> $DIR/clone-impl.rs:48:5 | LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:45:14 + --> $DIR/clone-impl.rs:46:14 | LL | drop(clonable_0); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 + --> $DIR/clone-impl.rs:92:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` - --> $DIR/clone-impl.rs:73:16 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:55:5: 55:12}` + --> $DIR/clone-impl.rs:60:5 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:55:5: 55:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:55:5: 55:12}`, the trait `Copy` is not implemented for `Vec` + | +note: coroutine does not implement `Copy` as this value is used across a yield + --> $DIR/clone-impl.rs:57:9 + | +LL | let v = vec!['a']; + | - has type `Vec` which does not implement `Copy` +LL | yield; + | ^^^^^ yield occurs here, with `v` maybe used later +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:92:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:68:5: 68:12}` + --> $DIR/clone-impl.rs:74:5 + | +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:68:5: 68:12}` +... +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:68:5: 68:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:71:14 + --> $DIR/clone-impl.rs:72:14 | LL | drop(clonable_1); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 + --> $DIR/clone-impl.rs:92:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` - --> $DIR/clone-impl.rs:85:16 +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` + --> $DIR/clone-impl.rs:86:5 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Copy` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}`, the trait `Copy` is not implemented for `NonClone` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:83:14 + --> $DIR/clone-impl.rs:84:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 + --> $DIR/clone-impl.rs:92:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` @@ -63,22 +85,22 @@ LL + #[derive(Copy)] LL | struct NonClone; | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` - --> $DIR/clone-impl.rs:87:17 +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` + --> $DIR/clone-impl.rs:88:5 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Clone` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}`, the trait `Clone` is not implemented for `NonClone` | note: captured value does not implement `Clone` - --> $DIR/clone-impl.rs:83:14 + --> $DIR/clone-impl.rs:84:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` note: required by a bound in `check_clone` - --> $DIR/clone-impl.rs:92:19 + --> $DIR/clone-impl.rs:93:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` @@ -88,28 +110,6 @@ LL + #[derive(Clone)] LL | struct NonClone; | -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` - --> $DIR/clone-impl.rs:59:5 - | -LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` -... -LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`, the trait `Copy` is not implemented for `Vec` - | -note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:56:9 - | -LL | let v = vec!['a']; - | - has type `Vec` which does not implement `Copy` -LL | yield; - | ^^^^^ yield occurs here, with `v` maybe used later -note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr index 892b5d261c2b..3a5e8ec4dab0 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.stderr +++ b/tests/ui/coroutine/ref-upvar-not-send.stderr @@ -1,14 +1,13 @@ error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:15:30 + --> $DIR/ref-upvar-not-send.rs:15:5 | -LL | assert_send(#[coroutine] move || { - | ______________________________^ +LL | / assert_send(#[coroutine] move || { LL | | LL | | LL | | yield; LL | | let _x = x; LL | | }); - | |_____^ coroutine is not `Send` + | |______^ coroutine is not `Send` | = help: the trait `Sync` is not implemented for `*mut ()` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` @@ -23,16 +22,15 @@ LL | fn assert_send(_: T) {} | ^^^^ required by this bound in `assert_send` error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:23:30 + --> $DIR/ref-upvar-not-send.rs:23:5 | -LL | assert_send(#[coroutine] move || { - | ______________________________^ +LL | / assert_send(#[coroutine] move || { LL | | LL | | LL | | yield; LL | | let _y = y; LL | | }); - | |_____^ coroutine is not `Send` + | |______^ coroutine is not `Send` | = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()` note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send` diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr index ce2dd7f02b4c..b7711e47468e 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr @@ -1,12 +1,3 @@ -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied - --> $DIR/issue-55872-3.rs:14:20 - | -LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` -... -LL | async {} - | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` here - error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias --> $DIR/issue-55872-3.rs:14:20 | @@ -21,6 +12,12 @@ LL | fn foo() -> Self::E { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied + --> $DIR/issue-55872-3.rs:14:20 + | +LL | fn foo() -> Self::E { + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. From e58e6f857f1335ef2436cb7bf3a4a55ddfc79387 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 31 Jul 2025 20:33:33 +0300 Subject: [PATCH 125/242] resolve: Cleanup some uses of extern prelude in diagnostics --- compiler/rustc_resolve/src/diagnostics.rs | 4 ++-- compiler/rustc_resolve/src/late/diagnostics.rs | 17 ++++------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 3af69b28780d..c80f8106049a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1098,7 +1098,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::ExternPrelude => { - suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| { + suggestions.extend(this.extern_prelude.keys().filter_map(|ident| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res)) })); @@ -1411,7 +1411,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); if lookup_ident.span.at_least_rust_2018() { - for ident in self.extern_prelude.clone().into_keys() { + for &ident in self.extern_prelude.keys() { if ident.span.from_expansion() { // Idents are adjusted to the root context before being // resolved in the extern prelude, so reporting this to the diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 98e48664e681..efafb2494c20 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2477,19 +2477,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // Items from the prelude if !module.no_implicit_prelude { - let extern_prelude = self.r.extern_prelude.clone(); - names.extend(extern_prelude.iter().flat_map(|(ident, _)| { - self.r - .cstore_mut() - .maybe_process_path_extern(self.r.tcx, ident.name) - .and_then(|crate_id| { - let crate_mod = - Res::Def(DefKind::Mod, crate_id.as_def_id()); - - filter_fn(crate_mod).then(|| { - TypoSuggestion::typo_from_ident(*ident, crate_mod) - }) - }) + names.extend(self.r.extern_prelude.keys().flat_map(|ident| { + let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); + filter_fn(res) + .then_some(TypoSuggestion::typo_from_ident(*ident, res)) })); if let Some(prelude) = self.r.prelude { From d05bb98d6bb448a221ed479842acda5923fb5eb1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 19:47:08 +0000 Subject: [PATCH 126/242] Extract borrowck coroutine drop-liveness hack --- .../src/traits/query/dropck_outlives.rs | 7 ++- compiler/rustc_ty_utils/src/needs_drop.rs | 43 +++++++++++-------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 38cfdcdc22d3..b1b331d1b61e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -318,7 +318,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( }) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { // rust-lang/rust#49918: types can be constructed, stored // in the interior, and sit idle when coroutine yields // (and is subsequently dropped). @@ -346,7 +346,10 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // While we conservatively assume that all coroutines require drop // to avoid query cycles during MIR building, we can check the actual // witness during borrowck to avoid unnecessary liveness constraints. - if args.witness().needs_drop(tcx, tcx.erase_regions(typing_env)) { + let typing_env = tcx.erase_regions(typing_env); + if tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| { + witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env)) + }) { constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from)); constraints.outlives.push(args.resume_ty().into()); } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index c3b04c20f4b6..13d56889bd12 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -101,9 +101,6 @@ fn has_significant_drop_raw<'tcx>( struct NeedsDropTypes<'tcx, F> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - /// Whether to reveal coroutine witnesses, this is set - /// to `false` unless we compute `needs_drop` for a coroutine witness. - reveal_coroutine_witnesses: bool, query_ty: Ty<'tcx>, seen_tys: FxHashSet>, /// A stack of types left to process, and the recursion depth when we @@ -115,6 +112,15 @@ struct NeedsDropTypes<'tcx, F> { adt_components: F, /// Set this to true if an exhaustive list of types involved in /// drop obligation is requested. + // FIXME: Calling this bool `exhaustive` is confusing and possibly a footgun, + // since it does two things: It makes the iterator yield *all* of the types + // that need drop, and it also affects the computation of the drop components + // on `Coroutine`s. The latter is somewhat confusing, and probably should be + // a function of `typing_env`. See the HACK comment below for why this is + // necessary. If this isn't possible, then we probably should turn this into + // a `NeedsDropMode` so that we can have a variant like `CollectAllSignificantDrops`, + // which will more accurately indicate that we want *all* of the *significant* + // drops, which are the two important behavioral changes toggled by this bool. exhaustive: bool, } @@ -131,7 +137,6 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { Self { tcx, typing_env, - reveal_coroutine_witnesses: exhaustive, seen_tys, query_ty: ty, unchecked_tys: vec![(ty, 0)], @@ -195,23 +200,27 @@ where // for the coroutine witness and check whether any of the contained types // need to be dropped, and only require the captured types to be live // if they do. - ty::Coroutine(_, args) => { - if self.reveal_coroutine_witnesses { - queue_type(self, args.as_coroutine().witness()); + ty::Coroutine(def_id, args) => { + // FIXME: See FIXME on `exhaustive` field above. + if self.exhaustive { + for upvar in args.as_coroutine().upvar_tys() { + queue_type(self, upvar); + } + queue_type(self, args.as_coroutine().resume_ty()); + if let Some(witness) = tcx.mir_coroutine_witnesses(def_id) { + for field_ty in &witness.field_tys { + queue_type( + self, + EarlyBinder::bind(field_ty.ty).instantiate(tcx, args), + ); + } + } } else { return Some(self.always_drop_component(ty)); } } - ty::CoroutineWitness(def_id, args) => { - if let Some(witness) = tcx.mir_coroutine_witnesses(def_id) { - self.reveal_coroutine_witnesses = true; - for field_ty in &witness.field_tys { - queue_type( - self, - EarlyBinder::bind(field_ty.ty).instantiate(tcx, args), - ); - } - } + ty::CoroutineWitness(..) => { + unreachable!("witness should be handled in parent"); } ty::UnsafeBinder(bound_ty) => { From e9765781b2857da90161157a3fc523f9e1d58848 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 25 Jul 2025 16:46:11 +0000 Subject: [PATCH 127/242] Remove the witness type from coroutine args --- .../src/type_check/input_output.rs | 1 - .../src/collect/generics_of.rs | 12 ++------ compiler/rustc_hir_typeck/src/closure.rs | 5 ---- compiler/rustc_middle/src/ty/generic_args.rs | 29 +++++++------------ compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++--- .../src/solve/assembly/structural_traits.rs | 20 +++++++++++-- .../src/traits/select/candidate_assembly.rs | 4 +-- .../src/traits/select/mod.rs | 14 +++++++-- compiler/rustc_type_ir/src/ty_kind/closure.rs | 27 ----------------- ...await.b-{closure#0}.coroutine_resume.0.mir | 8 ----- .../async-closures/def-path.stderr | 4 +-- ...-ranked-auto-trait-6.no_assumptions.stderr | 26 +---------------- .../print/coroutine-print-verbose-2.stderr | 4 +-- .../print/coroutine-print-verbose-3.stderr | 2 +- tests/ui/impl-trait/issues/issue-55872-2.rs | 1 - .../ui/impl-trait/issues/issue-55872-2.stderr | 10 +------ tests/ui/impl-trait/issues/issue-55872-3.rs | 1 - .../ui/impl-trait/issues/issue-55872-3.stderr | 14 ++------- 18 files changed, 54 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 99392ea19151..eb31b5de05d2 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -86,7 +86,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // them with fresh ty vars. resume_ty: next_ty_var(), yield_ty: next_ty_var(), - witness: next_ty_var(), }, ) .args, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 31e9c3b80fba..e2462c2d4659 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -379,20 +379,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // for info on the usage of each of these fields. let dummy_args = match kind { ClosureKind::Closure => &["", "", ""][..], - ClosureKind::Coroutine(_) => &[ - "", - "", - "", - "", - "", - "", - ][..], + ClosureKind::Coroutine(_) => { + &["", "", "", "", ""][..] + } ClosureKind::CoroutineClosure(_) => &[ "", "", "", "", - "", ][..], }; diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a413f805873d..82b7c578a1f2 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -161,8 +161,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args); - // Coroutines that come from coroutine closures have not yet determined // their kind ty, so make a fresh infer var which will be constrained // later during upvar analysis. Regular coroutines always have the kind @@ -182,7 +180,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { resume_ty, yield_ty, return_ty: liberated_sig.output(), - witness: interior, tupled_upvars_ty, }, ); @@ -210,7 +207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Compute all of the variables that will be used to populate the coroutine. let resume_ty = self.next_ty_var(expr_span); - let interior = self.next_ty_var(expr_span); let closure_kind_ty = match expected_kind { Some(kind) => Ty::from_closure_kind(tcx, kind), @@ -243,7 +239,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty: interior, }, ); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7d34d8df3f3b..b02abb5ab43b 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -96,14 +96,12 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArg signature_parts_ty, tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty, ] => ty::CoroutineClosureArgsParts { parent_args, closure_kind_ty: closure_kind_ty.expect_ty(), signature_parts_ty: signature_parts_ty.expect_ty(), tupled_upvars_ty: tupled_upvars_ty.expect_ty(), coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), - coroutine_witness_ty: coroutine_witness_ty.expect_ty(), }, _ => bug!("closure args missing synthetics"), } @@ -111,23 +109,16 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArg fn split_coroutine_args(self) -> ty::CoroutineArgsParts> { match self[..] { - [ - ref parent_args @ .., - kind_ty, - resume_ty, - yield_ty, - return_ty, - witness, - tupled_upvars_ty, - ] => ty::CoroutineArgsParts { - parent_args, - kind_ty: kind_ty.expect_ty(), - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - }, + [ref parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => { + ty::CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + } + } _ => bug!("coroutine args missing synthetics"), } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5c44b10ba71c..71eac294f155 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -913,9 +913,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { " yield_ty=", print(args.as_coroutine().yield_ty()), " return_ty=", - print(args.as_coroutine().return_ty()), - " witness=", - print(args.as_coroutine().witness()) + print(args.as_coroutine().return_ty()) ); } @@ -1035,9 +1033,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { " upvar_tys=", print(args.as_coroutine_closure().tupled_upvars_ty()), " coroutine_captures_by_ref_ty=", - print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), - " coroutine_witness_ty=", - print(args.as_coroutine_closure().coroutine_witness_ty()) + print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()) ); } p!("}}"); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c0bebdf6fb63..faa86734d08c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -75,9 +75,16 @@ where Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()])) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { let coroutine_args = args.as_coroutine(); - Ok(ty::Binder::dummy(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])) + Ok(ty::Binder::dummy(vec![ + coroutine_args.tupled_upvars_ty(), + Ty::new_coroutine_witness( + ecx.cx(), + def_id, + ecx.cx().mk_args(coroutine_args.parent_args().as_slice()), + ), + ])) } ty::CoroutineWitness(def_id, args) => Ok(ecx @@ -245,7 +252,14 @@ where Movability::Movable => { if ecx.cx().features().coroutine_clone() { let coroutine = args.as_coroutine(); - Ok(ty::Binder::dummy(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])) + Ok(ty::Binder::dummy(vec![ + coroutine.tupled_upvars_ty(), + Ty::new_coroutine_witness( + ecx.cx(), + def_id, + ecx.cx().mk_args(coroutine.parent_args().as_slice()), + ), + ])) } else { Err(NoSolution) } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index af6dafb30629..62795c8a3a68 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1166,9 +1166,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.tcx().features().coroutine_clone() { let resolved_upvars = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let resolved_witness = - self.infcx.shallow_resolve(args.as_coroutine().witness()); - if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { + if resolved_upvars.is_ty_var() { // Not yet resolved. candidates.ambiguous = true; } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e893add81c8f..7ea1548f8f29 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2196,7 +2196,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { args.as_coroutine() .upvar_tys() .iter() - .chain([args.as_coroutine().witness()]) + .chain([Ty::new_coroutine_witness( + self.tcx(), + coroutine_def_id, + self.tcx().mk_args(args.as_coroutine().parent_args()), + )]) .collect::>(), ) } else { @@ -2327,9 +2331,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let witness = args.as_coroutine().witness(); + let witness = Ty::new_coroutine_witness( + self.tcx(), + def_id, + self.tcx().mk_args(args.as_coroutine().parent_args()), + ); ty::Binder::dummy(AutoImplConstituents { types: [ty].into_iter().chain(iter::once(witness)).collect(), assumptions: vec![], diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index d1ca9bdb7fbd..c32f8339d0b7 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -101,7 +101,6 @@ use crate::{self as ty, Interner}; /// `yield` inside the coroutine. /// * `GR`: The "return type", which is the type of value returned upon /// completion of the coroutine. -/// * `GW`: The "coroutine witness". #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct ClosureArgs { @@ -239,8 +238,6 @@ pub struct CoroutineClosureArgsParts { /// while the `tupled_upvars_ty`, representing the by-move version of the same /// captures, will be `(String,)`. pub coroutine_captures_by_ref_ty: I::Ty, - /// Witness type returned by the generator produced by this coroutine-closure. - pub coroutine_witness_ty: I::Ty, } impl CoroutineClosureArgs { @@ -251,7 +248,6 @@ impl CoroutineClosureArgs { parts.signature_parts_ty.into(), parts.tupled_upvars_ty.into(), parts.coroutine_captures_by_ref_ty.into(), - parts.coroutine_witness_ty.into(), ])), } } @@ -292,7 +288,6 @@ impl CoroutineClosureArgs { } pub fn coroutine_closure_sig(self) -> ty::Binder> { - let interior = self.coroutine_witness_ty(); let ty::FnPtr(sig_tys, hdr) = self.signature_parts_ty().kind() else { panic!() }; sig_tys.map_bound(|sig_tys| { let [resume_ty, tupled_inputs_ty] = *sig_tys.inputs().as_slice() else { @@ -302,7 +297,6 @@ impl CoroutineClosureArgs { panic!() }; CoroutineClosureSignature { - interior, tupled_inputs_ty, resume_ty, yield_ty, @@ -318,10 +312,6 @@ impl CoroutineClosureArgs { self.split().coroutine_captures_by_ref_ty } - pub fn coroutine_witness_ty(self) -> I::Ty { - self.split().coroutine_witness_ty - } - pub fn has_self_borrows(&self) -> bool { match self.coroutine_captures_by_ref_ty().kind() { ty::FnPtr(sig_tys, _) => sig_tys @@ -361,7 +351,6 @@ impl TypeVisitor for HasRegionsBoundAt { #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct CoroutineClosureSignature { - pub interior: I::Ty, pub tupled_inputs_ty: I::Ty, pub resume_ty: I::Ty, pub yield_ty: I::Ty, @@ -407,7 +396,6 @@ impl CoroutineClosureSignature { resume_ty: self.resume_ty, yield_ty: self.yield_ty, return_ty: self.return_ty, - witness: self.interior, tupled_upvars_ty, }, ); @@ -587,11 +575,6 @@ pub struct CoroutineArgsParts { pub yield_ty: I::Ty, pub return_ty: I::Ty, - /// The interior type of the coroutine. - /// Represents all types that are stored in locals - /// in the coroutine's body. - pub witness: I::Ty, - /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: I::Ty, @@ -607,7 +590,6 @@ impl CoroutineArgs { parts.resume_ty.into(), parts.yield_ty.into(), parts.return_ty.into(), - parts.witness.into(), parts.tupled_upvars_ty.into(), ])), } @@ -629,15 +611,6 @@ impl CoroutineArgs { self.split().kind_ty } - /// This describes the types that can be contained in a coroutine. - /// It will be a type variable initially and unified in the last stages of typeck of a body. - /// It contains a tuple of all the types that could end up on a coroutine frame. - /// The state transformation MIR pass may only produce layouts which mention types - /// in this tuple. Upvars are not counted here. - pub fn witness(self) -> I::Ty { - self.split().witness - } - /// Returns an iterator over the list of types of captured paths by the coroutine. /// In case there was a type error in figuring out the types of the captured path, an /// empty iterator is returned. diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 109a41d1ef90..9bff257e0639 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -9,10 +9,6 @@ std::future::ResumeTy, (), (), - CoroutineWitness( - DefId(0:5 ~ async_await[ccf8]::a::{closure#0}), - [], - ), (), ], ), @@ -30,10 +26,6 @@ std::future::ResumeTy, (), (), - CoroutineWitness( - DefId(0:5 ~ async_await[ccf8]::a::{closure#0}), - [], - ), (), ], ), diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index 58a5b0b79c4e..a507fa697604 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr index d1f2d9a07530..d1c88101618a 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr @@ -21,30 +21,6 @@ LL | Box::new(async { new(|| async { f().await }).await }) = help: consider pinning your async block and casting it to a trait object = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-6.rs:16:5 - | -LL | Box::new(async { new(|| async { f().await }).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - = note: no two async blocks, even if identical, have the same type - = help: consider pinning your async block and casting it to a trait object - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-6.rs:16:5 - | -LL | Box::new(async { new(|| async { f().await }).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - = note: no two async blocks, even if identical, have the same type - = help: consider pinning your async block and casting it to a trait object - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index 8877d45dddad..11b78e3bcf89 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -9,7 +9,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync` + = help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Sync` is not implemented for `NotSync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:20:9 | @@ -34,7 +34,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend` + = help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Send` is not implemented for `NotSend` note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:27:9 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index 4a1e5b078a80..135e81757938 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -11,7 +11,7 @@ LL | | }; | |_____^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness={main::{closure#0}}}` + found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-55872-2.rs b/tests/ui/impl-trait/issues/issue-55872-2.rs index a3b2225126a2..aea00dd9e3d5 100644 --- a/tests/ui/impl-trait/issues/issue-55872-2.rs +++ b/tests/ui/impl-trait/issues/issue-55872-2.rs @@ -12,7 +12,6 @@ impl Bar for S { type E = impl std::marker::Send; fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - //~| ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias async {} } } diff --git a/tests/ui/impl-trait/issues/issue-55872-2.stderr b/tests/ui/impl-trait/issues/issue-55872-2.stderr index 51a7dd00ade6..91c2ecdc8a47 100644 --- a/tests/ui/impl-trait/issues/issue-55872-2.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-2.stderr @@ -4,13 +4,5 @@ error: type parameter `T` is part of concrete type but not used in parameter lis LL | fn foo() -> Self::E { | ^^^^^^^ -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-2.rs:13:20 - | -LL | fn foo() -> Self::E { - | ^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-55872-3.rs b/tests/ui/impl-trait/issues/issue-55872-3.rs index 763b4b9fd32d..698e7f362341 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.rs +++ b/tests/ui/impl-trait/issues/issue-55872-3.rs @@ -14,7 +14,6 @@ impl Bar for S { fn foo() -> Self::E { //~^ ERROR : Copy` is not satisfied [E0277] //~| ERROR type parameter `T` is part of concrete type - //~| ERROR type parameter `T` is part of concrete type async {} } } diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr index b7711e47468e..5124c46baeb9 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr @@ -4,20 +4,12 @@ error: type parameter `T` is part of concrete type but not used in parameter lis LL | fn foo() -> Self::E { | ^^^^^^^ -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}: Copy` is not satisfied --> $DIR/issue-55872-3.rs:14:20 | LL | fn foo() -> Self::E { - | ^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied - --> $DIR/issue-55872-3.rs:14:20 - | -LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. From 32f4876bf156317536c7a2a06f451fedf8afc22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 31 Jul 2025 19:39:59 +0200 Subject: [PATCH 128/242] Create a typed wrapper for codegen backends To avoid representing them just with strings. --- src/bootstrap/src/core/build_steps/check.rs | 19 +++++---- src/bootstrap/src/core/build_steps/compile.rs | 24 ++++++----- src/bootstrap/src/core/build_steps/dist.rs | 30 +++++++------- src/bootstrap/src/core/build_steps/install.rs | 4 +- src/bootstrap/src/core/build_steps/test.rs | 10 +++-- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 16 ++++---- src/bootstrap/src/core/builder/tests.rs | 24 +++++------ src/bootstrap/src/core/config/config.rs | 12 +++--- src/bootstrap/src/core/config/toml/rust.rs | 27 +++++++++---- src/bootstrap/src/core/config/toml/target.rs | 8 ++-- src/bootstrap/src/lib.rs | 40 +++++++++++++++++++ src/bootstrap/src/utils/build_stamp.rs | 6 +-- 13 files changed, 143 insertions(+), 79 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b4232409ba83..f6653ed899bf 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -13,7 +13,7 @@ use crate::core::builder::{ }; use crate::core::config::TargetSelection; use crate::utils::build_stamp::{self, BuildStamp}; -use crate::{Compiler, Mode, Subcommand}; +use crate::{CodegenBackendKind, Compiler, Mode, Subcommand}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Std { @@ -312,7 +312,7 @@ fn prepare_compiler_for_check( pub struct CodegenBackend { pub build_compiler: Compiler, pub target: TargetSelection, - pub backend: &'static str, + pub backend: CodegenBackendKind, } impl Step for CodegenBackend { @@ -327,14 +327,14 @@ impl Step for CodegenBackend { fn make_run(run: RunConfig<'_>) { // FIXME: only check the backend(s) that were actually selected in run.paths let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::Codegen); - for &backend in &["cranelift", "gcc"] { + for backend in [CodegenBackendKind::Cranelift, CodegenBackendKind::Gcc] { run.builder.ensure(CodegenBackend { build_compiler, target: run.target, backend }); } } fn run(self, builder: &Builder<'_>) { // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved - if builder.build.config.vendor && self.backend == "gcc" { + if builder.build.config.vendor && self.backend.is_gcc() { println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); return; } @@ -354,19 +354,22 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") - .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); + .arg(builder.src.join(format!("compiler/{}/Cargo.toml", backend.crate_name()))); rustc_cargo_env(builder, &mut cargo, target); - let _guard = builder.msg_check(format!("rustc_codegen_{backend}"), target, None); + let _guard = builder.msg_check(backend.crate_name(), target, None); - let stamp = build_stamp::codegen_backend_stamp(builder, build_compiler, target, backend) + let stamp = build_stamp::codegen_backend_stamp(builder, build_compiler, target, &backend) .with_prefix("check"); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } fn metadata(&self) -> Option { - Some(StepMetadata::check(self.backend, self.target).built_by(self.build_compiler)) + Some( + StepMetadata::check(&self.backend.crate_name(), self.target) + .built_by(self.build_compiler), + ) } } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4abfe1843ebe..59541bf12def 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -33,7 +33,10 @@ use crate::utils::exec::command; use crate::utils::helpers::{ exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; -use crate::{CLang, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, debug, trace}; +use crate::{ + CLang, CodegenBackendKind, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, + debug, trace, +}; /// Build a standard library for the given `target` using the given `compiler`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1330,7 +1333,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } if let Some(backend) = builder.config.default_codegen_backend(target) { - cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend); + cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend.name()); } let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); @@ -1543,7 +1546,7 @@ impl Step for RustcLink { pub struct CodegenBackend { pub target: TargetSelection, pub compiler: Compiler, - pub backend: String, + pub backend: CodegenBackendKind, } fn needs_codegen_config(run: &RunConfig<'_>) -> bool { @@ -1568,7 +1571,7 @@ fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool { if path.contains(CODEGEN_BACKEND_PREFIX) { let mut needs_codegen_backend_config = true; for backend in run.builder.config.codegen_backends(run.target) { - if path.ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend)) { + if path.ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend.name())) { needs_codegen_backend_config = false; } } @@ -1602,7 +1605,7 @@ impl Step for CodegenBackend { } for backend in run.builder.config.codegen_backends(run.target) { - if backend == "llvm" { + if backend.is_llvm() { continue; // Already built as part of rustc } @@ -1663,20 +1666,21 @@ impl Step for CodegenBackend { ); cargo .arg("--manifest-path") - .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); + .arg(builder.src.join(format!("compiler/{}/Cargo.toml", backend.crate_name()))); rustc_cargo_env(builder, &mut cargo, target); // Ideally, we'd have a separate step for the individual codegen backends, // like we have in tests (test::CodegenGCC) but that would require a lot of restructuring. // If the logic gets more complicated, it should probably be done. - if backend == "gcc" { + if backend.is_gcc() { let gcc = builder.ensure(Gcc { target }); add_cg_gcc_cargo_flags(&mut cargo, &gcc); } let tmp_stamp = BuildStamp::new(&out_dir).with_prefix("tmp"); - let _guard = builder.msg_build(compiler, format_args!("codegen backend {backend}"), target); + let _guard = + builder.msg_build(compiler, format_args!("codegen backend {}", backend.name()), target); let files = run_cargo(builder, cargo, vec![], &tmp_stamp, vec![], false, false); if builder.config.dry_run() { return; @@ -1731,7 +1735,7 @@ fn copy_codegen_backends_to_sysroot( } for backend in builder.config.codegen_backends(target) { - if backend == "llvm" { + if backend.is_llvm() { continue; // Already built as part of rustc } @@ -2161,7 +2165,7 @@ impl Step for Assemble { let _codegen_backend_span = span!(tracing::Level::DEBUG, "building requested codegen backends").entered(); for backend in builder.config.codegen_backends(target_compiler.host) { - if backend == "llvm" { + if backend.is_llvm() { debug!("llvm codegen backend is already built as part of rustc"); continue; // Already built as part of rustc } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index c8a54ad250cb..4699813abf42 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -32,7 +32,7 @@ use crate::utils::helpers::{ exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; -use crate::{Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace}; +use crate::{CodegenBackendKind, Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { format!("{}-{}", component, builder.rust_package_vers()) @@ -1372,10 +1372,10 @@ impl Step for Miri { } } -#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct CodegenBackend { pub compiler: Compiler, - pub backend: String, + pub backend: CodegenBackendKind, } impl Step for CodegenBackend { @@ -1389,7 +1389,7 @@ impl Step for CodegenBackend { fn make_run(run: RunConfig<'_>) { for backend in run.builder.config.codegen_backends(run.target) { - if backend == "llvm" { + if backend.is_llvm() { continue; // Already built as part of rustc } @@ -1412,12 +1412,11 @@ impl Step for CodegenBackend { return None; } - if !builder.config.codegen_backends(self.compiler.host).contains(&self.backend.to_string()) - { + if !builder.config.codegen_backends(self.compiler.host).contains(&self.backend) { return None; } - if self.backend == "cranelift" && !target_supports_cranelift_backend(self.compiler.host) { + if self.backend.is_cranelift() && !target_supports_cranelift_backend(self.compiler.host) { builder.info("target not supported by rustc_codegen_cranelift. skipping"); return None; } @@ -1425,15 +1424,18 @@ impl Step for CodegenBackend { let compiler = self.compiler; let backend = self.backend; - let mut tarball = - Tarball::new(builder, &format!("rustc-codegen-{backend}"), &compiler.host.triple); - if backend == "cranelift" { + let mut tarball = Tarball::new( + builder, + &format!("rustc-codegen-{}", backend.name()), + &compiler.host.triple, + ); + if backend.is_cranelift() { tarball.set_overlay(OverlayKind::RustcCodegenCranelift); } else { - panic!("Unknown backend rustc_codegen_{backend}"); + panic!("Unknown codegen backend {}", backend.name()); } tarball.is_preview(true); - tarball.add_legal_and_readme_to(format!("share/doc/rustc_codegen_{backend}")); + tarball.add_legal_and_readme_to(format!("share/doc/{}", backend.crate_name())); let src = builder.sysroot(compiler); let backends_src = builder.sysroot_codegen_backends(compiler); @@ -1445,7 +1447,7 @@ impl Step for CodegenBackend { // Don't use custom libdir here because ^lib/ will be resolved again with installer let backends_dst = PathBuf::from("lib").join(backends_rel); - let backend_name = format!("rustc_codegen_{backend}"); + let backend_name = backend.crate_name(); let mut found_backend = false; for backend in fs::read_dir(&backends_src).unwrap() { let file_name = backend.unwrap().file_name(); @@ -1575,7 +1577,7 @@ impl Step for Extended { add_component!("analysis" => Analysis { compiler, target }); add_component!("rustc-codegen-cranelift" => CodegenBackend { compiler: builder.compiler(stage, target), - backend: "cranelift".to_string(), + backend: CodegenBackendKind::Cranelift, }); add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker { build_compiler: compiler, diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 4156b49a8b33..4513a138e192 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -12,7 +12,7 @@ use crate::core::config::{Config, TargetSelection}; use crate::utils::exec::command; use crate::utils::helpers::t; use crate::utils::tarball::GeneratedTarball; -use crate::{Compiler, Kind}; +use crate::{CodegenBackendKind, Compiler, Kind}; #[cfg(target_os = "illumos")] const SHELL: &str = "bash"; @@ -276,7 +276,7 @@ install!((self, builder, _config), RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::CodegenBackend { compiler: self.compiler, - backend: "cranelift".to_string(), + backend: CodegenBackendKind::Cranelift, }) { install_sh(builder, "rustc-codegen-cranelift", self.compiler.stage, Some(self.target), &tarball); } else { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 951ca73fcc49..119fa4237bcf 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -33,7 +33,7 @@ use crate::utils::helpers::{ linker_flags, t, target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; -use crate::{CLang, DocTests, GitRepo, Mode, PathSet, debug, envify}; +use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; @@ -1786,7 +1786,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target)); if let Some(codegen_backend) = builder.config.default_codegen_backend(compiler.host) { - cmd.arg("--codegen-backend").arg(&codegen_backend); + // Tells compiletest which codegen backend is used by default by the compiler. + // It is used to e.g. ignore tests that don't support that codegen backend. + cmd.arg("--codegen-backend").arg(codegen_backend.name()); } if builder.build.config.llvm_enzyme { @@ -3406,7 +3408,7 @@ impl Step for CodegenCranelift { return; } - if !builder.config.codegen_backends(run.target).contains(&"cranelift".to_owned()) { + if !builder.config.codegen_backends(run.target).contains(&CodegenBackendKind::Cranelift) { builder.info("cranelift not in rust.codegen-backends. skipping"); return; } @@ -3533,7 +3535,7 @@ impl Step for CodegenGCC { return; } - if !builder.config.codegen_backends(run.target).contains(&"gcc".to_owned()) { + if !builder.config.codegen_backends(run.target).contains(&CodegenBackendKind::Gcc) { builder.info("gcc not in rust.codegen-backends. skipping"); return; } diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index badd5f24dba7..6b3236ef47ef 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -1286,7 +1286,7 @@ impl Builder<'_> { if let Some(limit) = limit && (build_compiler_stage == 0 - || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm") + || self.config.default_codegen_backend(target).unwrap_or_default().is_llvm()) { rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}")); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 020622d1c121..96289a63785e 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -141,7 +141,7 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { #[allow(unused)] #[derive(Debug, PartialEq, Eq)] pub struct StepMetadata { - name: &'static str, + name: String, kind: Kind, target: TargetSelection, built_by: Option, @@ -151,28 +151,28 @@ pub struct StepMetadata { } impl StepMetadata { - pub fn build(name: &'static str, target: TargetSelection) -> Self { + pub fn build(name: &str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Build) } - pub fn check(name: &'static str, target: TargetSelection) -> Self { + pub fn check(name: &str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Check) } - pub fn doc(name: &'static str, target: TargetSelection) -> Self { + pub fn doc(name: &str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Doc) } - pub fn dist(name: &'static str, target: TargetSelection) -> Self { + pub fn dist(name: &str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Dist) } - pub fn test(name: &'static str, target: TargetSelection) -> Self { + pub fn test(name: &str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Test) } - fn new(name: &'static str, target: TargetSelection, kind: Kind) -> Self { - Self { name, kind, target, built_by: None, stage: None, metadata: None } + fn new(name: &str, target: TargetSelection, kind: Kind) -> Self { + Self { name: name.to_string(), kind, target, built_by: None, stage: None, metadata: None } } pub fn built_by(mut self, compiler: Compiler) -> Self { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 6ea5d4e65532..7192c9f9a175 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1309,8 +1309,8 @@ mod snapshot { .path("compiler") .render_steps(), @r" [check] rustc 0 -> rustc 1 - [check] rustc 0 -> cranelift 1 - [check] rustc 0 -> gcc 1 + [check] rustc 0 -> rustc_codegen_cranelift 1 + [check] rustc 0 -> rustc_codegen_gcc 1 "); } @@ -1341,8 +1341,8 @@ mod snapshot { .stage(1) .render_steps(), @r" [check] rustc 0 -> rustc 1 - [check] rustc 0 -> cranelift 1 - [check] rustc 0 -> gcc 1 + [check] rustc 0 -> rustc_codegen_cranelift 1 + [check] rustc 0 -> rustc_codegen_gcc 1 "); } @@ -1358,8 +1358,8 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 [check] rustc 1 -> rustc 2 - [check] rustc 1 -> cranelift 2 - [check] rustc 1 -> gcc 2 + [check] rustc 1 -> rustc_codegen_cranelift 2 + [check] rustc 1 -> rustc_codegen_gcc 2 "); } @@ -1377,8 +1377,8 @@ mod snapshot { [build] rustc 1 -> std 1 [check] rustc 1 -> rustc 2 [check] rustc 1 -> Rustdoc 2 - [check] rustc 1 -> cranelift 2 - [check] rustc 1 -> gcc 2 + [check] rustc 1 -> rustc_codegen_cranelift 2 + [check] rustc 1 -> rustc_codegen_gcc 2 [check] rustc 1 -> Clippy 2 [check] rustc 1 -> Miri 2 [check] rustc 1 -> CargoMiri 2 @@ -1472,8 +1472,8 @@ mod snapshot { .args(&args) .render_steps(), @r" [check] rustc 0 -> rustc 1 - [check] rustc 0 -> cranelift 1 - [check] rustc 0 -> gcc 1 + [check] rustc 0 -> rustc_codegen_cranelift 1 + [check] rustc 0 -> rustc_codegen_gcc 1 "); } @@ -1557,8 +1557,8 @@ mod snapshot { .path("rustc_codegen_cranelift") .render_steps(), @r" [check] rustc 0 -> rustc 1 - [check] rustc 0 -> cranelift 1 - [check] rustc 0 -> gcc 1 + [check] rustc 0 -> rustc_codegen_cranelift 1 + [check] rustc 0 -> rustc_codegen_gcc 1 "); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 78abdd7f9b8c..6055876c4757 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -51,7 +51,7 @@ use crate::core::download::{ use crate::utils::channel; use crate::utils::exec::{ExecutionContext, command}; use crate::utils::helpers::{exe, get_host_target}; -use crate::{GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t}; +use crate::{CodegenBackendKind, GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t}; /// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic. /// This means they can be modified and changes to these paths should never trigger a compiler build @@ -208,7 +208,7 @@ pub struct Config { pub rustc_default_linker: Option, pub rust_optimize_tests: bool, pub rust_dist_src: bool, - pub rust_codegen_backends: Vec, + pub rust_codegen_backends: Vec, pub rust_verify_llvm_ir: bool, pub rust_thin_lto_import_instr_limit: Option, pub rust_randomize_layout: bool, @@ -350,7 +350,7 @@ impl Config { channel: "dev".to_string(), codegen_tests: true, rust_dist_src: true, - rust_codegen_backends: vec!["llvm".to_owned()], + rust_codegen_backends: vec![CodegenBackendKind::Llvm], deny_warnings: true, bindir: "bin".into(), dist_include_mingw_linker: true, @@ -1747,7 +1747,7 @@ impl Config { .unwrap_or(self.profiler) } - pub fn codegen_backends(&self, target: TargetSelection) -> &[String] { + pub fn codegen_backends(&self, target: TargetSelection) -> &[CodegenBackendKind] { self.target_config .get(&target) .and_then(|cfg| cfg.codegen_backends.as_deref()) @@ -1758,7 +1758,7 @@ impl Config { self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc) } - pub fn default_codegen_backend(&self, target: TargetSelection) -> Option { + pub fn default_codegen_backend(&self, target: TargetSelection) -> Option { self.codegen_backends(target).first().cloned() } @@ -1774,7 +1774,7 @@ impl Config { } pub fn llvm_enabled(&self, target: TargetSelection) -> bool { - self.codegen_backends(target).contains(&"llvm".to_owned()) + self.codegen_backends(target).contains(&CodegenBackendKind::Llvm) } pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index c136bd4a6f9b..03da993a17dd 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -11,7 +11,9 @@ use crate::core::config::{ DebuginfoLevel, Merge, ReplaceOpt, RustcLto, StringOrBool, set, threads_from_config, }; use crate::flags::Warnings; -use crate::{BTreeSet, Config, HashSet, PathBuf, TargetSelection, define_config, exit}; +use crate::{ + BTreeSet, CodegenBackendKind, Config, HashSet, PathBuf, TargetSelection, define_config, exit, +}; define_config! { /// TOML representation of how the Rust build is configured. @@ -389,9 +391,13 @@ pub fn check_incompatible_options_for_ci_rustc( Ok(()) } -pub(crate) const VALID_CODEGEN_BACKENDS: &[&str] = &["llvm", "cranelift", "gcc"]; +pub(crate) const BUILTIN_CODEGEN_BACKENDS: &[&str] = &["llvm", "cranelift", "gcc"]; -pub(crate) fn validate_codegen_backends(backends: Vec, section: &str) -> Vec { +pub(crate) fn parse_codegen_backends( + backends: Vec, + section: &str, +) -> Vec { + let mut found_backends = vec![]; for backend in &backends { if let Some(stripped) = backend.strip_prefix(CODEGEN_BACKEND_PREFIX) { panic!( @@ -400,14 +406,21 @@ pub(crate) fn validate_codegen_backends(backends: Vec, section: &str) -> Please, use '{stripped}' instead." ) } - if !VALID_CODEGEN_BACKENDS.contains(&backend.as_str()) { + if !BUILTIN_CODEGEN_BACKENDS.contains(&backend.as_str()) { println!( "HELP: '{backend}' for '{section}.codegen-backends' might fail. \ - List of known good values: {VALID_CODEGEN_BACKENDS:?}" + List of known codegen backends: {BUILTIN_CODEGEN_BACKENDS:?}" ); } + let backend = match backend.as_str() { + "llvm" => CodegenBackendKind::Llvm, + "cranelift" => CodegenBackendKind::Cranelift, + "gcc" => CodegenBackendKind::Gcc, + backend => CodegenBackendKind::Custom(backend.to_string()), + }; + found_backends.push(backend); } - backends + found_backends } #[cfg(not(test))] @@ -609,7 +622,7 @@ impl Config { llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); set( &mut self.rust_codegen_backends, - codegen_backends.map(|backends| validate_codegen_backends(backends, "rust")), + codegen_backends.map(|backends| parse_codegen_backends(backends, "rust")), ); self.rust_codegen_units = codegen_units.map(threads_from_config); diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 337276948b32..9dedadff3a19 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -16,9 +16,9 @@ use std::collections::HashMap; use serde::{Deserialize, Deserializer}; -use crate::core::config::toml::rust::validate_codegen_backends; +use crate::core::config::toml::rust::parse_codegen_backends; use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; -use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit}; +use crate::{CodegenBackendKind, Config, HashSet, PathBuf, TargetSelection, define_config, exit}; define_config! { /// TOML representation of how each build target is configured. @@ -76,7 +76,7 @@ pub struct Target { pub qemu_rootfs: Option, pub runner: Option, pub no_std: bool, - pub codegen_backends: Option>, + pub codegen_backends: Option>, pub optimized_compiler_builtins: Option, pub jemalloc: Option, } @@ -144,7 +144,7 @@ impl Config { target.jemalloc = cfg.jemalloc; if let Some(backends) = cfg.codegen_backends { target.codegen_backends = - Some(validate_codegen_backends(backends, &format!("target.{triple}"))) + Some(parse_codegen_backends(backends, &format!("target.{triple}"))) } target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 51a84ad5272c..011b52df97bb 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -123,6 +123,46 @@ impl PartialEq for Compiler { } } +/// Represents a codegen backend. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub enum CodegenBackendKind { + #[default] + Llvm, + Cranelift, + Gcc, + Custom(String), +} + +impl CodegenBackendKind { + /// Name of the codegen backend, as identified in the `compiler` directory + /// (`rustc_codegen_`). + pub fn name(&self) -> &str { + match self { + CodegenBackendKind::Llvm => "llvm", + CodegenBackendKind::Cranelift => "cranelift", + CodegenBackendKind::Gcc => "gcc", + CodegenBackendKind::Custom(name) => name, + } + } + + /// Name of the codegen backend's crate, e.g. `rustc_codegen_cranelift`. + pub fn crate_name(&self) -> String { + format!("rustc_codegen_{}", self.name()) + } + + pub fn is_llvm(&self) -> bool { + matches!(self, Self::Llvm) + } + + pub fn is_cranelift(&self) -> bool { + matches!(self, Self::Cranelift) + } + + pub fn is_gcc(&self) -> bool { + matches!(self, Self::Gcc) + } +} + #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum DocTests { /// Run normal tests and doc tests (default). diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index f43d860893f6..bd4eb790ae50 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -10,7 +10,7 @@ use sha2::digest::Digest; use crate::core::builder::Builder; use crate::core::config::TargetSelection; use crate::utils::helpers::{hex_encode, mtime}; -use crate::{Compiler, Mode, helpers, t}; +use crate::{CodegenBackendKind, Compiler, Mode, helpers, t}; #[cfg(test)] mod tests; @@ -129,10 +129,10 @@ pub fn codegen_backend_stamp( builder: &Builder<'_>, compiler: Compiler, target: TargetSelection, - backend: &str, + backend: &CodegenBackendKind, ) -> BuildStamp { BuildStamp::new(&builder.cargo_out(compiler, Mode::Codegen, target)) - .with_prefix(&format!("librustc_codegen_{backend}")) + .with_prefix(&format!("lib{}", backend.crate_name())) } /// Cargo's output path for the standard library in a given stage, compiled From f554c79ef819cbc0f9983d0d5306cd7a9bfea6d8 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 30 Jul 2025 15:35:19 -0500 Subject: [PATCH 129/242] Do not give function allocations alignment in consteval or miri. --- .../rustc_const_eval/src/interpret/memory.rs | 8 ++++-- src/tools/miri/tests/pass/fn_align.rs | 25 ------------------- 2 files changed, 6 insertions(+), 27 deletions(-) delete mode 100644 src/tools/miri/tests/pass/fn_align.rs diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 47bebf5371a9..bbde7c66acc0 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -937,8 +937,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { - FnVal::Instance(instance) => { - self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE) + FnVal::Instance(_instance) => { + // FIXME: Until we have a clear design for the effects of align(N) functions + // on the address of function pointers, we don't consider the align(N) + // attribute on functions in the interpreter. + //self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE) + Align::ONE } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, diff --git a/src/tools/miri/tests/pass/fn_align.rs b/src/tools/miri/tests/pass/fn_align.rs deleted file mode 100644 index 9752d033458d..000000000000 --- a/src/tools/miri/tests/pass/fn_align.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@compile-flags: -Zmin-function-alignment=8 - -// FIXME(rust-lang/rust#82232, rust-lang/rust#143834): temporarily renamed to mitigate `#[align]` -// nameres ambiguity -#![feature(rustc_attrs)] -#![feature(fn_align)] - -// When a function uses `align(N)`, the function address should be a multiple of `N`. - -#[rustc_align(256)] -fn foo() {} - -#[rustc_align(16)] -fn bar() {} - -#[rustc_align(4)] -fn baz() {} - -fn main() { - assert!((foo as usize).is_multiple_of(256)); - assert!((bar as usize).is_multiple_of(16)); - - // The maximum of `align(N)` and `-Zmin-function-alignment=N` is used. - assert!((baz as usize).is_multiple_of(8)); -} From cab16432fb3d2a54920eba9e6c49c5263077e80e Mon Sep 17 00:00:00 2001 From: lolbinarycat Date: Thu, 31 Jul 2025 13:33:51 -0500 Subject: [PATCH 130/242] improve linking in the "Auxilirary builds" section of directive index --- src/doc/rustc-dev-guide/src/tests/directives.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 5c3ae359ba0b..8ea76cd8da01 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -52,6 +52,8 @@ not be exhaustive. Directives can generally be found by browsing the ### Auxiliary builds +See [Building auxiliary crates](compiletest.html#building-auxiliary-crates) + | Directive | Explanation | Supported test suites | Possible values | |-----------------------|-------------------------------------------------------------------------------------------------------|-----------------------|-----------------------------------------------| | `aux-bin` | Build a aux binary, made available in `auxiliary/bin` relative to test directory | All except `run-make` | Path to auxiliary `.rs` file | @@ -61,8 +63,7 @@ not be exhaustive. Directives can generally be found by browsing the | `proc-macro` | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm]. | All except `run-make` | Path to auxiliary proc-macro `.rs` file | | `build-aux-docs` | Build docs for auxiliaries as well. Note that this only works with `aux-build`, not `aux-crate`. | All except `run-make` | N/A | -[^pm]: please see the Auxiliary proc-macro section in the - [compiletest](./compiletest.md) chapter for specifics. +[^pm]: please see the [Auxiliary proc-macro section](compiletest.html#auxiliary-proc-macro) in the compiletest chapter for specifics. ### Controlling outcome expectations From 37d52ed092b1bb2d263702f59da56c06b7b26613 Mon Sep 17 00:00:00 2001 From: Curtis D'Alves Date: Thu, 31 Jul 2025 15:49:23 -0400 Subject: [PATCH 131/242] add correct dynamic_lib_extension for aix --- src/tools/run-make-support/src/artifact_names.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs index a889b30e145d..a2bb11869446 100644 --- a/src/tools/run-make-support/src/artifact_names.rs +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -35,6 +35,8 @@ pub fn dynamic_lib_extension() -> &'static str { "dylib" } else if target.contains("windows") { "dll" + } else if target.contains("aix") { + "a" } else { "so" } From 4e806c8a342589f64f61119f69fc68c565e331c8 Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 30 Jul 2025 23:50:31 +0200 Subject: [PATCH 132/242] Add tracing calls to eval_statement/terminator --- .../rustc_const_eval/src/interpret/step.rs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 629dcc3523ca..b43854fd60bc 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -9,13 +9,14 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; use rustc_target::callconv::FnAbi; +use tracing::field::Empty; use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format, }; -use crate::util; +use crate::{enter_trace_span, util}; struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> { callee: FnVal<'tcx, M::ExtraFnVal>, @@ -74,7 +75,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// This does NOT move the statement counter forward, the caller has to do that! pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", stmt); + let _span = enter_trace_span!( + M, + step::eval_statement, + stmt = ?stmt.kind, + span = ?stmt.source_info.span, + tracing_separate_thread = Empty, + ); + info!(stmt = ?stmt.kind); use rustc_middle::mir::StatementKind::*; @@ -456,7 +464,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { - info!("{:?}", terminator.kind); + let _span = enter_trace_span!( + M, + step::eval_terminator, + terminator = ?terminator.kind, + span = ?terminator.source_info.span, + tracing_separate_thread = Empty, + ); + info!(terminator = ?terminator.kind); use rustc_middle::mir::TerminatorKind::*; match terminator.kind { From 188f7367bff680a9e3ef2141a08cec24163ba70d Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 31 Jul 2025 00:27:42 +0200 Subject: [PATCH 133/242] Add tracing to more functions related to step.rs --- compiler/rustc_const_eval/src/interpret/call.rs | 7 ++++++- compiler/rustc_const_eval/src/interpret/operand.rs | 12 ++++++++++++ compiler/rustc_const_eval/src/interpret/place.rs | 5 +++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 5b3adba02659..24c440844226 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use tracing::field::Empty; use tracing::{info, instrument, trace}; use super::{ @@ -18,7 +19,7 @@ use super::{ Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok, throw_ub, throw_ub_custom, throw_unsup_format, }; -use crate::fluent_generated as fluent; +use crate::{enter_trace_span, fluent_generated as fluent}; /// An argument passed to a function. #[derive(Clone, Debug)] @@ -344,6 +345,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { destination: &PlaceTy<'tcx, M::Provenance>, mut cont: ReturnContinuation, ) -> InterpResult<'tcx> { + let _span = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty); + // Compute callee information. // FIXME: for variadic support, do we have to somehow determine callee's extra_args? let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; @@ -523,6 +526,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { target: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { + let _span = + enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val); trace!("init_fn_call: {:#?}", fn_val); let instance = match fn_val { diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 21afd082a055..417134579086 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; use rustc_span::DUMMY_SP; +use tracing::field::Empty; use tracing::trace; use super::{ @@ -20,6 +21,7 @@ use super::{ OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, interp_ok, mir_assign_valid_types, throw_ub, }; +use crate::enter_trace_span; /// An `Immediate` represents a single immediate self-contained Rust value. /// @@ -770,6 +772,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir_place: mir::Place<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + let _span = enter_trace_span!( + M, + step::eval_place_to_op, + ?mir_place, + tracing_separate_thread = Empty + ); + // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. let layout = if mir_place.projection.is_empty() { layout } else { None }; @@ -813,6 +822,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir_op: &mir::Operand<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + let _span = + enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty); + use rustc_middle::mir::Operand::*; let op = match mir_op { // FIXME: do some more logic on `move` to invalidate the old location diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index e2284729efdc..45c4edb85037 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -9,6 +9,7 @@ use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::{bug, mir, span_bug}; +use tracing::field::Empty; use tracing::{instrument, trace}; use super::{ @@ -16,6 +17,7 @@ use super::{ InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types, }; +use crate::enter_trace_span; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] /// Information required for the sound usage of a `MemPlace`. @@ -524,6 +526,9 @@ where &self, mir_place: mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { + let _span = + enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty); + let mut place = self.local_to_place(mir_place.local)?; // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { From 88c9a256a94dfc3545dadd33fef15e52a6b7d73e Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 31 Jul 2025 00:12:48 +0200 Subject: [PATCH 134/242] Add EnteredTraceSpan::or_if_tracing_disabled --- .../rustc_const_eval/src/interpret/call.rs | 5 +-- .../rustc_const_eval/src/interpret/step.rs | 9 ++--- .../rustc_const_eval/src/interpret/util.rs | 35 ++++++++++++++++--- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 24c440844226..b8a653698258 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -19,6 +19,7 @@ use super::{ Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok, throw_ub, throw_ub_custom, throw_unsup_format, }; +use crate::interpret::EnteredTraceSpan; use crate::{enter_trace_span, fluent_generated as fluent}; /// An argument passed to a function. @@ -527,8 +528,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { let _span = - enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val); - trace!("init_fn_call: {:#?}", fn_val); + enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val) + .or_if_tracing_disabled(|| trace!("init_fn_call: {:#?}", fn_val)); let instance = match fn_val { FnVal::Instance(instance) => instance, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index b43854fd60bc..9df49c0f4ccd 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -16,6 +16,7 @@ use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format, }; +use crate::interpret::EnteredTraceSpan; use crate::{enter_trace_span, util}; struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> { @@ -81,8 +82,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { stmt = ?stmt.kind, span = ?stmt.source_info.span, tracing_separate_thread = Empty, - ); - info!(stmt = ?stmt.kind); + ) + .or_if_tracing_disabled(|| info!(stmt = ?stmt.kind)); use rustc_middle::mir::StatementKind::*; @@ -470,8 +471,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { terminator = ?terminator.kind, span = ?terminator.source_info.span, tracing_separate_thread = Empty, - ); - info!(terminator = ?terminator.kind); + ) + .or_if_tracing_disabled(|| info!(terminator = ?terminator.kind)); use rustc_middle::mir::TerminatorKind::*; match terminator.kind { diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 6696a0c50260..71800950faab 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -48,10 +48,24 @@ pub(crate) fn create_static_alloc<'tcx>( /// A marker trait returned by [crate::interpret::Machine::enter_trace_span], identifying either a /// real [tracing::span::EnteredSpan] in case tracing is enabled, or the dummy type `()` when -/// tracing is disabled. -pub trait EnteredTraceSpan {} -impl EnteredTraceSpan for () {} -impl EnteredTraceSpan for tracing::span::EnteredSpan {} +/// tracing is disabled. Also see [crate::enter_trace_span!] below. +pub trait EnteredTraceSpan { + /// Allows executing an alternative function when tracing is disabled. Useful for example if you + /// want to open a trace span when tracing is enabled, and alternatively just log a line when + /// tracing is disabled. + fn or_if_tracing_disabled(self, f: impl FnOnce()) -> Self; +} +impl EnteredTraceSpan for () { + fn or_if_tracing_disabled(self, f: impl FnOnce()) -> Self { + f(); // tracing is disabled, execute the function + self + } +} +impl EnteredTraceSpan for tracing::span::EnteredSpan { + fn or_if_tracing_disabled(self, _f: impl FnOnce()) -> Self { + self // tracing is enabled, don't execute anything + } +} /// Shortand for calling [crate::interpret::Machine::enter_trace_span] on a [tracing::info_span!]. /// This is supposed to be compiled out when [crate::interpret::Machine::enter_trace_span] has the @@ -112,6 +126,19 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {} /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; /// let _span = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); /// ``` +/// +/// ### Executing something else when tracing is disabled +/// +/// [crate::interpret::Machine::enter_trace_span] returns [EnteredTraceSpan], on which you can call +/// [EnteredTraceSpan::or_if_tracing_disabled], to e.g. log a line as an alternative to the tracing +/// span for when tracing is disabled. For example: +/// ```rust +/// # use rustc_const_eval::enter_trace_span; +/// # use rustc_const_eval::interpret::EnteredTraceSpan; +/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; +/// let _span = enter_trace_span!(M, step::eval_statement) +/// .or_if_tracing_disabled(|| tracing::info!("eval_statement")); +/// ``` #[macro_export] macro_rules! enter_trace_span { ($machine:ty, $name:ident :: $subname:ident $($tt:tt)*) => { From 8a3a7e625a8b607c018cdcf776fa79e29eaa56c8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 22 Jul 2025 20:54:22 +0200 Subject: [PATCH 135/242] Add lint against dangling pointers form local variables --- compiler/rustc_lint/messages.ftl | 6 + compiler/rustc_lint/src/dangling.rs | 150 ++++++++++- compiler/rustc_lint/src/lints.rs | 16 ++ .../ui/lint/dangling-pointers-from-locals.rs | 188 +++++++++++++ .../lint/dangling-pointers-from-locals.stderr | 247 ++++++++++++++++++ 5 files changed, 599 insertions(+), 8 deletions(-) create mode 100644 tests/ui/lint/dangling-pointers-from-locals.rs create mode 100644 tests/ui/lint/dangling-pointers-from-locals.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 69fe7fe83ffd..4d0c0c94a813 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i lint_custom_inner_attribute_unstable = custom inner attributes are unstable +lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped + .ret_ty = return type of the {$fn_kind} is `{$ret_ty}` + .local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind} + .created_at = dangling pointer created here + .note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned + lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 9e19949c3b6e..af4457f4314b 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -1,13 +1,14 @@ use rustc_ast::visit::{visit_opt, walk_list}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr}; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::{Span, sym}; -use crate::lints::DanglingPointersFromTemporaries; +use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -42,6 +43,36 @@ declare_lint! { "detects getting a pointer from a temporary" } +declare_lint! { + /// The `dangling_pointers_from_locals` lint detects getting a pointer to data + /// of a local that will be dropped at the end of the function. + /// + /// ### Example + /// + /// ```rust + /// fn f() -> *const u8 { + /// let x = 0; + /// &x // returns a dangling ptr to `x` + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Returning a pointer from a local value will not prolong its lifetime, + /// which means that the value can be dropped and the allocation freed + /// while the pointer still exists, making the pointer dangling. + /// This is not an error (as far as the type system is concerned) + /// but probably is not what the user intended either. + /// + /// If you need stronger guarantees, consider using references instead, + /// as they are statically verified by the borrow-checker to never dangle. + pub DANGLING_POINTERS_FROM_LOCALS, + Warn, + "detects returning a pointer from a local variable" +} + /// FIXME: false negatives (i.e. the lint is not emitted when it should be) /// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` @@ -53,20 +84,123 @@ declare_lint! { #[derive(Clone, Copy, Default)] pub(crate) struct DanglingPointers; -impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]); +impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]); // This skips over const blocks, but they cannot use or return a dangling pointer anyways. impl<'tcx> LateLintPass<'tcx> for DanglingPointers { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, body: &'tcx Body<'tcx>, _: Span, - _: LocalDefId, + def_id: LocalDefId, ) { - DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body) + DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body); + + if let FnRetTy::Return(ret_ty) = &fn_decl.output + && let TyKind::Ptr(_) = ret_ty.kind + { + // get the return type of the function or closure + let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() { + ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(), + ty::Closure(_, args) => args.as_closure().sig(), + _ => return, + }; + let ty = ty.output(); + + // this type is only used for layout computation and pretty-printing, neither of them rely on regions + let ty = cx.tcx.instantiate_bound_regions_with_erased(ty); + + // verify that we have a pointer type + let inner_ty = match ty.kind() { + ty::RawPtr(inner_ty, _) => *inner_ty, + _ => return, + }; + + if cx + .tcx + .layout_of(cx.typing_env().as_query_input(inner_ty)) + .is_ok_and(|layout| !layout.is_1zst()) + { + let dcx = &DanglingPointerLocalContext { + body: def_id, + fn_ret: ty, + fn_ret_span: ret_ty.span, + fn_ret_inner: inner_ty, + fn_kind: match fn_kind { + FnKind::ItemFn(..) => "function", + FnKind::Method(..) => "method", + FnKind::Closure => "closure", + }, + }; + + // look for `return`s + DanglingPointerReturnSearcher { cx, dcx }.visit_body(body); + + // analyze implicit return expression + if let ExprKind::Block(block, None) = &body.value.kind + && let innermost_block = block.innermost_block() + && let Some(expr) = innermost_block.expr + { + lint_addr_of_local(cx, dcx, expr); + } + } + } + } +} + +struct DanglingPointerLocalContext<'tcx> { + body: LocalDefId, + fn_ret: Ty<'tcx>, + fn_ret_span: Span, + fn_ret_inner: Ty<'tcx>, + fn_kind: &'static str, +} + +struct DanglingPointerReturnSearcher<'lcx, 'tcx> { + cx: &'lcx LateContext<'tcx>, + dcx: &'lcx DanglingPointerLocalContext<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Ret(Some(expr)) = expr.kind { + lint_addr_of_local(self.cx, self.dcx, expr); + } + walk_expr(self, expr) + } +} + +/// Look for `&` pattern and emit lint for it +fn lint_addr_of_local<'a>( + cx: &LateContext<'a>, + dcx: &DanglingPointerLocalContext<'a>, + expr: &'a Expr<'a>, +) { + // peel casts as they do not interest us here, we want the inner expression. + let (inner, _) = super::utils::peel_casts(cx, expr); + + if let ExprKind::AddrOf(_, _, inner_of) = inner.kind + && let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind + && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id) + && cx.tcx.hir_enclosing_body_owner(from) == dcx.body + { + cx.tcx.emit_node_span_lint( + DANGLING_POINTERS_FROM_LOCALS, + expr.hir_id, + expr.span, + DanglingPointersFromLocals { + ret_ty: dcx.fn_ret, + ret_ty_span: dcx.fn_ret_span, + fn_kind: dcx.fn_kind, + local_var: cx.tcx.hir_span(from), + local_var_name: cx.tcx.hir_ident(from), + local_var_ty: dcx.fn_ret_inner, + created_at: (expr.hir_id != inner.hir_id).then_some(inner.span), + }, + ); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fd8d0f832aa4..ef63c0dee8c2 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub temporary_span: Span, } +#[derive(LintDiagnostic)] +#[diag(lint_dangling_pointers_from_locals)] +#[note] +pub(crate) struct DanglingPointersFromLocals<'tcx> { + pub ret_ty: Ty<'tcx>, + #[label(lint_ret_ty)] + pub ret_ty_span: Span, + pub fn_kind: &'static str, + #[label(lint_local_var)] + pub local_var: Span, + pub local_var_name: Ident, + pub local_var_ty: Ty<'tcx>, + #[label(lint_created_at)] + pub created_at: Option, +} + // multiple_supertrait_upcastable.rs #[derive(LintDiagnostic)] #[diag(lint_multiple_supertrait_upcastable)] diff --git a/tests/ui/lint/dangling-pointers-from-locals.rs b/tests/ui/lint/dangling-pointers-from-locals.rs new file mode 100644 index 000000000000..e321df2f4279 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-locals.rs @@ -0,0 +1,188 @@ +//@ check-pass + +struct Zst((), ()); +struct Adt(u8); + +const X: u8 = 5; + +fn simple() -> *const u8 { + let x = 0; + &x + //~^ WARN a dangling pointer will be produced +} + +fn bindings() -> *const u8 { + let x = 0; + let x = &x; + x + //~^ WARN a dangling pointer will be produced +} + +fn bindings_with_return() -> *const u8 { + let x = 42; + let y = &x; + return y; + //~^ WARN a dangling pointer will be produced +} + +fn with_simple_cast() -> *const u8 { + let x = 0u8; + &x as *const u8 + //~^ WARN a dangling pointer will be produced +} + +fn bindings_and_casts() -> *const u8 { + let x = 0u8; + let x = &x as *const u8; + x as *const u8 + //~^ WARN a dangling pointer will be produced +} + +fn return_with_complex_cast() -> *mut u8 { + let mut x = 0u8; + return &mut x as *mut u8 as *const u8 as *mut u8; + //~^ WARN a dangling pointer will be produced +} + +fn with_block() -> *const u8 { + let x = 0; + &{ x } + //~^ WARN a dangling pointer will be produced +} + +fn with_many_blocks() -> *const u8 { + let x = 0; + { + { + &{ + //~^ WARN a dangling pointer will be produced + { x } + } + } + } +} + +fn simple_return() -> *const u8 { + let x = 0; + return &x; + //~^ WARN a dangling pointer will be produced +} + +fn return_mut() -> *mut u8 { + let mut x = 0; + return &mut x; + //~^ WARN a dangling pointer will be produced +} + +fn const_and_flow() -> *const u8 { + if false { + let x = 8; + return &x; + //~^ WARN a dangling pointer will be produced + } + &X // not dangling +} + +fn vector() -> *const Vec { + let x = vec![T::default()]; + &x + //~^ WARN a dangling pointer will be produced +} + +fn local_adt() -> *const Adt { + let x = Adt(5); + return &x; + //~^ WARN a dangling pointer will be produced +} + +fn closure() -> *const u8 { + let _x = || -> *const u8 { + let x = 8; + return &x; + //~^ WARN a dangling pointer will be produced + }; + &X // not dangling +} + +fn fn_ptr() -> *const fn() -> u8 { + fn ret_u8() -> u8 { + 0 + } + + let x = ret_u8 as fn() -> u8; + &x + //~^ WARN a dangling pointer will be produced +} + +fn as_arg(a: Adt) -> *const Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 { + &a + //~^ WARN a dangling pointer will be produced +} + +fn ptr_as_arg(a: *const Adt) -> *const *const Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn adt_as_arg(a: &Adt) -> *const &Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn unit() -> *const () { + let x = (); + &x // not dangling +} + +fn zst() -> *const Zst { + let x = Zst((), ()); + &x // not dangling +} + +fn ref_implicit(a: &Adt) -> *const Adt { + a // not dangling +} + +fn ref_explicit(a: &Adt) -> *const Adt { + &*a // not dangling +} + +fn identity(a: *const Adt) -> *const Adt { + a // not dangling +} + +fn from_ref(a: &Adt) -> *const Adt { + std::ptr::from_ref(a) // not dangling +} + +fn inner_static() -> *const u8 { + static U: u8 = 5; + if false { + return &U as *const u8; // not dangling + } + &U // not dangling +} + +fn return_in_closure() { + let x = 0; + let c = || -> *const u8 { + &x // not dangling by it-self + }; +} + +fn option() -> *const Option { + let x = Some(T::default()); + &x // can't compute layout of `Option`, so cnat' be sure it won't be a ZST +} + +fn generic() -> *const T { + let x = T::default(); + &x // can't compute layout of `T`, so can't be sure it won't be a ZST +} + +fn main() {} diff --git a/tests/ui/lint/dangling-pointers-from-locals.stderr b/tests/ui/lint/dangling-pointers-from-locals.stderr new file mode 100644 index 000000000000..e1d28bf22a0c --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-locals.stderr @@ -0,0 +1,247 @@ +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:10:5 + | +LL | fn simple() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + = note: `#[warn(dangling_pointers_from_locals)]` on by default + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:17:5 + | +LL | fn bindings() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | let x = &x; + | -- dangling pointer created here +LL | x + | ^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:24:12 + | +LL | fn bindings_with_return() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 42; + | - `x` is part the function and will be dropped at the end of the function +LL | let y = &x; + | -- dangling pointer created here +LL | return y; + | ^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:30:5 + | +LL | fn with_simple_cast() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0u8; + | - `x` is part the function and will be dropped at the end of the function +LL | &x as *const u8 + | --^^^^^^^^^^^^^ + | | + | dangling pointer created here + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:37:5 + | +LL | fn bindings_and_casts() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0u8; + | - `x` is part the function and will be dropped at the end of the function +LL | let x = &x as *const u8; + | -- dangling pointer created here +LL | x as *const u8 + | ^^^^^^^^^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:43:12 + | +LL | fn return_with_complex_cast() -> *mut u8 { + | ------- return type of the function is `*mut u8` +LL | let mut x = 0u8; + | ----- `x` is part the function and will be dropped at the end of the function +LL | return &mut x as *mut u8 as *const u8 as *mut u8; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | dangling pointer created here + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:49:5 + | +LL | fn with_block() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | &{ x } + | ^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:57:13 + | +LL | fn with_many_blocks() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +... +LL | / &{ +LL | | +LL | | { x } +LL | | } + | |_____________^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:67:12 + | +LL | fn simple_return() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:73:12 + | +LL | fn return_mut() -> *mut u8 { + | ------- return type of the function is `*mut u8` +LL | let mut x = 0; + | ----- `x` is part the function and will be dropped at the end of the function +LL | return &mut x; + | ^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:80:16 + | +LL | fn const_and_flow() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | if false { +LL | let x = 8; + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:88:5 + | +LL | fn vector() -> *const Vec { + | ------------- return type of the function is `*const Vec` +LL | let x = vec![T::default()]; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Vec` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:94:12 + | +LL | fn local_adt() -> *const Adt { + | ---------- return type of the function is `*const Adt` +LL | let x = Adt(5); + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:101:16 + | +LL | let _x = || -> *const u8 { + | --------- return type of the closure is `*const u8` +LL | let x = 8; + | - `x` is part the closure and will be dropped at the end of the closure +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the closure because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:113:5 + | +LL | fn fn_ptr() -> *const fn() -> u8 { + | ----------------- return type of the function is `*const fn() -> u8` +... +LL | let x = ret_u8 as fn() -> u8; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:118:5 + | +LL | fn as_arg(a: Adt) -> *const Adt { + | - ---------- return type of the function is `*const Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:123:5 + | +LL | fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 { + | - ----------------- return type of the function is `*const fn() -> u8` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:128:5 + | +LL | fn ptr_as_arg(a: *const Adt) -> *const *const Adt { + | - ----------------- return type of the function is `*const *const Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `*const Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:133:5 + | +LL | fn adt_as_arg(a: &Adt) -> *const &Adt { + | - ----------- return type of the function is `*const &Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `&Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: 19 warnings emitted + From 21ec0d5a4c0ebf11175a95f5f01749f8dcf134e7 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 22 Jul 2025 23:11:52 +0200 Subject: [PATCH 136/242] Allow `dangling_pointers_from_locals` lint in tests --- src/tools/miri/tests/fail/validity/dangling_ref3.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/miri/tests/fail/validity/dangling_ref3.rs b/src/tools/miri/tests/fail/validity/dangling_ref3.rs index 8e8a75bd7ec0..0fecd8f1c285 100644 --- a/src/tools/miri/tests/fail/validity/dangling_ref3.rs +++ b/src/tools/miri/tests/fail/validity/dangling_ref3.rs @@ -1,5 +1,8 @@ // Make sure we catch this even without Stacked Borrows //@compile-flags: -Zmiri-disable-stacked-borrows + +#![allow(dangling_pointers_from_locals)] + use std::mem; fn dangling() -> *const u8 { From 5aec4379e304ef280ee9a470e7ab121e4a81fd17 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 31 Jul 2025 23:59:06 +0200 Subject: [PATCH 137/242] detect infinite recursion with tail calls in ctfe --- compiler/rustc_mir_transform/src/ctfe_limit.rs | 2 +- .../infinite-recursion-in-ctfe.rs | 10 ++++++++++ .../infinite-recursion-in-ctfe.stderr | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs create mode 100644 tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index fb17cca30f4a..ac46336b8347 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -18,7 +18,7 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit { .basic_blocks .iter_enumerated() .filter_map(|(node, node_data)| { - if matches!(node_data.terminator().kind, TerminatorKind::Call { .. }) + if matches!(node_data.terminator().kind, TerminatorKind::Call { .. } | TerminatorKind::TailCall { .. }) // Back edges in a CFG indicate loops || has_back_edge(doms, node, node_data) { diff --git a/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs new file mode 100644 index 000000000000..0c55f13c16c2 --- /dev/null +++ b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs @@ -0,0 +1,10 @@ +#![feature(explicit_tail_calls)] +#![expect(incomplete_features)] + +const _: () = f(); + +const fn f() { + become f(); //~ error: constant evaluation is taking a long time +} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr new file mode 100644 index 000000000000..b5a96114a583 --- /dev/null +++ b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr @@ -0,0 +1,17 @@ +error: constant evaluation is taking a long time + --> $DIR/infinite-recursion-in-ctfe.rs:7:5 + | +LL | become f(); + | ^^^^^^^^^^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/infinite-recursion-in-ctfe.rs:4:1 + | +LL | const _: () = f(); + | ^^^^^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + From eae1d392e7453f6f1fcd03eb74452dd05929db4e Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 31 Jul 2025 15:57:41 -0600 Subject: [PATCH 138/242] chore: Ping Muscraft when annnotate snippets emitter is modified --- triagebot.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 168815465b61..819a4b108974 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1064,6 +1064,10 @@ cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@vakaras"] message = "`rustc_error_messages` was changed" cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] +[mentions."compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs"] +message = "`rustc_errors::annotate_snippet_emitter_writer` was changed" +cc = ["@Muscraft"] + [mentions."compiler/rustc_errors/src/translation.rs"] message = "`rustc_errors::translation` was changed" cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] From 1f787383d4463f18a8ec6da89ca962246b92f226 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 31 Jul 2025 15:57:41 -0600 Subject: [PATCH 139/242] chore: Ping Muscraft when rustc_errors::emitter is modified --- triagebot.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 819a4b108974..b0b0f8d87527 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1068,6 +1068,10 @@ cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] message = "`rustc_errors::annotate_snippet_emitter_writer` was changed" cc = ["@Muscraft"] +[mentions."compiler/rustc_errors/src/emitter.rs"] +message = "`rustc_errors::emitter` was changed" +cc = ["@Muscraft"] + [mentions."compiler/rustc_errors/src/translation.rs"] message = "`rustc_errors::translation` was changed" cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"] From 040f71e8123b5994177f787e64aecd9b06cdfa7e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Jul 2025 15:18:51 +0200 Subject: [PATCH 140/242] loop match: error on `#[const_continue]` outside `#[loop_match]` --- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_typeck/src/loops.rs | 50 +++++++++++-------- compiler/rustc_mir_build/messages.ftl | 2 +- compiler/rustc_mir_build/src/errors.rs | 4 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 +- .../ui/loop-match/const-continue-to-block.rs | 21 ++++++++ .../loop-match/const-continue-to-block.stderr | 17 ++++++- tests/ui/loop-match/invalid.rs | 19 +++++++ tests/ui/loop-match/invalid.stderr | 22 ++++++-- 9 files changed, 107 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1b1b3ced44db..08361718108b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3016,7 +3016,7 @@ impl fmt::Display for LoopIdError { } } -#[derive(Copy, Clone, Debug, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable_Generic)] pub struct Destination { /// This is `Some(_)` iff there is an explicit user-specified 'label pub label: Option