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 a94e39e7f440deb408637150b226f39e0d62ee11 Mon Sep 17 00:00:00 2001 From: sireliah Date: Sat, 9 Oct 2021 21:27:06 +0200 Subject: [PATCH 06/16] Add long explanation for error E0482 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0482.md | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0482.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 45d91c2047d41..1b4b58314b356 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -242,6 +242,7 @@ E0468: include_str!("./error_codes/E0468.md"), E0469: include_str!("./error_codes/E0469.md"), E0477: include_str!("./error_codes/E0477.md"), E0478: include_str!("./error_codes/E0478.md"), +E0482: include_str!("./error_codes/E0482.md"), E0491: include_str!("./error_codes/E0491.md"), E0492: include_str!("./error_codes/E0492.md"), E0493: include_str!("./error_codes/E0493.md"), @@ -599,7 +600,6 @@ E0785: include_str!("./error_codes/E0785.md"), // E0479, // the type `..` (provided as the value of a type parameter) is... // E0480, // lifetime of method receiver does not outlive the method call // E0481, // lifetime of function argument does not outlive the function call - E0482, // lifetime of return value does not outlive the function call // E0483, // lifetime of operand does not outlive the operation // E0484, // reference is not valid at the time of borrow // E0485, // automatically reference is not valid at the time of borrow diff --git a/compiler/rustc_error_codes/src/error_codes/E0482.md b/compiler/rustc_error_codes/src/error_codes/E0482.md new file mode 100644 index 0000000000000..5ae754b8252b8 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0482.md @@ -0,0 +1,68 @@ +A lifetime of return value does not outlive the function call. + +Erroneous code example: + +```compile_fail,E0482 +fn prefix<'a>( + words: impl Iterator +) -> impl Iterator { + words.map(|v| format!("foo-{}", v)) +} +``` + +To fix this error, make the lifetime of the returned value explicit. + +``` +fn prefix<'a>( + words: impl Iterator + 'a +) -> impl Iterator + 'a { + words.map(|v| format!("foo-{}", v)) +} +``` + +[`impl Trait`] feature in return type have implicit `'static` lifetime +restriction and the type implementing the `Iterator` passed to the function +lives just `'a`, so shorter time. + +The solution involves adding lifetime bound to both function argument and +the return value to make sure that the values inside the iterator +are not dropped when the function goes out of the scope. + +Alternative solution would be to guarantee that the `Item` references +in the iterator are alive for the whole lifetime of the program. + +``` +fn prefix( + words: impl Iterator +) -> impl Iterator { + words.map(|v| format!("foo-{}", v)) +} +``` + +Similar lifetime problem might arise when returning closures. + +Erroneous code example: + +```compile_fail,E0482 +fn foo(x: &mut Vec) -> impl FnMut(&mut Vec) -> &[i32] { + |y| { + y.append(x); + y + } +} +``` + +Analogically, solution here is to use explicit return lifetime +and move the ownership of the variable to the closure. + +``` +fn foo<'a>(x: &'a mut Vec) -> impl FnMut(&mut Vec) -> &[i32] + 'a { + move |y| { + y.append(x); + y + } +} +``` + +- [`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html +- [RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html From 14aae67bbc53eb248ee85eace8f648bd69e43c2a Mon Sep 17 00:00:00 2001 From: sireliah Date: Sat, 9 Oct 2021 21:54:02 +0200 Subject: [PATCH 07/16] Allow the E0482 to be tested --- src/tools/tidy/src/error_codes_check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 53c75a463390d..ce169867b7b1d 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -11,7 +11,7 @@ use regex::Regex; // A few of those error codes can't be tested but all the others can and *should* be tested! const EXEMPTED_FROM_TEST: &[&str] = &[ "E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0464", "E0465", "E0476", - "E0482", "E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729", + "E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729", ]; // Some error codes don't have any tests apparently... From 7f974d0aae1a6bf7c8211b6cbd80a4f21606280e Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 10 Oct 2021 21:16:01 -0500 Subject: [PATCH 08/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 09/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 6531cd8cba18711f112d7b528ab8fd891a31903e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 11 Oct 2021 17:20:45 +0200 Subject: [PATCH 10/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 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 7a7dfa8b67364be9a6fcd0d5876ed1c55b55843b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 11 Oct 2021 12:06:32 -0700 Subject: [PATCH 13/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 14/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() From 0fde6f672f91333f79c867ed9daee7350e4ec382 Mon Sep 17 00:00:00 2001 From: sireliah Date: Sun, 10 Oct 2021 14:58:12 +0200 Subject: [PATCH 15/16] Clarify the error descriptions --- .../src/error_codes/E0482.md | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0482.md b/compiler/rustc_error_codes/src/error_codes/E0482.md index 5ae754b8252b8..58ebf43cc98ce 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0482.md +++ b/compiler/rustc_error_codes/src/error_codes/E0482.md @@ -1,50 +1,50 @@ -A lifetime of return value does not outlive the function call. +A lifetime of a returned value does not outlive the function call. Erroneous code example: ```compile_fail,E0482 fn prefix<'a>( words: impl Iterator -) -> impl Iterator { +) -> impl Iterator { // error! words.map(|v| format!("foo-{}", v)) } ``` -To fix this error, make the lifetime of the returned value explicit. +To fix this error, make the lifetime of the returned value explicit: ``` fn prefix<'a>( words: impl Iterator + 'a -) -> impl Iterator + 'a { +) -> impl Iterator + 'a { // ok! words.map(|v| format!("foo-{}", v)) } ``` -[`impl Trait`] feature in return type have implicit `'static` lifetime -restriction and the type implementing the `Iterator` passed to the function -lives just `'a`, so shorter time. +The [`impl Trait`] feature in this example uses an implicit `'static` lifetime +restriction in the returned type. However the type implementing the `Iterator` +passed to the function lives just as long as `'a`, which is not long enough. The solution involves adding lifetime bound to both function argument and the return value to make sure that the values inside the iterator are not dropped when the function goes out of the scope. -Alternative solution would be to guarantee that the `Item` references +An alternative solution would be to guarantee that the `Item` references in the iterator are alive for the whole lifetime of the program. ``` fn prefix( words: impl Iterator -) -> impl Iterator { +) -> impl Iterator { // ok! words.map(|v| format!("foo-{}", v)) } ``` -Similar lifetime problem might arise when returning closures. - -Erroneous code example: +A similar lifetime problem might arise when returning closures: ```compile_fail,E0482 -fn foo(x: &mut Vec) -> impl FnMut(&mut Vec) -> &[i32] { +fn foo( + x: &mut Vec +) -> impl FnMut(&mut Vec) -> &[i32] { // error! |y| { y.append(x); y @@ -52,11 +52,13 @@ fn foo(x: &mut Vec) -> impl FnMut(&mut Vec) -> &[i32] { } ``` -Analogically, solution here is to use explicit return lifetime +Analogically, a solution here is to use explicit return lifetime and move the ownership of the variable to the closure. ``` -fn foo<'a>(x: &'a mut Vec) -> impl FnMut(&mut Vec) -> &[i32] + 'a { +fn foo<'a>( + x: &'a mut Vec +) -> impl FnMut(&mut Vec) -> &[i32] + 'a { // ok! move |y| { y.append(x); y @@ -64,5 +66,8 @@ fn foo<'a>(x: &'a mut Vec) -> impl FnMut(&mut Vec) -> &[i32] + 'a { } ``` -- [`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html -- [RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html +To better understand the lifetime treatment in the [`impl Trait`], +please see the [RFC 1951]. + +[`impl Trait`]: https://doc.rust-lang.org/reference/types/impl-trait.html +[RFC 1951]: https://rust-lang.github.io/rfcs/1951-expand-impl-trait.html From 148f456cc6fd12a19f45a75b1fd758605c657d0d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 11 Oct 2021 20:52:36 +0100 Subject: [PATCH 16/16] Fix ICE 89775 --- .../src/traits/error_reporting/suggestions.rs | 4 +++- library/core/src/marker.rs | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index a73d2285d4576..1a8f863952e6a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -704,7 +704,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) .collect(); - never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::Send).unwrap()); + if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) { + never_suggest_borrow.push(def_id); + } let param_env = obligation.param_env; let trait_ref = poly_trait_ref.skip_binder(); diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 37446bafacb24..e5c3fafe5f1f0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -30,7 +30,8 @@ use crate::hash::Hasher; /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Send")] +#[cfg_attr(all(not(test), bootstrap), rustc_diagnostic_item = "send_trait")] +#[cfg_attr(all(not(test), not(bootstrap)), rustc_diagnostic_item = "Send")] #[rustc_on_unimplemented( message = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely"