From 64f11b96396ded4388618af95d639ae9be0978e9 Mon Sep 17 00:00:00 2001 From: Dmitry Murygin Date: Fri, 4 Dec 2020 08:06:53 +0300 Subject: [PATCH 01/49] Update tests of "unused_lifetimes" lint for async functions and corresponding source code --- compiler/rustc_resolve/src/late/lifetimes.rs | 20 ++--- src/test/ui/async-await/unused-lifetime.rs | 79 ++++++++++--------- .../ui/async-await/unused-lifetime.stderr | 30 +++---- 3 files changed, 65 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 69f28045bb5bd..5214658638641 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -644,17 +644,17 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } else { bug!(); }; - if let hir::ParamName::Plain(param_name) = name { - if param_name.name == kw::UnderscoreLifetime { - // Pick the elided lifetime "definition" if one exists - // and use it to make an elision scope. - self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); - elision = Some(reg); - } else { - lifetimes.insert(name, reg); - } + // We cannot predict what lifetimes are unused in opaque type. + self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); + if let hir::ParamName::Plain(Ident { + name: kw::UnderscoreLifetime, + .. + }) = name + { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + elision = Some(reg); } else { - self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); lifetimes.insert(name, reg); } } diff --git a/src/test/ui/async-await/unused-lifetime.rs b/src/test/ui/async-await/unused-lifetime.rs index 1cf546bcb4266..5bd6ae8d3a42d 100644 --- a/src/test/ui/async-await/unused-lifetime.rs +++ b/src/test/ui/async-await/unused-lifetime.rs @@ -1,42 +1,47 @@ -// edition:2018 +// Check "unused_lifetimes" lint on both async and sync functions -// Avoid spurious warnings of unused lifetime. The below async functions -// are desugered to have an unused lifetime -// but we don't want to warn about that as there's nothing they can do about it. +// edition:2018 #![deny(unused_lifetimes)] -#![allow(dead_code)] - -pub async fn october(s: &str) { - println!("{}", s); -} - -pub async fn async_fn(&mut ref s: &mut[i32]) { - println!("{:?}", s); -} - -macro_rules! foo_macro { - () => { - pub async fn async_fn_in_macro(&mut ref _s: &mut[i32]) {} - }; -} - -foo_macro!(); - -pub async fn func_with_unused_lifetime<'a>(s: &'a str) { - //~^ ERROR lifetime parameter `'a` never used - println!("{}", s); -} - -pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) { - //~^ ERROR lifetime parameter `'a` never used - //~^^ ERROR lifetime parameter `'b` never used - println!("{}", s); -} - -pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) { - //~^ ERROR lifetime parameter `'c` never used - println!("{}", s); -} + + +// Async part with unused lifetimes +// +// Even wrong cases don't cause errors because async functions are desugared with all lifetimes +// involved in the signature. So, we cannot predict what lifetimes are unused in async function. +async fn async_wrong_without_args<'a>() {} + +async fn async_wrong_1_lifetime<'a>(_: &i32) {} + +async fn async_wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} + +async fn async_right_1_lifetime<'a>(_: &'a i32) {} + +async fn async_right_2_lifetimes<'a, 'b>(_: &'a i32, _: &'b i32) {} + +async fn async_right_trait_bound_lifetime<'a, I>(_: I) +where + I: Iterator +{} + + +// Sync part with unused lifetimes +// +// These functions are compiled as supposed +fn wrong_without_args<'a>() {} //~ ERROR lifetime parameter `'a` never used + +fn wrong_1_lifetime<'a>(_: &i32) {} //~ ERROR lifetime parameter `'a` never used + +fn wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} //~ ERROR lifetime parameter `'b` never used + +fn right_1_lifetime<'a>(_: &'a i32) {} + +fn right_2_lifetimes<'a, 'b>(_: &'a i32, _: &'b i32) {} + +fn right_trait_bound_lifetime<'a, I>(_: I) +where + I: Iterator +{} + fn main() {} diff --git a/src/test/ui/async-await/unused-lifetime.stderr b/src/test/ui/async-await/unused-lifetime.stderr index 2a7a12a364346..4e90f43fdd07b 100644 --- a/src/test/ui/async-await/unused-lifetime.stderr +++ b/src/test/ui/async-await/unused-lifetime.stderr @@ -1,32 +1,28 @@ error: lifetime parameter `'a` never used - --> $DIR/unused-lifetime.rs:26:40 + --> $DIR/unused-lifetime.rs:31:23 | -LL | pub async fn func_with_unused_lifetime<'a>(s: &'a str) { - | ^^ +LL | fn wrong_without_args<'a>() {} + | -^^- help: elide the unused lifetime | note: the lint level is defined here - --> $DIR/unused-lifetime.rs:7:9 + --> $DIR/unused-lifetime.rs:5:9 | LL | #![deny(unused_lifetimes)] | ^^^^^^^^^^^^^^^^ error: lifetime parameter `'a` never used - --> $DIR/unused-lifetime.rs:31:44 + --> $DIR/unused-lifetime.rs:33:21 | -LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) { - | ^^ +LL | fn wrong_1_lifetime<'a>(_: &i32) {} + | -^^- help: elide the unused lifetime error: lifetime parameter `'b` never used - --> $DIR/unused-lifetime.rs:31:48 + --> $DIR/unused-lifetime.rs:35:26 | -LL | pub async fn func_with_two_unused_lifetime<'a, 'b>(s: &'a str, t: &'b str) { - | ^^ +LL | fn wrong_2_lifetimes<'a, 'b>(_: &'a i32, _: &i32) {} + | --^^ + | | + | help: elide the unused lifetime -error: lifetime parameter `'c` never used - --> $DIR/unused-lifetime.rs:37:54 - | -LL | pub async fn func_with_unused_lifetime_in_two_params<'c>(s: &'c str, t: &'c str) { - | ^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 3ea744e2ac975456d14805100755d2e39a565e46 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 18 Dec 2020 17:03:45 -0500 Subject: [PATCH 02/49] Recommend panic::resume_unwind instead of panicking. Fixes https://github.com/rust-lang/rust/issues/79950. --- library/std/src/thread/mod.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 5d65f960fcd39..0d004a516f594 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1186,32 +1186,37 @@ impl fmt::Debug for Thread { /// the [`Error`](crate::error::Error) trait. /// /// Thus, a sensible way to handle a thread panic is to either: -/// 1. `unwrap` the `Result`, propagating the panic +/// +/// 1. propagate the panic with [`std::panic::resume_unwind`] /// 2. or in case the thread is intended to be a subsystem boundary /// that is supposed to isolate system-level failures, -/// match on the `Err` variant and handle the panic in an appropriate way. +/// match on the `Err` variant and handle the panic in an appropriate way /// /// A thread that completes without panicking is considered to exit successfully. /// /// # Examples /// +/// Matching on the result of a joined thread: +/// /// ```no_run -/// use std::thread; -/// use std::fs; +/// use std::{fs, thread, panic}; /// /// fn copy_in_thread() -> thread::Result<()> { -/// thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join() +/// thread::spawn(|| { +/// fs::copy("foo.txt", "bar.txt").unwrap(); +/// }).join() /// } /// /// fn main() { /// match copy_in_thread() { -/// Ok(_) => println!("this is fine"), -/// Err(_) => println!("thread panicked"), +/// Ok(_) => println!("copy succeeded"), +/// Err(e) => panic::resume_unwind(e), /// } /// } /// ``` /// /// [`Result`]: crate::result::Result +/// [`std::panic::resume_unwind`]: crate::panic::resume_unwind #[stable(feature = "rust1", since = "1.0.0")] pub type Result = crate::result::Result>; From 1f9a8a1620a677d668c981a8e6be3ce02ef06cd5 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 5 Nov 2020 00:44:42 -0800 Subject: [PATCH 03/49] Add a `std::io::read_to_string` function The equivalent of `std::fs::read_to_string`, but generalized to all `Read` impls. As the documentation on `std::io::read_to_string` says, the advantage of this function is that it means you don't have to create a variable first and it provides more type safety since you can only get the buffer out if there were no errors. If you use `Read::read_to_string`, you have to remember to check whether the read succeeded because otherwise your buffer will be empty. It's friendlier to newcomers and better in most cases to use an explicit return value instead of an out parameter. --- library/std/src/io/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index dfbf6c3f24443..7a1896e4e5901 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -945,6 +945,33 @@ pub trait Read { } } +/// Convenience function for [`Read::read_to_string`]. +/// +/// This avoids having to create a variable first and it provides more type safety +/// since you can only get the buffer out if there were no errors. (If you use +/// [`Read::read_to_string`] you have to remember to check whether the read succeeded +/// because otherwise your buffer will be empty.) +/// +/// # Examples +/// +/// ```no_run +/// #![feature(io_read_to_string)] +/// +/// # use std::io; +/// fn main() -> io::Result<()> { +/// let stdin = io::read_to_string(&mut io::stdin())?; +/// println!("Stdin was:"); +/// println!("{}", stdin); +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "io_read_to_string", issue = "80218")] +pub fn read_to_string(reader: &mut R) -> Result { + let mut buf = String::new(); + reader.read_to_string(&mut buf)?; + Ok(buf) +} + /// A buffer type used with `Read::read_vectored`. /// /// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be From 4ee6d1bf541a90206b9e5cba6840e774493abc57 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 30 Dec 2020 11:33:06 -0800 Subject: [PATCH 04/49] Add description independent of `Read::read_to_string` --- library/std/src/io/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 7a1896e4e5901..1fdd82400d061 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -945,12 +945,13 @@ pub trait Read { } } -/// Convenience function for [`Read::read_to_string`]. +/// Read all bytes from a [reader][Read] into a new [`String`]. /// -/// This avoids having to create a variable first and it provides more type safety -/// since you can only get the buffer out if there were no errors. (If you use -/// [`Read::read_to_string`] you have to remember to check whether the read succeeded -/// because otherwise your buffer will be empty.) +/// This is a convenience function for [`Read::read_to_string`]. Using this +/// function avoids having to create a variable first and provides more type +/// safety since you can only get the buffer out if there were no errors. (If you +/// use [`Read::read_to_string`] you have to remember to check whether the read +/// succeeded because otherwise your buffer will be empty.) /// /// # Examples /// From 588786a788a5606dd3f4b4769ecd2e0c26a3ad20 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 30 Dec 2020 11:44:03 -0800 Subject: [PATCH 05/49] Add error docs --- library/std/src/io/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 1fdd82400d061..fdc0198945ef9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -951,7 +951,14 @@ pub trait Read { /// function avoids having to create a variable first and provides more type /// safety since you can only get the buffer out if there were no errors. (If you /// use [`Read::read_to_string`] you have to remember to check whether the read -/// succeeded because otherwise your buffer will be empty.) +/// succeeded because otherwise your buffer will be empty or only partially full.) +/// +/// # Errors +/// +/// This function forces you to handle errors because the output (the `String`) +/// is wrapped in a [`Result`]. See [`Read::read_to_string`] for the errors +/// that can occur. If any error occurs, you will get an [`Err`], so you +/// don't have to worry about your buffer being empty or partially full. /// /// # Examples /// From 7ed824ebd158d24e0c570d0f4bedc3be566b4619 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Thu, 31 Dec 2020 22:14:19 +0100 Subject: [PATCH 06/49] Add Iterator::intersperse_with --- library/core/src/iter/adapters/intersperse.rs | 154 +++++++++++++++--- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 4 +- library/core/src/iter/traits/iterator.rs | 27 ++- library/core/tests/iter.rs | 30 ++++ 5 files changed, 192 insertions(+), 25 deletions(-) diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 362326725490f..adae47459f7f4 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -40,37 +40,149 @@ where } } - fn fold(mut self, init: B, mut f: F) -> B + fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - let mut accum = init; + let separator = self.separator; + intersperse_fold(self.iter, init, f, move || separator.clone(), self.needs_sep) + } + + fn size_hint(&self) -> (usize, Option) { + intersperse_size_hint(&self.iter, self.needs_sep) + } +} + +/// An iterator adapter that places a separator between all elements. +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +pub struct IntersperseWith +where + I: Iterator, +{ + separator: G, + iter: Peekable, + needs_sep: bool, +} + +// FIXME This manual implementation is needed as #[derive] misplaces trait bounds, +// requiring ::Item to be Debug on the struct-definition, which is +// not what we want. +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl crate::fmt::Debug for IntersperseWith +where + I: Iterator + crate::fmt::Debug, + I::Item: crate::fmt::Debug, + G: crate::fmt::Debug, +{ + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + f.debug_struct("IntersperseWith") + .field("separator", &self.separator) + .field("iter", &self.iter) + .field("needs_sep", &self.needs_sep) + .finish() + } +} - // Use `peek()` first to avoid calling `next()` on an empty iterator. - if !self.needs_sep || self.iter.peek().is_some() { - if let Some(x) = self.iter.next() { - accum = f(accum, x); - } +// FIXME This manual implementation is needed as #[derive] misplaces trait bounds, +// requiring ::Item to be Clone on the struct-definition, which is +// not what we want. +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl crate::clone::Clone for IntersperseWith +where + I: Iterator + crate::clone::Clone, + I::Item: crate::clone::Clone, + G: Clone, +{ + fn clone(&self) -> Self { + IntersperseWith { + separator: self.separator.clone(), + iter: self.iter.clone(), + needs_sep: self.needs_sep.clone(), } + } +} - let element = &self.separator; +impl IntersperseWith +where + I: Iterator, + G: FnMut() -> I::Item, +{ + pub(in crate::iter) fn new(iter: I, separator: G) -> Self { + Self { iter: iter.peekable(), separator, needs_sep: false } + } +} - self.iter.fold(accum, |mut accum, x| { - accum = f(accum, element.clone()); - accum = f(accum, x); - accum - }) +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +impl Iterator for IntersperseWith +where + I: Iterator, + G: FnMut() -> I::Item, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.needs_sep && self.iter.peek().is_some() { + self.needs_sep = false; + Some((self.separator)()) + } else { + self.needs_sep = true; + self.iter.next() + } + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + intersperse_fold(self.iter, init, f, self.separator, self.needs_sep) } fn size_hint(&self) -> (usize, Option) { - let (lo, hi) = self.iter.size_hint(); - let next_is_elem = !self.needs_sep; - let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo); - let hi = match hi { - Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi), - None => None, - }; - (lo, hi) + intersperse_size_hint(&self.iter, self.needs_sep) } } + +fn intersperse_size_hint(iter: &I, needs_sep: bool) -> (usize, Option) +where + I: Iterator, +{ + let (lo, hi) = iter.size_hint(); + let next_is_elem = !needs_sep; + let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo); + let hi = match hi { + Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi), + None => None, + }; + (lo, hi) +} + +fn intersperse_fold( + mut iter: Peekable, + init: B, + mut f: F, + mut separator: G, + needs_sep: bool, +) -> B +where + I: Iterator, + F: FnMut(B, I::Item) -> B, + G: FnMut() -> I::Item, +{ + let mut accum = init; + + // Use `peek()` first to avoid calling `next()` on an empty iterator. + if !needs_sep || iter.peek().is_some() { + if let Some(x) = iter.next() { + accum = f(accum, x); + } + } + + iter.fold(accum, |mut accum, x| { + accum = f(accum, separator()); + accum = f(accum, x); + accum + }) +} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 7dfbf32cea7b8..41a7b13232adf 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -43,7 +43,7 @@ pub use self::flatten::Flatten; pub use self::copied::Copied; #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -pub use self::intersperse::Intersperse; +pub use self::intersperse::{Intersperse, IntersperseWith}; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::map_while::MapWhile; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 569de719d03d6..c57ba2bf62645 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -395,8 +395,6 @@ pub use self::adapters::Cloned; pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; -#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] -pub use self::adapters::Intersperse; #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] pub use self::adapters::MapWhile; #[unstable(feature = "inplace_iteration", issue = "none")] @@ -410,6 +408,8 @@ pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] +pub use self::adapters::{Intersperse, IntersperseWith}; pub(crate) use self::adapters::process_results; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 633175702d870..91d7a47907a46 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -8,7 +8,7 @@ use crate::ops::{Add, ControlFlow, Try}; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; -use super::super::{FromIterator, Intersperse, Product, Sum, Zip}; +use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, }; @@ -591,6 +591,31 @@ pub trait Iterator { Intersperse::new(self, separator) } + /// Places an element generated by `separator` between all elements. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_intersperse)] + /// + /// let src = ["Hello", "to", "all", "people"].iter().copied(); + /// let mut separator = [" ❤️ ", " 😀 "].iter().copied().cycle(); + /// + /// let result = src.intersperse_with(|| separator.next().unwrap()).collect::(); + /// assert_eq!(result, "Hello ❤️ to 😀 all ❤️ people"); + /// ``` + #[inline] + #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] + fn intersperse_with(self, separator: G) -> IntersperseWith + where + Self: Sized, + G: FnMut() -> Self::Item, + { + IntersperseWith::new(self, separator) + } + /// Takes a closure and creates an iterator which calls that closure on each /// element. /// diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 7376e7848eff5..691767edea6d9 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3508,6 +3508,12 @@ pub fn extend_for_unit() { #[test] fn test_intersperse() { + let v = std::iter::empty().intersperse(0u32).collect::>(); + assert_eq!(v, vec![]); + + let v = std::iter::once(1).intersperse(0).collect::>(); + assert_eq!(v, vec![1]); + let xs = ["a", "", "b", "c"]; let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); let text: String = v.concat(); @@ -3520,6 +3526,9 @@ fn test_intersperse() { #[test] fn test_intersperse_size_hint() { + let iter = std::iter::empty::().intersperse(0); + assert_eq!(iter.size_hint(), (0, Some(0))); + let xs = ["a", "", "b", "c"]; let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); assert_eq!(iter.size_hint(), (7, Some(7))); @@ -3587,3 +3596,24 @@ fn test_try_fold_specialization_intersperse_err() { iter.try_for_each(|item| if item == "b" { None } else { Some(()) }); assert_eq!(iter.next(), None); } + +#[test] +fn test_intersperse_with() { + #[derive(PartialEq, Debug)] + struct NotClone { + u: u32, + } + let r = vec![NotClone { u: 0 }, NotClone { u: 1 }] + .into_iter() + .intersperse_with(|| NotClone { u: 2 }) + .collect::>(); + assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]); + + let mut ctr = 100; + let separator = || { + ctr *= 2; + ctr + }; + let r = (0..3).intersperse_with(separator).collect::>(); + assert_eq!(r, vec![0, 200, 1, 400, 2]); +} From 7a0ada0427ff1a8756f19f2bfb866a0c8461a029 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Thu, 7 Jan 2021 00:45:47 +0100 Subject: [PATCH 07/49] Remove FIXME-notes --- library/core/src/iter/adapters/intersperse.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index adae47459f7f4..9f5cca88206ef 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -65,9 +65,6 @@ where needs_sep: bool, } -// FIXME This manual implementation is needed as #[derive] misplaces trait bounds, -// requiring ::Item to be Debug on the struct-definition, which is -// not what we want. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl crate::fmt::Debug for IntersperseWith where @@ -84,9 +81,6 @@ where } } -// FIXME This manual implementation is needed as #[derive] misplaces trait bounds, -// requiring ::Item to be Clone on the struct-definition, which is -// not what we want. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl crate::clone::Clone for IntersperseWith where From f7d261c3b125c1d54bce9eae0da390f654d656b1 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 8 Jan 2021 18:00:25 -0500 Subject: [PATCH 08/49] Get rid of `DepConstructor` This removes fully 235 unused functions. --- .../rustc_middle/src/dep_graph/dep_node.rs | 45 ++++++------------- compiler/rustc_middle/src/dep_graph/mod.rs | 3 +- compiler/rustc_middle/src/mir/mono.rs | 4 +- 3 files changed, 17 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index b775846bba452..65e5301c96e9e 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -29,9 +29,10 @@ //! contained no `DefId` for thing that had been removed. //! //! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro -//! defines the `DepKind` enum and a corresponding `dep_constructor` module. The -//! `dep_constructor` module links a `DepKind` to the parameters that are needed at -//! runtime in order to construct a valid `DepNode` fingerprint. +//! defines the `DepKind` enum. Each `DepKind` has its own parameters that are +//! needed at runtime in order to construct a valid `DepNode` fingerprint. +//! However, only `CompileCodegenUnit` is constructed explicitly (with +//! `make_compile_codegen_unit`). //! //! Because the macro sees what parameters a given `DepKind` requires, it can //! "infer" some properties for each kind of `DepNode`: @@ -44,22 +45,14 @@ //! `DefId` it was computed from. In other cases, too much information gets //! lost during fingerprint computation. //! -//! The `dep_constructor` module, together with `DepNode::new()`, ensures that only +//! `make_compile_codegen_unit`, together with `DepNode::new()`, ensures that only //! valid `DepNode` instances can be constructed. For example, the API does not //! allow for constructing parameterless `DepNode`s with anything other //! than a zeroed out fingerprint. More generally speaking, it relieves the //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use crate::mir::interpret::{GlobalId, LitToConstInput}; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::subst::{GenericArg, SubstsRef}; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::TyCtxt; use rustc_data_structures::fingerprint::Fingerprint; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; @@ -338,25 +331,6 @@ macro_rules! define_dep_nodes { $($variant),* } - #[allow(non_camel_case_types)] - pub mod dep_constructor { - use super::*; - - $( - #[inline(always)] - #[allow(unreachable_code, non_snake_case)] - pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode { - // tuple args - $({ - erase!($tuple_arg_ty); - return DepNode::construct(_tcx, DepKind::$variant, &arg) - })* - - return DepNode::construct(_tcx, DepKind::$variant, &()) - } - )* - } - fn dep_kind_from_label_string(label: &str) -> Result { match label { $(stringify!($variant) => Ok(DepKind::$variant),)* @@ -384,9 +358,16 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> [anon] TraitSelect, + // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below. [] CompileCodegenUnit(Symbol), ]); +// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. +// Be very careful changing this type signature! +crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode { + DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name) +} + pub type DepNode = rustc_query_system::dep_graph::DepNode; // We keep a lot of `DepNode`s in memory during compilation. It's not diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 22e9cc1cd3ee4..ea4d8c1299709 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -13,7 +13,8 @@ pub use rustc_query_system::dep_graph::{ WorkProduct, WorkProductId, }; -pub use dep_node::{dep_constructor, label_strs, DepKind, DepNode, DepNodeExt}; +crate use dep_node::make_compile_codegen_unit; +pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 698c25215968b..b8b5390ec40fe 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{dep_constructor, DepNode, WorkProduct, WorkProductId}; +use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_data_structures::base_n; @@ -358,7 +358,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { - dep_constructor::CompileCodegenUnit(tcx, self.name()) + crate::dep_graph::make_compile_codegen_unit(tcx, self.name()) } } From ebe402dc9e708a8ed5e5860a7b30ea7826ab52a1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 07:27:03 -0500 Subject: [PATCH 09/49] Fix handling of malicious Readers in read_to_end --- library/std/src/io/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 7ad9e446c5997..0bc0e0e8e83d8 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -390,7 +390,14 @@ where ret = Ok(g.len - start_len); break; } - Ok(n) => g.len += n, + Ok(n) => { + // We can't let g.len overflow which would result in the vec shrinking when the function returns. In + // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. + // The minimal check would just be a checked_add, but this assert is a bit more precise and should be + // just about the same cost. + assert!(n <= g.buf.len() - g.len); + g.len += n; + } Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => { ret = Err(e); From a9ef7983a629fea829955608d67f474f856da53c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 07:48:24 -0500 Subject: [PATCH 10/49] clean up control flow --- library/std/src/io/mod.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 0bc0e0e8e83d8..a054c434d0739 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -366,7 +366,6 @@ where { let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf }; - let ret; loop { if g.len == g.buf.len() { unsafe { @@ -386,10 +385,7 @@ where } match r.read(&mut g.buf[g.len..]) { - Ok(0) => { - ret = Ok(g.len - start_len); - break; - } + Ok(0) => return Ok(g.len - start_len), Ok(n) => { // We can't let g.len overflow which would result in the vec shrinking when the function returns. In // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. @@ -399,14 +395,9 @@ where g.len += n; } Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - - ret } pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result From 5cb830397e8493f4bf923b411ec378cd00ce28f9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 17:13:50 -0500 Subject: [PATCH 11/49] make check a bit more clear --- library/std/src/io/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a054c434d0739..af570ac6e30ba 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -384,14 +384,15 @@ where } } - match r.read(&mut g.buf[g.len..]) { + let buf = &mut g.buf[g.len..]; + match r.read(buf) { Ok(0) => return Ok(g.len - start_len), Ok(n) => { // We can't let g.len overflow which would result in the vec shrinking when the function returns. In // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. // The minimal check would just be a checked_add, but this assert is a bit more precise and should be // just about the same cost. - assert!(n <= g.buf.len() - g.len); + assert!(n <= buf.len()); g.len += n; } Err(ref e) if e.kind() == ErrorKind::Interrupted => {} From e6c07b0628938b0003ecbae0f60b588eebf474aa Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 17:16:44 -0500 Subject: [PATCH 12/49] clarify docs a bit --- library/std/src/io/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index af570ac6e30ba..f73116ba106cc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -388,10 +388,9 @@ where match r.read(buf) { Ok(0) => return Ok(g.len - start_len), Ok(n) => { - // We can't let g.len overflow which would result in the vec shrinking when the function returns. In - // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. - // The minimal check would just be a checked_add, but this assert is a bit more precise and should be - // just about the same cost. + // We can't allow bogus values from read. If it is too large, the returned vec could have its length + // set past its capacity, or if it overflows the vec could be shortened which could create an invalid + // string if this is called via read_to_string. assert!(n <= buf.len()); g.len += n; } From 746329201546d38875bf1a7fa232453e833c01eb Mon Sep 17 00:00:00 2001 From: Camelid Date: Mon, 11 Jan 2021 19:17:13 -0800 Subject: [PATCH 13/49] Add docs on performance --- library/std/src/io/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index fdc0198945ef9..5540891c646d5 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -953,6 +953,19 @@ pub trait Read { /// use [`Read::read_to_string`] you have to remember to check whether the read /// succeeded because otherwise your buffer will be empty or only partially full.) /// +/// # Performance +/// +/// The downside of this function's increased ease of use and type safety is +/// that it gives you less control over performance. For example, you can't +/// pre-allocate memory like you can using [`String::with_capacity`] and +/// [`Read::read_to_string`]. Also, you can't re-use the buffer if an error +/// occurs while reading. +/// +/// In many cases, this function's performance will be adequate and the ease of use +/// and type safety tradeoffs will be worth it. However, there are cases where you +/// need more control over performance, and in those cases you should definitely use +/// [`Read::read_to_string`] directly. +/// /// # Errors /// /// This function forces you to handle errors because the output (the `String`) From 16692ab66a6e2c62b416f606f144d60711c14414 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 13 Dec 2020 14:13:52 -0800 Subject: [PATCH 14/49] Suggest `_` and `..` if a pattern has too few fields For example, this code: struct S(i32, f32); let S(x) = S(0, 1.0); will make the compiler suggest either: let S(x, _) = S(0, 1.0); or: let S(x, ..) = S(0, 1.0); --- compiler/rustc_typeck/src/check/pat.rs | 29 +++++ .../tuple_struct_destructure_fail.stderr | 18 +++ src/test/ui/error-codes/E0023.stderr | 9 ++ ...7-pat-tup-scrut-ty-diff-less-fields.stderr | 9 ++ src/test/ui/issues/issue-72574-2.stderr | 9 ++ .../match/match-pattern-field-mismatch.stderr | 9 ++ src/test/ui/pattern/issue-74539.stderr | 9 ++ src/test/ui/pattern/pat-tuple-underfield.rs | 49 +++++++ .../ui/pattern/pat-tuple-underfield.stderr | 121 ++++++++++++++++++ 9 files changed, 262 insertions(+) create mode 100644 src/test/ui/pattern/pat-tuple-underfield.rs create mode 100644 src/test/ui/pattern/pat-tuple-underfield.stderr diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 5fc573a57ad0b..942be1007f062 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -15,10 +15,12 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; +use rustc_span::{BytePos, DUMMY_SP}; use rustc_trait_selection::traits::{ObligationCause, Pattern}; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::iter; use super::report_unexpected_variant_res; @@ -1040,6 +1042,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())], Applicability::MachineApplicable, ); + } else if fields.len() > subpats.len() { + let after_fields_span = if pat_span == DUMMY_SP { + pat_span + } else { + pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi() + }; + + let mut wildcard_sugg = + iter::repeat("_").take(fields.len() - subpats.len()).collect::>().join(", "); + if !subpats.is_empty() { + wildcard_sugg = String::from(", ") + &wildcard_sugg; + } + + let rest_sugg = if subpats.is_empty() { "..".to_owned() } else { ", ..".to_owned() }; + + err.span_suggestion( + after_fields_span, + "use `_` to explicitly ignore each field", + wildcard_sugg, + Applicability::MaybeIncorrect, + ); + err.span_suggestion( + after_fields_span, + "use `..` to ignore all unmentioned fields", + rest_sugg, + Applicability::MaybeIncorrect, + ); } err.emit(); diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index 0e7174e5b19d6..623e1d674d71a 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -31,6 +31,15 @@ LL | struct TupleStruct(S, T); ... LL | TupleStruct(_) = TupleStruct(1, 2); | ^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | TupleStruct(_, _) = TupleStruct(1, 2); + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | TupleStruct(_, ..) = TupleStruct(1, 2); + | ^^^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:34:5 @@ -49,6 +58,15 @@ LL | SingleVariant(S, T) ... LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2); | ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | Enum::SingleVariant(_, ..) = Enum::SingleVariant(1, 2); + | ^^^^ error[E0070]: invalid left-hand side of assignment --> $DIR/tuple_struct_destructure_fail.rs:40:12 diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index a3610099294da..1d32eab15d33a 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -6,6 +6,15 @@ LL | Apple(String, String), ... LL | Fruit::Apple(a) => {}, | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | Fruit::Apple(a, _) => {}, + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | Fruit::Apple(a, ..) => {}, + | ^^^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:12:9 diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 6e8ea6bf618f2..38177d1515820 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -17,6 +17,15 @@ LL | struct P(T); // 1 type parameter wanted ... LL | let P() = U {}; | ^^^ expected 1 field, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | let P(_) = U {}; + | ^ +help: use `..` to ignore all unmentioned fields + | +LL | let P(..) = U {}; + | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr index 0a9c868af7af8..8edc6ca8f0ed6 100644 --- a/src/test/ui/issues/issue-72574-2.stderr +++ b/src/test/ui/issues/issue-72574-2.stderr @@ -26,6 +26,15 @@ LL | struct Binder(i32, i32, i32); ... LL | Binder(_a, _x @ ..) => {} | ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Binder(_a, _x @ .., _) => {} + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | Binder(_a, _x @ .., ..) => {} + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index c2298d6fbbf02..299b2d216db98 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -6,6 +6,15 @@ LL | Rgb(usize, usize, usize), ... LL | Color::Rgb(_, _) => { } | ^^^^^^^^^^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Color::Rgb(_, _, _) => { } + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | Color::Rgb(_, _, ..) => { } + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr index cbc90b5397d8b..7a73d39dbc0c6 100644 --- a/src/test/ui/pattern/issue-74539.stderr +++ b/src/test/ui/pattern/issue-74539.stderr @@ -26,6 +26,15 @@ LL | A(u8, u8), ... LL | E::A(x @ ..) => { | ^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::A(x @ .., _) => { + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | E::A(x @ .., ..) => { + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs new file mode 100644 index 0000000000000..246dd0b37b659 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -0,0 +1,49 @@ +struct S(i32, f32); +enum E { + S(i32, f32), +} + +fn main() { + match S(0, 1.0) { + S(x) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all unmentioned fields + } + match S(0, 1.0) { + S(_) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all unmentioned fields + } + match S(0, 1.0) { + S() => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all unmentioned fields + } + + match E::S(0, 1.0) { + E::S(x) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all unmentioned fields + } + match E::S(0, 1.0) { + E::S(_) => {} + //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all unmentioned fields + } + match E::S(0, 1.0) { + E::S() => {} + //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all unmentioned fields + } + match E::S(0, 1.0) { + E::S => {} + //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S` + //~| HELP use the tuple variant pattern syntax instead + } +} diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr new file mode 100644 index 0000000000000..5364053b8e526 --- /dev/null +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -0,0 +1,121 @@ +error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S` + --> $DIR/pat-tuple-underfield.rs:45:9 + | +LL | S(i32, f32), + | ----------- `E::S` defined here +... +LL | E::S => {} + | ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)` + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:8:9 + | +LL | struct S(i32, f32); + | ------------------- tuple struct defined here +... +LL | S(x) => {} + | ^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(x, _) => {} + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | S(x, ..) => {} + | ^^^^ + +error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:14:9 + | +LL | struct S(i32, f32); + | ------------------- tuple struct defined here +... +LL | S(_) => {} + | ^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | S(_, ..) => {} + | ^^^^ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields + --> $DIR/pat-tuple-underfield.rs:20:9 + | +LL | struct S(i32, f32); + | ------------------- tuple struct defined here +... +LL | S() => {} + | ^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | ^^^^ +help: use `..` to ignore all unmentioned fields + | +LL | S(..) => {} + | ^^ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:27:9 + | +LL | S(i32, f32), + | ----------- tuple variant defined here +... +LL | E::S(x) => {} + | ^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(x, _) => {} + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | E::S(x, ..) => {} + | ^^^^ + +error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:33:9 + | +LL | S(i32, f32), + | ----------- tuple variant defined here +... +LL | E::S(_) => {} + | ^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | ^^^ +help: use `..` to ignore all unmentioned fields + | +LL | E::S(_, ..) => {} + | ^^^^ + +error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields + --> $DIR/pat-tuple-underfield.rs:39:9 + | +LL | S(i32, f32), + | ----------- tuple variant defined here +... +LL | E::S() => {} + | ^^^^^^ expected 2 fields, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | ^^^^ +help: use `..` to ignore all unmentioned fields + | +LL | E::S(..) => {} + | ^^ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0023, E0532. +For more information about an error, try `rustc --explain E0023`. From 5fe61a79cc5d26a0843b7169d1c95fbb3cbda0ba Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 18 Dec 2020 17:09:53 -0800 Subject: [PATCH 15/49] Simplify code Co-authored-by: Esteban Kuber --- compiler/rustc_typeck/src/check/pat.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 942be1007f062..db2f4eca0c9d0 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1049,8 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi() }; - let mut wildcard_sugg = - iter::repeat("_").take(fields.len() - subpats.len()).collect::>().join(", "); + let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", "); if !subpats.is_empty() { wildcard_sugg = String::from(", ") + &wildcard_sugg; } From f3d9df54ee682d0b76909d27938b30c51ca5ec70 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 18 Dec 2020 19:51:39 -0800 Subject: [PATCH 16/49] Suggest `Variant(..)` if all of the mentioned fields are `_` --- compiler/rustc_typeck/src/check/pat.rs | 33 ++++++++++++++----- .../tuple_struct_destructure_fail.stderr | 8 ++--- .../match/match-pattern-field-mismatch.stderr | 4 +-- .../ui/pattern/pat-tuple-underfield.stderr | 8 ++--- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index db2f4eca0c9d0..474aed39eb2fd 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -20,7 +20,6 @@ use rustc_trait_selection::traits::{ObligationCause, Pattern}; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::iter; use super::report_unexpected_variant_res; @@ -1048,26 +1047,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi() }; + let all_fields_span = match subpats { + [] => after_fields_span, + [field] => field.span, + [first, .., last] => first.span.to(last.span), + }; + + // Check if all the fields in the pattern are wildcards. + let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild)); let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", "); if !subpats.is_empty() { wildcard_sugg = String::from(", ") + &wildcard_sugg; } - let rest_sugg = if subpats.is_empty() { "..".to_owned() } else { ", ..".to_owned() }; - err.span_suggestion( after_fields_span, "use `_` to explicitly ignore each field", wildcard_sugg, Applicability::MaybeIncorrect, ); - err.span_suggestion( - after_fields_span, - "use `..` to ignore all unmentioned fields", - rest_sugg, - Applicability::MaybeIncorrect, - ); + + if subpats.is_empty() || all_wildcards { + err.span_suggestion( + all_fields_span, + "use `..` to ignore all unmentioned fields", + String::from(".."), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion( + after_fields_span, + "use `..` to ignore all unmentioned fields", + String::from(", .."), + Applicability::MaybeIncorrect, + ); + } } err.emit(); diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index 623e1d674d71a..dd1fbbbd3bbe5 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -38,8 +38,8 @@ LL | TupleStruct(_, _) = TupleStruct(1, 2); | ^^^ help: use `..` to ignore all unmentioned fields | -LL | TupleStruct(_, ..) = TupleStruct(1, 2); - | ^^^^ +LL | TupleStruct(..) = TupleStruct(1, 2); + | ^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:34:5 @@ -65,8 +65,8 @@ LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); | ^^^ help: use `..` to ignore all unmentioned fields | -LL | Enum::SingleVariant(_, ..) = Enum::SingleVariant(1, 2); - | ^^^^ +LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2); + | ^^ error[E0070]: invalid left-hand side of assignment --> $DIR/tuple_struct_destructure_fail.rs:40:12 diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index 299b2d216db98..1ee45ca1b1ea6 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -13,8 +13,8 @@ LL | Color::Rgb(_, _, _) => { } | ^^^ help: use `..` to ignore all unmentioned fields | -LL | Color::Rgb(_, _, ..) => { } - | ^^^^ +LL | Color::Rgb(..) => { } + | ^^ error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr index 5364053b8e526..b7a5402663917 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.stderr +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -40,8 +40,8 @@ LL | S(_, _) => {} | ^^^ help: use `..` to ignore all unmentioned fields | -LL | S(_, ..) => {} - | ^^^^ +LL | S(..) => {} + | ^^ error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields --> $DIR/pat-tuple-underfield.rs:20:9 @@ -94,8 +94,8 @@ LL | E::S(_, _) => {} | ^^^ help: use `..` to ignore all unmentioned fields | -LL | E::S(_, ..) => {} - | ^^^^ +LL | E::S(..) => {} + | ^^ error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields --> $DIR/pat-tuple-underfield.rs:39:9 From a5e8e6ec2df58bd50963af57bbd08d0526f119db Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 18 Dec 2020 19:56:14 -0800 Subject: [PATCH 17/49] Pluralize 'parenthesis' correctly It's 'parentheses', not 'parenthesis', when you have more than one. --- compiler/rustc_typeck/src/check/pat.rs | 10 +++++----- src/test/ui/error-codes/E0023.stderr | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 474aed39eb2fd..a7670624f307c 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1002,7 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // More generally, the expected type wants a tuple variant with one field of an // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. - let missing_parenthesis = match (&expected.kind(), fields, had_err) { + let missing_parentheses = match (&expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the substs could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. @@ -1015,13 +1015,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => false, }; - if missing_parenthesis { + if missing_parentheses { let (left, right) = match subpats { // This is the zero case; we aim to get the "hi" part of the `QPath`'s // span as the "lo" and then the "hi" part of the pattern's span as the "hi". // This looks like: // - // help: missing parenthesis + // help: missing parentheses // | // L | let A(()) = A(()); // | ^ ^ @@ -1030,14 +1030,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // last sub-pattern. In the case of `A(x)` the first and last may coincide. // This looks like: // - // help: missing parenthesis + // help: missing parentheses // | // L | let A((x, y)) = A((1, 2)); // | ^ ^ [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span), }; err.multipart_suggestion( - "missing parenthesis", + "missing parentheses", vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())], Applicability::MachineApplicable, ); diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 1d32eab15d33a..965cf28c79f91 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -43,7 +43,7 @@ LL | Orange((String, String)), LL | Fruit::Orange(a, b) => {}, | ^^^^^^^^^^^^^^^^^^^ expected 1 field, found 2 | -help: missing parenthesis +help: missing parentheses | LL | Fruit::Orange((a, b)) => {}, | ^ ^ @@ -57,7 +57,7 @@ LL | Banana(()), LL | Fruit::Banana() => {}, | ^^^^^^^^^^^^^^^ expected 1 field, found 0 | -help: missing parenthesis +help: missing parentheses | LL | Fruit::Banana(()) => {}, | ^ ^ From fe82cc38a0b3e39b9425090e2107c0ba15760491 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 18 Dec 2020 20:17:09 -0800 Subject: [PATCH 18/49] Specialize `..` help message for all fields vs. the rest --- compiler/rustc_typeck/src/check/pat.rs | 4 ++-- .../tuple_struct_destructure_fail.stderr | 4 ++-- src/test/ui/error-codes/E0023.stderr | 2 +- ...ue-67037-pat-tup-scrut-ty-diff-less-fields.stderr | 2 +- src/test/ui/issues/issue-72574-2.stderr | 2 +- .../ui/match/match-pattern-field-mismatch.stderr | 2 +- src/test/ui/pattern/issue-74539.stderr | 2 +- src/test/ui/pattern/pat-tuple-underfield.rs | 12 ++++++------ src/test/ui/pattern/pat-tuple-underfield.stderr | 12 ++++++------ 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index a7670624f307c..43a69fe187431 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1071,14 +1071,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if subpats.is_empty() || all_wildcards { err.span_suggestion( all_fields_span, - "use `..` to ignore all unmentioned fields", + "use `..` to ignore all fields", String::from(".."), Applicability::MaybeIncorrect, ); } else { err.span_suggestion( after_fields_span, - "use `..` to ignore all unmentioned fields", + "use `..` to ignore the rest of the fields", String::from(", .."), Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index dd1fbbbd3bbe5..c270593cac741 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -36,7 +36,7 @@ help: use `_` to explicitly ignore each field | LL | TupleStruct(_, _) = TupleStruct(1, 2); | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | TupleStruct(..) = TupleStruct(1, 2); | ^^ @@ -63,7 +63,7 @@ help: use `_` to explicitly ignore each field | LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2); | ^^ diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 965cf28c79f91..aaaada518d3b7 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -11,7 +11,7 @@ help: use `_` to explicitly ignore each field | LL | Fruit::Apple(a, _) => {}, | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore the rest of the fields | LL | Fruit::Apple(a, ..) => {}, | ^^^^ diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 38177d1515820..9bdbf0bf9f40d 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -22,7 +22,7 @@ help: use `_` to explicitly ignore each field | LL | let P(_) = U {}; | ^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | let P(..) = U {}; | ^^ diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr index 8edc6ca8f0ed6..02497029960bf 100644 --- a/src/test/ui/issues/issue-72574-2.stderr +++ b/src/test/ui/issues/issue-72574-2.stderr @@ -31,7 +31,7 @@ help: use `_` to explicitly ignore each field | LL | Binder(_a, _x @ .., _) => {} | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore the rest of the fields | LL | Binder(_a, _x @ .., ..) => {} | ^^^^ diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index 1ee45ca1b1ea6..37839482b31a2 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -11,7 +11,7 @@ help: use `_` to explicitly ignore each field | LL | Color::Rgb(_, _, _) => { } | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | Color::Rgb(..) => { } | ^^ diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr index 7a73d39dbc0c6..78249ed057ff8 100644 --- a/src/test/ui/pattern/issue-74539.stderr +++ b/src/test/ui/pattern/issue-74539.stderr @@ -31,7 +31,7 @@ help: use `_` to explicitly ignore each field | LL | E::A(x @ .., _) => { | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore the rest of the fields | LL | E::A(x @ .., ..) => { | ^^^^ diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs index 246dd0b37b659..f306377e6e51d 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.rs +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -8,38 +8,38 @@ fn main() { S(x) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all unmentioned fields + //~| HELP use `..` to ignore the rest of the fields } match S(0, 1.0) { S(_) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all unmentioned fields + //~| HELP use `..` to ignore all fields } match S(0, 1.0) { S() => {} //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all unmentioned fields + //~| HELP use `..` to ignore all fields } match E::S(0, 1.0) { E::S(x) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all unmentioned fields + //~| HELP use `..` to ignore the rest of the fields } match E::S(0, 1.0) { E::S(_) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all unmentioned fields + //~| HELP use `..` to ignore all fields } match E::S(0, 1.0) { E::S() => {} //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all unmentioned fields + //~| HELP use `..` to ignore all fields } match E::S(0, 1.0) { E::S => {} diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr index b7a5402663917..d1aaeaeafa47e 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.stderr +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -20,7 +20,7 @@ help: use `_` to explicitly ignore each field | LL | S(x, _) => {} | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore the rest of the fields | LL | S(x, ..) => {} | ^^^^ @@ -38,7 +38,7 @@ help: use `_` to explicitly ignore each field | LL | S(_, _) => {} | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | S(..) => {} | ^^ @@ -56,7 +56,7 @@ help: use `_` to explicitly ignore each field | LL | S(_, _) => {} | ^^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | S(..) => {} | ^^ @@ -74,7 +74,7 @@ help: use `_` to explicitly ignore each field | LL | E::S(x, _) => {} | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore the rest of the fields | LL | E::S(x, ..) => {} | ^^^^ @@ -92,7 +92,7 @@ help: use `_` to explicitly ignore each field | LL | E::S(_, _) => {} | ^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | E::S(..) => {} | ^^ @@ -110,7 +110,7 @@ help: use `_` to explicitly ignore each field | LL | E::S(_, _) => {} | ^^^^ -help: use `..` to ignore all unmentioned fields +help: use `..` to ignore all fields | LL | E::S(..) => {} | ^^ From 9959d6deedbf39d58fac06949596073d9c0dbb23 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 20 Dec 2020 14:43:07 -0800 Subject: [PATCH 19/49] Only suggest `..` if more than one field is missing --- compiler/rustc_typeck/src/check/pat.rs | 33 +++++---- .../tuple_struct_destructure_fail.stderr | 28 +++----- src/test/ui/error-codes/E0023.stderr | 14 ++-- ...7-pat-tup-scrut-ty-diff-less-fields.stderr | 14 ++-- src/test/ui/issues/issue-72574-2.stderr | 14 ++-- .../match/match-pattern-field-mismatch.stderr | 14 ++-- src/test/ui/pattern/issue-74539.stderr | 14 ++-- src/test/ui/pattern/pat-tuple-underfield.rs | 4 -- .../ui/pattern/pat-tuple-underfield.stderr | 68 ++++++------------- 9 files changed, 68 insertions(+), 135 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 43a69fe187431..a863fc95e0ea1 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1061,27 +1061,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wildcard_sugg = String::from(", ") + &wildcard_sugg; } - err.span_suggestion( + err.span_suggestion_short( after_fields_span, "use `_` to explicitly ignore each field", wildcard_sugg, Applicability::MaybeIncorrect, ); - if subpats.is_empty() || all_wildcards { - err.span_suggestion( - all_fields_span, - "use `..` to ignore all fields", - String::from(".."), - Applicability::MaybeIncorrect, - ); - } else { - err.span_suggestion( - after_fields_span, - "use `..` to ignore the rest of the fields", - String::from(", .."), - Applicability::MaybeIncorrect, - ); + // Only suggest `..` if more than one field is missing. + if fields.len() - subpats.len() > 1 { + if subpats.is_empty() || all_wildcards { + err.span_suggestion_short( + all_fields_span, + "use `..` to ignore all fields", + String::from(".."), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_short( + after_fields_span, + "use `..` to ignore the rest of the fields", + String::from(", .."), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index c270593cac741..42859406e178d 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -30,16 +30,10 @@ LL | struct TupleStruct(S, T); | ------------------------------- tuple struct defined here ... LL | TupleStruct(_) = TupleStruct(1, 2); - | ^^^^^^^^^^^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | TupleStruct(_, _) = TupleStruct(1, 2); - | ^^^ -help: use `..` to ignore all fields - | -LL | TupleStruct(..) = TupleStruct(1, 2); - | ^^ + | ^^^^^^^^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:34:5 @@ -57,16 +51,10 @@ LL | SingleVariant(S, T) | ------------------- tuple variant defined here ... LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2); - | ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); - | ^^^ -help: use `..` to ignore all fields - | -LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2); - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0070]: invalid left-hand side of assignment --> $DIR/tuple_struct_destructure_fail.rs:40:12 diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index aaaada518d3b7..0c6f496cf4353 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -5,16 +5,10 @@ LL | Apple(String, String), | --------------------- tuple variant defined here ... LL | Fruit::Apple(a) => {}, - | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | Fruit::Apple(a, _) => {}, - | ^^^ -help: use `..` to ignore the rest of the fields - | -LL | Fruit::Apple(a, ..) => {}, - | ^^^^ + | ^^^^^^^^^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:12:9 diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 9bdbf0bf9f40d..86be8e7db4e6f 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -16,16 +16,10 @@ LL | struct P(T); // 1 type parameter wanted | --------------- tuple struct defined here ... LL | let P() = U {}; - | ^^^ expected 1 field, found 0 - | -help: use `_` to explicitly ignore each field - | -LL | let P(_) = U {}; - | ^ -help: use `..` to ignore all fields - | -LL | let P(..) = U {}; - | ^^ + | ^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 1 field, found 0 error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr index 02497029960bf..9479e365aee68 100644 --- a/src/test/ui/issues/issue-72574-2.stderr +++ b/src/test/ui/issues/issue-72574-2.stderr @@ -25,16 +25,10 @@ LL | struct Binder(i32, i32, i32); | ----------------------------- tuple struct defined here ... LL | Binder(_a, _x @ ..) => {} - | ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2 - | -help: use `_` to explicitly ignore each field - | -LL | Binder(_a, _x @ .., _) => {} - | ^^^ -help: use `..` to ignore the rest of the fields - | -LL | Binder(_a, _x @ .., ..) => {} - | ^^^^ + | ^^^^^^^^^^^^^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 3 fields, found 2 error: aborting due to 3 previous errors diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index 37839482b31a2..0bb5e726ccbd8 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -5,16 +5,10 @@ LL | Rgb(usize, usize, usize), | ------------------------ tuple variant defined here ... LL | Color::Rgb(_, _) => { } - | ^^^^^^^^^^^^^^^^ expected 3 fields, found 2 - | -help: use `_` to explicitly ignore each field - | -LL | Color::Rgb(_, _, _) => { } - | ^^^ -help: use `..` to ignore all fields - | -LL | Color::Rgb(..) => { } - | ^^ + | ^^^^^^^^^^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 3 fields, found 2 error: aborting due to previous error diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr index 78249ed057ff8..49011d83e5075 100644 --- a/src/test/ui/pattern/issue-74539.stderr +++ b/src/test/ui/pattern/issue-74539.stderr @@ -25,16 +25,10 @@ LL | A(u8, u8), | --------- tuple variant defined here ... LL | E::A(x @ ..) => { - | ^^^^^^^^^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | E::A(x @ .., _) => { - | ^^^ -help: use `..` to ignore the rest of the fields - | -LL | E::A(x @ .., ..) => { - | ^^^^ + | ^^^^^^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs index f306377e6e51d..f86d617801455 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.rs +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -8,13 +8,11 @@ fn main() { S(x) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore the rest of the fields } match S(0, 1.0) { S(_) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all fields } match S(0, 1.0) { S() => {} @@ -27,13 +25,11 @@ fn main() { E::S(x) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore the rest of the fields } match E::S(0, 1.0) { E::S(_) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields //~| HELP use `_` to explicitly ignore each field - //~| HELP use `..` to ignore all fields } match E::S(0, 1.0) { E::S() => {} diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr index d1aaeaeafa47e..6e7afd8e57b1d 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.stderr +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -1,5 +1,5 @@ error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S` - --> $DIR/pat-tuple-underfield.rs:45:9 + --> $DIR/pat-tuple-underfield.rs:41:9 | LL | S(i32, f32), | ----------- `E::S` defined here @@ -14,37 +14,25 @@ LL | struct S(i32, f32); | ------------------- tuple struct defined here ... LL | S(x) => {} - | ^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | S(x, _) => {} - | ^^^ -help: use `..` to ignore the rest of the fields - | -LL | S(x, ..) => {} - | ^^^^ + | ^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields - --> $DIR/pat-tuple-underfield.rs:14:9 + --> $DIR/pat-tuple-underfield.rs:13:9 | LL | struct S(i32, f32); | ------------------- tuple struct defined here ... LL | S(_) => {} - | ^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | S(_, _) => {} - | ^^^ -help: use `..` to ignore all fields - | -LL | S(..) => {} - | ^^ + | ^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields - --> $DIR/pat-tuple-underfield.rs:20:9 + --> $DIR/pat-tuple-underfield.rs:18:9 | LL | struct S(i32, f32); | ------------------- tuple struct defined here @@ -62,43 +50,31 @@ LL | S(..) => {} | ^^ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:27:9 + --> $DIR/pat-tuple-underfield.rs:25:9 | LL | S(i32, f32), | ----------- tuple variant defined here ... LL | E::S(x) => {} - | ^^^^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | E::S(x, _) => {} - | ^^^ -help: use `..` to ignore the rest of the fields - | -LL | E::S(x, ..) => {} - | ^^^^ + | ^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:33:9 + --> $DIR/pat-tuple-underfield.rs:30:9 | LL | S(i32, f32), | ----------- tuple variant defined here ... LL | E::S(_) => {} - | ^^^^^^^ expected 2 fields, found 1 - | -help: use `_` to explicitly ignore each field - | -LL | E::S(_, _) => {} - | ^^^ -help: use `..` to ignore all fields - | -LL | E::S(..) => {} - | ^^ + | ^^^^^^- + | | | + | | help: use `_` to explicitly ignore each field + | expected 2 fields, found 1 error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:39:9 + --> $DIR/pat-tuple-underfield.rs:35:9 | LL | S(i32, f32), | ----------- tuple variant defined here From 1bce77576964e069833edb1b3b6ca5baa68ae65e Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 12 Jan 2021 16:47:04 -0800 Subject: [PATCH 20/49] Add a test case with lots of whitespace --- src/test/ui/pattern/pat-tuple-underfield.rs | 8 +++++ .../ui/pattern/pat-tuple-underfield.stderr | 34 ++++++++++++++----- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs index f86d617801455..50f8a855d3639 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.rs +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -2,6 +2,7 @@ struct S(i32, f32); enum E { S(i32, f32), } +struct Point4(i32, i32, i32, i32); fn main() { match S(0, 1.0) { @@ -42,4 +43,11 @@ fn main() { //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S` //~| HELP use the tuple variant pattern syntax instead } + + match Point4(0, 1, 2, 3) { + Point4( a , _ ) => {} + //~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields + //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore the rest of the fields + } } diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr index 6e7afd8e57b1d..df6b216272e30 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.stderr +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -1,5 +1,5 @@ error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S` - --> $DIR/pat-tuple-underfield.rs:41:9 + --> $DIR/pat-tuple-underfield.rs:42:9 | LL | S(i32, f32), | ----------- `E::S` defined here @@ -8,7 +8,7 @@ LL | E::S => {} | ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)` error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields - --> $DIR/pat-tuple-underfield.rs:8:9 + --> $DIR/pat-tuple-underfield.rs:9:9 | LL | struct S(i32, f32); | ------------------- tuple struct defined here @@ -20,7 +20,7 @@ LL | S(x) => {} | expected 2 fields, found 1 error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields - --> $DIR/pat-tuple-underfield.rs:13:9 + --> $DIR/pat-tuple-underfield.rs:14:9 | LL | struct S(i32, f32); | ------------------- tuple struct defined here @@ -32,7 +32,7 @@ LL | S(_) => {} | expected 2 fields, found 1 error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields - --> $DIR/pat-tuple-underfield.rs:18:9 + --> $DIR/pat-tuple-underfield.rs:19:9 | LL | struct S(i32, f32); | ------------------- tuple struct defined here @@ -50,7 +50,7 @@ LL | S(..) => {} | ^^ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:25:9 + --> $DIR/pat-tuple-underfield.rs:26:9 | LL | S(i32, f32), | ----------- tuple variant defined here @@ -62,7 +62,7 @@ LL | E::S(x) => {} | expected 2 fields, found 1 error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:30:9 + --> $DIR/pat-tuple-underfield.rs:31:9 | LL | S(i32, f32), | ----------- tuple variant defined here @@ -74,7 +74,7 @@ LL | E::S(_) => {} | expected 2 fields, found 1 error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:35:9 + --> $DIR/pat-tuple-underfield.rs:36:9 | LL | S(i32, f32), | ----------- tuple variant defined here @@ -91,7 +91,25 @@ help: use `..` to ignore all fields LL | E::S(..) => {} | ^^ -error: aborting due to 7 previous errors +error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields + --> $DIR/pat-tuple-underfield.rs:48:9 + | +LL | struct Point4(i32, i32, i32, i32); + | ---------------------------------- tuple struct defined here +... +LL | Point4( a , _ ) => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 4 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Point4( a , _ , _, _) => {} + | ^^^^^^ +help: use `..` to ignore the rest of the fields + | +LL | Point4( a , _ , ..) => {} + | ^^^^ + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0023, E0532. For more information about an error, try `rustc --explain E0023`. From d7307a71f5e1893f7bd69ff160ce38dc97b5d195 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 12 Jan 2021 19:06:20 -0800 Subject: [PATCH 21/49] Always show suggestions in their own subwindows --- compiler/rustc_typeck/src/check/pat.rs | 6 +-- .../tuple_struct_destructure_fail.stderr | 20 ++++++---- src/test/ui/error-codes/E0023.stderr | 10 +++-- ...7-pat-tup-scrut-ty-diff-less-fields.stderr | 10 +++-- src/test/ui/issues/issue-72574-2.stderr | 10 +++-- .../match/match-pattern-field-mismatch.stderr | 10 +++-- src/test/ui/pattern/issue-74539.stderr | 10 +++-- .../ui/pattern/pat-tuple-underfield.stderr | 40 +++++++++++-------- 8 files changed, 69 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index a863fc95e0ea1..e176389f0e279 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1061,7 +1061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wildcard_sugg = String::from(", ") + &wildcard_sugg; } - err.span_suggestion_short( + err.span_suggestion_verbose( after_fields_span, "use `_` to explicitly ignore each field", wildcard_sugg, @@ -1071,14 +1071,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only suggest `..` if more than one field is missing. if fields.len() - subpats.len() > 1 { if subpats.is_empty() || all_wildcards { - err.span_suggestion_short( + err.span_suggestion_verbose( all_fields_span, "use `..` to ignore all fields", String::from(".."), Applicability::MaybeIncorrect, ); } else { - err.span_suggestion_short( + err.span_suggestion_verbose( after_fields_span, "use `..` to ignore the rest of the fields", String::from(", .."), diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index 42859406e178d..8c20bb4fb833c 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -30,10 +30,12 @@ LL | struct TupleStruct(S, T); | ------------------------------- tuple struct defined here ... LL | TupleStruct(_) = TupleStruct(1, 2); - | ^^^^^^^^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | TupleStruct(_, _) = TupleStruct(1, 2); + | ^^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:34:5 @@ -51,10 +53,12 @@ LL | SingleVariant(S, T) | ------------------- tuple variant defined here ... LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2); - | ^^^^^^^^^^^^^^^^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); + | ^^^ error[E0070]: invalid left-hand side of assignment --> $DIR/tuple_struct_destructure_fail.rs:40:12 diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr index 0c6f496cf4353..832eba6972213 100644 --- a/src/test/ui/error-codes/E0023.stderr +++ b/src/test/ui/error-codes/E0023.stderr @@ -5,10 +5,12 @@ LL | Apple(String, String), | --------------------- tuple variant defined here ... LL | Fruit::Apple(a) => {}, - | ^^^^^^^^^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | Fruit::Apple(a, _) => {}, + | ^^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/E0023.rs:12:9 diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 86be8e7db4e6f..46ffac48c1bad 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -16,10 +16,12 @@ LL | struct P(T); // 1 type parameter wanted | --------------- tuple struct defined here ... LL | let P() = U {}; - | ^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 1 field, found 0 + | ^^^ expected 1 field, found 0 + | +help: use `_` to explicitly ignore each field + | +LL | let P(_) = U {}; + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr index 9479e365aee68..a1e8ec1677db5 100644 --- a/src/test/ui/issues/issue-72574-2.stderr +++ b/src/test/ui/issues/issue-72574-2.stderr @@ -25,10 +25,12 @@ LL | struct Binder(i32, i32, i32); | ----------------------------- tuple struct defined here ... LL | Binder(_a, _x @ ..) => {} - | ^^^^^^^^^^^^^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 3 fields, found 2 + | ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Binder(_a, _x @ .., _) => {} + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index 0bb5e726ccbd8..04f8cab900e1b 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -5,10 +5,12 @@ LL | Rgb(usize, usize, usize), | ------------------------ tuple variant defined here ... LL | Color::Rgb(_, _) => { } - | ^^^^^^^^^^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 3 fields, found 2 + | ^^^^^^^^^^^^^^^^ expected 3 fields, found 2 + | +help: use `_` to explicitly ignore each field + | +LL | Color::Rgb(_, _, _) => { } + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr index 49011d83e5075..f7644c19ea0d9 100644 --- a/src/test/ui/pattern/issue-74539.stderr +++ b/src/test/ui/pattern/issue-74539.stderr @@ -25,10 +25,12 @@ LL | A(u8, u8), | --------- tuple variant defined here ... LL | E::A(x @ ..) => { - | ^^^^^^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^^^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::A(x @ .., _) => { + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr index df6b216272e30..cdf7cfe30054d 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.stderr +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -14,10 +14,12 @@ LL | struct S(i32, f32); | ------------------- tuple struct defined here ... LL | S(x) => {} - | ^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(x, _) => {} + | ^^^ error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields --> $DIR/pat-tuple-underfield.rs:14:9 @@ -26,10 +28,12 @@ LL | struct S(i32, f32); | ------------------- tuple struct defined here ... LL | S(_) => {} - | ^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | S(_, _) => {} + | ^^^ error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields --> $DIR/pat-tuple-underfield.rs:19:9 @@ -56,10 +60,12 @@ LL | S(i32, f32), | ----------- tuple variant defined here ... LL | E::S(x) => {} - | ^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(x, _) => {} + | ^^^ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields --> $DIR/pat-tuple-underfield.rs:31:9 @@ -68,10 +74,12 @@ LL | S(i32, f32), | ----------- tuple variant defined here ... LL | E::S(_) => {} - | ^^^^^^- - | | | - | | help: use `_` to explicitly ignore each field - | expected 2 fields, found 1 + | ^^^^^^^ expected 2 fields, found 1 + | +help: use `_` to explicitly ignore each field + | +LL | E::S(_, _) => {} + | ^^^ error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields --> $DIR/pat-tuple-underfield.rs:36:9 From c3f7429fb4edae31b5e4838404aa2a11117dabcc Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 12 Jan 2021 20:52:06 -0800 Subject: [PATCH 22/49] Use better ICE message when no MIR is available The ICE message is somewhat confusing and overly specific - the issue is that there's no MIR available. This should make debugging these ICEs easier since the error tells you what's actually wrong, not what it was trying to do when it failed. cc https://github.com/rust-lang/rust/pull/80952#issuecomment-759198841 --- compiler/rustc_mir/src/monomorphize/collector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 6370ead97e798..9a191e94b5dc7 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -823,7 +823,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> } if !tcx.is_mir_available(def_id) { - bug!("cannot create local mono-item for {:?}", def_id) + bug!("no MIR available for {:?}", def_id); } true From 7e83fece9159463746a53242b2c6c795a47ccf9b Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 13 Jan 2021 15:14:11 +1000 Subject: [PATCH 23/49] remove unstable deprecated Vec::remove_item --- library/alloc/src/vec/mod.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2a83eb33fe3ec..fc9e108a3c660 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1950,27 +1950,6 @@ impl Vec { } } -impl Vec { - /// Removes the first instance of `item` from the vector if the item exists. - /// - /// This method will be removed soon. - #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")] - #[rustc_deprecated( - reason = "Removing the first item equal to a needle is already easily possible \ - with iterators and the current Vec methods. Furthermore, having a method for \ - one particular case of removal (linear search, only the first item, no swap remove) \ - but not for others is inconsistent. This method will be removed soon.", - since = "1.46.0" - )] - pub fn remove_item(&mut self, item: &V) -> Option - where - T: PartialEq, - { - let pos = self.iter().position(|x| *x == *item)?; - Some(self.remove(pos)) - } -} - //////////////////////////////////////////////////////////////////////////////// // Internal methods and functions //////////////////////////////////////////////////////////////////////////////// From 6bfd987aa03c75e7bb300b13d1956b2b3b4b2d11 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 12 Jan 2021 20:42:46 -0800 Subject: [PATCH 24/49] Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 5bb44f8b5b0aa..ac57a0ddd23d1 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 5bb44f8b5b0aa105c8b22602e9b18800484afa21 +Subproject commit ac57a0ddd23d173b26731ccf939f3ba729753275 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index ba34b8a968f95..ceec19e873be8 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit ba34b8a968f9531d38c4dc4411d5568b7c076bfe +Subproject commit ceec19e873be87c6ee5666b030c6bb612f889a96 diff --git a/src/doc/nomicon b/src/doc/nomicon index a5a48441d411f..a8584998eacde 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit a5a48441d411f61556b57d762b03d6874afe575d +Subproject commit a8584998eacdea7106a1dfafcbf6c1c06fcdf925 diff --git a/src/doc/reference b/src/doc/reference index b278478b76617..50af691f83893 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b278478b766178491a8b6f67afa4bcd6b64d977a +Subproject commit 50af691f838937c300b47812d0507c6d88c14f97 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 1cce0737d6a7d..03e23af01f0b4 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 1cce0737d6a7d3ceafb139b4a206861fb1dcb2ab +Subproject commit 03e23af01f0b4f83a3a513da280e1ca92587f2ec From e8c87935e0004ff784ad361a5bac39d7677c3f4f Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 12 Jan 2021 20:39:51 -0800 Subject: [PATCH 25/49] Include `..` suggestion if fields are all wildcards --- compiler/rustc_typeck/src/check/pat.rs | 5 +++-- .../tuple_struct_destructure_fail.stderr | 8 ++++++++ ...7-pat-tup-scrut-ty-diff-less-fields.stderr | 4 ++++ .../match/match-pattern-field-mismatch.stderr | 4 ++++ src/test/ui/pattern/pat-tuple-underfield.rs | 2 ++ .../ui/pattern/pat-tuple-underfield.stderr | 20 +++++++++++++------ 6 files changed, 35 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index e176389f0e279..ecc6e8599ad01 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1068,8 +1068,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); - // Only suggest `..` if more than one field is missing. - if fields.len() - subpats.len() > 1 { + // Only suggest `..` if more than one field is missing + // or the pattern consists of all wildcards. + if fields.len() - subpats.len() > 1 || all_wildcards { if subpats.is_empty() || all_wildcards { err.span_suggestion_verbose( all_fields_span, diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr index 8c20bb4fb833c..c270593cac741 100644 --- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr +++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr @@ -36,6 +36,10 @@ help: use `_` to explicitly ignore each field | LL | TupleStruct(_, _) = TupleStruct(1, 2); | ^^^ +help: use `..` to ignore all fields + | +LL | TupleStruct(..) = TupleStruct(1, 2); + | ^^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/tuple_struct_destructure_fail.rs:34:5 @@ -59,6 +63,10 @@ help: use `_` to explicitly ignore each field | LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2); | ^^^ +help: use `..` to ignore all fields + | +LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2); + | ^^ error[E0070]: invalid left-hand side of assignment --> $DIR/tuple_struct_destructure_fail.rs:40:12 diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 46ffac48c1bad..9bdbf0bf9f40d 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -22,6 +22,10 @@ help: use `_` to explicitly ignore each field | LL | let P(_) = U {}; | ^ +help: use `..` to ignore all fields + | +LL | let P(..) = U {}; + | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr index 04f8cab900e1b..37839482b31a2 100644 --- a/src/test/ui/match/match-pattern-field-mismatch.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch.stderr @@ -11,6 +11,10 @@ help: use `_` to explicitly ignore each field | LL | Color::Rgb(_, _, _) => { } | ^^^ +help: use `..` to ignore all fields + | +LL | Color::Rgb(..) => { } + | ^^ error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs index 50f8a855d3639..ed852a47bb4ee 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.rs +++ b/src/test/ui/pattern/pat-tuple-underfield.rs @@ -14,6 +14,7 @@ fn main() { S(_) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields } match S(0, 1.0) { S() => {} @@ -31,6 +32,7 @@ fn main() { E::S(_) => {} //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields //~| HELP use `_` to explicitly ignore each field + //~| HELP use `..` to ignore all fields } match E::S(0, 1.0) { E::S() => {} diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr index cdf7cfe30054d..76323d9a7bf56 100644 --- a/src/test/ui/pattern/pat-tuple-underfield.stderr +++ b/src/test/ui/pattern/pat-tuple-underfield.stderr @@ -1,5 +1,5 @@ error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S` - --> $DIR/pat-tuple-underfield.rs:42:9 + --> $DIR/pat-tuple-underfield.rs:44:9 | LL | S(i32, f32), | ----------- `E::S` defined here @@ -34,9 +34,13 @@ help: use `_` to explicitly ignore each field | LL | S(_, _) => {} | ^^^ +help: use `..` to ignore all fields + | +LL | S(..) => {} + | ^^ error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields - --> $DIR/pat-tuple-underfield.rs:19:9 + --> $DIR/pat-tuple-underfield.rs:20:9 | LL | struct S(i32, f32); | ------------------- tuple struct defined here @@ -54,7 +58,7 @@ LL | S(..) => {} | ^^ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:26:9 + --> $DIR/pat-tuple-underfield.rs:27:9 | LL | S(i32, f32), | ----------- tuple variant defined here @@ -68,7 +72,7 @@ LL | E::S(x, _) => {} | ^^^ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:31:9 + --> $DIR/pat-tuple-underfield.rs:32:9 | LL | S(i32, f32), | ----------- tuple variant defined here @@ -80,9 +84,13 @@ help: use `_` to explicitly ignore each field | LL | E::S(_, _) => {} | ^^^ +help: use `..` to ignore all fields + | +LL | E::S(..) => {} + | ^^ error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields - --> $DIR/pat-tuple-underfield.rs:36:9 + --> $DIR/pat-tuple-underfield.rs:38:9 | LL | S(i32, f32), | ----------- tuple variant defined here @@ -100,7 +108,7 @@ LL | E::S(..) => {} | ^^ error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields - --> $DIR/pat-tuple-underfield.rs:48:9 + --> $DIR/pat-tuple-underfield.rs:50:9 | LL | struct Point4(i32, i32, i32, i32); | ---------------------------------- tuple struct defined here From d65cb6ebcedadbfdf190975228e5db7a5c8f1555 Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 13 Jan 2021 14:39:19 +1000 Subject: [PATCH 26/49] deprecate atomic::spin_loop_hint in favour of hint::spin_loop --- library/alloc/src/sync/tests.rs | 2 +- library/core/src/sync/atomic.rs | 27 +++++++++---------- library/std/src/sys/hermit/mutex.rs | 5 ++-- .../std/src/sys/sgx/waitqueue/spin_mutex.rs | 5 ++-- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index e8e1e66da5ed4..5067af1d4ff68 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -370,7 +370,7 @@ fn test_weak_count_locked() { let n = Arc::weak_count(&a2); assert!(n < 2, "bad weak count: {}", n); #[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint. - atomic::spin_loop_hint(); + std::hint::spin_loop(); } t.join().unwrap(); } diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index d03c19e51f3fa..decc1fc622100 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -120,21 +120,6 @@ use crate::intrinsics; use crate::hint::spin_loop; -/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). -/// -/// This function is expected to be deprecated in favor of -/// [`hint::spin_loop`]. -/// -/// **Note**: On platforms that do not support receiving spin-loop hints this function does not -/// do anything at all. -/// -/// [`hint::spin_loop`]: crate::hint::spin_loop -#[inline] -#[stable(feature = "spin_loop_hint", since = "1.24.0")] -pub fn spin_loop_hint() { - spin_loop() -} - /// A boolean type which can be safely shared between threads. /// /// This type has the same in-memory representation as a [`bool`]. @@ -2791,3 +2776,15 @@ impl fmt::Pointer for AtomicPtr { fmt::Pointer::fmt(&self.load(Ordering::SeqCst), f) } } + +/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). +/// +/// This function is deprecated in favor of [`hint::spin_loop`]. +/// +/// [`hint::spin_loop`]: crate::hint::spin_loop +#[inline] +#[stable(feature = "spin_loop_hint", since = "1.24.0")] +#[rustc_deprecated(since = "1.51.0", reason = "use hint::spin_loop instead")] +pub fn spin_loop_hint() { + spin_loop() +} diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index f988a019cfedb..885389ca54cd4 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -1,9 +1,10 @@ use crate::cell::UnsafeCell; use crate::collections::VecDeque; use crate::ffi::c_void; +use crate::hint; use crate::ops::{Deref, DerefMut, Drop}; use crate::ptr; -use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::hermit::abi; /// This type provides a lock based on busy waiting to realize mutual exclusion @@ -46,7 +47,7 @@ impl Spinlock { fn obtain_lock(&self) { let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1; while self.dequeue.load(Ordering::SeqCst) != ticket { - spin_loop_hint(); + hint::spin_loop(); } } diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs index 9140041c58414..7f1a671bab4eb 100644 --- a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs @@ -2,8 +2,9 @@ mod tests; use crate::cell::UnsafeCell; +use crate::hint; use crate::ops::{Deref, DerefMut}; -use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; +use crate::sync::atomic::{AtomicBool, Ordering}; #[derive(Default)] pub struct SpinMutex { @@ -32,7 +33,7 @@ impl SpinMutex { match self.try_lock() { None => { while self.lock.load(Ordering::Relaxed) { - spin_loop_hint() + hint::spin_loop() } } Some(guard) => return guard, From 697b20ff08f98fff289ef9a861ac9dea5e7f9314 Mon Sep 17 00:00:00 2001 From: trevor arjeski Date: Wed, 13 Jan 2021 13:49:46 +0300 Subject: [PATCH 27/49] Fixed incorrect doc comment ">" is right alignment, not left --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0c65c1c9eb7e9..7e817edeec1ee 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1555,7 +1555,7 @@ impl<'a> Formatter<'a> { /// } /// } /// - /// // We set alignment to the left with ">". + /// // We set alignment to the right with ">". /// assert_eq!(&format!("{:G>3}", Foo), "GGG"); /// assert_eq!(&format!("{:t>6}", Foo), "tttttt"); /// ``` From 52adfdde262ac85d4757c434b39e69c37744f47b Mon Sep 17 00:00:00 2001 From: LingMan Date: Mon, 11 Jan 2021 20:45:33 +0100 Subject: [PATCH 28/49] Use Option::map_or instead of `.map(..).unwrap_or(..)` --- compiler/rustc_ast_lowering/src/path.rs | 2 +- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- compiler/rustc_codegen_llvm/src/back/write.rs | 3 +-- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- compiler/rustc_data_structures/src/profiling.rs | 2 +- compiler/rustc_driver/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 4 ++-- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_expand/src/mbe/quoted.rs | 6 +++--- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_lint/src/types.rs | 3 +-- compiler/rustc_lint/src/unused.rs | 4 ++-- compiler/rustc_macros/src/query.rs | 2 +- compiler/rustc_metadata/src/creader.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 5 ++--- compiler/rustc_middle/src/ty/consts/kind.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 ++-- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_mir/src/borrow_check/borrow_set.rs | 2 +- .../src/borrow_check/diagnostics/explain_borrow.rs | 2 +- compiler/rustc_mir/src/interpret/eval_context.rs | 2 +- compiler/rustc_mir/src/interpret/util.rs | 3 +-- compiler/rustc_mir/src/monomorphize/partitioning/mod.rs | 3 +-- compiler/rustc_mir/src/transform/simplify_try.rs | 4 ++-- compiler/rustc_mir_build/src/thir/pattern/usefulness.rs | 2 +- compiler/rustc_parse/src/parser/diagnostics.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 4 ++-- compiler/rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 5 ++--- compiler/rustc_resolve/src/lib.rs | 4 ++-- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_session/src/session.rs | 2 +- compiler/rustc_span/src/source_map.rs | 4 ++-- compiler/rustc_span/src/source_map/tests.rs | 2 +- .../src/traits/error_reporting/mod.rs | 2 +- compiler/rustc_typeck/src/check/check.rs | 4 ++-- compiler/rustc_typeck/src/check/compare_method.rs | 5 +++-- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 5 ++--- compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 4 ++-- compiler/rustc_typeck/src/check/method/suggest.rs | 8 ++------ compiler/rustc_typeck/src/check/wfcheck.rs | 2 +- compiler/rustc_typeck/src/collect.rs | 2 +- compiler/rustc_typeck/src/mem_categorization.rs | 4 +--- compiler/rustc_typeck/src/outlives/implicit_infer.rs | 2 +- 50 files changed, 67 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6afed355dc338..3c005615083b5 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -273,7 +273,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if !generic_args.parenthesized && !has_lifetimes { generic_args.args = self .elided_path_lifetimes( - first_generic_span.map(|s| s.shrink_to_lo()).unwrap_or(segment.ident.span), + first_generic_span.map_or(segment.ident.span, |s| s.shrink_to_lo()), expected_lifetimes, ) .map(GenericArg::Lifetime) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d65bc820f8fb1..7bd805f91c857 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -370,7 +370,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!( &self, negative_impls, - span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(span)), + span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), "negative trait bounds are not yet fully implemented; \ use marker types for now" ); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 68f319ade1e79..e225730dce061 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1002,8 +1002,7 @@ pub unsafe fn with_llvm_pmb( // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_size = - config.opt_size.map(|x| to_llvm_opt_settings(x).1).unwrap_or(llvm::CodeGenOptSizeNone); + let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1); let inline_threshold = config.inline_threshold; let pgo_gen_path = get_pgo_gen_path(config); let pgo_use_path = get_pgo_use_path(config); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 728795cf50b85..ff77db9eab852 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -166,7 +166,7 @@ fn get_linker( _ => match flavor { LinkerFlavor::Lld(f) => Command::lld(linker, f), LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => { - Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker)) + Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path())) } _ => Command::new(linker), }, diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 5d13b7f27c704..b16d5a9e2b421 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -166,7 +166,7 @@ impl SelfProfilerRef { // If there is no SelfProfiler then the filter mask is set to NONE, // ensuring that nothing ever tries to actually access it. let event_filter_mask = - profiler.as_ref().map(|p| p.event_filter_mask).unwrap_or(EventFilter::empty()); + profiler.as_ref().map_or(EventFilter::empty(), |p| p.event_filter_mask); SelfProfilerRef { profiler, diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 509f81e16536b..aede631849aed 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1236,7 +1236,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { } // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); + let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); let num_frames = if backtrace { None } else { Some(2) }; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 593e0d92031ff..e184e929b0745 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -804,7 +804,7 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false) + self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c) } fn print_error_count(&mut self, registry: &Registry) { @@ -913,7 +913,7 @@ impl HandlerInner { // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before // incrementing `err_count` by one, so we need to +1 the comparing. // FIXME: Would be nice to increment err_count in a more coherent way. - if self.flags.treat_err_as_bug.map(|c| self.err_count() + 1 >= c).unwrap_or(false) { + if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 1193f66651ce9..b07bce94870c1 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -423,7 +423,7 @@ impl<'a> StripUnconfigured<'a> { /// If attributes are not allowed on expressions, emit an error for `attr` pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { - if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { + if !self.features.map_or(true, |features| features.stmt_expr_attributes) { let mut err = feature_err( &self.sess.parse_sess, sym::stmt_expr_attributes, diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index e76cc6f1fed7b..1aed42a24e2b3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -500,7 +500,7 @@ fn inner_parse_loop<'root, 'tt>( if idx == len && item.sep.is_some() { // We have a separator, and it is the current token. We can advance past the // separator token. - if item.sep.as_ref().map(|sep| token_name_eq(token, sep)).unwrap_or(false) { + if item.sep.as_ref().map_or(false, |sep| token_name_eq(token, sep)) { item.idx += 1; next_items.push(item); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 3d126749d541d..8373304ea9134 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -203,7 +203,7 @@ fn macro_rules_dummy_expander<'cx>( } fn trace_macros_note(cx_expansions: &mut FxHashMap>, sp: Span, message: String) { - let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); + let sp = sp.macro_backtrace().last().map_or(sp, |trace| trace.call_site); cx_expansions.entry(sp).or_default().push(message); } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index a4b44931fc1ae..c8049495d223c 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -99,10 +99,10 @@ pub(super) fn parse( } _ => token.span, }, - tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span), + tree => tree.as_ref().map_or(span, tokenstream::TokenTree::span), } } - tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), + tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span), }; if node_id != DUMMY_NODE_ID { // Macros loaded from other crates have dummy node ids. @@ -250,7 +250,7 @@ fn parse_kleene_op( Some(op) => Ok(Ok((op, token.span))), None => Ok(Err(token)), }, - tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)), + tree => Err(tree.as_ref().map_or(span, tokenstream::TokenTree::span)), } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 98c02d5741078..c8908686b44b3 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -528,7 +528,7 @@ impl WhereClause<'_> { /// in `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. pub fn tail_span_for_suggestion(&self) -> Span { let end = self.span_for_predicates_or_empty_place().shrink_to_hi(); - self.predicates.last().map(|p| p.span()).unwrap_or(end).shrink_to_hi().to(end) + self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 5d56744805f89..fee6f87ae42c3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2118,7 +2118,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let consider = format!( "{} {}...", msg, - if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) { + if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) { format!(" `{}` to `{}`", sub, bound_kind) } else { format!("`{}: {}`", bound_kind, sub) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 56d9634213ae5..27545c126857b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1533,7 +1533,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Note: if these two lines are combined into one we get // dynamic borrow errors on `self.inner`. let known = self.inner.borrow_mut().type_variables().probe(v).known(); - known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ) + known.map_or(typ, |t| self.shallow_resolve_ty(t)) } ty::Infer(ty::IntVar(v)) => self diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9ad9d53cd0db3..424f91b3f883e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -647,8 +647,7 @@ pub fn transparent_newtype_field<'a, 'tcx>( let param_env = tcx.param_env(variant.def_id); for field in &variant.fields { let field_ty = tcx.type_of(field.did); - let is_zst = - tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false); + let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst()); if !is_zst { return Some(field); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 35915dc7a9753..bc7363a69a6e8 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -529,8 +529,8 @@ trait UnusedDelimLint { pprust::expr_to_string(value) }; let keep_space = ( - left_pos.map(|s| s >= value.span.lo()).unwrap_or(false), - right_pos.map(|s| s <= value.span.hi()).unwrap_or(false), + left_pos.map_or(false, |s| s >= value.span.lo()), + right_pos.map_or(false, |s| s <= value.span.hi()), ); self.emit_unused_delims(cx, value.span, &expr_text, ctx.into(), keep_space); } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 6d876784be653..d264462bf0895 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -429,7 +429,7 @@ fn add_query_description_impl( }; let (tcx, desc) = modifiers.desc; - let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); + let tcx = tcx.as_ref().map_or(quote! { _ }, |t| quote! { #t }); let desc = quote! { #[allow(unused_variables)] diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 019ca5174a223..a7bf79d7e6743 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -326,7 +326,7 @@ impl<'a> CrateLoader<'a> { self.verify_no_symbol_conflicts(&crate_root)?; let private_dep = - self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false); + self.sess.opts.externs.get(&name.as_str()).map_or(false, |e| e.is_private_dep); // Claim this crate number and cache it let cnum = self.cstore.alloc_new_crate_num(); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 5b33678b25ae2..8d0994320e383 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -132,7 +132,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { impl Collector<'tcx> { fn register_native_lib(&mut self, span: Option, lib: NativeLib) { - if lib.name.as_ref().map(|&s| s == kw::Empty).unwrap_or(false) { + if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) { match span { Some(span) => { struct_span_err!( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 209d1838e3ebc..2568af23ef506 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -813,7 +813,7 @@ impl<'hir> Map<'hir> { /// Given a node ID, gets a list of attributes associated with the AST /// corresponding to the node-ID. pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { - let attrs = self.find_entry(id).map(|entry| match entry.node { + self.find_entry(id).map_or(&[], |entry| match entry.node { Node::Param(a) => &a.attrs[..], Node::Local(l) => &l.attrs[..], Node::Item(i) => &i.attrs[..], @@ -840,8 +840,7 @@ impl<'hir> Map<'hir> { | Node::Block(..) | Node::Lifetime(..) | Node::Visibility(..) => &[], - }); - attrs.unwrap_or(&[]) + }) } /// Gets the span of the definition of the specified HIR node. diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index ecf2837b3e423..a2638d8bddad0 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -82,7 +82,7 @@ impl<'tcx> ConstKind<'tcx> { /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { - self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self) + self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value) } #[inline] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3540f0f06b6e6..c3ad4c1c126d2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1338,7 +1338,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult { - self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(())) + self.queries.on_disk_cache.as_ref().map_or(Ok(()), |c| c.serialize(self, encoder)) } /// If `true`, we should use the MIR-based borrowck, but also @@ -2601,7 +2601,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner).map(|set| set.contains(&id.local_id)).unwrap_or(false) + self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id)) } pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 413c9cca589d9..6ca5dcc532d22 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -535,7 +535,7 @@ fn polymorphize<'tcx>( } else { None }; - let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false); + let has_upvars = upvars_ty.map_or(false, |ty| ty.tuple_fields().count() > 0); debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars); struct PolymorphizationFolder<'tcx> { diff --git a/compiler/rustc_mir/src/borrow_check/borrow_set.rs b/compiler/rustc_mir/src/borrow_check/borrow_set.rs index b4299fbc5a1fe..288eda32e414e 100644 --- a/compiler/rustc_mir/src/borrow_check/borrow_set.rs +++ b/compiler/rustc_mir/src/borrow_check/borrow_set.rs @@ -149,7 +149,7 @@ impl<'tcx> BorrowSet<'tcx> { } crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] { - self.activation_map.get(&location).map(|activations| &activations[..]).unwrap_or(&[]) + self.activation_map.get(&location).map_or(&[], |activations| &activations[..]) } crate fn len(&self) -> usize { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index eccb6168229c2..a3d09c3a8d4c1 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -75,7 +75,7 @@ impl BorrowExplanation { LaterUseKind::FakeLetRead => "stored here", LaterUseKind::Other => "used here", }; - if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) { + if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) { err.span_label( var_or_use_span, format!("{}borrow later {}", borrow_desc, message), diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 6d7781671d8cc..7e9594dd6bfd7 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -370,7 +370,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn cur_span(&self) -> Span { - self.stack().last().map(|f| f.current_span()).unwrap_or(self.tcx.span) + self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } #[inline(always)] diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index c2165db278fa0..89f34cd07aa4b 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -47,8 +47,7 @@ where let index = index .try_into() .expect("more generic parameters than can fit into a `u32`"); - let is_used = - unused_params.contains(index).map(|unused| !unused).unwrap_or(true); + let is_used = unused_params.contains(index).map_or(true, |unused| !unused); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. match (is_used, subst.needs_subst()) { diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index db6d3b2d912d6..b9fcd32250dcf 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -247,8 +247,7 @@ where for (mono_item, linkage) in cgu.items() { let symbol_name = mono_item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); - let symbol_hash = - symbol_hash_start.map(|i| &symbol_name[i..]).unwrap_or(""); + let symbol_hash = symbol_hash_start.map_or("", |i| &symbol_name[i..]); debug!( " - {} [{:?}] [{}] estimated size {}", diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index a3459887a9a75..05a88828070fb 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -113,7 +113,7 @@ fn get_arm_identity_info<'a, 'tcx>( test: impl Fn(&'a Statement<'tcx>) -> bool, mut action: impl FnMut(usize, &'a Statement<'tcx>), ) { - while stmt_iter.peek().map(|(_, stmt)| test(stmt)).unwrap_or(false) { + while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) { let (idx, stmt) = stmt_iter.next().unwrap(); action(idx, stmt); @@ -635,7 +635,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }) .peekable(); - let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(&targets_and_values[0]); + let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx); let mut all_successors_equivalent = StatementEquality::TrivialEqual; // All successor basic blocks must be equal or contain statements that are pairwise considered equal. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 83fee380ccce7..d7c08a2d1af6b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -952,7 +952,7 @@ fn is_useful<'p, 'tcx>( assert!(rows.iter().all(|r| r.len() == v.len())); // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). - let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); + let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty); let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head()); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 98c7b9a63a55f..35435baea7019 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -511,7 +511,7 @@ impl<'a> Parser<'a> { // // `x.foo::>>(3)` let parsed_angle_bracket_args = - segment.args.as_ref().map(|args| args.is_angle_bracketed()).unwrap_or(false); + segment.args.as_ref().map_or(false, |args| args.is_angle_bracketed()); debug!( "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}", diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 25e3e67e28e6c..f7b16bd991bfd 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -347,7 +347,7 @@ impl<'a> Parser<'a> { let mut pos = pos; // This handles the raw string case, the raw argument is the number of # // in r###"..."### (we need to add one because of the `r`). - let raw = self.style.map(|raw| raw + 1).unwrap_or(0); + let raw = self.style.map_or(0, |raw| raw + 1); for skip in &self.skips { if pos > *skip { pos += 1; @@ -814,7 +814,7 @@ fn find_skips_from_snippet( skips } - let r_start = str_style.map(|r| r + 1).unwrap_or(0); + let r_start = str_style.map_or(0, |r| r + 1); let r_end = str_style.unwrap_or(0); let s = &snippet[r_start + 1..snippet.len() - r_end - 1]; (find_skips(s, str_style.is_some()), true) diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 605d7ae4af678..151e056a5b356 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -953,7 +953,7 @@ impl DepGraph { // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions pub fn is_green(&self, dep_node: &DepNode) -> bool { - self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false) + self.node_color(dep_node).map_or(false, |c| c.is_green()) } // This method loads all on-disk cacheable query results into memory, so diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6219d1b08eb68..9de35a8006123 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1925,7 +1925,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { { // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8` let item_span = - path.iter().last().map(|segment| segment.ident.span).unwrap_or(span); + path.iter().last().map_or(span, |segment| segment.ident.span); let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); hm.insert(item_span, span); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 55623c9bd9cf6..3945afb4724a8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -264,7 +264,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // The current function has a `self' parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we // are resolving came from a different hygiene context. - if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) { + if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) { err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters"); } else { let doesnt = if is_assoc_fn { @@ -1452,8 +1452,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } else { let needs_placeholder = |def_id: DefId, kind: CtorKind| { - let has_no_fields = - self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); + let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty()); match kind { CtorKind::Const => false, CtorKind::Fn | CtorKind::Fictive if has_no_fields => false, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fb364053e241e..c5b8f7d647ca7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1052,7 +1052,7 @@ pub struct ResolverArenas<'a> { impl<'a> ResolverArenas<'a> { fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> { let module = self.modules.alloc(module); - if module.def_id().map(|def_id| def_id.is_local()).unwrap_or(true) { + if module.def_id().map_or(true, |def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } module @@ -3031,7 +3031,7 @@ impl<'a> Resolver<'a> { let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); let from_item = - self.extern_prelude.get(&ident).map(|entry| entry.introduced_by_item).unwrap_or(true); + self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by a item. diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index c8cdff4f7e5d3..129123349a028 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -670,7 +670,7 @@ impl<'tcx> SaveContext<'tcx> { ) -> Option { // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`. fn fn_type(seg: &hir::PathSegment<'_>) -> bool { - seg.args.map(|args| args.parenthesized).unwrap_or(false) + seg.args.map_or(false, |args| args.parenthesized) } let res = self.get_path_res(id); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1f9a1af0f6872..6d01854228662 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1358,7 +1358,7 @@ pub fn build_session( let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); let optimization_fuel = Lock::new(OptimizationFuel { - remaining: sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0), + remaining: sopts.debugging_opts.fuel.as_ref().map_or(0, |i| i.1), out_of_fuel: false, }); let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index a7b8c8ba1d492..46bb8bf5c17be 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -539,7 +539,7 @@ impl SourceMap { pub fn is_line_before_span_empty(&self, sp: Span) -> bool { match self.span_to_prev_source(sp) { - Ok(s) => s.split('\n').last().map(|l| l.trim_start().is_empty()).unwrap_or(false), + Ok(s) => s.split('\n').last().map_or(false, |l| l.trim_start().is_empty()), Err(_) => false, } } @@ -568,7 +568,7 @@ impl SourceMap { // asserting that the line numbers here are all indeed 1-based. let hi_line = hi.line.saturating_sub(1); for line_index in lo.line.saturating_sub(1)..hi_line { - let line_len = lo.file.get_line(line_index).map(|s| s.chars().count()).unwrap_or(0); + let line_len = lo.file.get_line(line_index).map_or(0, |s| s.chars().count()); lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) }); start_col = CharPos::from_usize(0); } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index b8459eee4ecf0..3f22829b049fe 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -107,7 +107,7 @@ fn t7() { fn span_from_selection(input: &str, selection: &str) -> Span { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; - let right_index = selection.rfind('~').map(|x| x as u32).unwrap_or(left_index); + let right_index = selection.rfind('~').map_or(left_index, |x| x as u32); Span::with_root_ctxt(BytePos(left_index), BytePos(right_index + 1)) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 0186d164a4c53..795cf2e19decc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -830,7 +830,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .collect::>(), ), Node::Ctor(ref variant_data) => { - let span = variant_data.ctor_hir_id().map(|id| hir.span(id)).unwrap_or(DUMMY_SP); + let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); let span = sm.guess_head_span(span); (span, vec![ArgKind::empty(); variant_data.fields().len()]) } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index f1fb2b800232d..8e339eb26b26c 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1259,8 +1259,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty let layout = tcx.layout_of(param_env.and(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); - let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); + let zst = layout.map_or(false, |layout| layout.is_zst()); + let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1); (span, zst, align1) }); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 320ded5334e21..0036edda36da5 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -364,13 +364,14 @@ fn check_region_bounds_on_impl_item<'tcx>( if trait_params != impl_params { let item_kind = assoc_item_kind_str(impl_m); let def_span = tcx.sess.source_map().guess_head_span(span); - let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span); + let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span); let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { let def_sp = tcx.sess.source_map().guess_head_span(sp); - Some(tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp)) + Some(tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)) } else { None }; + tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { span, item_kind, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 7126b62405968..f5cba60f0a4e5 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -904,8 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. - let def = - cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); + let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)); return (def, Some(ty), slice::from_ref(&**item_segment)); } let item_name = item_segment.ident; @@ -932,7 +931,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Write back the new resolution. self.write_resolution(hir_id, result); ( - result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), + result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), Some(ty), slice::from_ref(&**item_segment), ) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3e60924d6fcf8..ab7e03a62d9b6 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -818,7 +818,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(match &arm.body.kind { // Point at the tail expression when possible. hir::ExprKind::Block(block, _) => { - block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) + block.expr.as_ref().map_or(block.span, |e| e.span) } _ => arm.body.span, }) @@ -879,7 +879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Write back the new resolution. self.write_resolution(hir_id, result); - (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) + (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } QPath::LangItem(lang_item, span) => { self.resolve_lang_item_path(lang_item, span, hir_id) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 5cfd78ebeacad..e6bfa5e1497fe 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1193,7 +1193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .any(|imp_did| { let imp = self.tcx.impl_trait_ref(imp_did).unwrap(); let imp_simp = simplify_type(self.tcx, imp.self_ty(), true); - imp_simp.map(|s| s == simp_rcvr_ty).unwrap_or(false) + imp_simp.map_or(false, |s| s == simp_rcvr_ty) }) { explicitly_negative.push(candidate); @@ -1270,11 +1270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.kind() { ty::Adt(def, _) => def.did.is_local(), ty::Foreign(did) => did.is_local(), - - ty::Dynamic(ref tr, ..) => { - tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false) - } - + ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), ty::Param(_) => true, // Everything else (primitive types, etc.) is effectively diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index fc3dff2654257..2c720ce025b0b 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -108,7 +108,7 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { .impl_trait_ref(tcx.hir().local_def_id(item.hir_id)) .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id)); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { - let sp = impl_.of_trait.as_ref().map(|t| t.path.span).unwrap_or(item.span); + let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); let mut err = tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default"); err.span_labels(impl_.defaultness_span, "default because of this"); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 20804d55eeb66..a8afc6e28e3d6 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1658,7 +1658,7 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { .. }) => { if is_rustc_reservation { - let span = span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(*span)); + let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span)); tcx.sess.span_err(span, "reservation impls can't be negative"); } ty::ImplPolarity::Negative diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index a601123c8d055..4f11594d39813 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -653,9 +653,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // Then we see that to get the same result, we must start with // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. - for _ in - 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) - { + for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) { debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id); place_with_id = self.cat_deref(pat, place_with_id)?; } diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 3d0635e3fe437..02008e180b34d 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { // we walk the crates again and re-calculate predicates for all // items. let item_predicates_len: usize = - self.global_inferred_outlives.get(&item_did.to_def_id()).map(|p| p.len()).unwrap_or(0); + self.global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len()); if item_required_predicates.len() > item_predicates_len { *self.predicates_added = true; self.global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates); From 64c1b0d614949f405d8b4498a3b2ea59d9ec230e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 13 Jan 2021 12:15:42 +0100 Subject: [PATCH 29/49] Fix -Cpasses=list and llvm version print with -vV --- compiler/rustc_driver/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index f434673c39e10..c668c94bb08c4 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -808,7 +808,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(util::commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(util::release_str())); - if cfg!(llvm) { + if cfg!(feature = "llvm") { get_builtin_codegen_backend("llvm")().print_version(); } } @@ -1096,7 +1096,7 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.iter().any(|x| *x == "passes=list") { - if cfg!(llvm) { + if cfg!(feature = "llvm") { get_builtin_codegen_backend("llvm")().print_passes(); } return None; From 5b1316f78152a9c066b357ea9addf803d48e114a Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 21:31:54 +0000 Subject: [PATCH 30/49] unix ExitStatus: Do not treat WIFSTOPPED as WIFSIGNALED A unix wait status can contain, at least, exit statuses, termination signals, and stop signals. WTERMSIG is only valid if WIFSIGNALED. https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html It will not be easy to experience this bug with `Command`, because that doesn't pass WUNTRACED. But you could make an ExitStatus containing, say, a WIFSTOPPED, from a call to one of the libc wait functions. (In the WIFSTOPPED case, there is WSTOPSIG. But a stop signal is encoded differently to a termination signal, so WTERMSIG and WSTOPSIG are by no means the same.) Signed-off-by: Ian Jackson --- library/std/src/sys/unix/process/process_unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index a590c74435639..629180fd71231 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -479,7 +479,7 @@ impl ExitStatus { } pub fn signal(&self) -> Option { - if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } + if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None } } } From 12d62aa436ee3a7ae0a55f63c4089c09fe140ccb Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 21:37:34 +0000 Subject: [PATCH 31/49] unix ExitStatus: Clarify docs for .signal() We need to be clear that this never returns WSTOPSIG. That is, if WIFSTOPPED, the return value is None. Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 3615a8a5ee8b0..ab961a284d51b 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -171,6 +171,8 @@ pub trait ExitStatusExt { fn from_raw(raw: i32) -> Self; /// If the process was terminated by a signal, returns that signal. + /// + /// Ie, if `WIFSIGNALED`, this returns `WTERMSIG`. #[stable(feature = "rust1", since = "1.0.0")] fn signal(&self) -> Option; } From 530270f94a3d9f1c23257ad1c9c93675b31ecf6a Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 21:41:55 +0000 Subject: [PATCH 32/49] unix ExitStatus: Provide .into_raw() Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 8 ++++++++ library/std/src/sys/unix/process/process_unix.rs | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index ab961a284d51b..4b65629e2b368 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -175,6 +175,10 @@ pub trait ExitStatusExt { /// Ie, if `WIFSIGNALED`, this returns `WTERMSIG`. #[stable(feature = "rust1", since = "1.0.0")] fn signal(&self) -> Option; + + /// Returns the underlying raw `wait` status. + #[unstable(feature = "unix_process_wait_more", issue = "none")] + fn into_raw(self) -> i32; } #[stable(feature = "rust1", since = "1.0.0")] @@ -186,6 +190,10 @@ impl ExitStatusExt for process::ExitStatus { fn signal(&self) -> Option { self.as_inner().signal() } + + fn into_raw(self) -> i32 { + self.as_inner().into_raw().into() + } } #[stable(feature = "process_extensions", since = "1.2.0")] diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 629180fd71231..f1cf402805781 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -481,6 +481,10 @@ impl ExitStatus { pub fn signal(&self) -> Option { if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None } } + + pub fn into_raw(&self) -> c_int { + self.0 + } } /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. From 3f05051d6bcb7b8562577324d59a2435a40992e9 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 21:44:13 +0000 Subject: [PATCH 33/49] unix ExitStatus: Provide .core_dumped This is essential for proper reporting of child process status on Unix. Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 8 ++++++++ library/std/src/sys/unix/process/process_unix.rs | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 4b65629e2b368..827cc0b9828b4 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -176,6 +176,10 @@ pub trait ExitStatusExt { #[stable(feature = "rust1", since = "1.0.0")] fn signal(&self) -> Option; + /// If the process was terminated by a signal, says whether it dumped core. + #[unstable(feature = "unix_process_wait_more", issue = "none")] + fn core_dumped(&self) -> bool; + /// Returns the underlying raw `wait` status. #[unstable(feature = "unix_process_wait_more", issue = "none")] fn into_raw(self) -> i32; @@ -191,6 +195,10 @@ impl ExitStatusExt for process::ExitStatus { self.as_inner().signal() } + fn core_dumped(&self) -> bool { + self.as_inner().core_dumped() + } + fn into_raw(self) -> i32 { self.as_inner().into_raw().into() } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index f1cf402805781..99b1011578a5a 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -482,6 +482,10 @@ impl ExitStatus { if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None } } + pub fn core_dumped(&self) -> bool { + libc::WIFSIGNALED(self.0) && libc::WCOREDUMP(self.0) + } + pub fn into_raw(&self) -> c_int { self.0 } From f060b9e0d9277ae522a34ca06312c5857c9aadb0 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 21:47:47 +0000 Subject: [PATCH 34/49] unix ExitStatus: Provide .stopped_signal() Necessary to handle WIFSTOPPED. Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 11 +++++++++++ library/std/src/sys/unix/process/process_unix.rs | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 827cc0b9828b4..5efe08340f488 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -180,6 +180,13 @@ pub trait ExitStatusExt { #[unstable(feature = "unix_process_wait_more", issue = "none")] fn core_dumped(&self) -> bool; + /// If the process was stopped by a signal, returns that signal. + /// + /// Ie, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from + /// a `wait` system call which was passed `WUNTRACED`, was then converted into an `ExitStatus`. + #[unstable(feature = "unix_process_wait_more", issue = "none")] + fn stopped_signal(&self) -> Option; + /// Returns the underlying raw `wait` status. #[unstable(feature = "unix_process_wait_more", issue = "none")] fn into_raw(self) -> i32; @@ -199,6 +206,10 @@ impl ExitStatusExt for process::ExitStatus { self.as_inner().core_dumped() } + fn stopped_signal(&self) -> Option { + self.as_inner().stopped_signal() + } + fn into_raw(self) -> i32 { self.as_inner().into_raw().into() } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 99b1011578a5a..069a1145f7645 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -486,6 +486,10 @@ impl ExitStatus { libc::WIFSIGNALED(self.0) && libc::WCOREDUMP(self.0) } + pub fn stopped_signal(&self) -> Option { + if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None } + } + pub fn into_raw(&self) -> c_int { self.0 } From 42ea8f64347e8c57972a043b00e6c02c9973e7df Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sat, 12 Dec 2020 21:52:17 +0000 Subject: [PATCH 35/49] unix ExitStatus: Provide .continued() Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 11 +++++++++++ library/std/src/sys/unix/process/process_unix.rs | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 5efe08340f488..6ab109cdb08c2 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -187,6 +187,13 @@ pub trait ExitStatusExt { #[unstable(feature = "unix_process_wait_more", issue = "none")] fn stopped_signal(&self) -> Option; + /// Whether the process was continued from a stopped status. + /// + /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call + /// which was passed `WCONTINUED`, was then converted into an `ExitStatus`. + #[unstable(feature = "unix_process_wait_more", issue = "none")] + fn continued(&self) -> bool; + /// Returns the underlying raw `wait` status. #[unstable(feature = "unix_process_wait_more", issue = "none")] fn into_raw(self) -> i32; @@ -210,6 +217,10 @@ impl ExitStatusExt for process::ExitStatus { self.as_inner().stopped_signal() } + fn continued(&self) -> bool { + self.as_inner().continued() + } + fn into_raw(self) -> i32 { self.as_inner().into_raw().into() } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 069a1145f7645..945b43678a919 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -490,6 +490,10 @@ impl ExitStatus { if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None } } + pub fn continued(&self) -> bool { + libc::WIFCONTINUED(self.0) + } + pub fn into_raw(&self) -> c_int { self.0 } From 29c851aef6c75e4ddedca1d5603daf3a25bd1ce1 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 13 Dec 2020 11:03:17 +0000 Subject: [PATCH 36/49] Replace `Ie` with `In other words` Co-authored-by: Joshua Nelson --- library/std/src/sys/unix/ext/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 6ab109cdb08c2..7830148b7e888 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -182,7 +182,7 @@ pub trait ExitStatusExt { /// If the process was stopped by a signal, returns that signal. /// - /// Ie, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from + /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from /// a `wait` system call which was passed `WUNTRACED`, was then converted into an `ExitStatus`. #[unstable(feature = "unix_process_wait_more", issue = "none")] fn stopped_signal(&self) -> Option; From 06a405c49cfcdc091f1d84a3c6147d78fbdb5928 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 13 Dec 2020 11:03:37 +0000 Subject: [PATCH 37/49] Replace `Ie` with `In other words` Co-authored-by: Joshua Nelson --- library/std/src/sys/unix/ext/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 7830148b7e888..a20f826e7f05a 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -172,7 +172,7 @@ pub trait ExitStatusExt { /// If the process was terminated by a signal, returns that signal. /// - /// Ie, if `WIFSIGNALED`, this returns `WTERMSIG`. + /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`. #[stable(feature = "rust1", since = "1.0.0")] fn signal(&self) -> Option; From fa68567a1fa87e92ad39b1749a134faedbbeae48 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 4 Jan 2021 17:37:34 +0000 Subject: [PATCH 38/49] unix ExitStatus: Add tracking issue to new methods Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index a20f826e7f05a..889382d3ed4ec 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -177,25 +177,25 @@ pub trait ExitStatusExt { fn signal(&self) -> Option; /// If the process was terminated by a signal, says whether it dumped core. - #[unstable(feature = "unix_process_wait_more", issue = "none")] + #[unstable(feature = "unix_process_wait_more", issue = "80695")] fn core_dumped(&self) -> bool; /// If the process was stopped by a signal, returns that signal. /// /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from /// a `wait` system call which was passed `WUNTRACED`, was then converted into an `ExitStatus`. - #[unstable(feature = "unix_process_wait_more", issue = "none")] + #[unstable(feature = "unix_process_wait_more", issue = "80695")] fn stopped_signal(&self) -> Option; /// Whether the process was continued from a stopped status. /// /// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call /// which was passed `WCONTINUED`, was then converted into an `ExitStatus`. - #[unstable(feature = "unix_process_wait_more", issue = "none")] + #[unstable(feature = "unix_process_wait_more", issue = "80695")] fn continued(&self) -> bool; /// Returns the underlying raw `wait` status. - #[unstable(feature = "unix_process_wait_more", issue = "none")] + #[unstable(feature = "unix_process_wait_more", issue = "80695")] fn into_raw(self) -> i32; } From 70121941fffce3292e45b40c84d263af5bffb109 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 4 Jan 2021 17:11:41 +0000 Subject: [PATCH 39/49] ExitStatusExt unix: Retrospectively seal this trait As discussed in #79982. I think the "new interfaces", ie the new trait and impl, must be insta-stable. This seems OK because we are, in fact, adding a new restriction to the stable API. Signed-off-by: Ian Jackson --- library/std/src/sys/unix/ext/process.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 889382d3ed4ec..a72417818d066 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -9,6 +9,14 @@ use crate::process; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; +mod private { + /// This trait being unreachable from outside the crate + /// prevents other implementations of the `ExitStatusExt` trait, + /// which allows potentially adding more trait methods in the future. + #[stable(feature = "none", since = "1.51.0")] + pub trait Sealed {} +} + /// Unix-specific extensions to the [`process::Command`] builder. #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { @@ -163,8 +171,11 @@ impl CommandExt for process::Command { } /// Unix-specific extensions to [`process::ExitStatus`]. +/// +/// This trait is saeled (since Rust 1.51): it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { +pub trait ExitStatusExt: private::Sealed { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of /// a process. #[stable(feature = "exit_status_from", since = "1.12.0")] @@ -199,6 +210,9 @@ pub trait ExitStatusExt { fn into_raw(self) -> i32; } +#[stable(feature = "none", since = "1.51.0")] +impl private::Sealed for process::ExitStatus {} + #[stable(feature = "rust1", since = "1.0.0")] impl ExitStatusExt for process::ExitStatus { fn from_raw(raw: i32) -> Self { From f3e7199a79d23741e1fc6b0e58652d6de5f97fa0 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 4 Jan 2021 17:45:23 +0000 Subject: [PATCH 40/49] ExitStatusExt windows: Retrospectively seal this trait Signed-off-by: Ian Jackson --- library/std/src/sys/windows/ext/process.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs index 61e4c6a1d1718..300385e966d37 100644 --- a/library/std/src/sys/windows/ext/process.rs +++ b/library/std/src/sys/windows/ext/process.rs @@ -7,6 +7,14 @@ use crate::process; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; +mod private { + /// This trait being unreachable from outside the crate + /// prevents other implementations of the `ExitStatusExt` trait, + /// which allows potentially adding more trait methods in the future. + #[stable(feature = "none", since = "1.51.0")] + pub trait Sealed {} +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio { @@ -73,8 +81,11 @@ impl IntoRawHandle for process::ChildStderr { } /// Windows-specific extensions to [`process::ExitStatus`]. +/// +/// This trait is saeled (since Rust 1.51): it cannot be implemented outside the standard library. +/// This is so that future additional methods are not breaking changes. #[stable(feature = "exit_status_from", since = "1.12.0")] -pub trait ExitStatusExt { +pub trait ExitStatusExt: private::Sealed { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of /// a process. #[stable(feature = "exit_status_from", since = "1.12.0")] @@ -88,6 +99,9 @@ impl ExitStatusExt for process::ExitStatus { } } +#[stable(feature = "none", since = "1.51.0")] +impl private::Sealed for process::ExitStatus {} + /// Windows-specific extensions to the [`process::Command`] builder. #[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { From efddf5949f36d68ff28abddb2c297c934d5b8eb5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 10 Jan 2021 18:11:00 -0800 Subject: [PATCH 41/49] Fix typo saeled -> sealed --- library/std/src/sys/unix/ext/process.rs | 2 +- library/std/src/sys/windows/ext/process.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index a72417818d066..f4c67b225e6e1 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -172,7 +172,7 @@ impl CommandExt for process::Command { /// Unix-specific extensions to [`process::ExitStatus`]. /// -/// This trait is saeled (since Rust 1.51): it cannot be implemented outside the standard library. +/// This trait is sealed: it cannot be implemented outside the standard library. /// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt: private::Sealed { diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs index 300385e966d37..7a92381d6609b 100644 --- a/library/std/src/sys/windows/ext/process.rs +++ b/library/std/src/sys/windows/ext/process.rs @@ -82,7 +82,7 @@ impl IntoRawHandle for process::ChildStderr { /// Windows-specific extensions to [`process::ExitStatus`]. /// -/// This trait is saeled (since Rust 1.51): it cannot be implemented outside the standard library. +/// This trait is sealed: it cannot be implemented outside the standard library. /// This is so that future additional methods are not breaking changes. #[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt: private::Sealed { From 05a88aabc1bca6d06f5827bae9e8f448f5d39f28 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 13 Jan 2021 11:17:41 +0000 Subject: [PATCH 42/49] ExitStatusExt: Fix build on Fuchsia This is not particularly pretty but the current situation is a mess and I don't think I'm making it significantly worse. Signed-off-by: Ian Jackson --- .../src/sys/unix/process/process_fuchsia.rs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index b64636c3f3d15..3102661b83dad 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -245,6 +245,50 @@ impl ExitStatus { pub fn signal(&self) -> Option { None } + + // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al. + // I infer from the implementation of `success`, `code` and `signal` above that these are not + // available on Fuchsia. + // + // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many + // other things from std::os::unix) properly. This veneer is always going to be a bdoge. So + // while I don't know if these implementations are actually correct, I think they will do for + // now at least. + pub fn core_dumped(&self) -> bool { + false + } + pub fn stopped_signal(&self) -> Option { + None + } + pub fn continued(&self) -> bool { + false + } + + pub fn into_raw(&self) -> c_int { + // We don't know what someone who calls into_raw() will do with this value, but it should + // have the conventional Unix representation. Despite the fact that this is not + // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the + // same way. (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every + // Unix.) + // + // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may + // do their own shifting and masking, or even pass the status to another computer running a + // different Unix variant. + // + // The other view would be to say that the caller on Fuchsia ought to know that `into_raw` + // will give a raw Fuchsia status (whatever that is - I don't know, personally). That is + // not possible here becaause we must return a c_int because that's what Unix (including + // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't + // necessarily fit. + // + // It seems to me that that the right answer would be to provide std::os::fuchsia with its + // own ExitStatusExt, rather that trying to provide a not very convincing imitation of + // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But + // fixing this up that is beyond the scope of my efforts now. + let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to covert the value into a traditional Unix-style wait status, which cannot represent values greater than 255."); + let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8; + wait_status_as_if_unix + } } /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. From b59fa3d6343d560d5b5bde65c76d8a4ea4c27949 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 13 Jan 2021 14:21:18 +0000 Subject: [PATCH 43/49] Fix stabilisation version of slice_strip See https://github.com/rust-lang/rust/pull/77853#pullrequestreview-564921079 Signed-off-by: Ian Jackson --- library/core/src/slice/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 081d80f487605..6de2714059480 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1877,7 +1877,7 @@ impl [T] { /// Some(b"llo".as_ref())); /// ``` #[must_use = "returns the subslice without modifying the original"] - #[stable(feature = "slice_strip", since = "1.50.0")] + #[stable(feature = "slice_strip", since = "1.51.0")] pub fn strip_prefix + ?Sized>(&self, prefix: &P) -> Option<&[T]> where T: PartialEq, @@ -1911,7 +1911,7 @@ impl [T] { /// assert_eq!(v.strip_suffix(&[50, 30]), None); /// ``` #[must_use = "returns the subslice without modifying the original"] - #[stable(feature = "slice_strip", since = "1.50.0")] + #[stable(feature = "slice_strip", since = "1.51.0")] pub fn strip_suffix + ?Sized>(&self, suffix: &P) -> Option<&[T]> where T: PartialEq, @@ -3323,7 +3323,7 @@ pub trait SlicePattern { fn as_slice(&self) -> &[Self::Item]; } -#[stable(feature = "slice_strip", since = "1.50.0")] +#[stable(feature = "slice_strip", since = "1.51.0")] impl SlicePattern for [T] { type Item = T; @@ -3333,7 +3333,7 @@ impl SlicePattern for [T] { } } -#[stable(feature = "slice_strip", since = "1.50.0")] +#[stable(feature = "slice_strip", since = "1.51.0")] impl SlicePattern for [T; N] { type Item = T; From 95289889fe4b9a69abe2963974e2df7c9a065927 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 13 Jan 2021 19:47:41 +0100 Subject: [PATCH 44/49] Add doc intralinks --- library/core/src/iter/adapters/intersperse.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 9f5cca88206ef..25115beb85129 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -1,6 +1,9 @@ use super::Peekable; /// An iterator adapter that places a separator between all elements. +/// +/// This `struct` is created by [`Iterator::intersperse`]. See it's documentation +/// for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] #[derive(Debug, Clone)] pub struct Intersperse @@ -55,6 +58,9 @@ where } /// An iterator adapter that places a separator between all elements. +/// +/// This `struct` is created by [`Iterator::intersperse_with`]. See it's +/// documentation for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub struct IntersperseWith where From 0342fd16ffb146c849f1bb40d42ba1bb7a940b62 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 13 Jan 2021 11:55:49 -0800 Subject: [PATCH 45/49] Remove the unused context from CreateDebugLocation This went unused in commit 88d874de6395, part of #68965. --- compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 1 - compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 - compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 6 ++---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index ccbe7325cc6c2..955e739b2c126 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -552,7 +552,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation( - utils::debug_context(self).llcontext, line.unwrap_or(UNKNOWN_LINE_NUMBER), col.unwrap_or(UNKNOWN_COLUMN_NUMBER), scope, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e359d9f8c9c77..eb4f36266dbae 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2102,7 +2102,6 @@ extern "C" { ); pub fn LLVMRustDIBuilderCreateDebugLocation( - Context: &'a Context, Line: c_uint, Column: c_uint, Scope: &'a DIScope, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index c0ff62c17beb5..1d6f00562f136 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -994,11 +994,9 @@ LLVMRustDICompositeTypeReplaceArrays(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line, - unsigned Column, LLVMMetadataRef Scope, +LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, + LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt) { - LLVMContext &Context = *unwrap(ContextRef); - DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr(Scope), unwrapDIPtr(InlinedAt)); From 391b4cc3789b7585affc1bae8189900a36110c5e Mon Sep 17 00:00:00 2001 From: Caleb Sander Date: Wed, 13 Jan 2021 15:05:39 -0500 Subject: [PATCH 46/49] Fix formatting specifiers doc link Was incorrectly linked to `core::fmt`, which is empty, in d36e3e23a80f039ee98117ebba0bb2ea6e34f0c1 Some of the links were fixed already in 3baf6a4a749bd6ac4a8b9f1054d3f2ad2fc91e45 --- library/core/src/fmt/mod.rs | 36 +++++++++++++++++++++++++--------- library/core/src/macros/mod.rs | 6 +++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0c65c1c9eb7e9..a76248204422d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -456,7 +456,9 @@ impl Display for Arguments<'_> { /// /// When used with the alternate format specifier `#?`, the output is pretty-printed. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// This trait can be used with `#[derive]` if all fields implement `Debug`. When /// `derive`d for structs, it will use the name of the `struct`, then `{`, then a @@ -602,7 +604,9 @@ pub use macros::Debug; /// `Display` is similar to [`Debug`], but `Display` is for user-facing /// output, and so cannot be derived. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -674,7 +678,9 @@ pub trait Display { /// /// The alternate flag, `#`, adds a `0o` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -726,7 +732,9 @@ pub trait Octal { /// /// The alternate flag, `#`, adds a `0b` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -782,7 +790,9 @@ pub trait Binary { /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -835,7 +845,9 @@ pub trait LowerHex { /// /// The alternate flag, `#`, adds a `0x` in front of the output. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -883,7 +895,9 @@ pub trait UpperHex { /// The `Pointer` trait should format its output as a memory location. This is commonly presented /// as hexadecimal. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -932,7 +946,9 @@ pub trait Pointer { /// /// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// @@ -981,7 +997,9 @@ pub trait LowerExp { /// /// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`. /// -/// For more information on formatters, see [the module-level documentation][self]. +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../../std/fmt/index.html /// /// # Examples /// diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 1634aff7b4dc9..90964bae98c89 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -401,7 +401,7 @@ macro_rules! write { /// For more information, see [`write!`]. For information on the format string syntax, see /// [`std::fmt`]. /// -/// [`std::fmt`]: crate::fmt +/// [`std::fmt`]: ../std/fmt/index.html /// /// # Examples /// @@ -730,7 +730,7 @@ pub(crate) mod builtin { /// [`Display`]: crate::fmt::Display /// [`Debug`]: crate::fmt::Debug /// [`fmt::Arguments`]: crate::fmt::Arguments - /// [`std::fmt`]: crate::fmt + /// [`std::fmt`]: ../std/fmt/index.html /// [`format!`]: ../std/macro.format.html /// [`println!`]: ../std/macro.println.html /// @@ -1194,7 +1194,7 @@ pub(crate) mod builtin { /// be provided with or without arguments for formatting. See [`std::fmt`] /// for syntax for this form. /// - /// [`std::fmt`]: crate::fmt + /// [`std::fmt`]: ../std/fmt/index.html /// /// # Examples /// From 9b2f085110c70a8ae92a47ce0c510db82f759992 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 13 Jan 2021 21:07:59 +0100 Subject: [PATCH 47/49] Improve Iterator::intersperse_ docs --- library/core/src/iter/adapters/intersperse.rs | 4 ++-- library/core/src/iter/traits/iterator.rs | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index 25115beb85129..1d01e9b5fb7dc 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -2,7 +2,7 @@ use super::Peekable; /// An iterator adapter that places a separator between all elements. /// -/// This `struct` is created by [`Iterator::intersperse`]. See it's documentation +/// This `struct` is created by [`Iterator::intersperse`]. See its documentation /// for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] #[derive(Debug, Clone)] @@ -59,7 +59,7 @@ where /// An iterator adapter that places a separator between all elements. /// -/// This `struct` is created by [`Iterator::intersperse_with`]. See it's +/// This `struct` is created by [`Iterator::intersperse_with`]. See its /// documentation for more information. #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub struct IntersperseWith diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 91d7a47907a46..732d465fcaeb3 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -571,6 +571,9 @@ pub trait Iterator { /// Places a copy of `separator` between all elements. /// + /// In case the separator does not implement [`Clone`] or needs to be + /// computed every time, use [`intersperse_with`]. + /// /// # Examples /// /// Basic usage: @@ -578,9 +581,12 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::(); - /// assert_eq!(hello, "Hello World"); + /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::(); + /// assert_eq!(hello, "Hello World !"); /// ``` + /// + /// [`Clone`]: crate::clone::Clone + /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] fn intersperse(self, separator: Self::Item) -> Intersperse @@ -600,11 +606,13 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let src = ["Hello", "to", "all", "people"].iter().copied(); - /// let mut separator = [" ❤️ ", " 😀 "].iter().copied().cycle(); + /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); + /// + /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied(); + /// let separator = || happy_emojis.next().unwrap_or(" 🦀 "); /// - /// let result = src.intersperse_with(|| separator.next().unwrap()).collect::(); - /// assert_eq!(result, "Hello ❤️ to 😀 all ❤️ people"); + /// let result = src.intersperse_with(separator).collect::(); + /// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!"); /// ``` #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] From eb72dc5d40767f9267e0e42dc1139f7976a0abd1 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Mon, 28 Dec 2020 11:41:52 -0500 Subject: [PATCH 48/49] Add as_ref and as_mut methods for Bound Add as_ref and as_mut method for std::ops::range::Bound, patterned off of the methods of the same name on Option. --- library/core/src/ops/range.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 1d67e65e51f5f..0571dc74b9af9 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -678,6 +678,29 @@ pub enum Bound { Unbounded, } +#[unstable(feature = "bound_as_ref", issue = "80996")] +impl Bound { + /// Converts from `&Bound` to `Bound<&T>`. + #[inline] + pub fn as_ref(&self) -> Bound<&T> { + match *self { + Included(ref x) => Included(x), + Excluded(ref x) => Excluded(x), + Unbounded => Unbounded, + } + } + + /// Converts from `&mut Bound` to `Bound<&T>`. + #[inline] + pub fn as_mut(&mut self) -> Bound<&mut T> { + match *self { + Included(ref mut x) => Included(x), + Excluded(ref mut x) => Excluded(x), + Unbounded => Unbounded, + } + } +} + impl Bound<&T> { /// Map a `Bound<&T>` to a `Bound` by cloning the contents of the bound. /// From a8d01619608715e6abc4c6d3c6f347f393262725 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 13 Jan 2021 22:13:45 -0800 Subject: [PATCH 49/49] Fix typos in Fuchsia unix_process_wait_more --- library/std/src/sys/unix/process/process_fuchsia.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 3102661b83dad..0d4703d7f503a 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -251,7 +251,7 @@ impl ExitStatus { // available on Fuchsia. // // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many - // other things from std::os::unix) properly. This veneer is always going to be a bdoge. So + // other things from std::os::unix) properly. This veneer is always going to be a bodge. So // while I don't know if these implementations are actually correct, I think they will do for // now at least. pub fn core_dumped(&self) -> bool { @@ -285,7 +285,7 @@ impl ExitStatus { // own ExitStatusExt, rather that trying to provide a not very convincing imitation of // Unix. Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia. But // fixing this up that is beyond the scope of my efforts now. - let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to covert the value into a traditional Unix-style wait status, which cannot represent values greater than 255."); + let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255."); let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8; wait_status_as_if_unix }