From 41b1bcb40d3c5f40f56da88af7bab126682f9ca3 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 3 Dec 2021 01:20:25 +0100 Subject: [PATCH 01/10] Improve 'cannot contain emoji' error. --- compiler/rustc_interface/src/passes.rs | 26 +++++++++++++++++++++----- compiler/rustc_span/src/symbol.rs | 1 + 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index dbee92cf598b5..da76f221269fe 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{ErrorReported, PResult}; +use rustc_errors::{Applicability, ErrorReported, PResult}; use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::Crate; @@ -456,10 +456,26 @@ pub fn configure_and_expand( identifiers.sort_by_key(|&(key, _)| key); for (ident, mut spans) in identifiers.into_iter() { spans.sort(); - sess.diagnostic().span_err( - MultiSpan::from(spans), - &format!("identifiers cannot contain emoji: `{}`", ident), - ); + if ident == sym::ferris { + let first_span = spans[0]; + sess.diagnostic() + .struct_span_err( + MultiSpan::from(spans), + "Ferris cannot be used as an identifier", + ) + .span_suggestion( + first_span, + "try using their name instead", + "ferris".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } else { + sess.diagnostic().span_err( + MultiSpan::from(spans), + &format!("identifiers cannot contain emoji: `{}`", ident), + ); + } } }); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 247d69d6ee97b..983e74b2ccc5f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -627,6 +627,7 @@ symbols! { fdiv_fast, feature, fence, + ferris: "๐Ÿฆ€", fetch_update, ffi, ffi_const, From 9d535b4c04b81a54ba4b6143829349fb46fadc4c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 3 Dec 2021 01:20:42 +0100 Subject: [PATCH 02/10] Extend emoji-identifiers ui test. --- src/test/ui/parser/emoji-identifiers.rs | 3 +++ src/test/ui/parser/emoji-identifiers.stderr | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/test/ui/parser/emoji-identifiers.rs b/src/test/ui/parser/emoji-identifiers.rs index ef18939bbb80c..b50c046bcb204 100644 --- a/src/test/ui/parser/emoji-identifiers.rs +++ b/src/test/ui/parser/emoji-identifiers.rs @@ -13,4 +13,7 @@ fn main() { let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; //~ ERROR cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope //~^ ERROR identifiers cannot contain emoji //~| ERROR unknown start of token: \u{2796} + + let ๐Ÿฆ€ = 1;//~ ERROR Ferris cannot be used as an identifier + dbg!(๐Ÿฆ€); } diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr index 5f9263c4c13e7..7dc589e556386 100644 --- a/src/test/ui/parser/emoji-identifiers.stderr +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -18,6 +18,14 @@ LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_๐Ÿ˜…_a_lot` +error: Ferris cannot be used as an identifier + --> $DIR/emoji-identifiers.rs:17:9 + | +LL | let ๐Ÿฆ€ = 1; + | ^^ help: try using their name instead: `ferris` +LL | dbg!(๐Ÿฆ€); + | ^^ + error: identifiers cannot contain emoji: `ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily` --> $DIR/emoji-identifiers.rs:1:8 | @@ -77,7 +85,7 @@ LL | ๐Ÿ‘€::full_ofโœจ() | function or associated item not found in `๐Ÿ‘€` | help: there is an associated function with a similar name: `full_of_โœจ` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0425, E0599. For more information about an error, try `rustc --explain E0425`. From d761e84968de093ac2e0850293af1057b6fb44ee Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 7 Dec 2021 20:59:16 -0500 Subject: [PATCH 03/10] implement `core::future::join` --- library/core/src/future/join.rs | 147 ++++++++++++++++++++++++++++++++ library/core/src/future/mod.rs | 4 + 2 files changed, 151 insertions(+) create mode 100644 library/core/src/future/join.rs diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs new file mode 100644 index 0000000000000..752a3ea92ba41 --- /dev/null +++ b/library/core/src/future/join.rs @@ -0,0 +1,147 @@ +#![allow(unused_imports)] // items are used by the macro + +use crate::cell::UnsafeCell; +use crate::future::{poll_fn, Future}; +use crate::pin::Pin; +use crate::task::Poll; +/// Polls multiple futures simultaneously, returning a tuple +/// of all results once complete. +/// +/// While `join!(a, b)` is similar to `(a.await, b.await)`, +/// `join!` polls both futures concurrently and is therefore more efficient. +/// +/// # Examples +/// +/// ``` +/// #![feature(future_join, future_poll_fn)] +/// +/// use std::future::join; +/// +/// async fn one() -> usize { 1 } +/// async fn two() -> usize { 2 } +/// +/// # let _ = async { +/// let x = join!(one(), two()); +/// assert_eq!(x, (1, 2)); +/// # }; +/// ``` +/// +/// `join!` is variadic, so you can pass any number of futures: +/// +/// ``` +/// #![feature(future_join, future_poll_fn)] +/// +/// use std::future::join; +/// +/// async fn one() -> usize { 1 } +/// async fn two() -> usize { 2 } +/// async fn three() -> usize { 3 } +/// +/// # let _ = async { +/// let x = join!(one(), two(), three()); +/// assert_eq!(x, (1, 2, 3)); +/// # }; +/// ``` +#[unstable(feature = "future_join", issue = "91642")] +pub macro join { + ( $($fut:expr),* $(,)?) => { + join! { @count: (), @futures: {}, @rest: ($($fut,)*) } + }, + // Recurse until we have the position of each future in the tuple + ( + // A token for each future that has been expanded: "_ _ _" + @count: ($($count:tt)*), + // Futures and their positions in the tuple: "{ a => (_), b => (_ _)) }" + @futures: { $($fut:tt)* }, + // The future currently being expanded, and the rest + @rest: ($current:expr, $($rest:tt)*) + ) => { + join! { + @count: ($($count)* _), // Add to the count + @futures: { $($fut)* $current => ($($count)*), }, // Add the future from @rest with it's position + @rest: ($($rest)*) // And leave the rest + } + }, + // Now generate the output future + ( + @count: ($($count:tt)*), + @futures: { + $( $fut:expr => ( $($pos:tt)* ), )* + }, + @rest: () + ) => {{ + let mut futures = ( $( MaybeDone::Future($fut), )* ); + + poll_fn(move |cx| { + let mut done = true; + + $( + // Extract the future from the tuple + let ( $($pos,)* fut, .. ) = &mut futures; + + // SAFETY: the futures are never moved + done &= unsafe { Pin::new_unchecked(fut).poll(cx).is_ready() }; + )* + + if done { + Poll::Ready(($({ + let ( $($pos,)* fut, .. ) = &mut futures; + + // SAFETY: the futures are never moved + unsafe { Pin::new_unchecked(fut).take_output().unwrap() } + }),*)) + } else { + Poll::Pending + } + }).await + }} +} + +/// Future used by `join!` that stores it's output to +/// be later taken and doesn't panic when polled after ready. +#[allow(dead_code)] +#[unstable(feature = "future_join", issue = "none")] +enum MaybeDone { + Future(F), + Done(F::Output), + Took, +} + +#[unstable(feature = "future_join", issue = "none")] +impl Unpin for MaybeDone {} + +#[unstable(feature = "future_join", issue = "none")] +impl MaybeDone { + #[allow(dead_code)] + fn take_output(self: Pin<&mut Self>) -> Option { + unsafe { + match &*self { + MaybeDone::Done(_) => match mem::replace(self.get_unchecked_mut(), Self::Took) { + MaybeDone::Done(val) => Some(val), + _ => unreachable!(), + }, + _ => None, + } + } + } +} + +#[unstable(feature = "future_join", issue = "none")] +impl Future for MaybeDone { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + unsafe { + match self.as_mut().get_unchecked_mut() { + MaybeDone::Future(f) => match Pin::new_unchecked(f).poll(cx) { + Poll::Ready(val) => self.set(Self::Done(val)), + Poll::Pending => return Poll::Pending, + }, + MaybeDone::Done(_) => {} + MaybeDone::Took => unreachable!(), + } + } + + Poll::Ready(()) + } +} diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 7a3af70d6d97c..88db584aefd08 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -11,6 +11,7 @@ use crate::{ mod future; mod into_future; +mod join; mod pending; mod poll_fn; mod ready; @@ -18,6 +19,9 @@ mod ready; #[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; +#[unstable(feature = "future_join", issue = "91642")] +pub use self::join::join; + #[unstable(feature = "into_future", issue = "67644")] pub use into_future::IntoFuture; From 08dca1933b68456486e9d2f18aa3409cce49c37c Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 7 Dec 2021 21:01:10 -0500 Subject: [PATCH 04/10] generate `MaybeDone` futures inline `join` --- library/core/src/future/join.rs | 110 ++++++++++++++------------------ 1 file changed, 47 insertions(+), 63 deletions(-) diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index 752a3ea92ba41..03d106c969bd8 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -4,6 +4,7 @@ use crate::cell::UnsafeCell; use crate::future::{poll_fn, Future}; use crate::pin::Pin; use crate::task::Poll; + /// Polls multiple futures simultaneously, returning a tuple /// of all results once complete. /// @@ -53,42 +54,74 @@ pub macro join { @count: ($($count:tt)*), // Futures and their positions in the tuple: "{ a => (_), b => (_ _)) }" @futures: { $($fut:tt)* }, - // The future currently being expanded, and the rest + // Take a future from @rest to expand @rest: ($current:expr, $($rest:tt)*) ) => { join! { - @count: ($($count)* _), // Add to the count - @futures: { $($fut)* $current => ($($count)*), }, // Add the future from @rest with it's position - @rest: ($($rest)*) // And leave the rest + @count: ($($count)* _), + @futures: { $($fut)* $current => ($($count)*), }, + @rest: ($($rest)*) } }, // Now generate the output future ( @count: ($($count:tt)*), @futures: { - $( $fut:expr => ( $($pos:tt)* ), )* + $( $(@$f:tt)? $fut:expr => ( $($pos:tt)* ), )* }, @rest: () ) => {{ - let mut futures = ( $( MaybeDone::Future($fut), )* ); + // The futures and whether they have completed + let mut state = ( $( UnsafeCell::new(($fut, false)), )* ); + + // Make sure the futures don't panic + // if polled after completion, and + // store their output separately + let mut futures = ($( + ({ + let ( $($pos,)* state, .. ) = &state; + + poll_fn(move |cx| { + // SAFETY: each future borrows a distinct element + // of the tuple + let (fut, done) = unsafe { &mut *state.get() }; + + if *done { + return Poll::Ready(None) + } + + // SAFETY: The futures are never moved + match unsafe { Pin::new_unchecked(fut).poll(cx) } { + Poll::Ready(val) => { + *done = true; + Poll::Ready(Some(val)) + } + Poll::Pending => Poll::Pending + } + }) + }, None), + )*); poll_fn(move |cx| { let mut done = true; $( - // Extract the future from the tuple - let ( $($pos,)* fut, .. ) = &mut futures; + let ( $($pos,)* (fut, out), .. ) = &mut futures; - // SAFETY: the futures are never moved - done &= unsafe { Pin::new_unchecked(fut).poll(cx).is_ready() }; + // SAFETY: The futures are never moved + match unsafe { Pin::new_unchecked(fut).poll(cx) } { + Poll::Ready(Some(val)) => *out = Some(val), + // the future was already done + Poll::Ready(None) => {}, + Poll::Pending => done = false, + } )* if done { + // Extract all the outputs Poll::Ready(($({ - let ( $($pos,)* fut, .. ) = &mut futures; - - // SAFETY: the futures are never moved - unsafe { Pin::new_unchecked(fut).take_output().unwrap() } + let ( $($pos,)* (_, val), .. ) = &mut futures; + val.unwrap() }),*)) } else { Poll::Pending @@ -96,52 +129,3 @@ pub macro join { }).await }} } - -/// Future used by `join!` that stores it's output to -/// be later taken and doesn't panic when polled after ready. -#[allow(dead_code)] -#[unstable(feature = "future_join", issue = "none")] -enum MaybeDone { - Future(F), - Done(F::Output), - Took, -} - -#[unstable(feature = "future_join", issue = "none")] -impl Unpin for MaybeDone {} - -#[unstable(feature = "future_join", issue = "none")] -impl MaybeDone { - #[allow(dead_code)] - fn take_output(self: Pin<&mut Self>) -> Option { - unsafe { - match &*self { - MaybeDone::Done(_) => match mem::replace(self.get_unchecked_mut(), Self::Took) { - MaybeDone::Done(val) => Some(val), - _ => unreachable!(), - }, - _ => None, - } - } - } -} - -#[unstable(feature = "future_join", issue = "none")] -impl Future for MaybeDone { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - unsafe { - match self.as_mut().get_unchecked_mut() { - MaybeDone::Future(f) => match Pin::new_unchecked(f).poll(cx) { - Poll::Ready(val) => self.set(Self::Done(val)), - Poll::Pending => return Poll::Pending, - }, - MaybeDone::Done(_) => {} - MaybeDone::Took => unreachable!(), - } - } - - Poll::Ready(()) - } -} From d07cef22b0397eee2649807cd1dddf6d983e215f Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Tue, 7 Dec 2021 21:10:39 -0500 Subject: [PATCH 05/10] add tests for `core::future::join` --- library/core/tests/future.rs | 76 ++++++++++++++++++++++++++++++++++++ library/core/tests/lib.rs | 3 ++ 2 files changed, 79 insertions(+) create mode 100644 library/core/tests/future.rs diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs new file mode 100644 index 0000000000000..f47dcc70434cf --- /dev/null +++ b/library/core/tests/future.rs @@ -0,0 +1,76 @@ +use std::future::{join, Future}; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll, Wake}; +use std::thread; + +struct PollN { + val: usize, + polled: usize, + num: usize, +} + +impl Future for PollN { + type Output = usize; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.polled += 1; + + if self.polled == self.num { + return Poll::Ready(self.val); + } + + cx.waker().wake_by_ref(); + Poll::Pending + } +} + +fn poll_n(val: usize, num: usize) -> PollN { + PollN { val, num, polled: 0 } +} + +#[test] +fn test_join() { + block_on(async move { + let x = join!(async { 0 }); + assert_eq!(x, 0); + + let x = join!(async { 0 }, async { 1 }); + assert_eq!(x, (0, 1)); + + let x = join!(async { 0 }, async { 1 }, async { 2 }); + assert_eq!(x, (0, 1, 2)); + + let x = join!( + poll_n(0, 1), + poll_n(1, 5), + poll_n(2, 2), + poll_n(3, 1), + poll_n(4, 2), + poll_n(5, 3), + poll_n(6, 4), + poll_n(7, 1) + ); + assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7)); + }); +} + +fn block_on(fut: impl Future) { + struct Waker; + impl Wake for Waker { + fn wake(self: Arc) { + thread::current().unpark() + } + } + + let waker = Arc::new(Waker).into(); + let mut cx = Context::from_waker(&waker); + let mut fut = Box::pin(fut); + + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(_) => break, + Poll::Pending => thread::park(), + } + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 9ab98ba88865a..73a3a1fc3e0af 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -29,6 +29,8 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(float_minimum_maximum)] +#![feature(future_join)] +#![feature(future_poll_fn)] #![feature(array_from_fn)] #![feature(hashmap_internals)] #![feature(try_find)] @@ -94,6 +96,7 @@ mod clone; mod cmp; mod const_ptr; mod fmt; +mod future; mod hash; mod intrinsics; mod iter; From d3167a22e005d9655a4b4f4e9ccada96abd810ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Dec 2021 10:53:12 -0500 Subject: [PATCH 06/10] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 81e59e6b92cf1..dadcbebfbd017 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 81e59e6b92cf1729aabbbbf09b81a81a03775d64 +Subproject commit dadcbebfbd017aac2358cf652a4bd71a91694edc From a8c931410020840584a2efa5f77239a9c5fcb85c Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Wed, 8 Dec 2021 16:44:48 -0500 Subject: [PATCH 07/10] remove implicit .await from `core::future::join` --- library/core/src/future/join.rs | 100 ++++++++++++++++---------------- library/core/tests/future.rs | 17 ++++-- 2 files changed, 64 insertions(+), 53 deletions(-) diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index 03d106c969bd8..bed9f3dd51cc5 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -22,7 +22,7 @@ use crate::task::Poll; /// async fn two() -> usize { 2 } /// /// # let _ = async { -/// let x = join!(one(), two()); +/// let x = join!(one(), two()).await; /// assert_eq!(x, (1, 2)); /// # }; /// ``` @@ -39,7 +39,7 @@ use crate::task::Poll; /// async fn three() -> usize { 3 } /// /// # let _ = async { -/// let x = join!(one(), two(), three()); +/// let x = join!(one(), two(), three()).await; /// assert_eq!(x, (1, 2, 3)); /// # }; /// ``` @@ -71,61 +71,63 @@ pub macro join { }, @rest: () ) => {{ - // The futures and whether they have completed - let mut state = ( $( UnsafeCell::new(($fut, false)), )* ); + async move { + // The futures and whether they have completed + let mut state = ( $( UnsafeCell::new(($fut, false)), )* ); - // Make sure the futures don't panic - // if polled after completion, and - // store their output separately - let mut futures = ($( - ({ - let ( $($pos,)* state, .. ) = &state; + // Make sure the futures don't panic + // if polled after completion, and + // store their output separately + let mut futures = ($( + ({ + let ( $($pos,)* state, .. ) = &state; - poll_fn(move |cx| { - // SAFETY: each future borrows a distinct element - // of the tuple - let (fut, done) = unsafe { &mut *state.get() }; + poll_fn(move |cx| { + // SAFETY: each future borrows a distinct element + // of the tuple + let (fut, done) = unsafe { &mut *state.get() }; - if *done { - return Poll::Ready(None) - } + if *done { + return Poll::Ready(None) + } - // SAFETY: The futures are never moved - match unsafe { Pin::new_unchecked(fut).poll(cx) } { - Poll::Ready(val) => { - *done = true; - Poll::Ready(Some(val)) + // SAFETY: The futures are never moved + match unsafe { Pin::new_unchecked(fut).poll(cx) } { + Poll::Ready(val) => { + *done = true; + Poll::Ready(Some(val)) + } + Poll::Pending => Poll::Pending } - Poll::Pending => Poll::Pending - } - }) - }, None), - )*); + }) + }, None), + )*); - poll_fn(move |cx| { - let mut done = true; + poll_fn(move |cx| { + let mut done = true; - $( - let ( $($pos,)* (fut, out), .. ) = &mut futures; + $( + let ( $($pos,)* (fut, out), .. ) = &mut futures; - // SAFETY: The futures are never moved - match unsafe { Pin::new_unchecked(fut).poll(cx) } { - Poll::Ready(Some(val)) => *out = Some(val), - // the future was already done - Poll::Ready(None) => {}, - Poll::Pending => done = false, - } - )* + // SAFETY: The futures are never moved + match unsafe { Pin::new_unchecked(fut).poll(cx) } { + Poll::Ready(Some(val)) => *out = Some(val), + // the future was already done + Poll::Ready(None) => {}, + Poll::Pending => done = false, + } + )* - if done { - // Extract all the outputs - Poll::Ready(($({ - let ( $($pos,)* (_, val), .. ) = &mut futures; - val.unwrap() - }),*)) - } else { - Poll::Pending - } - }).await + if done { + // Extract all the outputs + Poll::Ready(($({ + let ( $($pos,)* (_, val), .. ) = &mut futures; + val.unwrap() + }),*)) + } else { + Poll::Pending + } + }).await + } }} } diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs index f47dcc70434cf..73249b1b8a435 100644 --- a/library/core/tests/future.rs +++ b/library/core/tests/future.rs @@ -32,13 +32,13 @@ fn poll_n(val: usize, num: usize) -> PollN { #[test] fn test_join() { block_on(async move { - let x = join!(async { 0 }); + let x = join!(async { 0 }).await; assert_eq!(x, 0); - let x = join!(async { 0 }, async { 1 }); + let x = join!(async { 0 }, async { 1 }).await; assert_eq!(x, (0, 1)); - let x = join!(async { 0 }, async { 1 }, async { 2 }); + let x = join!(async { 0 }, async { 1 }, async { 2 }).await; assert_eq!(x, (0, 1, 2)); let x = join!( @@ -50,8 +50,17 @@ fn test_join() { poll_n(5, 3), poll_n(6, 4), poll_n(7, 1) - ); + ) + .await; assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7)); + + let y = String::new(); + let x = join!(async { + println!("{}", &y); + 1 + }) + .await; + assert_eq!(x, 1); }); } From 883d0a7aa541abc900e2b597e847bd3140263df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 8 Dec 2021 22:56:26 +0100 Subject: [PATCH 08/10] Use Vec extend instead of repeated pushes in several places --- compiler/rustc_mir_transform/src/coverage/spans.rs | 4 +--- compiler/rustc_trait_selection/src/traits/coherence.rs | 4 +--- .../src/traits/select/candidate_assembly.rs | 4 +--- compiler/rustc_typeck/src/check/mod.rs | 5 ++--- compiler/rustc_typeck/src/check/upvar.rs | 5 +---- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 146cabf350880..01e72a6c1588d 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -329,9 +329,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { fn mir_to_initial_sorted_coverage_spans(&self) -> Vec { let mut initial_spans = Vec::::with_capacity(self.mir_body.num_nodes() * 2); for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { - for coverage_span in self.bcb_to_initial_coverage_spans(bcb, bcb_data) { - initial_spans.push(coverage_span); - } + initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data)); } if initial_spans.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 42d3194aed48a..aec9da9f8d4f8 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -498,9 +498,7 @@ fn orphan_check_trait_ref<'tcx>( return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type)); } - for input_ty in non_local_tys { - non_local_spans.push((input_ty, i == 0)); - } + non_local_spans.extend(non_local_tys.into_iter().map(|input_ty| (input_ty, i == 0))); } // If we exit above loop, never found a local type. debug!("orphan_check_trait_ref: no local type"); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 6e3e3b9b14480..4d9559c96af0e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -362,9 +362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); - for predicate_index in result { - candidates.vec.push(ProjectionCandidate(predicate_index)); - } + candidates.vec.extend(result.into_iter().map(ProjectionCandidate)); } /// Given an obligation like ``, searches the obligations that the caller diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 7bfd3f0ee8047..2e80f85972fa7 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -686,9 +686,8 @@ fn bounds_from_generic_predicates<'tcx>( }; let mut where_clauses = vec![]; for (ty, bounds) in types { - for bound in &bounds { - where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound))); - } + where_clauses + .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound)))); } for projection in &projections { let p = projection.skip_binder(); diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 41bbf322a6ecc..a98afd1e3e1dc 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -904,10 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> MigrationWarningReason { let mut reasons = MigrationWarningReason::default(); - for auto_trait in auto_trait_reasons { - reasons.auto_traits.push(auto_trait); - } - + reasons.auto_traits.extend(auto_trait_reasons); reasons.drop_order = drop_order; reasons From 5478f439e13b55c7b9b858f76986786371b97c8f Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Wed, 8 Dec 2021 17:08:23 -0500 Subject: [PATCH 09/10] trim down expansion of `core::future::join` --- library/core/src/future/join.rs | 98 +++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index bed9f3dd51cc5..aadff103ebab4 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -2,8 +2,9 @@ use crate::cell::UnsafeCell; use crate::future::{poll_fn, Future}; +use crate::mem; use crate::pin::Pin; -use crate::task::Poll; +use crate::task::{Context, Poll}; /// Polls multiple futures simultaneously, returning a tuple /// of all results once complete. @@ -70,64 +71,77 @@ pub macro join { $( $(@$f:tt)? $fut:expr => ( $($pos:tt)* ), )* }, @rest: () - ) => {{ + ) => { async move { - // The futures and whether they have completed - let mut state = ( $( UnsafeCell::new(($fut, false)), )* ); - - // Make sure the futures don't panic - // if polled after completion, and - // store their output separately - let mut futures = ($( - ({ - let ( $($pos,)* state, .. ) = &state; - - poll_fn(move |cx| { - // SAFETY: each future borrows a distinct element - // of the tuple - let (fut, done) = unsafe { &mut *state.get() }; - - if *done { - return Poll::Ready(None) - } - - // SAFETY: The futures are never moved - match unsafe { Pin::new_unchecked(fut).poll(cx) } { - Poll::Ready(val) => { - *done = true; - Poll::Ready(Some(val)) - } - Poll::Pending => Poll::Pending - } - }) - }, None), - )*); + let mut futures = ( $( MaybeDone::Future($fut), )* ); poll_fn(move |cx| { let mut done = true; $( - let ( $($pos,)* (fut, out), .. ) = &mut futures; + let ( $($pos,)* fut, .. ) = &mut futures; // SAFETY: The futures are never moved - match unsafe { Pin::new_unchecked(fut).poll(cx) } { - Poll::Ready(Some(val)) => *out = Some(val), - // the future was already done - Poll::Ready(None) => {}, - Poll::Pending => done = false, - } + done &= unsafe { Pin::new_unchecked(fut).poll(cx).is_ready() }; )* if done { // Extract all the outputs Poll::Ready(($({ - let ( $($pos,)* (_, val), .. ) = &mut futures; - val.unwrap() + let ( $($pos,)* fut, .. ) = &mut futures; + + fut.take_output().unwrap() }),*)) } else { Poll::Pending } }).await } - }} + } +} + +/// Future used by `join!` that stores it's output to +/// be later taken and doesn't panic when polled after ready. +/// +/// This type is public in a private module for use by the macro. +#[allow(missing_debug_implementations)] +#[unstable(feature = "future_join", issue = "91642")] +pub enum MaybeDone { + Future(F), + Done(F::Output), + Took, +} + +#[unstable(feature = "future_join", issue = "91642")] +impl MaybeDone { + pub fn take_output(&mut self) -> Option { + match &*self { + MaybeDone::Done(_) => match mem::replace(self, Self::Took) { + MaybeDone::Done(val) => Some(val), + _ => unreachable!(), + }, + _ => None, + } + } +} + +#[unstable(feature = "future_join", issue = "91642")] +impl Future for MaybeDone { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: pinning in structural for `f` + unsafe { + match self.as_mut().get_unchecked_mut() { + MaybeDone::Future(f) => match Pin::new_unchecked(f).poll(cx) { + Poll::Ready(val) => self.set(Self::Done(val)), + Poll::Pending => return Poll::Pending, + }, + MaybeDone::Done(_) => {} + MaybeDone::Took => unreachable!(), + } + } + + Poll::Ready(()) + } } From f0f7b8d44abde324082a91e47f08112f4c0adae8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 5 Dec 2021 12:35:09 -0800 Subject: [PATCH 10/10] Pretty print break and continue without redundant space --- compiler/rustc_ast_pretty/src/pprust/state.rs | 8 +++----- compiler/rustc_hir_pretty/src/lib.rs | 8 +++----- src/test/pretty/ast-stmt-expr-attr.rs | 4 ++-- src/test/pretty/hir-pretty-loop.pp | 2 +- src/test/pretty/stmt_expr_attributes.rs | 5 ++--- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 74f2a2b2e09d6..6c70cafb01fab 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2135,22 +2135,20 @@ impl<'a> State<'a> { ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true), ast::ExprKind::Break(opt_label, ref opt_expr) => { self.word("break"); - self.space(); if let Some(label) = opt_label { - self.print_ident(label.ident); self.space(); + self.print_ident(label.ident); } if let Some(ref expr) = *opt_expr { - self.print_expr_maybe_paren(expr, parser::PREC_JUMP); self.space(); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } } ast::ExprKind::Continue(opt_label) => { self.word("continue"); - self.space(); if let Some(label) = opt_label { + self.space(); self.print_ident(label.ident); - self.space() } } ast::ExprKind::Ret(ref result) => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 4240a4045a1ec..c3601d0997c23 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1543,22 +1543,20 @@ impl<'a> State<'a> { hir::ExprKind::Path(ref qpath) => self.print_qpath(qpath, true), hir::ExprKind::Break(destination, ref opt_expr) => { self.word("break"); - self.space(); if let Some(label) = destination.label { - self.print_ident(label.ident); self.space(); + self.print_ident(label.ident); } if let Some(ref expr) = *opt_expr { - self.print_expr_maybe_paren(expr, parser::PREC_JUMP); self.space(); + self.print_expr_maybe_paren(expr, parser::PREC_JUMP); } } hir::ExprKind::Continue(destination) => { self.word("continue"); - self.space(); if let Some(label) = destination.label { + self.space(); self.print_ident(label.ident); - self.space() } } hir::ExprKind::Ret(ref result) => { diff --git a/src/test/pretty/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs index c80bce2d140b9..e32f5ca24ea0f 100644 --- a/src/test/pretty/ast-stmt-expr-attr.rs +++ b/src/test/pretty/ast-stmt-expr-attr.rs @@ -110,8 +110,8 @@ fn syntax() { let _ = #[attr] &mut 0; let _ = #[attr] &#[attr] 0; let _ = #[attr] &mut #[attr] 0; - let _ = #[attr] break ; - let _ = #[attr] continue ; + let _ = #[attr] break; + let _ = #[attr] continue; let _ = #[attr] return; let _ = #[attr] foo!(); let _ = #[attr] foo!(#! [attr]); diff --git a/src/test/pretty/hir-pretty-loop.pp b/src/test/pretty/hir-pretty-loop.pp index 19b3a1775cf36..9b10fd86c4778 100644 --- a/src/test/pretty/hir-pretty-loop.pp +++ b/src/test/pretty/hir-pretty-loop.pp @@ -6,4 +6,4 @@ // pretty-mode:hir // pp-exact:hir-pretty-loop.pp -pub fn foo() { loop { break ; } } +pub fn foo() { loop { break; } } diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index 12204c8cd30ed..01533cd8107b0 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -229,9 +229,8 @@ fn _11() { let _ = #[rustc_dummy] &mut 0; let _ = #[rustc_dummy] &#[rustc_dummy] 0; let _ = #[rustc_dummy] &mut #[rustc_dummy] 0; - // FIXME: pp bug, extra space after keyword? - while false { let _ = #[rustc_dummy] continue ; } - while true { let _ = #[rustc_dummy] break ; } + while false { let _ = #[rustc_dummy] continue; } + while true { let _ = #[rustc_dummy] break; } || #[rustc_dummy] return; let _ = #[rustc_dummy] expr_mac!(); let _ = #[rustc_dummy] expr_mac![];