From a57c18b5e182f32218ace2620163d86b9412182d Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 7 Oct 2021 15:47:28 -0400 Subject: [PATCH 01/16] add `Poll::ready` --- library/core/src/task/mod.rs | 2 ++ library/core/src/task/poll.rs | 33 ++++++++++++++++++++ library/core/src/task/ready.rs | 57 ++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index 5f077f77bbc9f..a872320aca65a 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -13,3 +13,5 @@ pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; #[stable(feature = "ready_macro", since = "1.56.0")] pub use ready::ready; +#[unstable(feature = "poll_ready", issue = "none")] +pub use ready::Ready; diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 57416aeb7018f..924c424548fd1 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -3,6 +3,7 @@ use crate::convert; use crate::ops::{self, ControlFlow}; use crate::result::Result; +use crate::task::Ready; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -92,6 +93,38 @@ impl Poll { pub const fn is_pending(&self) -> bool { !self.is_ready() } + + /// Extracts the successful type of a [`Poll`]. + /// + /// When combined with the `?` operator, this function will + /// propogate any [`Poll::Pending`] values to the caller, and + /// extract the `T` from [`Poll::Ready`]. + /// + /// # Examples + /// + /// ```rust + /// #![feature(poll_ready)] + /// + /// use std::task::{Context, Poll}; + /// use std::future::{self, Future}; + /// use std::pin::Pin; + /// + /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { + /// let mut fut = future::ready(42); + /// let fut = Pin::new(&mut fut); + /// + /// let num = fut.poll(cx).ready()?; + /// # drop(num); + /// // ... use num + /// + /// Poll::Ready(()) + /// } + /// ``` + #[inline] + #[unstable(feature = "poll_ready", issue = "none")] + pub fn ready(self) -> Ready { + Ready(self) + } } impl Poll> { diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index 2834ca5fe2224..8b6e259134e7c 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,3 +1,8 @@ +use core::convert; +use core::fmt; +use core::ops::{ControlFlow, FromResidual, Try}; +use core::task::Poll; + /// Extracts the successful type of a [`Poll`]. /// /// This macro bakes in propagation of [`Pending`] signals by returning early. @@ -55,3 +60,55 @@ pub macro ready($e:expr) { } } } + +/// Extracts the successful type of a [`Poll`]. +/// +/// See [`Poll::ready`] for details. +#[unstable(feature = "poll_ready", issue = "none")] +pub struct Ready(pub(crate) Poll); + +#[unstable(feature = "poll_ready", issue = "none")] +impl Try for Ready { + type Output = T; + type Residual = Ready; + + #[inline] + fn from_output(output: Self::Output) -> Self { + Ready(Poll::Ready(output)) + } + + #[inline] + fn branch(self) -> ControlFlow { + match self.0 { + Poll::Ready(v) => ControlFlow::Continue(v), + Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)), + } + } +} + +#[unstable(feature = "poll_ready", issue = "none")] +impl FromResidual for Ready { + #[inline] + fn from_residual(residual: Ready) -> Self { + match residual.0 { + Poll::Pending => Ready(Poll::Pending), + } + } +} + +#[unstable(feature = "poll_ready", issue = "none")] +impl FromResidual> for Poll { + #[inline] + fn from_residual(residual: Ready) -> Self { + match residual.0 { + Poll::Pending => Poll::Pending, + } + } +} + +#[unstable(feature = "poll_ready", issue = "none")] +impl fmt::Debug for Ready { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Ready").finish() + } +} From a3f98a7501384d4cd11ba94a46bdf88b7e2bc816 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 7 Oct 2021 21:56:40 +0200 Subject: [PATCH 02/16] Fix inherent impl overlap check. --- compiler/rustc_index/src/vec.rs | 6 + .../src/coherence/inherent_impls_overlap.rs | 103 ++++++++++-------- compiler/rustc_typeck/src/lib.rs | 1 + 3 files changed, 65 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 8831524683432..66399d2999848 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -741,6 +741,12 @@ impl IndexVec> { self.ensure_contains_elem(index, || None); self[index].get_or_insert_with(value) } + + #[inline] + pub fn remove(&mut self, index: I) -> Option { + self.ensure_contains_elem(index, || None); + self[index].take() + } } impl IndexVec { diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index b5eb74f708d5c..0373035a09ad8 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -3,6 +3,7 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_index::vec::IndexVec; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; use rustc_trait_selection::traits::{self, SkipLeakCheck}; @@ -158,14 +159,18 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { // This is advantageous to running the algorithm over the // entire graph when there are many connected regions. + rustc_index::newtype_index! { + pub struct RegionId { + ENCODABLE = custom + } + } struct ConnectedRegion { idents: SmallVec<[Symbol; 8]>, impl_blocks: FxHashSet, } - // Highest connected region id - let mut highest_region_id = 0; + let mut connected_regions: IndexVec = Default::default(); + // Reverse map from the Symbol to the connected region id. let mut connected_region_ids = FxHashMap::default(); - let mut connected_regions = FxHashMap::default(); for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { if impl_items.len() == 0 { @@ -173,7 +178,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { } // First obtain a list of existing connected region ids let mut idents_to_add = SmallVec::<[Symbol; 8]>::new(); - let ids = impl_items + let mut ids = impl_items .in_definition_order() .filter_map(|item| { let entry = connected_region_ids.entry(item.ident.name); @@ -184,62 +189,64 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { None } }) - .collect::>(); - match ids.len() { - 0 | 1 => { - let id_to_set = if ids.is_empty() { - // Create a new connected region - let region = ConnectedRegion { + .collect::>(); + // Sort the id list so that the algorithm is deterministic + ids.sort_unstable(); + let ids = ids; + match &ids[..] { + // Create a new connected region + [] => { + let id_to_set = connected_regions.next_index(); + // Update the connected region ids + for ident in &idents_to_add { + connected_region_ids.insert(*ident, id_to_set); + } + connected_regions.insert( + id_to_set, + ConnectedRegion { idents: idents_to_add, impl_blocks: std::iter::once(i).collect(), - }; - connected_regions.insert(highest_region_id, region); - (highest_region_id, highest_region_id += 1).0 - } else { - // Take the only id inside the list - let id_to_set = *ids.iter().next().unwrap(); - let region = connected_regions.get_mut(&id_to_set).unwrap(); - region.impl_blocks.insert(i); - region.idents.extend_from_slice(&idents_to_add); - id_to_set - }; - let (_id, region) = connected_regions.iter().next().unwrap(); + }, + ); + } + // Take the only id inside the list + &[id_to_set] => { + let region = connected_regions[id_to_set].as_mut().unwrap(); + region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); // Update the connected region ids - for ident in region.idents.iter() { + for ident in &idents_to_add { connected_region_ids.insert(*ident, id_to_set); } } - _ => { - // We have multiple connected regions to merge. - // In the worst case this might add impl blocks - // one by one and can thus be O(n^2) in the size - // of the resulting final connected region, but - // this is no issue as the final step to check - // for overlaps runs in O(n^2) as well. - - // Take the smallest id from the list - let id_to_set = *ids.iter().min().unwrap(); - - // Sort the id list so that the algorithm is deterministic - let mut ids = ids.into_iter().collect::>(); - ids.sort_unstable(); - - let mut region = connected_regions.remove(&id_to_set).unwrap(); - region.idents.extend_from_slice(&idents_to_add); + // We have multiple connected regions to merge. + // In the worst case this might add impl blocks + // one by one and can thus be O(n^2) in the size + // of the resulting final connected region, but + // this is no issue as the final step to check + // for overlaps runs in O(n^2) as well. + &[id_to_set, ..] => { + let mut region = connected_regions.remove(id_to_set).unwrap(); region.impl_blocks.insert(i); + region.idents.extend_from_slice(&idents_to_add); + // Update the connected region ids + for ident in &idents_to_add { + connected_region_ids.insert(*ident, id_to_set); + } + // Remove other regions from ids. for &id in ids.iter() { if id == id_to_set { continue; } - let r = connected_regions.remove(&id).unwrap(); - // Update the connected region ids + let r = connected_regions.remove(id).unwrap(); for ident in r.idents.iter() { connected_region_ids.insert(*ident, id_to_set); } region.idents.extend_from_slice(&r.idents); region.impl_blocks.extend(r.impl_blocks); } + connected_regions.insert(id_to_set, region); } } @@ -254,16 +261,22 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { let avg = impls.len() / connected_regions.len(); let s = connected_regions .iter() - .map(|r| r.1.impl_blocks.len() as isize - avg as isize) + .flatten() + .map(|r| r.impl_blocks.len() as isize - avg as isize) .map(|v| v.abs() as usize) .sum::(); s / connected_regions.len() }, - connected_regions.iter().map(|r| r.1.impl_blocks.len()).max().unwrap() + connected_regions + .iter() + .flatten() + .map(|r| r.impl_blocks.len()) + .max() + .unwrap() ); // List of connected regions is built. Now, run the overlap check // for each pair of impl blocks in the same connected region. - for (_id, region) in connected_regions.into_iter() { + for region in connected_regions.into_iter().flatten() { let mut impl_blocks = region.impl_blocks.into_iter().collect::>(); impl_blocks.sort_unstable(); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 65eedd2daafa8..971776c882a15 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -63,6 +63,7 @@ This API is completely unstable and subject to change. #![feature(in_band_lifetimes)] #![feature(is_sorted)] #![feature(iter_zip)] +#![feature(min_specialization)] #![feature(nll)] #![feature(try_blocks)] #![feature(never_type)] From 5f7e7d2e93afd9478856d3dc026c6923a0f21641 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 7 Oct 2021 15:47:59 -0400 Subject: [PATCH 03/16] revert stabilization of `core::task::ready!` --- library/core/src/task/mod.rs | 2 +- library/core/src/task/ready.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index a872320aca65a..b6128bb70c93c 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -11,7 +11,7 @@ mod wake; pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; -#[stable(feature = "ready_macro", since = "1.56.0")] +#[unstable(feature = "ready_macro", issue = "70922")] pub use ready::ready; #[unstable(feature = "poll_ready", issue = "none")] pub use ready::Ready; diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index 8b6e259134e7c..bb1b7ed6c6c05 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -13,6 +13,8 @@ use core::task::Poll; /// # Examples /// /// ``` +/// #![feature(ready_macro)] +/// /// use std::task::{ready, Context, Poll}; /// use std::future::{self, Future}; /// use std::pin::Pin; @@ -32,6 +34,7 @@ use core::task::Poll; /// The `ready!` call expands to: /// /// ``` +/// # #![feature(ready_macro)] /// # use std::task::{Context, Poll}; /// # use std::future::{self, Future}; /// # use std::pin::Pin; @@ -50,7 +53,7 @@ use core::task::Poll; /// # Poll::Ready(()) /// # } /// ``` -#[stable(feature = "ready_macro", since = "1.56.0")] +#[unstable(feature = "ready_macro", issue = "70922")] #[rustc_macro_transparency = "semitransparent"] pub macro ready($e:expr) { match $e { From 597090ee147b957aae81383ec68b33880b6050da Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 30 Sep 2021 15:23:21 +0000 Subject: [PATCH 04/16] Re-use TypeChecker instead of passing around some of its fields --- compiler/rustc_borrowck/src/type_check/mod.rs | 11 +-- .../src/type_check/relate_tys.rs | 68 ++++++++----------- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 55790bd2daa9b..696f7c9e00ff7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1163,16 +1163,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - relate_tys::relate_types( - self.infcx, - self.param_env, - a, - v, - b, - locations, - category, - self.borrowck_context, - ) + relate_tys::relate_types(self, a, v, b, locations, category) } /// Try to relate `sub <: sup` diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index b788529dc1cd4..1d1c50e3f59f2 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Const, Ty}; @@ -7,7 +7,7 @@ use rustc_trait_selection::traits::query::Fallible; use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; -use crate::type_check::{BorrowCheckContext, Locations}; +use crate::type_check::{Locations, TypeChecker}; /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: /// @@ -17,27 +17,18 @@ use crate::type_check::{BorrowCheckContext, Locations}; /// /// N.B., the type `a` is permitted to have unresolved inference /// variables, but not the type `b`. -#[instrument(skip(infcx, param_env, borrowck_context), level = "debug")] +#[instrument(skip(type_checker), level = "debug")] pub(super) fn relate_types<'tcx>( - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, + type_checker: &mut TypeChecker<'_, 'tcx>, a: Ty<'tcx>, v: ty::Variance, b: Ty<'tcx>, locations: Locations, category: ConstraintCategory, - borrowck_context: &mut BorrowCheckContext<'_, 'tcx>, ) -> Fallible<()> { TypeRelating::new( - infcx, - NllTypeRelatingDelegate::new( - infcx, - borrowck_context, - param_env, - locations, - category, - UniverseInfo::relate(a, b), - ), + type_checker.infcx, + NllTypeRelatingDelegate::new(type_checker, locations, category, UniverseInfo::relate(a, b)), v, ) .relate(a, b)?; @@ -45,10 +36,7 @@ pub(super) fn relate_types<'tcx>( } struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, - borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>, - - param_env: ty::ParamEnv<'tcx>, + type_checker: &'me mut TypeChecker<'bccx, 'tcx>, /// Where (and why) is this relation taking place? locations: Locations, @@ -63,25 +51,24 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { fn new( - infcx: &'me InferCtxt<'me, 'tcx>, - borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, + type_checker: &'me mut TypeChecker<'bccx, 'tcx>, locations: Locations, category: ConstraintCategory, universe_info: UniverseInfo<'tcx>, ) -> Self { - Self { infcx, borrowck_context, param_env, locations, category, universe_info } + Self { type_checker, locations, category, universe_info } } } impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env + self.type_checker.param_env } fn create_next_universe(&mut self) -> ty::UniverseIndex { - let universe = self.infcx.create_next_universe(); - self.borrowck_context + let universe = self.type_checker.infcx.create_next_universe(); + self.type_checker + .borrowck_context .constraints .universe_causes .insert(universe, self.universe_info.clone()); @@ -90,15 +77,18 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { let origin = NllRegionVariableOrigin::Existential { from_forall }; - self.infcx.next_nll_region_var(origin) + self.type_checker.infcx.next_nll_region_var(origin) } fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder) + self.type_checker + .borrowck_context + .constraints + .placeholder_region(self.type_checker.infcx, placeholder) } fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.infcx.next_nll_region_var_in_universe( + self.type_checker.infcx.next_nll_region_var_in_universe( NllRegionVariableOrigin::Existential { from_forall: false }, universe, ) @@ -110,15 +100,17 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { sub: ty::Region<'tcx>, info: ty::VarianceDiagInfo<'tcx>, ) { - let sub = self.borrowck_context.universal_regions.to_region_vid(sub); - let sup = self.borrowck_context.universal_regions.to_region_vid(sup); - self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint { - sup, - sub, - locations: self.locations, - category: self.category, - variance_info: info, - }); + let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); + let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); + self.type_checker.borrowck_context.constraints.outlives_constraints.push( + OutlivesConstraint { + sup, + sub, + locations: self.locations, + category: self.category, + variance_info: info, + }, + ); } // We don't have to worry about the equality of consts during borrow checking From 49b06a2b60d07ad8b10554bcc700d1e1df014104 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Oct 2021 17:53:41 +0000 Subject: [PATCH 05/16] Directly call relate_types function instead of having a method wrapper --- compiler/rustc_borrowck/src/type_check/mod.rs | 13 ----- .../src/type_check/relate_tys.rs | 50 ++++++++++--------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 696f7c9e00ff7..07eadce17738e 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1153,19 +1153,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .convert_all(data); } - /// Convenient wrapper around `relate_tys::relate_types` -- see - /// that fn for docs. - fn relate_types( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, - ) -> Fallible<()> { - relate_tys::relate_types(self, a, v, b, locations, category) - } - /// Try to relate `sub <: sup` fn sub_types( &mut self, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 1d1c50e3f59f2..415d1abaa8b08 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -9,30 +9,32 @@ use crate::constraints::OutlivesConstraint; use crate::diagnostics::UniverseInfo; use crate::type_check::{Locations, TypeChecker}; -/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: -/// -/// - "Covariant" `a <: b` -/// - "Invariant" `a == b` -/// - "Contravariant" `a :> b` -/// -/// N.B., the type `a` is permitted to have unresolved inference -/// variables, but not the type `b`. -#[instrument(skip(type_checker), level = "debug")] -pub(super) fn relate_types<'tcx>( - type_checker: &mut TypeChecker<'_, 'tcx>, - a: Ty<'tcx>, - v: ty::Variance, - b: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory, -) -> Fallible<()> { - TypeRelating::new( - type_checker.infcx, - NllTypeRelatingDelegate::new(type_checker, locations, category, UniverseInfo::relate(a, b)), - v, - ) - .relate(a, b)?; - Ok(()) +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + /// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`: + /// + /// - "Covariant" `a <: b` + /// - "Invariant" `a == b` + /// - "Contravariant" `a :> b` + /// + /// N.B., the type `a` is permitted to have unresolved inference + /// variables, but not the type `b`. + #[instrument(skip(self), level = "debug")] + pub(super) fn relate_types( + &mut self, + a: Ty<'tcx>, + v: ty::Variance, + b: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + TypeRelating::new( + self.infcx, + NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)), + v, + ) + .relate(a, b)?; + Ok(()) + } } struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> { From 7f974d0aae1a6bf7c8211b6cbd80a4f21606280e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 10 Oct 2021 21:16:01 -0500 Subject: [PATCH 06/16] Greatly reduce amount of debuginfo compiled for bootstrap itself Rather than compiling rustbuild and all its dependencies with `debuginfo=2`, this compiles dependencies without debuginfo and rustbuild with `debuginfo=1`. On my laptop, this brings compile times down from ~1:20 to ~1:05. --- Cargo.toml | 9 +++++++++ src/bootstrap/bootstrap.py | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 42dd5d7ef432e..8d6afd2b44837 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,15 @@ gimli.debug = 0 miniz_oxide.debug = 0 object.debug = 0 +# The only package that ever uses debug builds is bootstrap. +# We care a lot about bootstrap's compile times, so don't include debug info for +# dependencies, only bootstrap itself. +[profile.dev] +debug = 0 +[profile.dev.package] +# Only use debuginfo=1 to further reduce compile times. +bootstrap.debug = 1 + # We want the RLS to use the version of Cargo that we've got vendored in this # repository to ensure that the same exact version of Cargo is used by both the # RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 05d7b0f611f72..c51fdfe7aa477 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -921,10 +921,9 @@ def build_bootstrap(self): env["LIBRARY_PATH"] = os.path.join(self.bin_root(True), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" + # preserve existing RUSTFLAGS env.setdefault("RUSTFLAGS", "") - env["RUSTFLAGS"] += " -Cdebuginfo=2" - build_section = "target.{}".format(self.build) target_features = [] if self.get_toml("crt-static", build_section) == "true": From 1b283d49c7a1b21143b5827dfeb41becf4c9398b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 11 Oct 2021 04:50:12 +0000 Subject: [PATCH 07/16] Remove hack ignoring unused attributes for stage 0 std This seems to no longer be giving spurious errors when incremental is enabled. --- src/bootstrap/builder.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0a6ed2f49b787..abfd530e0c2ae 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1342,12 +1342,6 @@ impl<'a> Builder<'a> { rustdocflags.arg("-Dwarnings"); } - // FIXME(#58633) hide "unused attribute" errors in incremental - // builds of the standard library, as the underlying checks are - // not yet properly integrated with incremental recompilation. - if mode == Mode::Std && compiler.stage == 0 && self.config.incremental { - lint_flags.push("-Aunused-attributes"); - } // This does not use RUSTFLAGS due to caching issues with Cargo. // Clippy is treated as an "in tree" tool, but shares the same // cache as other "submodule" tools. With these options set in From 3ac0ae21d5c1a8222ad466e3c7c761199e547f1c Mon Sep 17 00:00:00 2001 From: John Kugelman Date: Mon, 11 Oct 2021 10:03:55 -0400 Subject: [PATCH 08/16] Add #[must_use] to MaybeUninit::new --- library/core/src/mem/maybe_uninit.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 9c88a62336161..6c5fc331837c0 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -291,6 +291,7 @@ impl MaybeUninit { /// [`assume_init`]: MaybeUninit::assume_init #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")] + #[must_use = "use `ManuallyDrop` or `forget` to avoid running drop code"] #[inline(always)] pub const fn new(val: T) -> MaybeUninit { MaybeUninit { value: ManuallyDrop::new(val) } From 6531cd8cba18711f112d7b528ab8fd891a31903e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 11 Oct 2021 17:20:45 +0200 Subject: [PATCH 09/16] Fix function-names test for GDB 10.1 --- src/test/debuginfo/function-names.rs | 31 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs index dec25bb4c203c..61d5fc93cd2ad 100644 --- a/src/test/debuginfo/function-names.rs +++ b/src/test/debuginfo/function-names.rs @@ -9,36 +9,37 @@ // gdb-command:info functions -q function_names::main // gdb-check:[...]static fn function_names::main(); // gdb-command:info functions -q function_names::generic_func<* -// gdb-check:[...]static fn function_names::generic_func(i32) -> i32; +// gdb-check:[...]static fn function_names::generic_func(i32) -> i32; // Implementations // gdb-command:info functions -q function_names::.*::impl_function.* -// gdb-check:[...]static fn function_names::GenericStruct::impl_function(); +// gdb-check:[...]static fn function_names::GenericStruct::impl_function(); // gdb-check:[...]static fn function_names::Mod1::TestStruct2::impl_function(); // gdb-check:[...]static fn function_names::TestStruct1::impl_function(); // Trait implementations // gdb-command:info functions -q function_names::.*::trait_function.* -// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); -// gdb-check:[...]static fn as function_names::TestTrait1>::trait_function(); -// gdb-check:[...]static fn ::trait_function(); -// gdb-check:[...]static fn ::trait_function(); +// gdb-check:[...]static fn function_names::Mod1::{impl#1}::trait_function(); +// gdb-check:[...]static fn function_names::{impl#1}::trait_function(); +// gdb-check:[...]static fn function_names::{impl#3}::trait_function(); +// gdb-check:[...]static fn function_names::{impl#5}::trait_function3(); +// gdb-check:[...]static fn function_names::{impl#6}::trait_function(); // Closure -// gdb-command:info functions -q function_names::.*::{{closure.* -// gdb-check:[...]static fn function_names::GenericStruct::impl_function::{{closure}}(*mut function_names::{impl#2}::impl_function::{closure#0}); -// gdb-check:[...]static fn function_names::generic_func::{{closure}}(*mut function_names::generic_func::{closure#0}); -// gdb-check:[...]static fn function_names::main::{{closure}}(*mut function_names::main::{closure#0}); +// gdb-command:info functions -q function_names::.*::{closure.* +// gdb-check:[...]static fn function_names::generic_func::{closure#0}(*mut function_names::generic_func::{closure#0}); +// gdb-check:[...]static fn function_names::main::{closure#0}(*mut function_names::main::{closure#0}); +// gdb-check:[...]static fn function_names::{impl#2}::impl_function::{closure#0}(*mut function_names::{impl#2}::impl_function::{closure#0}); // Generator // Generators don't seem to appear in GDB's symbol table. // Const generic parameter // gdb-command:info functions -q function_names::const_generic_fn.* -// gdb-check:[...]static fn function_names::const_generic_fn_bool(); -// gdb-check:[...]static fn function_names::const_generic_fn_non_int(); -// gdb-check:[...]static fn function_names::const_generic_fn_signed_int(); -// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int(); +// gdb-check:[...]static fn function_names::const_generic_fn_bool(); +// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>(); +// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); +// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); // === CDB TESTS =================================================================================== @@ -103,7 +104,7 @@ fn main() { GenericStruct::::trait_function3(); // Generic function - let _ = generic_func(42); + let _ = generic_func(42i32); // Closure let closure = || { TestStruct1 }; From 3d1996a84b6eba8e09f735a4742aab9641bb3250 Mon Sep 17 00:00:00 2001 From: John Kugelman Date: Mon, 11 Oct 2021 10:13:50 -0400 Subject: [PATCH 10/16] Add #[must_use] to From::from and Into::into --- library/core/src/convert/mod.rs | 2 ++ .../never-value-fallback-issue-66757.nofallback.stderr | 2 +- src/test/ui/never_type/never-value-fallback-issue-66757.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index abeeef1a17ee0..83a73d9cbe506 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -273,6 +273,7 @@ pub trait AsMut { #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn into(self) -> T; } @@ -367,6 +368,7 @@ pub trait Into: Sized { pub trait From: Sized { /// Performs the conversion. #[lang = "from"] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn from(_: T) -> Self; } diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr b/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr index f374266626bcc..614cdff1f8022 100644 --- a/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `E: From<()>` is not satisfied - --> $DIR/never-value-fallback-issue-66757.rs:27:5 + --> $DIR/never-value-fallback-issue-66757.rs:28:5 | LL | >::from(never); | ^^^^^^^^^^^^^^^^^^^^ the trait `From<()>` is not implemented for `E` diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.rs b/src/test/ui/never_type/never-value-fallback-issue-66757.rs index 6dc7e6ad2d93d..fc6fe6eb5cc02 100644 --- a/src/test/ui/never_type/never-value-fallback-issue-66757.rs +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.rs @@ -22,6 +22,7 @@ impl From for E { #[allow(unreachable_code)] #[allow(dead_code)] +#[allow(unused_must_use)] fn foo(never: !) { >::from(never); // Ok >::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied From de940fc72553065cdf213a55c2d8bc7059e414ff Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 2 Oct 2021 19:02:22 +0100 Subject: [PATCH 11/16] Use Ancestory to check default fn in const impl instead of comparing idents --- compiler/rustc_passes/src/check_const.rs | 44 ++++++++++++++---------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 4a82252a32b13..a0ceb567f25a6 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -8,7 +8,6 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; -use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -83,30 +82,39 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< let _: Option<_> = try { if let hir::ItemKind::Impl(ref imp) = item.kind { if let hir::Constness::Const = imp.constness { - let did = imp.of_trait.as_ref()?.trait_def_id()?; - let mut to_implement = FxHashSet::default(); - - for did in self.tcx.associated_item_def_ids(did) { + let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?; + let ancestors = self + .tcx + .trait_def(trait_def_id) + .ancestors(self.tcx, item.def_id.to_def_id()) + .ok()?; + let mut to_implement = Vec::new(); + + for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() + { if let ty::AssocItem { kind: ty::AssocKind::Fn, ident, defaultness, .. - } = self.tcx.associated_item(*did) + } = trait_item { // we can ignore functions that do not have default bodies: // if those are unimplemented it will be catched by typeck. - if defaultness.has_value() - && !self.tcx.has_attr(*did, sym::default_method_body_is_const) + if !defaultness.has_value() + || self + .tcx + .has_attr(trait_item.def_id, sym::default_method_body_is_const) { - to_implement.insert(ident); + continue; } - } - } - for it in imp - .items - .iter() - .filter(|it| matches!(it.kind, hir::AssocItemKind::Fn { .. })) - { - to_implement.remove(&it.ident); + let is_implemented = ancestors + .leaf_def(self.tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented { + to_implement.push(ident.to_string()); + } + } } // all nonconst trait functions (not marked with #[default_method_body_is_const]) @@ -118,7 +126,7 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< item.span, "const trait implementations may not use non-const default functions", ) - .note(&format!("`{}` not implemented", to_implement.into_iter().map(|id| id.to_string()).collect::>().join("`, `"))) + .note(&format!("`{}` not implemented", to_implement.join("`, `"))) .emit(); } } From 0a03f8c78bff3adf164ad2fefd6ea767de25ec9e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 11 Oct 2021 18:20:20 +0100 Subject: [PATCH 12/16] Split impl-with-default-fn test into a pass test and a fail test --- ...ult-fn.rs => impl-with-default-fn-fail.rs} | 6 +--- ...tderr => impl-with-default-fn-fail.stderr} | 6 ++-- .../impl-with-default-fn-pass.rs | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) rename src/test/ui/rfc-2632-const-trait-impl/{impl-with-default-fn.rs => impl-with-default-fn-fail.rs} (89%) rename src/test/ui/rfc-2632-const-trait-impl/{impl-with-default-fn.stderr => impl-with-default-fn-fail.stderr} (84%) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs similarity index 89% rename from src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs rename to src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs index 59de9e9571944..8eefb375b8c1b 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.rs @@ -1,4 +1,5 @@ #![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] trait Tr { fn req(&self); @@ -18,11 +19,6 @@ impl const Tr for S { fn req(&self) {} } //~^^ ERROR const trait implementations may not use non-const default functions -impl const Tr for u8 { - fn req(&self) {} - fn prov(&self) {} -} - impl const Tr for u16 { fn prov(&self) {} fn default() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr similarity index 84% rename from src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr rename to src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr index 5301e0ad12ef1..a091679704111 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-fail.stderr @@ -1,5 +1,5 @@ error: const trait implementations may not use non-const default functions - --> $DIR/impl-with-default-fn.rs:17:1 + --> $DIR/impl-with-default-fn-fail.rs:18:1 | LL | / impl const Tr for S { LL | | fn req(&self) {} @@ -9,7 +9,7 @@ LL | | } = note: `prov` not implemented error: const trait implementations may not use non-const default functions - --> $DIR/impl-with-default-fn.rs:32:1 + --> $DIR/impl-with-default-fn-fail.rs:28:1 | LL | / impl const Tr for u32 { LL | | fn req(&self) {} @@ -20,7 +20,7 @@ LL | | } = note: `prov` not implemented error[E0046]: not all trait items implemented, missing: `req` - --> $DIR/impl-with-default-fn.rs:26:1 + --> $DIR/impl-with-default-fn-fail.rs:22:1 | LL | fn req(&self); | -------------- `req` from trait diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs new file mode 100644 index 0000000000000..ba3fec0882b02 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/impl-with-default-fn-pass.rs @@ -0,0 +1,34 @@ +// check-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +trait Tr { + fn req(&self); + + fn prov(&self) { + println!("lul"); + self.req(); + } + + #[default_method_body_is_const] + fn default() {} +} + +impl const Tr for u8 { + fn req(&self) {} + fn prov(&self) {} +} + +macro_rules! impl_tr { + ($ty: ty) => { + impl const Tr for $ty { + fn req(&self) {} + fn prov(&self) {} + } + } +} + +impl_tr!(u64); + +fn main() {} From 06e625f7d582601f5e2ff69ba80f6d3a11632b24 Mon Sep 17 00:00:00 2001 From: John Kugelman Date: Mon, 11 Oct 2021 13:57:38 -0400 Subject: [PATCH 13/16] Add #[must_use] to as_type conversions --- library/alloc/src/collections/binary_heap.rs | 1 + library/alloc/src/collections/linked_list.rs | 1 + library/alloc/src/rc.rs | 1 + library/alloc/src/string.rs | 5 +++++ library/alloc/src/sync.rs | 2 ++ library/alloc/src/vec/drain.rs | 1 + library/core/src/fmt/mod.rs | 1 + library/core/src/option.rs | 2 ++ library/core/src/ptr/non_null.rs | 9 +++++++++ library/core/src/ptr/unique.rs | 2 ++ library/core/src/slice/iter.rs | 2 ++ library/core/src/str/iter.rs | 4 ++++ library/core/src/str/mod.rs | 4 ++++ library/core/src/time.rs | 6 ++++++ library/std/src/ffi/c_str.rs | 5 +++++ library/std/src/ffi/os_str.rs | 1 + library/std/src/os/unix/net/addr.rs | 1 + library/std/src/path.rs | 5 +++++ library/std/src/thread/mod.rs | 1 + 19 files changed, 54 insertions(+) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 75720a970a31f..9bc9c6ef1629f 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -1007,6 +1007,7 @@ impl BinaryHeap { /// /// io::sink().write(heap.as_slice()).unwrap(); /// ``` + #[must_use] #[unstable(feature = "binary_heap_as_slice", issue = "83659")] pub fn as_slice(&self) -> &[T] { self.data.as_slice() diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index a769c558b4fa9..82e866c950457 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1384,6 +1384,7 @@ impl<'a, T> CursorMut<'a, T> { /// The lifetime of the returned `Cursor` is bound to that of the /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the /// `CursorMut` is frozen for the lifetime of the `Cursor`. + #[must_use] #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn as_cursor(&self) -> Cursor<'_, T> { Cursor { list: self.list, current: self.current, index: self.index } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c6573597b1e8c..c337b7c5a5901 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2087,6 +2087,7 @@ impl Weak { /// ``` /// /// [`null`]: ptr::null + #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d00792b9c3e71..4be8dddeda83d 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -800,6 +800,7 @@ impl String { /// assert_eq!("foo", s.as_str()); /// ``` #[inline] + #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] pub fn as_str(&self) -> &str { self @@ -820,6 +821,7 @@ impl String { /// assert_eq!("FOOBAR", s_mut_str); /// ``` #[inline] + #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] pub fn as_mut_str(&mut self) -> &mut str { self @@ -1160,6 +1162,7 @@ impl String { /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { &self.vec @@ -1763,6 +1766,7 @@ impl FromUtf8Error { /// /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); /// ``` + #[must_use] #[stable(feature = "from_utf8_error_as_bytes", since = "1.26.0")] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] @@ -2779,6 +2783,7 @@ impl<'a> Drain<'a> { /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_str(), "bc"); /// ``` + #[must_use] #[stable(feature = "string_drain_as_str", since = "1.55.0")] pub fn as_str(&self) -> &str { self.iter.as_str() diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7dd1bc5156039..d0bbab514665f 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -822,6 +822,7 @@ impl Arc { /// assert_eq!(x_ptr, Arc::as_ptr(&y)); /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` + #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); @@ -1718,6 +1719,7 @@ impl Weak { /// ``` /// /// [`null`]: core::ptr::null "ptr::null" + #[must_use] #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index fb32d144f872c..e643940d017ba 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -52,6 +52,7 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> { /// let _ = drain.next().unwrap(); /// assert_eq!(drain.as_slice(), &['b', 'c']); /// ``` + #[must_use] #[stable(feature = "vec_drain_as_slice", since = "1.46.0")] pub fn as_slice(&self) -> &[T] { self.iter.as_slice() diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index d10563a40976d..b8ad7720e0c55 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -491,6 +491,7 @@ impl<'a> Arguments<'a> { /// ``` #[stable(feature = "fmt_as_str", since = "1.52.0")] #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "none")] + #[must_use] #[inline] pub const fn as_str(&self) -> Option<&'static str> { match (self.pieces, self.args) { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index df8af22a317bc..401267f5613ee 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -657,6 +657,7 @@ impl Option { /// /// [&]: reference "shared reference" #[inline] + #[must_use] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_ref(self: Pin<&Self>) -> Option> { // SAFETY: `x` is guaranteed to be pinned because it comes from `self` @@ -668,6 +669,7 @@ impl Option { /// /// [&mut]: reference "mutable reference" #[inline] + #[must_use] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_mut(self: Pin<&mut Self>) -> Option> { // SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`. diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 87c8674af0dc5..af9daf8297401 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -119,6 +119,7 @@ impl NonNull { /// /// [the module documentation]: crate::ptr#safety #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_ref<'a>(&self) -> &'a MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the @@ -151,6 +152,7 @@ impl NonNull { /// /// [the module documentation]: crate::ptr#safety #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_mut<'a>(&mut self) -> &'a mut MaybeUninit { // SAFETY: the caller must guarantee that `self` meets all the @@ -264,6 +266,7 @@ impl NonNull { /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] + #[must_use] #[inline] pub const fn as_ptr(self) -> *mut T { self.pointer as *mut T @@ -310,6 +313,7 @@ impl NonNull { /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] + #[must_use] #[inline] pub unsafe fn as_ref<'a>(&self) -> &'a T { // SAFETY: the caller must guarantee that `self` meets all the @@ -359,6 +363,7 @@ impl NonNull { /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] + #[must_use] #[inline] pub unsafe fn as_mut<'a>(&mut self) -> &'a mut T { // SAFETY: the caller must guarantee that `self` meets all the @@ -455,6 +460,7 @@ impl NonNull<[T]> { /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap()); /// ``` #[inline] + #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_non_null_ptr(self) -> NonNull { @@ -474,6 +480,7 @@ impl NonNull<[T]> { /// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8); /// ``` #[inline] + #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] pub const fn as_mut_ptr(self) -> *mut T { @@ -518,6 +525,7 @@ impl NonNull<[T]> { /// /// [valid]: crate::ptr#safety #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice<'a>(&self) -> &'a [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice`. @@ -579,6 +587,7 @@ impl NonNull<[T]> { /// # Ok::<_, std::alloc::AllocError>(()) /// ``` #[inline] + #[must_use] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub unsafe fn as_uninit_slice_mut<'a>(&self) -> &'a mut [MaybeUninit] { // SAFETY: the caller must uphold the safety contract for `as_uninit_slice_mut`. diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index b3deddca18efe..5baceefb504a5 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -112,6 +112,7 @@ impl Unique { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + #[must_use] #[inline] pub unsafe fn as_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` meets all the @@ -124,6 +125,7 @@ impl Unique { /// The resulting lifetime is bound to self so this behaves "as if" /// it were actually an instance of T that is getting borrowed. If a longer /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + #[must_use] #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` meets all the diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 70e59cda63f26..dbf97851b03e4 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -124,6 +124,7 @@ impl<'a, T> Iter<'a, T> { /// // Now `as_slice` returns "[2, 3]": /// println!("{:?}", iter.as_slice()); /// ``` + #[must_use] #[stable(feature = "iter_to_slice", since = "1.4.0")] pub fn as_slice(&self) -> &'a [T] { self.make_slice() @@ -298,6 +299,7 @@ impl<'a, T> IterMut<'a, T> { /// // Now `as_slice` returns "[2, 3]": /// assert_eq!(iter.as_slice(), &[2, 3]); /// ``` + #[must_use] #[stable(feature = "slice_iter_mut_as_slice", since = "1.53.0")] pub fn as_slice(&self) -> &[T] { self.make_slice() diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 8db9edc61472f..94cb81e9d41a1 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -109,6 +109,7 @@ impl<'a> Chars<'a> { /// assert_eq!(chars.as_str(), ""); /// ``` #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[must_use] #[inline] pub fn as_str(&self) -> &'a str { // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. @@ -185,6 +186,7 @@ impl<'a> CharIndices<'a> { /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[must_use] #[inline] pub fn as_str(&self) -> &'a str { self.iter.as_str() @@ -1247,6 +1249,7 @@ impl<'a> SplitWhitespace<'a> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] + #[must_use] #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { self.inner.iter.as_str() @@ -1302,6 +1305,7 @@ impl<'a> SplitAsciiWhitespace<'a> { /// assert_eq!(split.as_str(), ""); /// ``` #[inline] + #[must_use] #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")] pub fn as_str(&self) -> &'a str { if self.inner.iter.iter.finished { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 14ce94c178c5b..607a0179ff4b9 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -230,6 +230,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "str_as_bytes", since = "1.39.0")] + #[must_use] #[inline(always)] #[allow(unused_attributes)] pub const fn as_bytes(&self) -> &[u8] { @@ -274,6 +275,7 @@ impl str { /// assert_eq!("🍔∈🌏", s); /// ``` #[stable(feature = "str_mut_extras", since = "1.20.0")] + #[must_use] #[inline(always)] pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { // SAFETY: the cast from `&str` to `&[u8]` is safe since `str` @@ -304,6 +306,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] + #[must_use] #[inline] pub const fn as_ptr(&self) -> *const u8 { self as *const str as *const u8 @@ -318,6 +321,7 @@ impl str { /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] + #[must_use] #[inline] pub fn as_mut_ptr(&mut self) -> *mut u8 { self as *mut str as *mut u8 diff --git a/library/core/src/time.rs b/library/core/src/time.rs index e1408c7cc2ecc..3e853e28f14e9 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -329,6 +329,7 @@ impl Duration { /// [`subsec_nanos`]: Duration::subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[rustc_const_stable(feature = "duration", since = "1.32.0")] + #[must_use] #[inline] pub const fn as_secs(&self) -> u64 { self.secs @@ -412,6 +413,7 @@ impl Duration { /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] + #[must_use] #[inline] pub const fn as_millis(&self) -> u128 { self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128 @@ -429,6 +431,7 @@ impl Duration { /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] + #[must_use] #[inline] pub const fn as_micros(&self) -> u128 { self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128 @@ -446,6 +449,7 @@ impl Duration { /// ``` #[stable(feature = "duration_as_u128", since = "1.33.0")] #[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")] + #[must_use] #[inline] pub const fn as_nanos(&self) -> u128 { self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 @@ -669,6 +673,7 @@ impl Duration { /// assert_eq!(dur.as_secs_f64(), 2.7); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn as_secs_f64(&self) -> f64 { @@ -687,6 +692,7 @@ impl Duration { /// assert_eq!(dur.as_secs_f32(), 2.7); /// ``` #[stable(feature = "duration_float", since = "1.38.0")] + #[must_use] #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn as_secs_f32(&self) -> f32 { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 6b488e49ed74b..8bf9f5dae6ea4 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -297,6 +297,7 @@ impl FromVecWithNulError { /// /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes()); /// ``` + #[must_use] pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] } @@ -616,6 +617,7 @@ impl CString { /// assert_eq!(bytes, &[b'f', b'o', b'o']); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { // SAFETY: CString has a length at least 1 @@ -635,6 +637,7 @@ impl CString { /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); /// ``` #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner @@ -653,6 +656,7 @@ impl CString { /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); /// ``` #[inline] + #[must_use] #[stable(feature = "as_c_str", since = "1.20.0")] pub fn as_c_str(&self) -> &CStr { &*self @@ -1308,6 +1312,7 @@ impl CStr { /// This way, the lifetime of the [`CString`] in `hello` encompasses /// the lifetime of `ptr` and the `unsafe` block. #[inline] + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] pub const fn as_ptr(&self) -> *const c_char { diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f5cef60e1267a..844d866b3dd35 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -136,6 +136,7 @@ impl OsString { /// assert_eq!(os_string.as_os_str(), os_str); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_os_str(&self) -> &OsStr { self diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 62bfde8bfd436..d741096893a69 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -192,6 +192,7 @@ impl SocketAddr { /// } /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] + #[must_use] pub fn as_pathname(&self) -> Option<&Path> { if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 6bfc7b0a5c1df..6ad7e1dfdfded 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -427,6 +427,7 @@ impl<'a> PrefixComponent<'a> { /// Returns the raw [`OsStr`] slice for this prefix. #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_os_str(&self) -> &'a OsStr { self.raw @@ -676,6 +677,7 @@ impl<'a> Components<'a> { /// /// assert_eq!(Path::new("foo/bar.txt"), components.as_path()); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); @@ -821,6 +823,7 @@ impl<'a> Iter<'a> { /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -1186,6 +1189,7 @@ impl PathBuf { /// assert_eq!(Path::new("/test"), p.as_path()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_path(&self) -> &Path { self @@ -1921,6 +1925,7 @@ impl Path { /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] #[inline] pub fn as_os_str(&self) -> &OsStr { &self.inner diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 7d404aff30e07..82847d83ad225 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1031,6 +1031,7 @@ impl ThreadId { /// value is entirely opaque -- only equality testing is stable. Note that /// it is not guaranteed which values new threads will return, and this may /// change across Rust versions. + #[must_use] #[unstable(feature = "thread_id_value", issue = "67939")] pub fn as_u64(&self) -> NonZeroU64 { self.0 From b0b09f0842734b6594dbe3aa24cf4e01edcb9f49 Mon Sep 17 00:00:00 2001 From: John Kugelman Date: Mon, 11 Oct 2021 14:46:08 -0400 Subject: [PATCH 14/16] Update library/core/src/mem/maybe_uninit.rs Co-authored-by: Josh Triplett --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 6c5fc331837c0..98c6f99abdee6 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -291,7 +291,7 @@ impl MaybeUninit { /// [`assume_init`]: MaybeUninit::assume_init #[stable(feature = "maybe_uninit", since = "1.36.0")] #[rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0")] - #[must_use = "use `ManuallyDrop` or `forget` to avoid running drop code"] + #[must_use = "use `forget` to avoid running Drop code"] #[inline(always)] pub const fn new(val: T) -> MaybeUninit { MaybeUninit { value: ManuallyDrop::new(val) } From 7a7dfa8b67364be9a6fcd0d5876ed1c55b55843b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 11 Oct 2021 12:06:32 -0700 Subject: [PATCH 15/16] Remove task::ready! from 1.56.0 release notes --- RELEASES.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ef1377a4a32df..269740c171cfb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -64,7 +64,6 @@ Stabilised APIs - [`VecDeque::shrink_to`] - [`HashMap::shrink_to`] - [`HashSet::shrink_to`] -- [`task::ready!`] These APIs are now usable in const contexts: @@ -128,7 +127,6 @@ and related tools. [`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to [`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to [`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to -[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html [`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html [`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first [`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first From a1e03fc563eaaab04b747cf8d3f1a0d8931e39fd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 11 Oct 2021 12:17:41 -0700 Subject: [PATCH 16/16] Add library tracking issue for poll_ready feature --- library/core/src/task/mod.rs | 2 +- library/core/src/task/poll.rs | 2 +- library/core/src/task/ready.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index b6128bb70c93c..71a67a2793a46 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -13,5 +13,5 @@ pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; #[unstable(feature = "ready_macro", issue = "70922")] pub use ready::ready; -#[unstable(feature = "poll_ready", issue = "none")] +#[unstable(feature = "poll_ready", issue = "89780")] pub use ready::Ready; diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 924c424548fd1..3e0b3e89758a6 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -121,7 +121,7 @@ impl Poll { /// } /// ``` #[inline] - #[unstable(feature = "poll_ready", issue = "none")] + #[unstable(feature = "poll_ready", issue = "89780")] pub fn ready(self) -> Ready { Ready(self) } diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index bb1b7ed6c6c05..174ca67546033 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -67,10 +67,10 @@ pub macro ready($e:expr) { /// Extracts the successful type of a [`Poll`]. /// /// See [`Poll::ready`] for details. -#[unstable(feature = "poll_ready", issue = "none")] +#[unstable(feature = "poll_ready", issue = "89780")] pub struct Ready(pub(crate) Poll); -#[unstable(feature = "poll_ready", issue = "none")] +#[unstable(feature = "poll_ready", issue = "89780")] impl Try for Ready { type Output = T; type Residual = Ready; @@ -89,7 +89,7 @@ impl Try for Ready { } } -#[unstable(feature = "poll_ready", issue = "none")] +#[unstable(feature = "poll_ready", issue = "89780")] impl FromResidual for Ready { #[inline] fn from_residual(residual: Ready) -> Self { @@ -99,7 +99,7 @@ impl FromResidual for Ready { } } -#[unstable(feature = "poll_ready", issue = "none")] +#[unstable(feature = "poll_ready", issue = "89780")] impl FromResidual> for Poll { #[inline] fn from_residual(residual: Ready) -> Self { @@ -109,7 +109,7 @@ impl FromResidual> for Poll { } } -#[unstable(feature = "poll_ready", issue = "none")] +#[unstable(feature = "poll_ready", issue = "89780")] impl fmt::Debug for Ready { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Ready").finish()