From 04d9b08c85646acbd50f0081c5d7150a3b2cb2b0 Mon Sep 17 00:00:00 2001 From: Evelyn Harthbrooke Date: Sat, 3 Aug 2024 02:26:30 -0600 Subject: [PATCH 01/17] Promote aarch64-apple-darwin to Tier 1 Per rust-lang/rfcs#3671. --- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- src/doc/rustc/src/platform-support.md | 2 +- src/doc/rustc/src/platform-support/apple-darwin.md | 3 --- src/tools/miri/README.md | 1 - src/tools/miri/ci/ci.sh | 2 +- 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 81e591be6997c..4746a969a2d53 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -194,6 +194,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { let supported_platforms = [ // tier 1 ("aarch64-unknown-linux-gnu", false), + ("aarch64-apple-darwin", false), ("i686-pc-windows-gnu", false), ("i686-pc-windows-msvc", false), ("i686-unknown-linux-gnu", false), @@ -202,7 +203,6 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { ("x86_64-pc-windows-gnu", true), ("x86_64-pc-windows-msvc", true), // tier 2 with host tools - ("aarch64-apple-darwin", false), ("aarch64-pc-windows-msvc", false), ("aarch64-unknown-linux-musl", false), ("arm-unknown-linux-gnueabi", false), diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f3b49a65aad28..3b65329f6d5b4 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -33,6 +33,7 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) +[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) `i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI] `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI] @@ -86,7 +87,6 @@ so Rustup may install the documentation for a similar tier 1 target instead. target | notes -------|------- -[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) `aarch64-pc-windows-msvc` | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17) diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md index 0fb86949a4b79..c3a7b81f411e8 100644 --- a/src/doc/rustc/src/platform-support/apple-darwin.md +++ b/src/doc/rustc/src/platform-support/apple-darwin.md @@ -5,9 +5,6 @@ Apple macOS targets. **Tier: 1** - `x86_64-apple-darwin`: macOS on 64-bit x86. - -**Tier: 2 (with Host Tools)** - - `aarch64-apple-darwin`: macOS on ARM64 (M1-family or later Apple Silicon CPUs). ## Target maintainers diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index b1be596c00679..909a5d40b4cfc 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -212,7 +212,6 @@ degree documented below): - All Rust [Tier 1 targets](https://doc.rust-lang.org/rustc/platform-support.html) are supported by Miri. They are all checked on Miri's CI, and some (at least one per OS) are even checked on every Rust PR, so the shipped Miri should always work on these targets. -- `aarch64-apple-darwin` is supported. - `s390x-unknown-linux-gnu` is supported as our "big-endian target of choice". - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we make no promises and we don't run tests for such targets. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 5e75638f46709..3e90ecc5c0397 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -137,7 +137,7 @@ case $HOST_TARGET in MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests ;; aarch64-apple-darwin) - # Host (tier 2) + # Host GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests From ccfd94e33473b610127aec56ab72c9eef4a9d1c8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 19:55:16 +1000 Subject: [PATCH 02/17] Break up `print::Pat` printing into several helper functions --- .../rustc_pattern_analysis/src/rustc/print.rs | 255 ++++++++++-------- 1 file changed, 142 insertions(+), 113 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 4b76764e8b136..59e6b1480c701 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -64,130 +64,159 @@ pub(crate) enum PatKind<'tcx> { impl<'tcx> fmt::Display for Pat<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Printing lists is a chore. - let mut first = true; - let mut start_or_continue = |s| { - if first { - first = false; - "" - } else { - s - } - }; - let mut start_or_comma = || start_or_continue(", "); - match self.kind { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant_and_name = match self.kind { - PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { - let variant = adt_def.variant(variant_index); - let adt_did = adt_def.did(); - let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) - || tcx.get_diagnostic_item(sym::Result) == Some(adt_did) - { - variant.name.to_string() - } else { - format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) - }; - Some((variant, name)) - }), - _ => self.ty.ty_adt_def().and_then(|adt_def| { - if !adt_def.is_enum() { - ty::tls::with(|tcx| { - Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) - }) - } else { - None - } - }), - }; - - if let Some((variant, name)) = &variant_and_name { - write!(f, "{name}")?; - - // Only for Adt we can have `S {...}`, - // which we handle separately here. - if variant.ctor.is_none() { - write!(f, " {{ ")?; - - let mut printed = 0; - for p in subpatterns { - if let PatKind::Wild = p.pattern.kind { - continue; - } - let name = variant.fields[p.field].name; - write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; - printed += 1; - } - - let is_union = self.ty.ty_adt_def().is_some_and(|adt| adt.is_union()); - if printed < variant.fields.len() && (!is_union || printed == 0) { - write!(f, "{}..", start_or_comma())?; - } - - return write!(f, " }}"); - } - } - - let num_fields = - variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len()); - if num_fields != 0 || variant_and_name.is_none() { - write!(f, "(")?; - for i in 0..num_fields { - write!(f, "{}", start_or_comma())?; - - // Common case: the field is where we expect it. - if let Some(p) = subpatterns.get(i) { - if p.field.index() == i { - write!(f, "{}", p.pattern)?; - continue; - } - } - - // Otherwise, we have to go looking for it. - if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { - write!(f, "{}", p.pattern)?; - } else { - write!(f, "_")?; - } - } - write!(f, ")")?; - } - - Ok(()) - } - PatKind::Deref { ref subpattern } => { - match self.ty.kind() { - ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, - ty::Ref(_, _, mutbl) => { - write!(f, "&{}", mutbl.prefix_str())?; - } - _ => bug!("{} is a bad Deref pattern type", self.ty), - } - write!(f, "{subpattern}") + write_struct_like(f, self.ty, &self.kind, subpatterns) } + PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern), PatKind::Constant { value } => write!(f, "{value}"), PatKind::Range(ref range) => write!(f, "{range}"), PatKind::Slice { ref prefix, ref slice, ref suffix } => { - write!(f, "[")?; - for p in prefix.iter() { - write!(f, "{}{}", start_or_comma(), p)?; - } - if let Some(ref slice) = *slice { - write!(f, "{}", start_or_comma())?; - match slice.kind { - PatKind::Wild => {} - _ => write!(f, "{slice}")?, - } - write!(f, "..")?; + write_slice_like(f, prefix, slice, suffix) + } + } + } +} + +/// Returns a closure that will return `""` when called the first time, +/// and then return `", "` when called any subsequent times. +/// Useful for printing comma-separated lists. +fn start_or_comma() -> impl FnMut() -> &'static str { + let mut first = true; + move || { + if first { + first = false; + "" + } else { + ", " + } + } +} + +fn write_struct_like<'tcx>( + f: &mut impl fmt::Write, + ty: Ty<'tcx>, + kind: &PatKind<'tcx>, + subpatterns: &[FieldPat<'tcx>], +) -> fmt::Result { + let variant_and_name = match *kind { + PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { + let variant = adt_def.variant(variant_index); + let adt_did = adt_def.did(); + let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) + || tcx.get_diagnostic_item(sym::Result) == Some(adt_did) + { + variant.name.to_string() + } else { + format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) + }; + Some((variant, name)) + }), + _ => ty.ty_adt_def().and_then(|adt_def| { + if !adt_def.is_enum() { + ty::tls::with(|tcx| { + Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) + }) + } else { + None + } + }), + }; + + let mut start_or_comma = start_or_comma(); + + if let Some((variant, name)) = &variant_and_name { + write!(f, "{name}")?; + + // Only for Adt we can have `S {...}`, + // which we handle separately here. + if variant.ctor.is_none() { + write!(f, " {{ ")?; + + let mut printed = 0; + for p in subpatterns { + if let PatKind::Wild = p.pattern.kind { + continue; } - for p in suffix.iter() { - write!(f, "{}{}", start_or_comma(), p)?; + let name = variant.fields[p.field].name; + write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; + printed += 1; + } + + let is_union = ty.ty_adt_def().is_some_and(|adt| adt.is_union()); + if printed < variant.fields.len() && (!is_union || printed == 0) { + write!(f, "{}..", start_or_comma())?; + } + + return write!(f, " }}"); + } + } + + let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len()); + if num_fields != 0 || variant_and_name.is_none() { + write!(f, "(")?; + for i in 0..num_fields { + write!(f, "{}", start_or_comma())?; + + // Common case: the field is where we expect it. + if let Some(p) = subpatterns.get(i) { + if p.field.index() == i { + write!(f, "{}", p.pattern)?; + continue; } - write!(f, "]") + } + + // Otherwise, we have to go looking for it. + if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { + write!(f, "{}", p.pattern)?; + } else { + write!(f, "_")?; } } + write!(f, ")")?; + } + + Ok(()) +} + +fn write_ref_like<'tcx>( + f: &mut impl fmt::Write, + ty: Ty<'tcx>, + subpattern: &Pat<'tcx>, +) -> fmt::Result { + match ty.kind() { + ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, + ty::Ref(_, _, mutbl) => { + write!(f, "&{}", mutbl.prefix_str())?; + } + _ => bug!("{ty} is a bad ref pattern type"), + } + write!(f, "{subpattern}") +} + +fn write_slice_like<'tcx>( + f: &mut impl fmt::Write, + prefix: &[Box>], + slice: &Option>>, + suffix: &[Box>], +) -> fmt::Result { + let mut start_or_comma = start_or_comma(); + write!(f, "[")?; + for p in prefix.iter() { + write!(f, "{}{}", start_or_comma(), p)?; + } + if let Some(ref slice) = *slice { + write!(f, "{}", start_or_comma())?; + match slice.kind { + PatKind::Wild => {} + _ => write!(f, "{slice}")?, + } + write!(f, "..")?; + } + for p in suffix.iter() { + write!(f, "{}{}", start_or_comma(), p)?; } + write!(f, "]") } From 74f76ae5ea1a9fcd0b3d7adbac93b98237e4063e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 20:05:44 +1000 Subject: [PATCH 03/17] Unify `Variant` and `Leaf` into `print::PatKind::StructLike` --- compiler/rustc_pattern_analysis/src/rustc.rs | 18 ++++++++----- .../rustc_pattern_analysis/src/rustc/print.rs | 27 ++++++++++--------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 6290aeb252312..7fe2c14a74588 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -23,6 +23,7 @@ use crate::constructor::{ }; use crate::lints::lint_nonexhaustive_missing_variants; use crate::pat_column::PatternColumn; +use crate::rustc::print::EnumInfo; use crate::usefulness::{compute_match_usefulness, PlaceValidity}; use crate::{errors, Captures, PatCx, PrivateUninhabitedField}; @@ -832,7 +833,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) }, IntRange(range) => return self.hoist_pat_range(range, *pat.ty()), Struct | Variant(_) | UnionField => match pat.ty().kind() { - ty::Tuple(..) => PatKind::Leaf { + ty::Tuple(..) => PatKind::StructLike { + enum_info: EnumInfo::NotEnum, subpatterns: subpatterns .enumerate() .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) @@ -844,18 +846,20 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // the pattern is a box pattern. PatKind::Deref { subpattern: subpatterns.next().unwrap() } } - ty::Adt(adt_def, _args) => { - let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), *adt_def); + &ty::Adt(adt_def, _) => { + let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), adt_def); let subpatterns = subpatterns .enumerate() .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) .collect(); - if adt_def.is_enum() { - PatKind::Variant { adt_def: *adt_def, variant_index, subpatterns } + let enum_info = if adt_def.is_enum() { + EnumInfo::Enum { adt_def, variant_index } } else { - PatKind::Leaf { subpatterns } - } + EnumInfo::NotEnum + }; + + PatKind::StructLike { enum_info, subpatterns } } _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()), }, diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 59e6b1480c701..b85c15d83920b 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -33,13 +33,8 @@ pub(crate) struct Pat<'tcx> { pub(crate) enum PatKind<'tcx> { Wild, - Variant { - adt_def: AdtDef<'tcx>, - variant_index: VariantIdx, - subpatterns: Vec>, - }, - - Leaf { + StructLike { + enum_info: EnumInfo<'tcx>, subpatterns: Vec>, }, @@ -67,8 +62,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> { match self.kind { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), - PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - write_struct_like(f, self.ty, &self.kind, subpatterns) + PatKind::StructLike { ref enum_info, ref subpatterns } => { + write_struct_like(f, self.ty, enum_info, subpatterns) } PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern), PatKind::Constant { value } => write!(f, "{value}"), @@ -95,14 +90,20 @@ fn start_or_comma() -> impl FnMut() -> &'static str { } } +#[derive(Clone, Debug)] +pub(crate) enum EnumInfo<'tcx> { + Enum { adt_def: AdtDef<'tcx>, variant_index: VariantIdx }, + NotEnum, +} + fn write_struct_like<'tcx>( f: &mut impl fmt::Write, ty: Ty<'tcx>, - kind: &PatKind<'tcx>, + enum_info: &EnumInfo<'tcx>, subpatterns: &[FieldPat<'tcx>], ) -> fmt::Result { - let variant_and_name = match *kind { - PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { + let variant_and_name = match *enum_info { + EnumInfo::Enum { adt_def, variant_index } => ty::tls::with(|tcx| { let variant = adt_def.variant(variant_index); let adt_did = adt_def.did(); let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) @@ -114,7 +115,7 @@ fn write_struct_like<'tcx>( }; Some((variant, name)) }), - _ => ty.ty_adt_def().and_then(|adt_def| { + EnumInfo::NotEnum => ty.ty_adt_def().and_then(|adt_def| { if !adt_def.is_enum() { ty::tls::with(|tcx| { Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) From 4cd800503f0c0ba3c26f30c98aff755be6b9be43 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 20:10:17 +1000 Subject: [PATCH 04/17] Remove an impossible case under `EnumInfo::NotEnum` --- compiler/rustc_pattern_analysis/src/rustc/print.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index b85c15d83920b..d14233ee0242b 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -116,13 +116,7 @@ fn write_struct_like<'tcx>( Some((variant, name)) }), EnumInfo::NotEnum => ty.ty_adt_def().and_then(|adt_def| { - if !adt_def.is_enum() { - ty::tls::with(|tcx| { - Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) - }) - } else { - None - } + ty::tls::with(|tcx| Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))) }), }; From e98e19e49108b6e49e452c3bd22c1aeccd43e507 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 20:09:12 +1000 Subject: [PATCH 05/17] Replace an unnecessary slice pattern with `has_dot_dot: bool` --- compiler/rustc_pattern_analysis/src/rustc.rs | 5 ++--- .../rustc_pattern_analysis/src/rustc/print.rs | 19 ++++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7fe2c14a74588..f27c279912f78 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -872,7 +872,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { match slice.kind { SliceKind::FixedLen(_) => PatKind::Slice { prefix: subpatterns.collect(), - slice: None, + has_dot_dot: false, suffix: Box::new([]), }, SliceKind::VarLen(prefix, _) => { @@ -893,10 +893,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } } let suffix: Box<[_]> = subpatterns.collect(); - let wild = Pat { ty: pat.ty().inner(), kind: PatKind::Wild }; PatKind::Slice { prefix: prefix.into_boxed_slice(), - slice: Some(Box::new(wild)), + has_dot_dot: true, suffix, } } diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index d14233ee0242b..e7568b9e2bd3e 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -50,7 +50,9 @@ pub(crate) enum PatKind<'tcx> { Slice { prefix: Box<[Box>]>, - slice: Option>>, + /// True if this slice-like pattern should include a `..` between the + /// prefix and suffix. + has_dot_dot: bool, suffix: Box<[Box>]>, }, @@ -68,8 +70,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> { PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern), PatKind::Constant { value } => write!(f, "{value}"), PatKind::Range(ref range) => write!(f, "{range}"), - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - write_slice_like(f, prefix, slice, suffix) + PatKind::Slice { ref prefix, has_dot_dot, ref suffix } => { + write_slice_like(f, prefix, has_dot_dot, suffix) } } } @@ -194,7 +196,7 @@ fn write_ref_like<'tcx>( fn write_slice_like<'tcx>( f: &mut impl fmt::Write, prefix: &[Box>], - slice: &Option>>, + has_dot_dot: bool, suffix: &[Box>], ) -> fmt::Result { let mut start_or_comma = start_or_comma(); @@ -202,13 +204,8 @@ fn write_slice_like<'tcx>( for p in prefix.iter() { write!(f, "{}{}", start_or_comma(), p)?; } - if let Some(ref slice) = *slice { - write!(f, "{}", start_or_comma())?; - match slice.kind { - PatKind::Wild => {} - _ => write!(f, "{slice}")?, - } - write!(f, "..")?; + if has_dot_dot { + write!(f, "{}..", start_or_comma())?; } for p in suffix.iter() { write!(f, "{}{}", start_or_comma(), p)?; From 7f48851416c0faf0333a23ba37904f4a407c723b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 1 Aug 2024 20:49:52 +1000 Subject: [PATCH 06/17] Split out a `hoist` helper in `hoist_witness_pat` --- compiler/rustc_pattern_analysis/src/rustc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index f27c279912f78..9fa5222452ea0 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -828,7 +828,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { use print::{FieldPat, Pat, PatKind}; let cx = self; let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild); - let mut subpatterns = pat.iter_fields().map(|p| Box::new(cx.hoist_witness_pat(p))); + let hoist = |p| Box::new(cx.hoist_witness_pat(p)); + let mut subpatterns = pat.iter_fields().map(hoist); let kind = match pat.ctor() { Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) }, IntRange(range) => return self.hoist_pat_range(range, *pat.ty()), From a5ed6fb646f554a3e2071dfdd3a3de2f83b759ec Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 1 Aug 2024 20:29:06 +1000 Subject: [PATCH 07/17] Split out hoisting/printing of `box` patterns --- compiler/rustc_pattern_analysis/src/rustc.rs | 11 +++++------ compiler/rustc_pattern_analysis/src/rustc/print.rs | 6 +++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 9fa5222452ea0..7eee5220ce4dd 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -833,6 +833,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let kind = match pat.ctor() { Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) }, IntRange(range) => return self.hoist_pat_range(range, *pat.ty()), + Struct if pat.ty().is_box() => { + // Outside of the `alloc` crate, the only way to create a struct pattern + // of type `Box` is to use a `box` pattern via #[feature(box_patterns)]. + PatKind::Box { subpattern: hoist(&pat.fields[0]) } + } Struct | Variant(_) | UnionField => match pat.ty().kind() { ty::Tuple(..) => PatKind::StructLike { enum_info: EnumInfo::NotEnum, @@ -841,12 +846,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) .collect(), }, - ty::Adt(adt_def, _) if adt_def.is_box() => { - // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside - // of `std`). So this branch is only reachable when the feature is enabled and - // the pattern is a box pattern. - PatKind::Deref { subpattern: subpatterns.next().unwrap() } - } &ty::Adt(adt_def, _) => { let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), adt_def); let subpatterns = subpatterns diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index e7568b9e2bd3e..64f041dc21a76 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -38,6 +38,10 @@ pub(crate) enum PatKind<'tcx> { subpatterns: Vec>, }, + Box { + subpattern: Box>, + }, + Deref { subpattern: Box>, }, @@ -64,6 +68,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { match self.kind { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), + PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"), PatKind::StructLike { ref enum_info, ref subpatterns } => { write_struct_like(f, self.ty, enum_info, subpatterns) } @@ -184,7 +189,6 @@ fn write_ref_like<'tcx>( subpattern: &Pat<'tcx>, ) -> fmt::Result { match ty.kind() { - ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, ty::Ref(_, _, mutbl) => { write!(f, "&{}", mutbl.prefix_str())?; } From c764bea0c3d8ca9b9fc40b032376d5a1ea1e9096 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 20:28:56 +1000 Subject: [PATCH 08/17] Simplify hoisting of struct-like patterns --- compiler/rustc_pattern_analysis/src/rustc.rs | 39 ++++++++------------ 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7eee5220ce4dd..78355d6c762b5 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -838,31 +838,24 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // of type `Box` is to use a `box` pattern via #[feature(box_patterns)]. PatKind::Box { subpattern: hoist(&pat.fields[0]) } } - Struct | Variant(_) | UnionField => match pat.ty().kind() { - ty::Tuple(..) => PatKind::StructLike { - enum_info: EnumInfo::NotEnum, - subpatterns: subpatterns - .enumerate() - .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) - .collect(), - }, - &ty::Adt(adt_def, _) => { - let variant_index = RustcPatCtxt::variant_index_for_adt(&pat.ctor(), adt_def); - let subpatterns = subpatterns - .enumerate() - .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern }) - .collect(); + Struct | Variant(_) | UnionField => { + let enum_info = match *pat.ty().kind() { + ty::Adt(adt_def, _) if adt_def.is_enum() => EnumInfo::Enum { + adt_def, + variant_index: RustcPatCtxt::variant_index_for_adt(pat.ctor(), adt_def), + }, + ty::Adt(..) | ty::Tuple(..) => EnumInfo::NotEnum, + _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()), + }; - let enum_info = if adt_def.is_enum() { - EnumInfo::Enum { adt_def, variant_index } - } else { - EnumInfo::NotEnum - }; + let subpatterns = pat + .iter_fields() + .enumerate() + .map(|(i, pat)| FieldPat { field: FieldIdx::new(i), pattern: hoist(pat) }) + .collect::>(); - PatKind::StructLike { enum_info, subpatterns } - } - _ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), *pat.ty()), - }, + PatKind::StructLike { enum_info, subpatterns } + } // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to reconstruct the correct constant pattern here. However a string // literal pattern will never be reported as a non-exhaustiveness witness, so we From c4c518d2d496774ecc7a368e826480d1928ed1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 7 Aug 2024 12:41:49 +0200 Subject: [PATCH 09/17] Use more slice patterns inside the compiler --- compiler/rustc_ast/src/ast.rs | 12 ++-- compiler/rustc_ast_lowering/src/delegation.rs | 4 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 4 +- .../rustc_ast_pretty/src/pprust/state/item.rs | 4 +- compiler/rustc_attr/src/builtin.rs | 14 ++--- .../src/diagnostics/outlives_suggestion.rs | 4 +- compiler/rustc_builtin_macros/src/asm.rs | 7 +-- .../src/deriving/generic/mod.rs | 8 +-- compiler/rustc_builtin_macros/src/format.rs | 8 +-- .../src/transitive_relation.rs | 6 +- compiler/rustc_driver_impl/src/lib.rs | 55 +++++++++---------- compiler/rustc_errors/src/emitter.rs | 29 +++++----- compiler/rustc_errors/src/lib.rs | 10 ++-- compiler/rustc_expand/src/base.rs | 8 +-- compiler/rustc_hir_typeck/src/expr.rs | 11 +--- .../rustc_hir_typeck/src/method/confirm.rs | 8 +-- .../rustc_hir_typeck/src/method/suggest.rs | 43 +++++++-------- compiler/rustc_lint/src/nonstandard_style.rs | 4 +- compiler/rustc_lint/src/types.rs | 9 +-- compiler/rustc_lint/src/unused.rs | 10 ++-- .../src/thir/pattern/check_match.rs | 6 +- .../rustc_mir_transform/src/coverage/graph.rs | 4 +- .../src/early_otherwise_branch.rs | 6 +- .../rustc_mir_transform/src/instsimplify.rs | 6 +- compiler/rustc_mir_transform/src/validate.rs | 14 ++--- compiler/rustc_parse/src/parser/expr.rs | 6 +- compiler/rustc_parse/src/parser/item.rs | 5 +- compiler/rustc_parse/src/parser/path.rs | 3 +- compiler/rustc_parse/src/parser/stmt.rs | 6 +- compiler/rustc_passes/src/check_attr.rs | 4 +- .../rustc_passes/src/debugger_visualizer.rs | 4 +- .../rustc_query_system/src/dep_graph/debug.rs | 11 ++-- compiler/rustc_resolve/src/late.rs | 20 +++---- .../rustc_resolve/src/late/diagnostics.rs | 13 ++--- compiler/rustc_resolve/src/macros.rs | 10 ++-- compiler/rustc_session/src/options.rs | 13 +---- compiler/rustc_target/src/spec/mod.rs | 9 ++- .../traits/fulfillment_errors.rs | 3 +- .../traits/on_unimplemented.rs | 8 +-- .../src/error_reporting/traits/suggestions.rs | 3 +- 40 files changed, 191 insertions(+), 221 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fc1af3fc3dd11..a44ed82850480 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -585,7 +585,9 @@ impl Pat { } // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array, // when `P` can be reparsed as a type `T`. - PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?, + PatKind::Slice(pats) if let [pat] = pats.as_slice() => { + pat.to_ty().map(TyKind::Slice)? + } // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)` // assuming `T0` to `Tn` are all syntactically valid as types. PatKind::Tuple(pats) => { @@ -1187,8 +1189,8 @@ impl Expr { /// Does not ensure that the path resolves to a const param, the caller should check this. pub fn is_potential_trivial_const_arg(&self) -> bool { let this = if let ExprKind::Block(block, None) = &self.kind - && block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind + && let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind { expr } else { @@ -1248,7 +1250,9 @@ impl Expr { expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))? } - ExprKind::Array(exprs) if exprs.len() == 1 => exprs[0].to_ty().map(TyKind::Slice)?, + ExprKind::Array(exprs) if let [expr] = exprs.as_slice() => { + expr.to_ty().map(TyKind::Slice)? + } ExprKind::Tup(exprs) => { let tys = exprs.iter().map(|expr| expr.to_ty()).collect::>>()?; diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 6e8ff72cf8759..300bfa101c6bd 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -275,8 +275,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(fn_delegation): Alternatives for target expression lowering: // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600. fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> { - if block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind + if let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind { return self.lower_expr_mut(expr); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index ee4514758c212..c7ff39d23ed26 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -502,8 +502,8 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere if !self.is_beginning_of_line() { self.word(" "); } - if cmnt.lines.len() == 1 { - self.word(cmnt.lines[0].clone()); + if let [line] = cmnt.lines.as_slice() { + self.word(line.clone()); self.hardbreak() } else { self.visual_align(); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 56204d8835a33..85a0b3b202292 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -783,8 +783,8 @@ impl<'a> State<'a> { } if items.is_empty() { self.word("{}"); - } else if items.len() == 1 { - self.print_use_tree(&items[0].0); + } else if let [(item, _)] = items.as_slice() { + self.print_use_tree(item); } else { self.cbox(INDENT_UNIT); self.word("{"); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 12a19ae5c3db9..cf86a6942da7e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -665,12 +665,12 @@ pub fn eval_condition( res & eval_condition(mi.meta_item().unwrap(), sess, features, eval) }), sym::not => { - if mis.len() != 1 { + let [mi] = mis.as_slice() else { dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); return false; - } + }; - !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) + !eval_condition(mi.meta_item().unwrap(), sess, features, eval) } sym::target => { if let Some(features) = features @@ -1051,10 +1051,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { MetaItemKind::List(nested_items) => { if meta_item.has_name(sym::align) { recognised = true; - if nested_items.len() == 1 { + if let [nested_item] = nested_items.as_slice() { sess.dcx().emit_err( session_diagnostics::IncorrectReprFormatExpectInteger { - span: nested_items[0].span(), + span: nested_item.span(), }, ); } else { @@ -1066,10 +1066,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { } } else if meta_item.has_name(sym::packed) { recognised = true; - if nested_items.len() == 1 { + if let [nested_item] = nested_items.as_slice() { sess.dcx().emit_err( session_diagnostics::IncorrectReprFormatPackedExpectInteger { - span: nested_items[0].span(), + span: nested_item.span(), }, ); } else { diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 9356c24d018f7..de0df3474299a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -206,8 +206,8 @@ impl OutlivesSuggestionBuilder { // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a // list of diagnostics. - let mut diag = if suggested.len() == 1 { - mbcx.dcx().struct_help(match suggested.last().unwrap() { + let mut diag = if let [constraint] = suggested.as_slice() { + mbcx.dcx().struct_help(match constraint { SuggestedConstraint::Outlives(a, bs) => { let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect(); format!("add bound `{a}: {}`", bs.join(" + ")) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 17439dd3e3eda..ed54c0c86626e 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -745,10 +745,9 @@ fn expand_preparsed_asm( unused_operands.push((args.operands[idx].1, msg)); } } - match unused_operands.len() { - 0 => {} - 1 => { - let (sp, msg) = unused_operands.into_iter().next().unwrap(); + match unused_operands[..] { + [] => {} + [(sp, msg)] => { ecx.dcx() .struct_span_err(sp, msg) .with_span_label(sp, msg) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index c8ab8ed681c15..c90a916488606 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -378,8 +378,8 @@ impl BlockOrExpr { None => cx.expr_block(cx.block(span, ThinVec::new())), Some(expr) => expr, } - } else if self.0.len() == 1 - && let ast::StmtKind::Expr(expr) = &self.0[0].kind + } else if let [stmt] = self.0.as_slice() + && let ast::StmtKind::Expr(expr) = &stmt.kind && self.1.is_none() { // There's only a single statement expression. Pull it out. @@ -1273,7 +1273,7 @@ impl<'a> MethodDef<'a> { } FieldlessVariantsStrategy::Default => (), } - } else if variants.len() == 1 { + } else if let [variant] = variants.as_slice() { // If there is a single variant, we don't need an operation on // the discriminant(s). Just use the most degenerate result. return self.call_substructure_method( @@ -1281,7 +1281,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, nonselflike_args, - &EnumMatching(0, &variants[0], Vec::new()), + &EnumMatching(0, variant, Vec::new()), ); } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 9c70f7ede8c7e..306490a49751f 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -180,8 +180,8 @@ fn make_format_args( Ok((mut err, suggested)) => { if !suggested { if let ExprKind::Block(block, None) = &efmt.kind - && block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind + && let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind && let ExprKind::Path(None, path) = &expr.kind && path.is_potential_trivial_const_arg() { @@ -196,8 +196,8 @@ fn make_format_args( } else { let sugg_fmt = match args.explicit_args().len() { 0 => "{}".to_string(), - _ => { - format!("{}{{}}", "{} ".repeat(args.explicit_args().len())) + count => { + format!("{}{{}}", "{} ".repeat(count)) } }; err.span_suggestion( diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs index 26b00e0af3a8a..e81ebb9a4be22 100644 --- a/compiler/rustc_data_structures/src/transitive_relation.rs +++ b/compiler/rustc_data_structures/src/transitive_relation.rs @@ -203,9 +203,9 @@ impl TransitiveRelation { /// exists). See `postdom_upper_bound` for details. pub fn mutual_immediate_postdominator(&self, mut mubs: Vec) -> Option { loop { - match mubs.len() { - 0 => return None, - 1 => return Some(mubs[0]), + match mubs[..] { + [] => return None, + [mub] => return Some(mub), _ => { let m = mubs.pop().unwrap(); let n = mubs.pop().unwrap(); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 627a0ebb4e5e3..3b88c63e21b08 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -335,12 +335,11 @@ fn run_compiler( config.input = input; true // has input: normal compilation } - Ok(None) => match matches.free.len() { - 0 => false, // no input: we will exit early - 1 => panic!("make_input should have provided valid inputs"), - _ => default_early_dcx.early_fatal(format!( - "multiple input filenames provided (first two filenames are `{}` and `{}`)", - matches.free[0], matches.free[1], + Ok(None) => match matches.free.as_slice() { + [] => false, // no input: we will exit early + [_] => panic!("make_input should have provided valid inputs"), + [fst, snd, ..] => default_early_dcx.early_fatal(format!( + "multiple input filenames provided (first two filenames are `{fst}` and `{snd}`)" )), }, }; @@ -488,34 +487,30 @@ fn make_input( early_dcx: &EarlyDiagCtxt, free_matches: &[String], ) -> Result, ErrorGuaranteed> { - if free_matches.len() == 1 { - let ifile = &free_matches[0]; - if ifile == "-" { - let mut src = String::new(); - if io::stdin().read_to_string(&mut src).is_err() { - // Immediately stop compilation if there was an issue reading - // the input (for example if the input stream is not UTF-8). - let reported = early_dcx - .early_err("couldn't read from stdin, as it did not contain valid UTF-8"); - return Err(reported); - } - if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") { - let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect( - "when UNSTABLE_RUSTDOC_TEST_PATH is set \ + let [ifile] = free_matches else { return Ok(None) }; + if ifile == "-" { + let mut src = String::new(); + if io::stdin().read_to_string(&mut src).is_err() { + // Immediately stop compilation if there was an issue reading + // the input (for example if the input stream is not UTF-8). + let reported = + early_dcx.early_err("couldn't read from stdin, as it did not contain valid UTF-8"); + return Err(reported); + } + if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") { + let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE").expect( + "when UNSTABLE_RUSTDOC_TEST_PATH is set \ UNSTABLE_RUSTDOC_TEST_LINE also needs to be set", - ); - let line = isize::from_str_radix(&line, 10) - .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number"); - let file_name = FileName::doc_test_source_code(PathBuf::from(path), line); - Ok(Some(Input::Str { name: file_name, input: src })) - } else { - Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src })) - } + ); + let line = isize::from_str_radix(&line, 10) + .expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number"); + let file_name = FileName::doc_test_source_code(PathBuf::from(path), line); + Ok(Some(Input::Str { name: file_name, input: src })) } else { - Ok(Some(Input::File(PathBuf::from(ifile)))) + Ok(Some(Input::Str { name: FileName::anon_source_code(&src), input: src })) } } else { - Ok(None) + Ok(Some(Input::File(PathBuf::from(ifile)))) } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 483b757f20c18..04c7b252111d4 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -231,17 +231,17 @@ pub trait Emitter: Translate { ) { if let Some((sugg, rest)) = suggestions.split_first() { let msg = self.translate_message(&sugg.msg, fluent_args).map_err(Report::new).unwrap(); - if rest.is_empty() && + if rest.is_empty() // ^ if there is only one suggestion // don't display multi-suggestions as labels - sugg.substitutions.len() == 1 && + && let [substitution] = sugg.substitutions.as_slice() // don't display multipart suggestions as labels - sugg.substitutions[0].parts.len() == 1 && + && let [part] = substitution.parts.as_slice() // don't display long messages as labels - msg.split_whitespace().count() < 10 && + && msg.split_whitespace().count() < 10 // don't display multiline suggestions as labels - !sugg.substitutions[0].parts[0].snippet.contains('\n') && - ![ + && !part.snippet.contains('\n') + && ![ // when this style is set we want the suggestion to be a message, not inline SuggestionStyle::HideCodeAlways, // trivial suggestion for tooling's sake, never shown @@ -250,8 +250,8 @@ pub trait Emitter: Translate { SuggestionStyle::ShowAlways, ].contains(&sugg.style) { - let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); - let msg = if substitution.is_empty() || sugg.style.hide_inline() { + let snippet = part.snippet.trim(); + let msg = if snippet.is_empty() || sugg.style.hide_inline() { // This substitution is only removal OR we explicitly don't want to show the // code inline (`hide_inline`). Therefore, we don't show the substitution. format!("help: {msg}") @@ -260,19 +260,18 @@ pub trait Emitter: Translate { format!( "help: {}{}: `{}`", msg, - if self.source_map().is_some_and(|sm| is_case_difference( - sm, - substitution, - sugg.substitutions[0].parts[0].span, - )) { + if self + .source_map() + .is_some_and(|sm| is_case_difference(sm, snippet, part.span,)) + { " (notice the capitalization)" } else { "" }, - substitution, + snippet, ) }; - primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); + primary_span.push_span_label(part.span, msg); // We return only the modified primary_span suggestions.clear(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ceebcd46a6f7f..aefbf05a1fcc6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2024,11 +2024,11 @@ pub fn a_or_an(s: &str) -> &'static str { /// /// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" pub fn display_list_with_comma_and(v: &[T]) -> String { - match v.len() { - 0 => "".to_string(), - 1 => v[0].to_string(), - 2 => format!("{} and {}", v[0], v[1]), - _ => format!("{}, {}", v[0], display_list_with_comma_and(&v[1..])), + match v { + [] => "".to_string(), + [a] => a.to_string(), + [a, b] => format!("{a} and {b}"), + [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)), } } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c195d69258899..7712915d490db 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1306,12 +1306,12 @@ pub fn parse_macro_name_and_helper_attrs( // that it's of the form `#[proc_macro_derive(Foo)]` or // `#[proc_macro_derive(Foo, attributes(A, ..))]` let list = attr.meta_item_list()?; - if list.len() != 1 && list.len() != 2 { + let ([trait_attr] | [trait_attr, _]) = list.as_slice() else { dcx.emit_err(errors::AttrNoArguments { span: attr.span }); return None; - } - let Some(trait_attr) = list[0].meta_item() else { - dcx.emit_err(errors::NotAMetaItem { span: list[0].span() }); + }; + let Some(trait_attr) = trait_attr.meta_item() else { + dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() }); return None; }; let trait_ident = match trait_attr.ident() { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index e54f9486f6a89..9893c8ff32439 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2734,15 +2734,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if let ty::RawPtr(ptr_ty, _) = expr_t.kind() && let ty::Adt(adt_def, _) = ptr_ty.kind() && let ExprKind::Field(base_expr, _) = expr.kind - && adt_def.variants().len() == 1 - && adt_def - .variants() - .iter() - .next() - .unwrap() - .fields - .iter() - .any(|f| f.ident(self.tcx) == field) + && let [variant] = &adt_def.variants().raw + && variant.fields.iter().any(|f| f.ident(self.tcx) == field) { err.multipart_suggestion( "to access the field, dereference first", diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f14159dc35a57..e0c0adac0767c 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -654,17 +654,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::upcast_choices(self.tcx, source_trait_ref, target_trait_def_id); // must be exactly one trait ref or we'd get an ambig error etc - if upcast_trait_refs.len() != 1 { + let [upcast_trait_ref] = upcast_trait_refs.as_slice() else { span_bug!( self.span, "cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`", source_trait_ref, target_trait_def_id, upcast_trait_refs - ); - } + ) + }; - upcast_trait_refs.into_iter().next().unwrap() + *upcast_trait_ref } fn instantiate_binder_with_fresh_vars(&self, value: ty::Binder<'tcx, T>) -> T diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 94133357a3eb5..61287d98676b2 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -321,19 +321,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); }; let suggest_for_privacy = - |err: &mut Diag<'_>, mut msg: String, sugg: Vec| { - if sugg.len() == 1 { - let msg = format!("\ + |err: &mut Diag<'_>, mut msg: String, suggs: Vec| { + if let [sugg] = suggs.as_slice() { + err.help(format!("\ trait `{}` provides `{item_name}` is implemented but not reachable", - sugg[0].trim() - ); - err.help(msg); + sugg.trim(), + )); } else { - msg += &format!(" but {} not reachable", pluralize!("is", sugg.len())); + msg += &format!(" but {} not reachable", pluralize!("is", suggs.len())); err.span_suggestions( span, msg, - sugg, + suggs, Applicability::MaybeIncorrect, ); } @@ -2988,11 +2987,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if local_spans.primary_span().is_some() { - let msg = if local_preds.len() == 1 { + let msg = if let [local_pred] = local_preds.as_slice() { format!( "an implementation of `{}` might be missing for `{}`", - local_preds[0].trait_ref.print_trait_sugared(), - local_preds[0].self_ty() + local_pred.trait_ref.print_trait_sugared(), + local_pred.self_ty() ) } else { format!( @@ -3034,11 +3033,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if foreign_spans.primary_span().is_some() { - let msg = if foreign_preds.len() == 1 { + let msg = if let [foreign_pred] = foreign_preds.as_slice() { format!( "the foreign item type `{}` doesn't implement `{}`", - foreign_preds[0].self_ty(), - foreign_preds[0].trait_ref.print_trait_sugared() + foreign_pred.self_ty(), + foreign_pred.trait_ref.print_trait_sugared() ) } else { format!( @@ -3388,26 +3387,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.suggest_use_candidates(candidates, |accessible_sugg, inaccessible_sugg, span| { - let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, sugg: Vec<_>| { + let suggest_for_access = |err: &mut Diag<'_>, mut msg: String, suggs: Vec<_>| { msg += &format!( "; perhaps you want to import {one_of}", - one_of = if sugg.len() == 1 { "it" } else { "one of them" }, + one_of = if suggs.len() == 1 { "it" } else { "one of them" }, ); - err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect); + err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect); }; - let suggest_for_privacy = |err: &mut Diag<'_>, sugg: Vec| { + let suggest_for_privacy = |err: &mut Diag<'_>, suggs: Vec| { let msg = format!( "{this_trait_is} implemented but not reachable", - this_trait_is = if sugg.len() == 1 { - format!("trait `{}` which provides `{item_name}` is", sugg[0].trim()) + this_trait_is = if let [sugg] = suggs.as_slice() { + format!("trait `{}` which provides `{item_name}` is", sugg.trim()) } else { format!("the following traits which provide `{item_name}` are") } ); - if sugg.len() == 1 { + if suggs.len() == 1 { err.help(msg); } else { - err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect); + err.span_suggestions(span, msg, suggs, Applicability::MaybeIncorrect); } }; if accessible_sugg.is_empty() { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index ce7d203d8c05b..d7fd41c0ad7a3 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -527,11 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind { if let Res::Def(DefKind::Const, _) = path.res { - if path.segments.len() == 1 { + if let [segment] = path.segments { NonUpperCaseGlobals::check_upper_case( cx, "constant in pattern", - &path.segments[0].ident, + &segment.ident, ); } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f3196cfed533e..60309f120751c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -211,15 +211,12 @@ fn lint_overflowing_range_endpoint<'tcx>( if !is_range_literal(struct_expr) { return false; }; - let ExprKind::Struct(_, eps, _) = &struct_expr.kind else { return false }; - if eps.len() != 2 { - return false; - } + let ExprKind::Struct(_, [start, end], _) = &struct_expr.kind else { return false }; // We can suggest using an inclusive range // (`..=`) instead only if it is the `end` that is // overflowing and only by 1. - if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) { + if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) { return false; }; @@ -232,7 +229,7 @@ fn lint_overflowing_range_endpoint<'tcx>( }; let sub_sugg = if expr.span.lo() == lit_span.lo() { - let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false }; + let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false }; UseInclusiveRange::WithoutParen { sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()), start, diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 795333224ba00..cbf6cb0833004 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -801,7 +801,7 @@ trait UnusedDelimLint { return; } let spans = match value.kind { - ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0] + ast::ExprKind::Block(ref block, None) if let [stmt] = block.stmts.as_slice() => stmt .span .find_ancestor_inside(value.span) .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))), @@ -1537,14 +1537,12 @@ impl UnusedImportBraces { } // Trigger the lint only if there is one nested item - if items.len() != 1 { - return; - } + let [(tree, _)] = items.as_slice() else { return }; // Trigger the lint if the nested item is a non-self single item - let node_name = match items[0].0.kind { + let node_name = match tree.kind { ast::UseTreeKind::Simple(rename) => { - let orig_ident = items[0].0.prefix.segments.last().unwrap().ident; + let orig_ident = tree.prefix.segments.last().unwrap().ident; if orig_ident.name == kw::SelfLower { return; } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 64c6ff952c686..5e6e1a9c0a414 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -483,9 +483,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // Check if the match is exhaustive. let witnesses = report.non_exhaustiveness_witnesses; if !witnesses.is_empty() { - if source == hir::MatchSource::ForLoopDesugar && arms.len() == 2 { + if source == hir::MatchSource::ForLoopDesugar + && let [_, snd_arm] = *arms + { // the for loop pattern is not irrefutable - let pat = &self.thir[arms[1]].pattern; + let pat = &self.thir[snd_arm].pattern; // `pat` should be `Some()` from a desugared for loop. debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop)); let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() }; diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index c3f4bbf1a6521..31b207751942b 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -350,8 +350,8 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera // An inline asm terminator can normally be chained, except when it diverges or uses asm // goto. InlineAsm { ref targets, .. } => { - if targets.len() == 1 { - CoverageSuccessors::Chainable(targets[0]) + if let [target] = targets[..] { + CoverageSuccessors::Chainable(target) } else { CoverageSuccessors::NotChainable(targets) } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index e4fec786814d6..49e41c35f1f24 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -309,11 +309,11 @@ fn verify_candidate_branch<'tcx>( ) -> bool { // In order for the optimization to be correct, the branch must... // ...have exactly one statement - if branch.statements.len() != 1 { + let [statement] = branch.statements.as_slice() else { return false; - } + }; // ...assign the discriminant of `place` in that statement - let StatementKind::Assign(boxed) = &branch.statements[0].kind else { return false }; + let StatementKind::Assign(boxed) = &statement.kind else { return false }; let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { return false }; if *from_place != place { return false; diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 2fc5f7e536ba8..1589653968c2e 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -264,9 +264,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { }; // It's definitely not a clone if there are multiple arguments - if args.len() != 1 { - return; - } + let [arg] = &args[..] else { return }; let Some(destination_block) = *target else { return }; @@ -280,7 +278,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { // These types are easily available from locals, so check that before // doing DefId lookups to figure out what we're actually calling. - let arg_ty = args[0].node.ty(self.local_decls, self.tcx); + let arg_ty = arg.node.ty(self.local_decls, self.tcx); let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return }; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 746d423b7a98c..491ae1c0d083f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -898,8 +898,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.param_env, adt_def.non_enum_variant().fields[field].ty(self.tcx, args), ); - if fields.len() == 1 { - let src_ty = fields.raw[0].ty(self.body, self.tcx); + if let [field] = fields.raw.as_slice() { + let src_ty = field.ty(self.body, self.tcx); if !self.mir_assign_valid_types(src_ty, dest_ty) { self.fail(location, "union field has the wrong type"); } @@ -967,11 +967,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, "RawPtr should be in runtime MIR only"); } - if fields.len() != 2 { - self.fail(location, "raw pointer aggregate must have 2 fields"); - } else { - let data_ptr_ty = fields.raw[0].ty(self.body, self.tcx); - let metadata_ty = fields.raw[1].ty(self.body, self.tcx); + if let [data_ptr, metadata] = fields.raw.as_slice() { + let data_ptr_ty = data_ptr.ty(self.body, self.tcx); + let metadata_ty = metadata.ty(self.body, self.tcx); if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() { if *in_mut != mutability { self.fail(location, "input and output mutability must match"); @@ -998,6 +996,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, "metadata for pointer-to-thin must be unit"); } } + } else { + self.fail(location, "raw pointer aggregate must have 2 fields"); } } }, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ccf8dcdf0b6f2..cf5d65708ab0f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -694,12 +694,12 @@ impl<'a> Parser<'a> { // `foo: ` ExprKind::Path(None, ast::Path { segments, .. }), token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No), - ) if segments.len() == 1 => { + ) if let [segment] = segments.as_slice() => { let snapshot = self.create_snapshot_for_diagnostic(); let label = Label { ident: Ident::from_str_and_span( - &format!("'{}", segments[0].ident), - segments[0].ident.span, + &format!("'{}", segment.ident), + segment.ident.span, ), }; match self.parse_expr_labeled(label, false) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index baa5eb2df635d..8775d792c3d2b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -471,9 +471,8 @@ impl<'a> Parser<'a> { Err(mut err) => { // Maybe the user misspelled `macro_rules` (issue #91227) if self.token.is_ident() - && path.segments.len() == 1 - && edit_distance("macro_rules", &path.segments[0].ident.to_string(), 2) - .is_some() + && let [segment] = path.segments.as_slice() + && edit_distance("macro_rules", &segment.ident.to_string(), 2).is_some() { err.span_suggestion( path.span, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 70d2c98d4f1bd..6f82d6b9826b5 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -826,7 +826,8 @@ impl<'a> Parser<'a> { // We can only resolve single-segment paths at the moment, because multi-segment paths // require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`. ast::ExprKind::Path(None, path) - if path.segments.len() == 1 && path.segments[0].args.is_none() => + if let [segment] = path.segments.as_slice() + && segment.args.is_none() => { true } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index b3efb87a4a26a..8c8b2241c0cfe 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -672,7 +672,7 @@ impl<'a> Parser<'a> { match &expr.kind { ExprKind::Path(None, ast::Path { segments, .. }) - if segments.len() == 1 => + if let [segment] = segments.as_slice() => { if self.token == token::Colon && self.look_ahead(1, |token| { @@ -689,8 +689,8 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); let label = Label { ident: Ident::from_str_and_span( - &format!("'{}", segments[0].ident), - segments[0].ident.span, + &format!("'{}", segment.ident), + segment.ident.span, ), }; match self.parse_expr_labeled(label, false) { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a0d0d80b9572e..a6195733fe5a8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2207,8 +2207,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { attr.name_or_empty(), sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect ) && let Some(meta) = attr.meta_item_list() - && meta.len() == 1 - && let Some(item) = meta[0].meta_item() + && let [meta] = meta.as_slice() + && let Some(item) = meta.meta_item() && let MetaItemKind::NameValue(_) = &item.kind && item.path == sym::reason { diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 0537d3a69f6dc..5d871bacb1dae 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -19,9 +19,7 @@ impl DebuggerVisualizerCollector<'_> { return; }; - let hint = if hints.len() == 1 { - &hints[0] - } else { + let [hint] = hints.as_slice() else { self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span }); return; }; diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs index 4d009d63de59c..12ed574271162 100644 --- a/compiler/rustc_query_system/src/dep_graph/debug.rs +++ b/compiler/rustc_query_system/src/dep_graph/debug.rs @@ -46,15 +46,14 @@ pub struct EdgeFilter { impl EdgeFilter { pub fn new(test: &str) -> Result> { - let parts: Vec<_> = test.split("->").collect(); - if parts.len() != 2 { - Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into()) - } else { + if let [source, target] = *test.split("->").collect::>() { Ok(EdgeFilter { - source: DepNodeFilter::new(parts[0]), - target: DepNodeFilter::new(parts[1]), + source: DepNodeFilter::new(source), + target: DepNodeFilter::new(target), index_to_node: Lock::new(FxHashMap::default()), }) + } else { + Err(format!("expected a filter like `a&b -> c&d`, not `{test}`").into()) } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f844930ad265e..6fcb4cfd8adf2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -445,8 +445,8 @@ impl<'a> PathSource<'a> { Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind { // the case of `::some_crate()` ExprKind::Path(_, path) - if path.segments.len() == 2 - && path.segments[0].ident.name == kw::PathRoot => + if let [segment, _] = path.segments.as_slice() + && segment.ident.name == kw::PathRoot => { "external crate" } @@ -2395,15 +2395,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } fn future_proof_import(&mut self, use_tree: &UseTree) { - let segments = &use_tree.prefix.segments; - if !segments.is_empty() { - let ident = segments[0].ident; + if let [segment, rest @ ..] = use_tree.prefix.segments.as_slice() { + let ident = segment.ident; if ident.is_path_segment_keyword() || ident.span.is_rust_2015() { return; } let nss = match use_tree.kind { - UseTreeKind::Simple(..) if segments.len() == 1 => &[TypeNS, ValueNS][..], + UseTreeKind::Simple(..) if rest.is_empty() => &[TypeNS, ValueNS][..], _ => &[TypeNS], }; let report_error = |this: &Self, ns| { @@ -3999,16 +3998,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if this.should_report_errs() { if candidates.is_empty() { - if path.len() == 2 && prefix_path.len() == 1 { + if path.len() == 2 + && let [segment] = prefix_path + { // Delay to check whether methond name is an associated function or not // ``` // let foo = Foo {}; // foo::bar(); // possibly suggest to foo.bar(); //``` - err.stash( - prefix_path[0].ident.span, - rustc_errors::StashKey::CallAssocMethod, - ); + err.stash(segment.ident.span, rustc_errors::StashKey::CallAssocMethod); } else { // When there is no suggested imports, we can just emit the error // and suggestions immediately. Note that we bypass the usually error diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index f126563fe58f0..9031c96027edc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -650,14 +650,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let typo_sugg = self .lookup_typo_candidate(path, following_seg, source.namespace(), is_expected) .to_opt_suggestion(); - if path.len() == 1 + if let [segment] = path && !matches!(source, PathSource::Delegation) && self.self_type_is_available() { if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call()) { - let self_is_available = self.self_value_is_available(path[0].ident.span); + let self_is_available = self.self_value_is_available(segment.ident.span); // Account for `Foo { field }` when suggesting `self.field` so we result on // `Foo { field: self.field }`. let pre = match source { @@ -665,7 +665,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { if expr .fields .iter() - .any(|f| f.ident == path[0].ident && f.is_shorthand) => + .any(|f| f.ident == segment.ident && f.is_shorthand) => { format!("{path_str}: ") } @@ -1258,8 +1258,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ) }) .collect(); - if targets.len() == 1 { - let target = targets[0]; + if let [target] = targets.as_slice() { return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); } } @@ -2104,8 +2103,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { filter_fn: &impl Fn(Res) -> bool, ) -> TypoCandidate { let mut names = Vec::new(); - if path.len() == 1 { - let mut ctxt = path.last().unwrap().ident.span.ctxt(); + if let [segment] = path { + let mut ctxt = segment.ident.span.ctxt(); // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 64ae0d82952d5..77808df973c39 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -108,8 +108,8 @@ pub(crate) fn sub_namespace_match( // `format!("{}", path)`, because that tries to insert // line-breaks and is slow. fn fast_print_path(path: &ast::Path) -> Symbol { - if path.segments.len() == 1 { - path.segments[0].ident.name + if let [segment] = path.segments.as_slice() { + segment.ident.name } else { let mut path_str = String::with_capacity(64); for (i, segment) in path.segments.iter().enumerate() { @@ -724,10 +724,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Possibly apply the macro helper hack if deleg_impl.is_none() && kind == Some(MacroKind::Bang) - && path.len() == 1 - && path[0].ident.span.ctxt().outer_expn_data().local_inner_macros + && let [segment] = path.as_slice() + && segment.ident.span.ctxt().outer_expn_data().local_inner_macros { - let root = Ident::new(kw::DollarCrate, path[0].ident.span); + let root = Ident::new(kw::DollarCrate, segment.ident.span); path.insert(0, Segment::from_ident(root)); } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index bf54aae1cfeb0..3cbe502c91e85 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -912,16 +912,9 @@ mod parse { match v { None => false, Some(s) => { - let parts = s.split('=').collect::>(); - if parts.len() != 2 { - return false; - } - let crate_name = parts[0].to_string(); - let fuel = parts[1].parse::(); - if fuel.is_err() { - return false; - } - *slot = Some((crate_name, fuel.unwrap())); + let [crate_name, fuel] = *s.split('=').collect::>() else { return false }; + let Ok(fuel) = fuel.parse::() else { return false }; + *slot = Some((crate_name.to_string(), fuel)); true } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 946947124c6eb..8ce51ba2463aa 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3149,11 +3149,10 @@ impl Target { if let Some(a) = o.as_array() { for o in a { if let Some(s) = o.as_str() { - let p = s.split('=').collect::>(); - if p.len() == 2 { - let k = p[0].to_string(); - let v = p[1].to_string(); - base.$key_name.to_mut().push((k.into(), v.into())); + if let [k, v] = *s.split('=').collect::>() { + base.$key_name + .to_mut() + .push((k.to_string().into(), v.to_string().into())) } } } 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 2ce1b955af521..4a79ff38255bf 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 @@ -943,8 +943,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // The current method call returns `Result<_, ()>` && self.can_eq(obligation.param_env, ty, found_ty) // There's a single argument in the method call and it is a closure - && args.len() == 1 - && let Some(arg) = args.get(0) + && let [arg] = args && let hir::ExprKind::Closure(closure) = arg.kind // The closure has a block for its body with no tail expression && let body = self.tcx.hir().body(closure.body) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 3a082893c5c66..f656f9b0e383f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -73,10 +73,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } }); - let impl_def_id_and_args = if self_match_impls.len() == 1 { - self_match_impls[0] - } else if fuzzy_match_impls.len() == 1 { - fuzzy_match_impls[0] + let impl_def_id_and_args = if let [impl_] = self_match_impls[..] { + impl_ + } else if let [impl_] = fuzzy_match_impls[..] { + impl_ } else { return None; }; 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 0d15ef55e24e7..9269177eb5035 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5300,7 +5300,8 @@ impl<'v> Visitor<'v> for FindTypeParam { match ty.kind { hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {} hir::TyKind::Path(hir::QPath::Resolved(None, path)) - if path.segments.len() == 1 && path.segments[0].ident.name == self.param => + if let [segment] = path.segments + && segment.ident.name == self.param => { if !self.nested { debug!(?ty, "FindTypeParam::visit_ty"); From a245bfa61792cfa4c9cf29adae7dbe1b833f705c Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 20:55:53 +1000 Subject: [PATCH 10/17] Simplify hoisting of array/slice patterns We can replace some tricky iterator-mutation code with a much simpler version that uses `while let` to shrink a slice. We also check whether a subpattern would be a wildcard _before_ hoisting it, which will be very useful when trying to get rid of `print::PatKind` later. --- compiler/rustc_pattern_analysis/src/lib.rs | 1 + compiler/rustc_pattern_analysis/src/rustc.rs | 73 ++++++++++++-------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index a5c0b13c90be1..4c8c865e721ae 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -5,6 +5,7 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(feature = "rustc", feature(let_chains))] // tidy-alphabetical-end pub mod constructor; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 78355d6c762b5..bb882e79647a4 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -827,7 +827,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> { use print::{FieldPat, Pat, PatKind}; let cx = self; - let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild); let hoist = |p| Box::new(cx.hoist_witness_pat(p)); let mut subpatterns = pat.iter_fields().map(hoist); let kind = match pat.ctor() { @@ -862,37 +861,35 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // ignore this issue. Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(slice) => { - match slice.kind { - SliceKind::FixedLen(_) => PatKind::Slice { - prefix: subpatterns.collect(), - has_dot_dot: false, - suffix: Box::new([]), - }, - SliceKind::VarLen(prefix, _) => { - let mut subpatterns = subpatterns.peekable(); - let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect(); - if slice.array_len.is_some() { - // Improves diagnostics a bit: if the type is a known-size array, instead - // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. - // This is incorrect if the size is not known, since `[_, ..]` captures - // arrays of lengths `>= 1` whereas `[..]` captures any length. - while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { - prefix.pop(); - } - while subpatterns.peek().is_some() - && is_wildcard(subpatterns.peek().unwrap()) - { - subpatterns.next(); - } - } - let suffix: Box<[_]> = subpatterns.collect(); - PatKind::Slice { - prefix: prefix.into_boxed_slice(), - has_dot_dot: true, - suffix, - } + let (prefix_len, has_dot_dot) = match slice.kind { + SliceKind::FixedLen(len) => (len, false), + SliceKind::VarLen(prefix_len, _) => (prefix_len, true), + }; + + let (mut prefix, mut suffix) = pat.fields.split_at(prefix_len); + + // If the pattern contains a `..`, but is applied to values of statically-known + // length (arrays), then we can slightly simplify diagnostics by merging any + // adjacent wildcard patterns into the `..`: `[x, _, .., _, y]` => `[x, .., y]`. + // (This simplification isn't allowed for slice values, because in that case + // `[x, .., y]` would match some slices that `[x, _, .., _, y]` would not.) + if has_dot_dot && slice.array_len.is_some() { + while let [rest @ .., last] = prefix + && would_print_as_wildcard(cx.tcx, last) + { + prefix = rest; + } + while let [first, rest @ ..] = suffix + && would_print_as_wildcard(cx.tcx, first) + { + suffix = rest; } } + + let prefix = prefix.iter().map(hoist).collect(); + let suffix = suffix.iter().map(hoist).collect(); + + PatKind::Slice { prefix, has_dot_dot, suffix } } &Str(value) => PatKind::Constant { value }, Never if self.tcx.features().never_patterns => PatKind::Never, @@ -910,6 +907,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } } +/// Returns `true` if the given pattern would be printed as a wildcard (`_`). +fn would_print_as_wildcard(tcx: TyCtxt<'_>, p: &WitnessPat<'_, '_>) -> bool { + match p.ctor() { + Constructor::IntRange(IntRange { + lo: MaybeInfiniteInt::NegInfinity, + hi: MaybeInfiniteInt::PosInfinity, + }) + | Constructor::Wildcard + | Constructor::NonExhaustive + | Constructor::Hidden + | Constructor::PrivateUninhabited => true, + Constructor::Never if !tcx.features().never_patterns => true, + _ => false, + } +} + impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { type Ty = RevealedTy<'tcx>; type Error = ErrorGuaranteed; From 582208b0f26dd448b7a869f3a3e11ad07cd76346 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 20:59:25 +1000 Subject: [PATCH 11/17] Simplify hoisting of ref patterns (`&` and `&mut`) --- compiler/rustc_pattern_analysis/src/rustc.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index bb882e79647a4..2ddd35923bccc 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -828,7 +828,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { use print::{FieldPat, Pat, PatKind}; let cx = self; let hoist = |p| Box::new(cx.hoist_witness_pat(p)); - let mut subpatterns = pat.iter_fields().map(hoist); let kind = match pat.ctor() { Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) }, IntRange(range) => return self.hoist_pat_range(range, *pat.ty()), @@ -855,11 +854,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { PatKind::StructLike { enum_info, subpatterns } } - // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should - // be careful to reconstruct the correct constant pattern here. However a string - // literal pattern will never be reported as a non-exhaustiveness witness, so we - // ignore this issue. - Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, + Ref => PatKind::Deref { subpattern: hoist(&pat.fields[0]) }, Slice(slice) => { let (prefix_len, has_dot_dot) = match slice.kind { SliceKind::FixedLen(len) => (len, false), From 29245ec75914a32fcb33ba5282f73d6d741ab2f7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 21:12:04 +1000 Subject: [PATCH 12/17] Avoid using `ty::tls::with` in `write_struct_like` --- compiler/rustc_pattern_analysis/src/rustc/print.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 64f041dc21a76..dba6022320220 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -12,7 +12,7 @@ use std::fmt; use rustc_middle::thir::PatRange; -use rustc_middle::ty::{self, AdtDef, Ty}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::sym; use rustc_target::abi::{FieldIdx, VariantIdx}; @@ -70,7 +70,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { PatKind::Never => write!(f, "!"), PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"), PatKind::StructLike { ref enum_info, ref subpatterns } => { - write_struct_like(f, self.ty, enum_info, subpatterns) + ty::tls::with(|tcx| write_struct_like(f, tcx, self.ty, enum_info, subpatterns)) } PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern), PatKind::Constant { value } => write!(f, "{value}"), @@ -105,12 +105,13 @@ pub(crate) enum EnumInfo<'tcx> { fn write_struct_like<'tcx>( f: &mut impl fmt::Write, + tcx: TyCtxt<'_>, ty: Ty<'tcx>, enum_info: &EnumInfo<'tcx>, subpatterns: &[FieldPat<'tcx>], ) -> fmt::Result { let variant_and_name = match *enum_info { - EnumInfo::Enum { adt_def, variant_index } => ty::tls::with(|tcx| { + EnumInfo::Enum { adt_def, variant_index } => { let variant = adt_def.variant(variant_index); let adt_did = adt_def.did(); let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) @@ -121,9 +122,9 @@ fn write_struct_like<'tcx>( format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) }; Some((variant, name)) - }), + } EnumInfo::NotEnum => ty.ty_adt_def().and_then(|adt_def| { - ty::tls::with(|tcx| Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))) + Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) }), }; From 482412c98ad714ae386a85fc44222197be3d3ffc Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Aug 2024 21:14:08 +1000 Subject: [PATCH 13/17] Use `TyCtxt::is_diagnostic_item` --- compiler/rustc_pattern_analysis/src/rustc/print.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index dba6022320220..7d6387146054e 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -114,8 +114,8 @@ fn write_struct_like<'tcx>( EnumInfo::Enum { adt_def, variant_index } => { let variant = adt_def.variant(variant_index); let adt_did = adt_def.did(); - let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) - || tcx.get_diagnostic_item(sym::Result) == Some(adt_did) + let name = if tcx.is_diagnostic_item(sym::Option, adt_did) + || tcx.is_diagnostic_item(sym::Result, adt_did) { variant.name.to_string() } else { From ae09340350fd8b7aa7a00a81132a7e77772504cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2024 18:05:57 +0200 Subject: [PATCH 14/17] make LocalWaker::will_wake consistent with Waker::will_wake --- library/core/src/task/wake.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 8ce3eb2ea3921..29932c0d1ffeb 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -502,6 +502,8 @@ impl Waker { #[must_use] #[stable(feature = "futures_api", since = "1.36.0")] pub fn will_wake(&self, other: &Waker) -> bool { + // We optimize this by comparing vtable addresses instead of vtable contents. + // This is permitted since the function is documented as best-effort. let RawWaker { data: a_data, vtable: a_vtable } = self.waker; let RawWaker { data: b_data, vtable: b_vtable } = other.waker; a_data == b_data && ptr::eq(a_vtable, b_vtable) @@ -761,7 +763,11 @@ impl LocalWaker { #[must_use] #[unstable(feature = "local_waker", issue = "118959")] pub fn will_wake(&self, other: &LocalWaker) -> bool { - self.waker == other.waker + // We optimize this by comparing vtable addresses instead of vtable contents. + // This is permitted since the function is documented as best-effort. + let RawWaker { data: a_data, vtable: a_vtable } = self.waker; + let RawWaker { data: b_data, vtable: b_vtable } = other.waker; + a_data == b_data && ptr::eq(a_vtable, b_vtable) } /// Creates a new `LocalWaker` from [`RawWaker`]. From 7d1de7f9942e4f91f3fc6dbfd56491caccd02f64 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Wed, 24 Jan 2024 16:48:54 +0100 Subject: [PATCH 15/17] core: optimise Debug impl for ascii::Char Rather than writing character at a time, optimise Debug implementation for core::ascii::Char such that it writes the entire representation as with a single write_str call. With that, add tests for Display and Debug implementations. --- library/core/src/ascii/ascii_char.rs | 32 +++++++++++----------------- library/core/tests/ascii_char.rs | 28 ++++++++++++++++++++++++ library/core/tests/lib.rs | 1 + 3 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 library/core/tests/ascii_char.rs diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 34a05ac38884d..375358dddf5c1 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -3,7 +3,7 @@ //! suggestions from rustc if you get anything slightly wrong in here, and overall //! helps with clarity as we're also referring to `char` intentionally in here. -use crate::fmt::{self, Write}; +use crate::fmt; use crate::mem::transmute; /// One of the 128 Unicode characters from U+0000 through U+007F, @@ -583,9 +583,10 @@ impl fmt::Display for AsciiChar { #[unstable(feature = "ascii_char", issue = "110998")] impl fmt::Debug for AsciiChar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[inline] - fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) { - ([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2) + use AsciiChar::{Apostrophe, Null, ReverseSolidus as Backslash}; + + fn backslash(a: AsciiChar) -> ([AsciiChar; 6], usize) { + ([Apostrophe, Backslash, a, Apostrophe, Null, Null], 4) } let (buf, len) = match self { @@ -595,24 +596,17 @@ impl fmt::Debug for AsciiChar { AsciiChar::LineFeed => backslash(AsciiChar::SmallN), AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus), AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe), - _ => { - let byte = self.to_u8(); - if !byte.is_ascii_control() { - ([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1) - } else { - const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap(); + _ if self.to_u8().is_ascii_control() => { + const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap(); - let hi = HEX_DIGITS[usize::from(byte >> 4)]; - let lo = HEX_DIGITS[usize::from(byte & 0xf)]; - ([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4) - } + let byte = self.to_u8(); + let hi = HEX_DIGITS[usize::from(byte >> 4)]; + let lo = HEX_DIGITS[usize::from(byte & 0xf)]; + ([Apostrophe, Backslash, AsciiChar::SmallX, hi, lo, Apostrophe], 6) } + _ => ([Apostrophe, *self, Apostrophe, Null, Null, Null], 3), }; - f.write_char('\'')?; - for byte in &buf[..len as usize] { - f.write_str(byte.as_str())?; - } - f.write_char('\'') + f.write_str(buf[..len].as_str()) } } diff --git a/library/core/tests/ascii_char.rs b/library/core/tests/ascii_char.rs new file mode 100644 index 0000000000000..75b5fd4b9e61d --- /dev/null +++ b/library/core/tests/ascii_char.rs @@ -0,0 +1,28 @@ +use core::ascii::Char; +use core::fmt::Write; + +/// Tests Display implementation for ascii::Char. +#[test] +fn test_display() { + let want = (0..128u8).map(|b| b as char).collect::(); + let mut got = String::with_capacity(128); + for byte in 0..128 { + write!(&mut got, "{}", Char::from_u8(byte).unwrap()).unwrap(); + } + assert_eq!(want, got); +} + +/// Tests Debug implementation for ascii::Char. +#[test] +fn test_debug_control() { + for byte in 0..128u8 { + let mut want = format!("{:?}", byte as char); + // `char` uses `'\u{#}'` representation where ascii::char uses `'\x##'`. + // Transform former into the latter. + if let Some(rest) = want.strip_prefix("'\\u{") { + want = format!("'\\x{:0>2}'", rest.strip_suffix("}'").unwrap()); + } + let chr = core::ascii::Char::from_u8(byte).unwrap(); + assert_eq!(want, format!("{chr:?}"), "byte: {byte}"); + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 1e336bf96b8fa..8872b4cbfd5ba 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -122,6 +122,7 @@ mod alloc; mod any; mod array; mod ascii; +mod ascii_char; mod asserting; mod async_iter; mod atomic; From 1c02e2b5f17fa9f093bc9c46b54c993d52040e40 Mon Sep 17 00:00:00 2001 From: Evelyn Harthbrooke Date: Fri, 9 Aug 2024 16:59:36 -0600 Subject: [PATCH 16/17] fix incorrect value --- compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index f37781c3f638a..65f2a1e306987 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { llvm_target: macos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { description: Some("ARM64 macOS (11.0+, Big Sur+)".into()), - tier: Some(2), + tier: Some(1), host_tools: Some(true), std: Some(true), }, From 217ee32ac7f9f2f1cccd0b99360229a52c5948ea Mon Sep 17 00:00:00 2001 From: bohan Date: Fri, 9 Aug 2024 18:33:20 +0800 Subject: [PATCH 17/17] rm `import.used` --- compiler/rustc_resolve/src/build_reduced_graph.rs | 8 ++++---- compiler/rustc_resolve/src/check_unused.rs | 6 +++--- compiler/rustc_resolve/src/imports.rs | 5 ++--- compiler/rustc_resolve/src/lib.rs | 12 +++++++----- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 307625bcfb17c..d57dabdd78d91 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -374,7 +374,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { root_span, root_id, vis, - used: Default::default(), }); self.r.indeterminate_imports.push(import); @@ -890,8 +889,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { span: item.span, module_path: Vec::new(), vis, - used: Cell::new(used.then_some(Used::Other)), }); + if used { + self.r.import_use_map.insert(import, Used::Other); + } self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); if parent == self.r.graph_root { @@ -1091,7 +1092,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { span, module_path: Vec::new(), vis: ty::Visibility::Restricted(CRATE_DEF_ID), - used: Default::default(), }) }; @@ -1256,8 +1256,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { span, module_path: Vec::new(), vis, - used: Cell::new(Some(Used::Other)), }); + self.r.import_use_map.insert(import, Used::Other); let import_binding = self.r.import(binding, import); self.r.define(self.r.graph_root, ident, MacroNS, import_binding); } else { diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 75b8ecebdd914..1cee876b80fea 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -381,9 +381,9 @@ impl Resolver<'_, '_> { for import in self.potentially_unused_imports.iter() { match import.kind { - _ if import.used.get().is_some() - || import.vis.is_public() - || import.span.is_dummy() => + _ if import.vis.is_public() + || import.span.is_dummy() + || self.import_use_map.contains_key(import) => { if let ImportKind::MacroUse { .. } = import.kind { if !import.span.is_dummy() { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 4a891d12281c4..42171edf75749 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -176,7 +176,6 @@ pub(crate) struct ImportData<'a> { /// The resolution of `module_path`. pub imported_module: Cell>>, pub vis: ty::Visibility, - pub used: Cell>, } /// All imports are unique and allocated on a same arena, @@ -484,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); self.record_use(target, dummy_binding, Used::Other); } else if import.imported_module.get().is_none() { - import.used.set(Some(Used::Other)); + self.import_use_map.insert(import, Used::Other); if let Some(id) = import.id() { self.used_imports.insert(id); } @@ -1347,7 +1346,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // module defined by a block). // Skip if the import is public or was used through non scope-based resolution, // e.g. through a module-relative path. - if import.used.get() == Some(Used::Other) + if self.import_use_map.get(&import) == Some(&Used::Other) || self.effective_visibilities.is_exported(self.local_def_id(id)) { return false; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 89ac839651fb1..02fdc1ae6685e 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1016,6 +1016,8 @@ pub struct Resolver<'a, 'tcx> { partial_res_map: NodeMap, /// Resolutions for import nodes, which have multiple resolutions in different namespaces. import_res_map: NodeMap>>, + /// An import will be inserted into this map if it has been used. + import_use_map: FxHashMap, Used>, /// Resolutions for labels (node IDs of their corresponding blocks or loops). label_res_map: NodeMap, /// Resolutions for lifetimes. @@ -1422,6 +1424,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pat_span_map: Default::default(), partial_res_map: Default::default(), import_res_map: Default::default(), + import_use_map: Default::default(), label_res_map: Default::default(), lifetimes_res_map: Default::default(), extra_lifetime_params_map: Default::default(), @@ -1839,7 +1842,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } /// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors - fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool { + fn matches_previous_ambiguity_error(&self, ambi: &AmbiguityError<'_>) -> bool { for ambiguity_error in &self.ambiguity_errors { // if the span location and ident as well as its span are the same if ambiguity_error.kind == ambi.kind @@ -1900,10 +1903,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } - let old_used = import.used.get(); - let new_used = Some(used); - if new_used > old_used { - import.used.set(new_used); + let old_used = self.import_use_map.entry(import).or_insert(used); + if *old_used < used { + *old_used = used; } if let Some(id) = import.id() { self.used_imports.insert(id);