From dfa581ff8747c1d5804a08e8201031a37c2ea14a Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Feb 2021 20:46:58 +0000 Subject: [PATCH 01/20] Fix pretty printing of generic associated type constraints --- compiler/rustc_ast_pretty/src/pprust/state.rs | 1 + src/test/pretty/gat-bounds.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 01e234c9be972..cbeaa6018d149 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -914,6 +914,7 @@ impl<'a> State<'a> { pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { self.print_ident(constraint.ident); + constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false)); self.s.space(); match &constraint.kind { ast::AssocTyConstraintKind::Equality { ty } => { diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs index 789e4bc80ace9..8877c6cc9927b 100644 --- a/src/test/pretty/gat-bounds.rs +++ b/src/test/pretty/gat-bounds.rs @@ -13,4 +13,6 @@ impl X for () { type Y where Self: Sized = u32; } +fn f = i32>>() {} + fn main() { } From 9bbd3e0f8e51beb4c3ea6674327b17cd9d38d9da Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 11 Feb 2021 21:02:27 +0000 Subject: [PATCH 02/20] Remove ProjectionTy::from_ref_and_name --- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_middle/src/ty/sty.rs | 16 ---------------- compiler/rustc_trait_selection/src/autoderef.rs | 10 ++++------ library/core/src/ops/deref.rs | 1 + 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 26ce30cb51177..a5222e5c70237 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -238,6 +238,7 @@ language_item_table! { Deref, sym::deref, deref_trait, Target::Trait; DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait; + DerefTarget, sym::deref_target, deref_target, Target::AssocTy; Receiver, sym::receiver, receiver_trait, Target::Trait; Fn, kw::Fn, fn_trait, Target::Trait; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 04cc4db0bcf64..8a8e70f76ced3 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1112,22 +1112,6 @@ pub struct ProjectionTy<'tcx> { } impl<'tcx> ProjectionTy<'tcx> { - /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the - /// associated item named `item_name`. - pub fn from_ref_and_name( - tcx: TyCtxt<'_>, - trait_ref: ty::TraitRef<'tcx>, - item_name: Ident, - ) -> ProjectionTy<'tcx> { - let item_def_id = tcx - .associated_items(trait_ref.def_id) - .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id) - .unwrap() - .def_id; - - ProjectionTy { substs: trait_ref.substs, item_def_id } - } - /// Extracts the underlying trait reference from this projection. /// For example, if this is a projection of `::Item`, /// then this function would return a `T: Iterator` trait reference. diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 05b6c4a48de1e..3f24a33f7d570 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -6,7 +6,6 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; use rustc_session::DiagnosticMessageId; -use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; #[derive(Copy, Clone, Debug)] @@ -146,11 +145,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let normalized_ty = fulfillcx.normalize_projection_type( &self.infcx, self.param_env, - ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::with_dummy_span(sym::Target), - ), + ty::ProjectionTy { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, cause, ); if let Err(e) = fulfillcx.select_where_possible(&self.infcx) { diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 245152e5490d8..2419771eae212 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -64,6 +64,7 @@ pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "deref_target"] + #[cfg_attr(not(bootstrap), lang = "deref_target")] type Target: ?Sized; /// Dereferences the value. From 0bf1d73d229fdd0c22ef87b1c764c88cf35dd616 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:07:46 +0000 Subject: [PATCH 03/20] Don't go through TraitRef to relate projections --- compiler/rustc_infer/src/infer/at.rs | 25 ++++++++++++++++++- .../src/traits/project.rs | 15 ++++++----- .../src/traits/select/mod.rs | 20 ++++++++------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index a7749d33b7c13..11ee8fb17ad1b 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { fn to_trace( + tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); + let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b); Trace { at: self, trace, a_is_expected } } } @@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { fn to_trace( + _: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { } } } + +impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> { + fn to_trace( + tcx: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + let a_ty = tcx.mk_projection(a.item_def_id, a.substs); + let b_ty = tcx.mk_projection(b.item_def_id, b.substs); + TypeTrace { + cause: cause.clone(), + values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)), + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6908480f431e6..a38e3817a95e5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -921,8 +921,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( && infcx.probe(|_| { selcx.match_projection_projections( obligation, - obligation_trait_ref, - &data, + data, potentially_unnormalized_candidates, ) }); @@ -1344,25 +1343,25 @@ fn confirm_param_env_candidate<'cx, 'tcx>( poly_cache_entry, ); - let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); - let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); + let cache_projection = cache_entry.projection_ty; + let obligation_projection = obligation.predicate; let mut nested_obligations = Vec::new(); - let cache_trait_ref = if potentially_unnormalized_candidate { + let cache_projection = if potentially_unnormalized_candidate { ensure_sufficient_stack(|| { normalize_with_depth_to( selcx, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - cache_trait_ref, + cache_projection, &mut nested_obligations, ) }) } else { - cache_trait_ref + cache_projection }; - match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { + match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 87c8099dc3a51..f0970a48808ad 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,7 @@ use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Constness; +use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; @@ -1254,32 +1255,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub(super) fn match_projection_projections( &mut self, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - data: &PolyProjectionPredicate<'tcx>, + env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, ) -> bool { let mut nested_obligations = Vec::new(); - let projection_ty = if potentially_unnormalized_candidates { + let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars( + obligation.cause.span, + LateBoundRegionConversionTime::HigherRankedType, + env_predicate, + ); + let infer_projection = if potentially_unnormalized_candidates { ensure_sufficient_stack(|| { project::normalize_with_depth_to( self, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - data.map_bound(|data| data.projection_ty), + infer_predicate.projection_ty, &mut nested_obligations, ) }) } else { - data.map_bound(|data| data.projection_ty) + infer_predicate.projection_ty }; - // FIXME(generic_associated_types): Compare the whole projections - let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx())); - let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); self.infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) + .sup(obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { self.evaluate_predicates_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), From 9526c0c6e83f37deb1d48e9761ee9bee2ae94f60 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:32:46 +0000 Subject: [PATCH 04/20] Avoid `trait_ref` when lowering ExistentialProjections --- compiler/rustc_middle/src/ty/sty.rs | 23 +++++++--- compiler/rustc_typeck/src/astconv/mod.rs | 57 +++++++++++------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8a8e70f76ced3..388a576787055 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1477,12 +1477,11 @@ impl<'tcx> ExistentialProjection<'tcx> { /// For example, if this is a projection of `exists T. ::Item == X`, /// then this function would return a `exists T. T: Iterator` existential trait /// reference. - pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> { - // FIXME(generic_associated_types): substs is the substs of the - // associated type, which should be truncated to get the correct substs - // for the trait. + pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> { let def_id = tcx.associated_item(self.item_def_id).container.id(); - ty::ExistentialTraitRef { def_id, substs: self.substs } + let subst_count = tcx.generics_of(def_id).count() - 1; + let substs = tcx.intern_substs(&self.substs[..subst_count]); + ty::ExistentialTraitRef { def_id, substs } } pub fn with_self_ty( @@ -1501,6 +1500,20 @@ impl<'tcx> ExistentialProjection<'tcx> { ty: self.ty, } } + + pub fn erase_self_ty( + tcx: TyCtxt<'tcx>, + projection_predicate: ty::ProjectionPredicate<'tcx>, + ) -> Self { + // Assert there is a Self. + projection_predicate.projection_ty.substs.type_at(0); + + Self { + item_def_id: projection_predicate.projection_ty.item_def_id, + substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]), + ty: projection_predicate.ty, + } + } } impl<'tcx> PolyExistentialProjection<'tcx> { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 244eba8ad5e02..aa496f8722e95 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -985,10 +985,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // // We want to produce `>::T == foo`. - debug!( - "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}", - hir_ref_id, trait_ref, binding, bounds - ); + debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",); let tcx = self.tcx(); let candidate = @@ -1326,37 +1323,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("regular_traits: {:?}", regular_traits); debug!("auto_traits: {:?}", auto_traits); - // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - // removing the dummy `Self` type (`trait_object_dummy_self`). - let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), - ); - } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }; - // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = - regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential)); + let existential_trait_refs = regular_traits.iter().map(|i| { + i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { + if trait_ref.self_ty() != dummy_self { + // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, + // which picks up non-supertraits where clauses - but also, the object safety + // completely ignores trait aliases, which could be object safety hazards. We + // `delay_span_bug` here to avoid an ICE in stable even when the feature is + // disabled. (#66420) + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "trait_ref_to_existential called on {:?} with non-dummy Self", + trait_ref, + ), + ); + } + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }) + }); let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { - let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); - ty::ExistentialProjection { - ty: b.ty, - item_def_id: b.projection_ty.item_def_id, - substs: trait_ref.substs, + if b.projection_ty.self_ty() != dummy_self { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b), + ); } + ty::ExistentialProjection::erase_self_ty(tcx, b) }) }); From 79f6f11816cbef2bba6f5da6d4a4f0aa10535b88 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:41:00 +0000 Subject: [PATCH 05/20] Remove some unnecessary `trait_ref` calls --- compiler/rustc_privacy/src/lib.rs | 27 ++++++++++++++++--- .../src/traits/fulfill.rs | 20 +++++++------- .../src/traits/object_safety.rs | 6 +---- .../src/constrained_generic_params.rs | 2 +- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 631dcb60594f1..0c340b2faaa47 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -77,6 +77,12 @@ trait DefIdVisitor<'tcx> { fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow { self.skeleton().visit_trait(trait_ref) } + fn visit_projection_ty( + &mut self, + projection: ty::ProjectionTy<'tcx>, + ) -> ControlFlow { + self.skeleton().visit_projection_ty(projection) + } fn visit_predicates( &mut self, predicates: ty::GenericPredicates<'tcx>, @@ -101,6 +107,20 @@ where if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } } + fn visit_projection_ty( + &mut self, + projection: ty::ProjectionTy<'tcx>, + ) -> ControlFlow { + let (trait_ref, assoc_substs) = + projection.trait_ref_and_own_substs(self.def_id_visitor.tcx()); + self.visit_trait(trait_ref)?; + if self.def_id_visitor.shallow() { + ControlFlow::CONTINUE + } else { + assoc_substs.iter().try_for_each(|subst| subst.visit_with(self)) + } + } + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { match predicate.kind().skip_binder() { ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => { @@ -108,7 +128,7 @@ where } ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => { ty.visit_with(self)?; - self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) + self.visit_projection_ty(projection_ty) } ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => { ty.visit_with(self) @@ -197,7 +217,7 @@ where return ControlFlow::CONTINUE; } // This will also visit substs if necessary, so we don't need to recurse. - return self.visit_trait(proj.trait_ref(tcx)); + return self.visit_projection_ty(proj); } ty::Dynamic(predicates, ..) => { // All traits in the list are considered the "primary" part of the type @@ -1204,10 +1224,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } for (poly_predicate, _) in bounds.projection_bounds { - let tcx = self.tcx; if self.visit(poly_predicate.skip_binder().ty).is_break() || self - .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) + .visit_projection_ty(poly_predicate.skip_binder().projection_ty) .is_break() { return; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d4ced20f86319..f3bbf9016835e 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,6 +6,7 @@ use rustc_errors::ErrorReported; use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; @@ -633,9 +634,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // only reason we can fail to make progress on // trait selection is because we don't have enough // information about the types in the trait. - *stalled_on = trait_ref_infer_vars( + *stalled_on = substs_infer_vars( self.selcx, - trait_obligation.predicate.map_bound(|pred| pred.trait_ref), + trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs), ); debug!( @@ -663,9 +664,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { match project::poly_project_and_unify_type(self.selcx, &project_obligation) { Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)), Ok(Ok(None)) => { - *stalled_on = trait_ref_infer_vars( + *stalled_on = substs_infer_vars( self.selcx, - project_obligation.predicate.to_poly_trait_ref(tcx), + project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs), ); ProcessResult::Unchanged } @@ -678,16 +679,15 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } -/// Returns the set of inference variables contained in a trait ref. -fn trait_ref_infer_vars<'a, 'tcx>( +/// Returns the set of inference variables contained in `substs`. +fn substs_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + substs: ty::Binder>, ) -> Vec> { selcx .infcx() - .resolve_vars_if_possible(trait_ref) - .skip_binder() - .substs + .resolve_vars_if_possible(substs) + .skip_binder() // ok because this check doesn't care about regions .iter() // FIXME(eddyb) try using `skip_current_subtree` to skip everything that // doesn't contain inference variables, not just the outermost level. diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e155f0366e19f..7de20e477fe04 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -292,11 +292,7 @@ fn predicate_references_self( // // This is ALT2 in issue #56288, see that for discussion of the // possible alternatives. - if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) { - Some(sp) - } else { - None - } + if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None } } ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 95670b9bdb983..529de1a287484 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true); + let inputs = parameters_for(&projection.projection_ty, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; From dfee89f75545b4fadc559eee324afc8bb0bdc1be Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:44:43 +0000 Subject: [PATCH 06/20] Make ProjectionTy::trait_ref truncate substs again Also make sure that type arguments of associated types are printed in some error messages. --- compiler/rustc_middle/src/ty/error.rs | 40 ++++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 16 +++++++- compiler/rustc_middle/src/ty/sty.rs | 37 ++++++++++++----- .../src/traits/error_reporting/mod.rs | 3 +- compiler/rustc_traits/src/chalk/lowering.rs | 7 +--- compiler/rustc_typeck/src/check/closure.rs | 14 +++---- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 7 ++-- .../rustc_typeck/src/check/method/suggest.rs | 33 ++++++++------- .../constraint-assoc-type-suggestion.rs | 17 ++++++++ .../constraint-assoc-type-suggestion.stderr | 27 +++++++++++++ .../method-unsatified-assoc-type-predicate.rs | 35 ++++++++++++++++ ...hod-unsatified-assoc-type-predicate.stderr | 29 ++++++++++++++ 12 files changed, 216 insertions(+), 49 deletions(-) create mode 100644 src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs create mode 100644 src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr create mode 100644 src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs create mode 100644 src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 1669c59d7f1b9..ff95524492409 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,5 +1,6 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::diagnostics::suggest_constraining_type_param; +use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, DiagnosticBuilder}; @@ -400,14 +401,22 @@ impl<'tcx> TyCtxt<'tcx> { { // Synthesize the associated type restriction `Add`. // FIXME: extract this logic for use in other diagnostics. - let trait_ref = proj.trait_ref(self); + let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self); let path = self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); let item_name = self.item_name(proj.item_def_id); + let item_args = self.format_generic_args(assoc_substs); + let path = if path.ends_with('>') { - format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p) + format!( + "{}, {}{} = {}>", + &path[..path.len() - 1], + item_name, + item_args, + p + ) } else { - format!("{}<{} = {}>", path, item_name, p) + format!("{}<{}{} = {}>", path, item_name, item_args, p) }; note = !suggest_constraining_type_param( self, @@ -556,7 +565,7 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(self); + let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. @@ -590,6 +599,7 @@ impl Trait for X { &trait_ref, pred.bounds, &assoc, + assoc_substs, ty, msg, ) { @@ -607,6 +617,7 @@ impl Trait for X { &trait_ref, param.bounds, &assoc, + assoc_substs, ty, msg, ); @@ -692,6 +703,7 @@ impl Trait for X { db, self.def_span(def_id), &assoc, + proj_ty.trait_ref_and_own_substs(self).1, values.found, &msg, ) { @@ -856,6 +868,7 @@ fn foo(&self) -> Self::T { String::new() } trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, assoc: &ty::AssocItem, + assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, ) -> bool { @@ -865,7 +878,12 @@ fn foo(&self) -> Self::T { String::new() } // Relate the type param against `T` in `::Foo`. ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id) && self.constrain_associated_type_structured_suggestion( - db, ptr.span, assoc, ty, msg, + db, + ptr.span, + assoc, + assoc_substs, + ty, + msg, ) } _ => false, @@ -879,6 +897,7 @@ fn foo(&self) -> Self::T { String::new() } db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, + assoc_substs: &[ty::GenericArg<'tcx>], ty: Ty<'tcx>, msg: &str, ) -> bool { @@ -890,11 +909,20 @@ fn foo(&self) -> Self::T { String::new() } let span = Span::new(pos, pos, span.ctxt()); (span, format!(", {} = {}", assoc.ident, ty)) } else { - (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty)) + let item_args = self.format_generic_args(assoc_substs); + (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty)) }; db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); return true; } false } + + fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String { + let mut item_args = String::new(); + FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS) + .path_generic_args(Ok, args) + .expect("could not write to `String`."); + item_args + } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index babab005edb2b..b7f62437fa5a8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1289,8 +1289,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { self.skip_binder().projection_ty.item_def_id } + /// Returns the `DefId` of the trait of the associated item being projected. #[inline] - pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { + pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { + self.skip_binder().projection_ty.trait_def_id(tcx) + } + + #[inline] + pub fn projection_self_ty(&self) -> Binder> { + self.map_bound(|predicate| predicate.projection_ty.self_ty()) + } + + /// Get the [PolyTraitRef] required for this projection to be well formed. + /// Note that for generic associated types the predicates of the associated + /// type also need to be checked. + #[inline] + pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> { // Note: unlike with `TraitRef::to_poly_trait_ref()`, // `self.0.trait_ref` is permitted to have escaping regions. // This is because here `self` has a `Binder` and so does our diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 388a576787055..754108ea3c58a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -17,7 +17,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_macros::HashStable; -use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::symbol::{kw, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi; use std::borrow::Cow; @@ -1112,20 +1112,35 @@ pub struct ProjectionTy<'tcx> { } impl<'tcx> ProjectionTy<'tcx> { + pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { + tcx.associated_item(self.item_def_id).container.id() + } + + /// Extracts the underlying trait reference and own substs from this projection. + /// For example, if this is a projection of `::Item<'a>`, + /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs + pub fn trait_ref_and_own_substs( + &self, + tcx: TyCtxt<'tcx>, + ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) { + let def_id = tcx.associated_item(self.item_def_id).container.id(); + let trait_generics = tcx.generics_of(def_id); + ( + ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) }, + &self.substs[trait_generics.count()..], + ) + } + /// Extracts the underlying trait reference from this projection. /// For example, if this is a projection of `::Item`, /// then this function would return a `T: Iterator` trait reference. + /// + /// WARNING: This will drop the substs for generic associated types + /// consider calling [Self::trait_ref_and_own_substs] to get those + /// as well. pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { - // FIXME: This method probably shouldn't exist at all, since it's not - // clear what this method really intends to do. Be careful when - // using this method since the resulting TraitRef additionally - // contains the substs for the assoc_item, which strictly speaking - // is not correct - let def_id = tcx.associated_item(self.item_def_id).container.id(); - // Include substitutions for generic arguments of associated types - let assoc_item = tcx.associated_item(self.item_def_id); - let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id)); - ty::TraitRef { def_id, substs: substs_assoc_item } + let def_id = self.trait_def_id(tcx); + ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) } } pub fn self_ty(&self) -> Ty<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 3233d1e048bf7..e9aaa65256419 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1589,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282) } ty::PredicateKind::Projection(data) => { - let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx); - let self_ty = trait_ref.skip_binder().self_ty(); + let self_ty = data.projection_ty.self_ty(); let ty = data.ty; if predicate.references_error() { return; diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 7d3589c4b6bd8..fdf5f697e6117 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound self, interner: &RustInterner<'tcx>, ) -> chalk_solve::rust_ir::AliasEqBound> { - let trait_ref = self.projection_ty.trait_ref(interner.tcx); + let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx); chalk_solve::rust_ir::AliasEqBound { trait_bound: trait_ref.lower_into(interner), associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id), - parameters: self.projection_ty.substs[trait_ref.substs.len()..] - .iter() - .map(|arg| arg.lower_into(interner)) - .collect(), + parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(), value: self.ty.lower_into(interner), } } diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index f34aaec10a9b9..431e6d70ff35c 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); // Even if we can't infer the full signature, we may be able to - // infer the kind. This can occur if there is a trait-reference + // infer the kind. This can occur when we elaborate a predicate // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let expected_kind = self @@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("deduce_sig_from_projection({:?})", projection); - let trait_ref = projection.to_poly_trait_ref(tcx); + let trait_def_id = projection.trait_def_id(tcx); - let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some(); + let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some(); let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span); - let is_gen = gen_trait == trait_ref.def_id(); + let is_gen = gen_trait == trait_def_id; if !is_fn && !is_gen { debug!("deduce_sig_from_projection: not fn or generator"); return None; @@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let input_tys = if is_fn { - let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); + let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1); let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); @@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Check that this is a projection from the `Future` trait. - let trait_ref = predicate.projection_ty.trait_ref(self.tcx); + let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx); let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span)); - if trait_ref.def_id != future_trait { + if trait_def_id != future_trait { debug!("deduce_future_output_from_projection: not a future"); return None; } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index bc1a07801ae87..75c73e0b67c07 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(move |obligation| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { - ty::PredicateKind::Projection(data) => { - Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation)) - } + ty::PredicateKind::Projection(data) => Some(( + bound_predicate.rebind(data).required_poly_trait_ref(self.tcx), + obligation, + )), ty::PredicateKind::Trait(data, _) => { Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation)) } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index d49c7cae8222b..14d019fa01a74 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -24,6 +24,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; use std::cmp::Ordering; +use std::iter; use super::probe::Mode; use super::{CandidateSource, MethodError, NoMatchData}; @@ -649,21 +650,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Projection(pred) => { let pred = bound_predicate.rebind(pred); // `::Item = String`. - let trait_ref = - pred.skip_binder().projection_ty.trait_ref(self.tcx); - let assoc = self - .tcx - .associated_item(pred.skip_binder().projection_ty.item_def_id); - let ty = pred.skip_binder().ty; - let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty); - let quiet = format!( - "<_ as {}>::{} = {}", - trait_ref.print_only_trait_path(), - assoc.ident, - ty + let projection_ty = pred.skip_binder().projection_ty; + + let substs_with_infer_self = tcx.mk_substs( + iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into()) + .chain(projection_ty.substs.iter().skip(1)), ); - bound_span_label(trait_ref.self_ty(), &obligation, &quiet); - Some((obligation, trait_ref.self_ty())) + + let quiet_projection_ty = ty::ProjectionTy { + substs: substs_with_infer_self, + item_def_id: projection_ty.item_def_id, + }; + + let ty = pred.skip_binder().ty; + + let obligation = format!("{} = {}", projection_ty, ty); + let quiet = format!("{} = {}", quiet_projection_ty, ty); + + bound_span_label(projection_ty.self_ty(), &obligation, &quiet); + Some((obligation, projection_ty.self_ty())) } ty::PredicateKind::Trait(poly_trait_ref, _) => { let p = poly_trait_ref.trait_ref; diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs new file mode 100644 index 0000000000000..36db3d1bb9e47 --- /dev/null +++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs @@ -0,0 +1,17 @@ +// Test that correct syntax is used in suggestion to constrain associated type + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete + +trait X { + type Y; +} + +fn f(a: T::Y) { + //~^ HELP consider constraining the associated type `::Y` to `Vec` + //~| SUGGESTION Y = Vec> + let b: Vec = a; + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr new file mode 100644 index 0000000000000..ecf559d9e94a1 --- /dev/null +++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr @@ -0,0 +1,27 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/constraint-assoc-type-suggestion.rs:3:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0308]: mismatched types + --> $DIR/constraint-assoc-type-suggestion.rs:13:23 + | +LL | let b: Vec = a; + | -------- ^ expected struct `Vec`, found associated type + | | + | expected due to this + | + = note: expected struct `Vec` + found associated type `::Y` +help: consider constraining the associated type `::Y` to `Vec` + | +LL | fn f = Vec>>(a: T::Y) { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs new file mode 100644 index 0000000000000..2de4c7b8492a3 --- /dev/null +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs @@ -0,0 +1,35 @@ +// Test that the predicate printed in an unresolved method error prints the +// generics for a generic associated type. + +#![feature(generic_associated_types)] +//~^ WARNING the feature `generic_associated_types` is incomplete +//~| NOTE `#[warn(incomplete_features)]` on by default +//~| NOTE see issue #44265 + +trait X { + type Y; +} + +trait M { + fn f(&self) {} +} + +impl = i32>> M for T {} + +struct S; +//~^ NOTE method `f` not found for this +//~| NOTE doesn't satisfy `::Y = i32` +//~| NOTE doesn't satisfy `S: M` + +impl X for S { + type Y = bool; +} + +fn f(a: S) { + a.f(); + //~^ ERROR the method `f` exists for struct `S`, but its trait bounds were not satisfied + //~| NOTE method cannot be called on `S` due to unsatisfied trait bounds + //~| NOTE the following trait bounds were not satisfied: +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr new file mode 100644 index 0000000000000..c94155d13c344 --- /dev/null +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr @@ -0,0 +1,29 @@ +warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/method-unsatified-assoc-type-predicate.rs:4:12 + | +LL | #![feature(generic_associated_types)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44265 for more information + +error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied + --> $DIR/method-unsatified-assoc-type-predicate.rs:29:7 + | +LL | struct S; + | --------- + | | + | method `f` not found for this + | doesn't satisfy `::Y = i32` + | doesn't satisfy `S: M` +... +LL | a.f(); + | ^ method cannot be called on `S` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `::Y = i32` + which is required by `S: M` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0599`. From d785c8c447bd7f972e68e346a3f7b04c56ce486b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:45:19 +0000 Subject: [PATCH 07/20] Remove unnecessary function parameters project.rs --- .../src/traits/project.rs | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a38e3817a95e5..bfaca4215edb7 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -741,11 +741,7 @@ fn project_type<'cx, 'tcx>( return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); } - let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - - debug!(?obligation_trait_ref); - - if obligation_trait_ref.references_error() { + if obligation.predicate.references_error() { return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); } @@ -754,19 +750,19 @@ fn project_type<'cx, 'tcx>( // Make sure that the following procedures are kept in order. ParamEnv // needs to be first because it has highest priority, and Select checks // the return value of push_candidate which assumes it's ran at last. - assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_param_env(selcx, obligation, &mut candidates); - assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_trait_def(selcx, obligation, &mut candidates); - assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates { // Avoid normalization cycle from selection (see // `assemble_candidates_from_object_ty`). // FIXME(lazy_normalization): Lazy normalization should save us from - // having to do special case this. + // having to special case this. } else { - assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); + assemble_candidates_from_impls(selcx, obligation, &mut candidates); }; match candidates { @@ -792,14 +788,12 @@ fn project_type<'cx, 'tcx>( fn assemble_candidates_from_param_env<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_param_env(..)"); assemble_candidates_from_predicates( selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::ParamEnv, obligation.param_env.caller_bounds().iter(), @@ -820,7 +814,6 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( fn assemble_candidates_from_trait_def<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_trait_def(..)"); @@ -828,7 +821,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match *obligation_trait_ref.self_ty().kind() { + let bounds = match *obligation.predicate.self_ty().kind() { ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs), ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs), ty::Infer(ty::TyVar(_)) => { @@ -843,7 +836,6 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( assemble_candidates_from_predicates( selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::TraitDef, bounds.iter(), @@ -863,14 +855,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( fn assemble_candidates_from_object_ty<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_object_ty(..)"); let tcx = selcx.tcx(); - let self_ty = obligation_trait_ref.self_ty(); + let self_ty = obligation.predicate.self_ty(); let object_ty = selcx.infcx().shallow_resolve(self_ty); let data = match object_ty.kind() { ty::Dynamic(data, ..) => data, @@ -890,7 +881,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( assemble_candidates_from_predicates( selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::Object, env_predicates, @@ -901,7 +891,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( fn assemble_candidates_from_predicates<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, env_predicates: impl Iterator>, @@ -947,14 +936,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { debug!("assemble_candidates_from_impls"); // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref); + let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref(); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { From eeb82e45fe42ec77efd99b706f96b3e66bcfb524 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 12 Feb 2021 22:45:54 +0000 Subject: [PATCH 08/20] Add more tests for generic associated type bounds --- .../generic-associated-type-bounds.rs | 35 +++++++++++++ .../generic-associated-types/issue-76535.rs | 6 +-- .../issue-76535.stderr | 39 +-------------- .../generic-associated-types/issue-79422.rs | 5 +- .../issue-79422.stderr | 40 +++------------ .../projection-type-lifetime-mismatch.rs | 36 +++++++++++++ .../projection-type-lifetime-mismatch.stderr | 27 ++++++++++ .../unsatified-item-lifetime-bound.rs | 28 +++++++++++ .../unsatified-item-lifetime-bound.stderr | 50 +++++++++++++++++++ 9 files changed, 190 insertions(+), 76 deletions(-) create mode 100644 src/test/ui/generic-associated-types/generic-associated-type-bounds.rs create mode 100644 src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs create mode 100644 src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr create mode 100644 src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs create mode 100644 src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs new file mode 100644 index 0000000000000..8094450e5e137 --- /dev/null +++ b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs @@ -0,0 +1,35 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +pub trait X { + type Y<'a>; + fn m(&self) -> Self::Y<'_>; +} + +impl X for () { + type Y<'a> = &'a (); + + fn m(&self) -> Self::Y<'_> { + self + } +} + +fn f(x: &impl for<'a> X = &'a ()>) -> &() { + x.m() +} + +fn g X = &'a ()>>(x: &T) -> &() { + x.m() +} + +fn h(x: &()) -> &() { + x.m() +} + +fn main() { + f(&()); + g(&()); + h(&()); +} diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs index 2b4757d8d15ed..5e73a88298622 100644 --- a/src/test/ui/generic-associated-types/issue-76535.rs +++ b/src/test/ui/generic-associated-types/issue-76535.rs @@ -1,11 +1,11 @@ #![feature(generic_associated_types)] - //~^ WARNING the feature +//~^ WARNING the feature pub trait SubTrait {} pub trait SuperTrait { type SubType<'a>: SubTrait; - //~^ ERROR missing generics for associated + //~^ ERROR missing generics for associated fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; } @@ -36,6 +36,4 @@ impl SuperTrait for SuperStruct { fn main() { let sub: Box> = Box::new(SuperStruct::new(0)); - //~^ ERROR the trait - //~| ERROR the trait } diff --git a/src/test/ui/generic-associated-types/issue-76535.stderr b/src/test/ui/generic-associated-types/issue-76535.stderr index ce4875af9c012..17661e0d90a4a 100644 --- a/src/test/ui/generic-associated-types/issue-76535.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.stderr @@ -23,41 +23,6 @@ help: use angle brackets to add missing lifetime argument LL | type SubType<'a><'a>: SubTrait; | ^^^^ -error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/issue-76535.rs:38:14 - | -LL | let sub: Box> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object - | - = help: consider moving `get_sub` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-76535.rs:10:37 - | -LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... -... -LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; - | ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type - -error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/issue-76535.rs:38:57 - | -LL | let sub: Box> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object - | - = help: consider moving `get_sub` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-76535.rs:10:37 - | -LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... -... -LL | fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>; - | ^^^^^^^^^^^^^^^^^ ...because method `get_sub` references the `Self` type in its return type - = note: required because of the requirements on the impl of `CoerceUnsized>>>` for `Box` - = note: required by cast to type `Box>>` - -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to previous error; 1 warning emitted -Some errors have detailed explanations: E0038, E0107. -For more information about an error, try `rustc --explain E0038`. +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs index 26b38430dd9a5..aeb33ca54641c 100644 --- a/src/test/ui/generic-associated-types/issue-79422.rs +++ b/src/test/ui/generic-associated-types/issue-79422.rs @@ -19,7 +19,7 @@ impl<'a, T> RefCont<'a, T> for Box { trait MapLike { type VRefCont<'a>: RefCont<'a, V>; - //~^ ERROR missing generics + //~^ ERROR missing generics fn get<'a>(&'a self, key: &K) -> Option>; } @@ -42,6 +42,5 @@ impl MapLike for Source { fn main() { let m = Box::new(std::collections::BTreeMap::::new()) as Box>>; - //~^ ERROR the trait - //~^^^ ERROR the trait + //~^^ ERROR type mismatch resolving } diff --git a/src/test/ui/generic-associated-types/issue-79422.stderr b/src/test/ui/generic-associated-types/issue-79422.stderr index d2e12962715f0..a119bff03e290 100644 --- a/src/test/ui/generic-associated-types/issue-79422.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.stderr @@ -14,41 +14,17 @@ help: use angle brackets to add missing lifetime argument LL | type VRefCont<'a><'a>: RefCont<'a, V>; | ^^^^ -error[E0038]: the trait `MapLike` cannot be made into an object - --> $DIR/issue-79422.rs:44:12 - | -LL | as Box>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object - | - = help: consider moving `get` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-79422.rs:23:38 - | -LL | trait MapLike { - | ------- this trait cannot be made into an object... -... -LL | fn get<'a>(&'a self, key: &K) -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type - -error[E0038]: the trait `MapLike` cannot be made into an object +error[E0271]: type mismatch resolving ` as MapLike>::VRefCont<'static> == (dyn RefCont<'_, u8> + 'static)` --> $DIR/issue-79422.rs:43:13 | LL | let m = Box::new(std::collections::BTreeMap::::new()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object - | - = help: consider moving `get` to another trait -note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-79422.rs:23:38 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn RefCont`, found reference | -LL | trait MapLike { - | ------- this trait cannot be made into an object... -... -LL | fn get<'a>(&'a self, key: &K) -> Option>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `get` references the `Self` type in its return type - = note: required because of the requirements on the impl of `CoerceUnsized + 'static)>>>` for `Box>` - = note: required by cast to type `Box + 'static)>>` + = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` + found reference `&'static u8` + = note: required for the cast to the object type `dyn MapLike + 'static)>` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0038, E0107. -For more information about an error, try `rustc --explain E0038`. +Some errors have detailed explanations: E0107, E0271. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs new file mode 100644 index 0000000000000..0024e127a982c --- /dev/null +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs @@ -0,0 +1,36 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +pub trait X { + type Y<'a>; + fn m(&self) -> Self::Y<'_>; +} + +impl X for () { + type Y<'a> = &'a (); + + fn m(&self) -> Self::Y<'_> { + self + } +} + +fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { + x.m() + //~^ ERROR explicit lifetime required +} + +fn g X = &'a ()>>(x: &T) -> &'static () { + x.m() + //~^ ERROR explicit lifetime required +} + +fn h(x: &()) -> &'static () { + x.m() + //~^ ERROR explicit lifetime required +} + +fn main() { + f(&()); + g(&()); + h(&()); +} diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr new file mode 100644 index 0000000000000..13b765dfa5719 --- /dev/null +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr @@ -0,0 +1,27 @@ +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/projection-type-lifetime-mismatch.rs:18:5 + | +LL | fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { + | ------------------------------- help: add explicit lifetime `'static` to the type of `x`: `&'static impl for<'a> X = &'a ()>` +LL | x.m() + | ^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/projection-type-lifetime-mismatch.rs:23:5 + | +LL | fn g X = &'a ()>>(x: &T) -> &'static () { + | -- help: add explicit lifetime `'static` to the type of `x`: `&'static T` +LL | x.m() + | ^^^^^ lifetime `'static` required + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/projection-type-lifetime-mismatch.rs:28:5 + | +LL | fn h(x: &()) -> &'static () { + | --- help: add explicit lifetime `'static` to the type of `x`: `&'static ()` +LL | x.m() + | ^^^^^ lifetime `'static` required + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs new file mode 100644 index 0000000000000..7bcc7ba752ad0 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs @@ -0,0 +1,28 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +pub trait X { + type Y<'a: 'static>; + //~^ WARNING unnecessary lifetime parameter +} + +impl X for () { + type Y<'a> = &'a (); +} + +struct B<'a, T: for<'r> X = &'r ()>> { + f: ::Y<'a>, + //~^ ERROR lifetime bound not satisfied +} + +struct C<'a, T: X> { + f: ::Y<'a>, + //~^ ERROR lifetime bound not satisfied +} + +struct D<'a> { + f: <() as X>::Y<'a>, + //~^ ERROR lifetime bound not satisfied +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr new file mode 100644 index 0000000000000..1c81d33ccfe72 --- /dev/null +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr @@ -0,0 +1,50 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/unsatified-item-lifetime-bound.rs:5:12 + | +LL | type Y<'a: 'static>; + | ^^^^^^^^^^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatified-item-lifetime-bound.rs:14:8 + | +LL | f: ::Y<'a>, + | ^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 13:10 + --> $DIR/unsatified-item-lifetime-bound.rs:13:10 + | +LL | struct B<'a, T: for<'r> X = &'r ()>> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatified-item-lifetime-bound.rs:19:8 + | +LL | f: ::Y<'a>, + | ^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 18:10 + --> $DIR/unsatified-item-lifetime-bound.rs:18:10 + | +LL | struct C<'a, T: X> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatified-item-lifetime-bound.rs:24:8 + | +LL | f: <() as X>::Y<'a>, + | ^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined on the struct at 23:10 + --> $DIR/unsatified-item-lifetime-bound.rs:23:10 + | +LL | struct D<'a> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0478`. From 7e368e57f278b8073193c73001f4efc4af08fdfd Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 15 Feb 2021 11:38:20 +0000 Subject: [PATCH 09/20] the environment round here is awfully empty capitalism --- .../src/traits/const_evaluatable.rs | 13 +++++----- .../error_reporting/on_unimplemented.rs | 25 +++++++------------ .../dont-evaluate-array-len-on-err-1.rs | 22 ++++++++++++++++ .../dont-evaluate-array-len-on-err-1.stderr | 12 +++++++++ 4 files changed, 49 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs create mode 100644 src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b1ac02d9fed5a..8a1be7ea1726d 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -72,17 +72,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>( // We were unable to unify the abstract constant with // a constant found in the caller bounds, there are // now three possible cases here. - // - // - The substs are concrete enough that we can simply - // try and evaluate the given constant. - // - The abstract const still references an inference - // variable, in this case we return `TooGeneric`. - // - The abstract const references a generic parameter, - // this means that we emit an error here. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] enum FailureKind { + /// The abstract const still references an inference + /// variable, in this case we return `TooGeneric`. MentionsInfer, + /// The abstract const references a generic parameter, + /// this means that we emit an error here. MentionsParam, + /// The substs are concrete enough that we can simply + /// try and evaluate the given constant. Concrete, } let mut failure_kind = FailureKind::Concrete; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 69f66f6e6b1aa..e6a1cf58fe373 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -200,22 +200,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(def) = aty.ty_adt_def() { // We also want to be able to select the array's type's original // signature with no type arguments resolved - flags.push(( - sym::_Self, - Some(format!("[{}]", self.tcx.type_of(def.did).to_string())), - )); - let tcx = self.tcx; - if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) { - flags.push(( - sym::_Self, - Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)), - )); - } else { - flags.push(( - sym::_Self, - Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())), - )); - } + let type_string = self.tcx.type_of(def.did).to_string(); + flags.push((sym::_Self, Some(format!("[{}]", type_string)))); + + let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); + let string = match len { + Some(n) => format!("[{}; {}]", type_string, n), + None => format!("[{}; _]", type_string), + }; + flags.push((sym::_Self, Some(string))); } } if let ty::Dynamic(traits, _) = self_ty.kind() { diff --git a/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs new file mode 100644 index 0000000000000..afef748ff4690 --- /dev/null +++ b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.rs @@ -0,0 +1,22 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// This tests that during error handling for the "trait not implemented" error +// we dont try to evaluate std::mem::size_of:: causing an ICE + +struct Adt; + +trait Foo { + type Assoc; + fn foo() + where + [Adt; std::mem::size_of::()]: , + { + <[Adt; std::mem::size_of::()] as Foo>::bar() + //~^ Error: the trait bound + } + + fn bar() {} +} + +fn main() {} diff --git a/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr new file mode 100644 index 0000000000000..d894fa90ba9e1 --- /dev/null +++ b/src/test/ui/const-generics/dont-evaluate-array-len-on-err-1.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `[Adt; _]: Foo` is not satisfied + --> $DIR/dont-evaluate-array-len-on-err-1.rs:15:9 + | +LL | <[Adt; std::mem::size_of::()] as Foo>::bar() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[Adt; _]` +... +LL | fn bar() {} + | -------- required by `Foo::bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 0f04875d2e21919e5f716b9946407ba07de08840 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 17 Feb 2021 19:26:38 +0900 Subject: [PATCH 10/20] replace if-let and while-let with `if let` and `while let` --- .../rustc_error_codes/src/error_codes/E0162.md | 2 +- .../rustc_error_codes/src/error_codes/E0165.md | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 10 +++++----- .../src/thir/pattern/check_match.rs | 6 +++--- compiler/rustc_passes/src/check_const.rs | 2 +- src/test/ui/binding/if-let.rs | 4 ++-- .../closure-origin-single-variant-diagnostics.rs | 2 +- ...sure-origin-single-variant-diagnostics.stderr | 2 +- src/test/ui/expr/if/if-let.rs | 16 ++++++++-------- src/test/ui/expr/if/if-let.stderr | 16 ++++++++-------- src/test/ui/issues/issue-19991.rs | 2 +- .../usefulness/deny-irrefutable-let-patterns.rs | 4 ++-- .../deny-irrefutable-let-patterns.stderr | 4 ++-- src/test/ui/rfc-2294-if-let-guard/warns.rs | 2 +- src/test/ui/rfc-2294-if-let-guard/warns.stderr | 2 +- src/test/ui/while-let.rs | 6 +++--- src/test/ui/while-let.stderr | 6 +++--- src/tools/clippy/clippy_lints/src/loops.rs | 2 +- 18 files changed, 45 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0162.md b/compiler/rustc_error_codes/src/error_codes/E0162.md index 98146147f3950..0161c9325c211 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0162.md +++ b/compiler/rustc_error_codes/src/error_codes/E0162.md @@ -1,6 +1,6 @@ #### Note: this error code is no longer emitted by the compiler. -An if-let pattern attempts to match the pattern, and enters the body if the +An `if let` pattern attempts to match the pattern, and enters the body if the match was successful. If the match is irrefutable (when it cannot fail to match), use a regular `let`-binding instead. For instance: diff --git a/compiler/rustc_error_codes/src/error_codes/E0165.md b/compiler/rustc_error_codes/src/error_codes/E0165.md index 92243db455015..7bcd6c0cbf379 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0165.md +++ b/compiler/rustc_error_codes/src/error_codes/E0165.md @@ -1,6 +1,6 @@ #### Note: this error code is no longer emitted by the compiler. -A while-let pattern attempts to match the pattern, and enters the body if the +A `while let` pattern attempts to match the pattern, and enters the body if the match was successful. If the match is irrefutable (when it cannot fail to match), use a regular `let`-binding inside a `loop` instead. For instance: diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f0a5ea150b719..8eeee19cc298a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1815,7 +1815,7 @@ declare_lint! { declare_lint! { /// The `irrefutable_let_patterns` lint detects detects [irrefutable - /// patterns] in [if-let] and [while-let] statements. + /// patterns] in [`if let`] and [`while let`] statements. /// /// /// @@ -1832,7 +1832,7 @@ declare_lint! { /// ### Explanation /// /// There usually isn't a reason to have an irrefutable pattern in an - /// if-let or while-let statement, because the pattern will always match + /// `if let` or `while let` statement, because the pattern will always match /// successfully. A [`let`] or [`loop`] statement will suffice. However, /// when generating code with a macro, forbidding irrefutable patterns /// would require awkward workarounds in situations where the macro @@ -1843,14 +1843,14 @@ declare_lint! { /// See [RFC 2086] for more details. /// /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability - /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions - /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops + /// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions + /// [`while let`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md pub IRREFUTABLE_LET_PATTERNS, Warn, - "detects irrefutable patterns in if-let and while-let statements" + "detects irrefutable patterns in `if let` and `while let` statements" } declare_lint! { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 6ec602ff59b9c..e928f3c5d4d09 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -368,9 +368,9 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option< fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) { tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| { let msg = match source { - hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern", - hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern", - hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard", + hir::MatchSource::IfLetDesugar { .. } => "irrefutable `if let` pattern", + hir::MatchSource::WhileLetDesugar => "irrefutable `while let` pattern", + hir::MatchSource::IfLetGuardDesugar => "irrefutable `if let` guard", _ => bug!(), }; lint.build(msg).emit() diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 8950f9b33b6da..9328f7cd9ec7b 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -45,7 +45,7 @@ impl NonConstExpr { return None; } - Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"), + Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"), // All other expressions are allowed. Self::Loop(Loop | While | WhileLet) diff --git a/src/test/ui/binding/if-let.rs b/src/test/ui/binding/if-let.rs index 3ea8d402a3ef4..28d57e92c3731 100644 --- a/src/test/ui/binding/if-let.rs +++ b/src/test/ui/binding/if-let.rs @@ -6,7 +6,7 @@ pub fn main() { if let Some(y) = x { assert_eq!(y, 3); } else { - panic!("if-let panicked"); + panic!("`if let` panicked"); } let mut worked = false; if let Some(_) = x { @@ -54,7 +54,7 @@ pub fn main() { if let Foo::Two(b) = a { assert_eq!(b, 42_usize); } else { - panic!("panic in nested if-let"); + panic!("panic in nested `if let`"); } } } diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs index 8486f03f2eb8e..6107a082237c6 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.rs @@ -16,7 +16,7 @@ fn main() { // FIXME(project-rfc-2229#24): Change this to be a destructure pattern // once this is fixed, to remove the warning. if let SingleVariant::Point(ref mut x, _) = point { - //~^ WARNING: irrefutable if-let pattern + //~^ WARNING: irrefutable `if let` pattern *x += 1; } }; diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr index ad66f6d7ffcaa..5c7a56c7ceda4 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr @@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #53488 for more information -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/closure-origin-single-variant-diagnostics.rs:18:9 | LL | / if let SingleVariant::Point(ref mut x, _) = point { diff --git a/src/test/ui/expr/if/if-let.rs b/src/test/ui/expr/if/if-let.rs index 2ab0f9fed3fc6..7208e388a1621 100644 --- a/src/test/ui/expr/if/if-let.rs +++ b/src/test/ui/expr/if/if-let.rs @@ -4,8 +4,8 @@ fn macros() { macro_rules! foo{ ($p:pat, $e:expr, $b:block) => {{ if let $p = $e $b - //~^ WARN irrefutable if-let - //~| WARN irrefutable if-let + //~^ WARN irrefutable `if let` + //~| WARN irrefutable `if let` }} } macro_rules! bar{ @@ -23,27 +23,27 @@ fn macros() { } pub fn main() { - if let a = 1 { //~ WARN irrefutable if-let + if let a = 1 { //~ WARN irrefutable `if let` println!("irrefutable pattern"); } - if let a = 1 { //~ WARN irrefutable if-let + if let a = 1 { //~ WARN irrefutable `if let` println!("irrefutable pattern"); } else if true { - println!("else-if in irrefutable if-let"); + println!("else-if in irrefutable `if let`"); } else { - println!("else in irrefutable if-let"); + println!("else in irrefutable `if let`"); } if let 1 = 2 { println!("refutable pattern"); - } else if let a = 1 { //~ WARN irrefutable if-let + } else if let a = 1 { //~ WARN irrefutable `if let` println!("irrefutable pattern"); } if true { println!("if"); - } else if let a = 1 { //~ WARN irrefutable if-let + } else if let a = 1 { //~ WARN irrefutable `if let` println!("irrefutable pattern"); } } diff --git a/src/test/ui/expr/if/if-let.stderr b/src/test/ui/expr/if/if-let.stderr index ee2b78af3b84d..468e913a773c0 100644 --- a/src/test/ui/expr/if/if-let.stderr +++ b/src/test/ui/expr/if/if-let.stderr @@ -1,4 +1,4 @@ -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/if-let.rs:6:13 | LL | if let $p = $e $b @@ -12,7 +12,7 @@ LL | | }); = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/if-let.rs:6:13 | LL | if let $p = $e $b @@ -25,7 +25,7 @@ LL | | }); | = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/if-let.rs:26:5 | LL | / if let a = 1 { @@ -33,19 +33,19 @@ LL | | println!("irrefutable pattern"); LL | | } | |_____^ -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/if-let.rs:30:5 | LL | / if let a = 1 { LL | | println!("irrefutable pattern"); LL | | } else if true { -LL | | println!("else-if in irrefutable if-let"); +LL | | println!("else-if in irrefutable `if let`"); LL | | } else { -LL | | println!("else in irrefutable if-let"); +LL | | println!("else in irrefutable `if let`"); LL | | } | |_____^ -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/if-let.rs:40:12 | LL | } else if let a = 1 { @@ -54,7 +54,7 @@ LL | | println!("irrefutable pattern"); LL | | } | |_____^ -warning: irrefutable if-let pattern +warning: irrefutable `if let` pattern --> $DIR/if-let.rs:46:12 | LL | } else if let a = 1 { diff --git a/src/test/ui/issues/issue-19991.rs b/src/test/ui/issues/issue-19991.rs index 0f3f83001d3c6..1f3b73f96d8b9 100644 --- a/src/test/ui/issues/issue-19991.rs +++ b/src/test/ui/issues/issue-19991.rs @@ -1,4 +1,4 @@ -// Test if the sugared if-let construct correctly prints "missing an else clause" when an else +// Test if the sugared `if let` construct correctly prints "missing an else clause" when an else // clause does not exist, instead of the unsympathetic "`match` arms have incompatible types" fn main() { diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs index 14040c8ada67d..c1cfa4695c9ee 100644 --- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.rs @@ -1,9 +1,9 @@ #![deny(irrefutable_let_patterns)] fn main() { - if let _ = 5 {} //~ ERROR irrefutable if-let pattern + if let _ = 5 {} //~ ERROR irrefutable `if let` pattern - while let _ = 5 { //~ ERROR irrefutable while-let pattern + while let _ = 5 { //~ ERROR irrefutable `while let` pattern break; } } diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr index 308a6c7c58e66..1de30f7db0698 100644 --- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr @@ -1,4 +1,4 @@ -error: irrefutable if-let pattern +error: irrefutable `if let` pattern --> $DIR/deny-irrefutable-let-patterns.rs:4:5 | LL | if let _ = 5 {} @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(irrefutable_let_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: irrefutable while-let pattern +error: irrefutable `while let` pattern --> $DIR/deny-irrefutable-let-patterns.rs:6:5 | LL | / while let _ = 5 { diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.rs b/src/test/ui/rfc-2294-if-let-guard/warns.rs index 9691a12f45b05..d921367b91775 100644 --- a/src/test/ui/rfc-2294-if-let-guard/warns.rs +++ b/src/test/ui/rfc-2294-if-let-guard/warns.rs @@ -5,7 +5,7 @@ fn irrefutable_let_guard() { match Some(()) { Some(x) if let () = x => {} - //~^ ERROR irrefutable if-let guard + //~^ ERROR irrefutable `if let` guard _ => {} } } diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr index 45720f9fbc551..33fa25d32fb1b 100644 --- a/src/test/ui/rfc-2294-if-let-guard/warns.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr @@ -1,4 +1,4 @@ -error: irrefutable if-let guard +error: irrefutable `if let` guard --> $DIR/warns.rs:7:24 | LL | Some(x) if let () = x => {} diff --git a/src/test/ui/while-let.rs b/src/test/ui/while-let.rs index cfbf7565cb6c8..b9a49b47c8ff5 100644 --- a/src/test/ui/while-let.rs +++ b/src/test/ui/while-let.rs @@ -5,8 +5,8 @@ fn macros() { macro_rules! foo{ ($p:pat, $e:expr, $b:block) => {{ while let $p = $e $b - //~^ WARN irrefutable while-let - //~| WARN irrefutable while-let + //~^ WARN irrefutable `while let` + //~| WARN irrefutable `while let` }} } macro_rules! bar{ @@ -24,7 +24,7 @@ fn macros() { } pub fn main() { - while let _a = 1 { //~ WARN irrefutable while-let + while let _a = 1 { //~ WARN irrefutable `while let` println!("irrefutable pattern"); break; } diff --git a/src/test/ui/while-let.stderr b/src/test/ui/while-let.stderr index 867c95c0e023d..6538b9fbe6f28 100644 --- a/src/test/ui/while-let.stderr +++ b/src/test/ui/while-let.stderr @@ -1,4 +1,4 @@ -warning: irrefutable while-let pattern +warning: irrefutable `while let` pattern --> $DIR/while-let.rs:7:13 | LL | while let $p = $e $b @@ -12,7 +12,7 @@ LL | | }); = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -warning: irrefutable while-let pattern +warning: irrefutable `while let` pattern --> $DIR/while-let.rs:7:13 | LL | while let $p = $e $b @@ -25,7 +25,7 @@ LL | | }); | = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -warning: irrefutable while-let pattern +warning: irrefutable `while let` pattern --> $DIR/while-let.rs:27:5 | LL | / while let _a = 1 { diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 5211ca7da323a..eb0047602fd22 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -341,7 +341,7 @@ declare_clippy_lint! { /// ``` pub WHILE_LET_ON_ITERATOR, style, - "using a while-let loop instead of a for loop on an iterator" + "using a `while let` loop instead of a for loop on an iterator" } declare_clippy_lint! { From 43aed7441ee289c6228ecead91ee66245122b880 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 30 Jan 2021 00:23:56 +0800 Subject: [PATCH 11/20] [libtest] Run the test synchronously when hitting thread limit --- library/test/src/lib.rs | 13 ++++++++++++- src/test/run-make/libtest-thread-limit/Makefile | 7 +++++++ src/test/run-make/libtest-thread-limit/test.rs | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/test/run-make/libtest-thread-limit/Makefile create mode 100644 src/test/run-make/libtest-thread-limit/test.rs diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 3ff79eaea49ab..50b71cb561f34 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -506,7 +506,18 @@ pub fn run_test( let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32"); if concurrency == Concurrent::Yes && supports_threads { let cfg = thread::Builder::new().name(name.as_slice().to_owned()); - Some(cfg.spawn(runtest).unwrap()) + let mut runtest = Arc::new(Mutex::new(Some(runtest))); + let runtest2 = runtest.clone(); + match cfg.spawn(move || runtest2.lock().unwrap().take().unwrap()()) { + Ok(handle) => Some(handle), + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + // `ErrorKind::WouldBlock` means hitting the thread limit on some + // platforms, so run the test synchronously here instead. + Arc::get_mut(&mut runtest).unwrap().get_mut().unwrap().take().unwrap()(); + None + } + Err(e) => panic!("failed to spawn thread to run test: {}", e), + } } else { runtest(); None diff --git a/src/test/run-make/libtest-thread-limit/Makefile b/src/test/run-make/libtest-thread-limit/Makefile new file mode 100644 index 0000000000000..29c1bc71d8704 --- /dev/null +++ b/src/test/run-make/libtest-thread-limit/Makefile @@ -0,0 +1,7 @@ +-include ../../run-make-fulldeps/tools.mk + +# only-linux + +all: + $(RUSTC) test.rs --test --target $(TARGET) + $(shell ulimit -p 0 && $(call RUN,test)) diff --git a/src/test/run-make/libtest-thread-limit/test.rs b/src/test/run-make/libtest-thread-limit/test.rs new file mode 100644 index 0000000000000..d899411a49ea0 --- /dev/null +++ b/src/test/run-make/libtest-thread-limit/test.rs @@ -0,0 +1,16 @@ +#![feature(once_cell)] + +use std::{io::ErrorKind, lazy::SyncOnceCell, thread::{self, Builder, ThreadId}}; + +static THREAD_ID: SyncOnceCell = SyncOnceCell::new(); + +#[test] +fn spawn_thread_would_block() { + assert_eq!(Builder::new().spawn(|| unreachable!()).unwrap_err().kind(), ErrorKind::WouldBlock); + THREAD_ID.set(thread::current().id()).unwrap(); +} + +#[test] +fn run_in_same_thread() { + assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id()); +} From 2a66685ebfdcd58a3c3fff0caeff6b13774543f5 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 17 Feb 2021 15:07:36 +0100 Subject: [PATCH 12/20] Make sure pdbs are copied along with exe and dlls when bootstrapping --- src/bootstrap/compile.rs | 6 ++++-- src/bootstrap/util.rs | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index dee0c15420136..7d5e3d05b11fa 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -27,7 +27,7 @@ use crate::config::TargetSelection; use crate::dist; use crate::native; use crate::tool::SourceType; -use crate::util::{exe, is_dylib, symlink_dir}; +use crate::util::{exe, is_debug_info, is_dylib, symlink_dir}; use crate::{Compiler, DependencyType, GitRepo, Mode}; #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] @@ -1049,7 +1049,8 @@ impl Step for Assemble { let src_libdir = builder.sysroot_libdir(build_compiler, host); for f in builder.read_dir(&src_libdir) { let filename = f.file_name().into_string().unwrap(); - if is_dylib(&filename) && !proc_macros.contains(&filename) { + if (is_dylib(&filename) || is_debug_info(&filename)) && !proc_macros.contains(&filename) + { builder.copy(&f.path(), &rustc_libdir.join(&filename)); } } @@ -1166,6 +1167,7 @@ pub fn run_cargo( if !(filename.ends_with(".rlib") || filename.ends_with(".lib") || filename.ends_with(".a") + || is_debug_info(&filename) || is_dylib(&filename) || (is_check && filename.ends_with(".rmeta"))) { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index b35d1b99fa5c7..b4421a82714fc 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -32,6 +32,12 @@ pub fn is_dylib(name: &str) -> bool { name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll") } +/// Returns `true` if the file name given looks like a debug info file +pub fn is_debug_info(name: &str) -> bool { + // FIXME: consider split debug info on other platforms (e.g., Linux, macOS) + name.ends_with(".pdb") +} + /// Returns the corresponding relative library directory that the compiler's /// dylibs will be found in. pub fn libdir(target: TargetSelection) -> &'static str { From 32c97da0f466ceff1512d62729c246a8e3951afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 16 Feb 2021 11:02:39 -0800 Subject: [PATCH 13/20] In some limited cases, suggest `where` bounds for non-type params Partially address #81971. --- compiler/rustc_middle/src/ty/diagnostics.rs | 30 +++++++++++++++++++ .../src/traits/error_reporting/suggestions.rs | 26 ++++++++++++++-- src/test/ui/partialeq_help.stderr | 4 +++ .../deafult-associated-type-bound-2.stderr | 4 +++ src/test/ui/suggestions/suggest-change-mut.rs | 2 +- .../ui/suggestions/suggest-change-mut.stderr | 4 +++ .../ui/traits/suggest-where-clause.stderr | 8 +++++ 7 files changed, 74 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 3b7dc25b6cf50..f41bb7e6d6350 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -75,6 +75,36 @@ impl<'tcx> TyS<'tcx> { } } +pub fn suggest_arbitrary_trait_bound( + generics: &hir::Generics<'_>, + err: &mut DiagnosticBuilder<'_>, + param_name: &str, + constraint: &str, +) -> bool { + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); + match (param, param_name) { + (Some(_), "Self") => return false, + _ => {} + } + // Suggest a where clause bound for a non-type paremeter. + let (action, prefix) = if generics.where_clause.predicates.is_empty() { + ("introducing a", " where ") + } else { + ("extending the", ", ") + }; + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &format!( + "consider {} `where` bound, but there might be an alternative better way to express \ + this requirement", + action, + ), + format!("{}{}: {}", prefix, param_name, constraint), + Applicability::MaybeIncorrect, + ); + true +} + /// Suggest restricting a type param with a new bound. pub fn suggest_constraining_type_param( tcx: TyCtxt<'_>, 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 9fd2f12100740..5c97791530d99 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -17,8 +17,8 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::{ - self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, - TyCtxt, TypeFoldable, WithConstness, + self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, + Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -334,7 +334,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let (param_ty, projection) = match self_ty.kind() { ty::Param(_) => (true, None), ty::Projection(projection) => (false, Some(projection)), - _ => return, + _ => (false, None), }; // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we @@ -453,6 +453,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Struct(_, generics) + | hir::ItemKind::Enum(_, generics) + | hir::ItemKind::Union(_, generics) + | hir::ItemKind::Trait(_, _, generics, ..) + | hir::ItemKind::Impl(hir::Impl { generics, .. }) + | hir::ItemKind::Fn(_, generics, _) + | hir::ItemKind::TyAlias(_, generics) + | hir::ItemKind::TraitAlias(generics, _) + | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), + .. + }) if !param_ty => { + // Missing generic type parameter bound. + let param_name = self_ty.to_string(); + let constraint = trait_ref.print_only_trait_path().to_string(); + if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) { + return; + } + } hir::Node::Crate(..) => return, _ => {} diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 6decbef1af4a2..e14e17c162233 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -5,6 +5,10 @@ LL | a == b; | ^^ no implementation for `&T == T` | = help: the trait `PartialEq` is not implemented for `&T` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn foo(a: &T, b: T) where &T: PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index 2bc14dbe3b2e7..0e8a774bce37f 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -18,6 +18,10 @@ LL | default type U = &'static B; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` | = help: the trait `PartialEq` is not implemented for `&'static B` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | impl X for T where &'static B: PartialEq { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/suggestions/suggest-change-mut.rs b/src/test/ui/suggestions/suggest-change-mut.rs index 8b465aae66b6e..a2bc6fd09b566 100644 --- a/src/test/ui/suggestions/suggest-change-mut.rs +++ b/src/test/ui/suggestions/suggest-change-mut.rs @@ -2,7 +2,7 @@ use std::io::{BufRead, BufReader, Read, Write}; -fn issue_81421(mut stream: T) { +fn issue_81421(mut stream: T) { //~ HELP consider introducing a `where` bound let initial_message = format!("Hello world"); let mut buffer: Vec = Vec::new(); let bytes_written = stream.write_all(initial_message.as_bytes()); diff --git a/src/test/ui/suggestions/suggest-change-mut.stderr b/src/test/ui/suggestions/suggest-change-mut.stderr index cb156f7c7877a..9b8181647a0c1 100644 --- a/src/test/ui/suggestions/suggest-change-mut.stderr +++ b/src/test/ui/suggestions/suggest-change-mut.stderr @@ -9,6 +9,10 @@ help: consider removing the leading `&`-reference | LL | let mut stream_reader = BufReader::new(stream); | -- +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn issue_81421(mut stream: T) where &T: std::io::Read { + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing this borrow's mutability | LL | let mut stream_reader = BufReader::new(&mut stream); diff --git a/src/test/ui/traits/suggest-where-clause.stderr b/src/test/ui/traits/suggest-where-clause.stderr index b50017afa4d63..86d589ffa9e31 100644 --- a/src/test/ui/traits/suggest-where-clause.stderr +++ b/src/test/ui/traits/suggest-where-clause.stderr @@ -35,6 +35,10 @@ LL | >::from; | ^^^^^^^^^^^^^^^^^^^^^^ the trait `From` is not implemented for `u64` | = note: required by `from` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn check() where u64: From { + | ^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `u64: From<::Item>` is not satisfied --> $DIR/suggest-where-clause.rs:18:5 @@ -43,6 +47,10 @@ LL | ::Item>>::from; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<::Item>` is not implemented for `u64` | = note: required by `from` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn check() where u64: From<::Item> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Misc<_>: From` is not satisfied --> $DIR/suggest-where-clause.rs:23:5 From ec50a2086a7263b24795f70cfefb3a83737599f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 17 Feb 2021 20:37:09 +0100 Subject: [PATCH 14/20] avoid converting types into themselves (clippy::useless_conversion) --- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/stmt.rs | 6 +++--- compiler/rustc_typeck/src/astconv/mod.rs | 1 - src/bootstrap/install.rs | 2 +- src/librustdoc/core.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 20430ece05b06..20398d3321db0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -513,7 +513,7 @@ impl<'a> Parser<'a> { token::Ident(..) if this.is_mistaken_not_ident_negation() => { make_it!(this, attrs, |this, _| this.recover_not_expr(lo)) } - _ => return this.parse_dot_or_call_expr(Some(attrs.into())), + _ => return this.parse_dot_or_call_expr(Some(attrs)), } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index e36ebd5e48113..9a236925eff43 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -97,7 +97,7 @@ impl<'a> Parser<'a> { self.mk_stmt(lo, StmtKind::Empty) } else if self.token != token::CloseDelim(token::Brace) { // Remainder are line-expr stmts. - let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; + let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?; self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)) } else { self.error_outer_attrs(&attrs.take_for_recovery()); @@ -131,7 +131,7 @@ impl<'a> Parser<'a> { }; let expr = this.with_res(Restrictions::STMT_EXPR, |this| { - let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; + let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; Ok(( @@ -213,7 +213,7 @@ impl<'a> Parser<'a> { } fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> { - let local = self.parse_local(attrs.into())?; + let local = self.parse_local(attrs)?; Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local))) } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2e1fb44d3b573..a132cda6fefe9 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1473,7 +1473,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }), assoc_name, ) - .into_iter() }, || param_name.to_string(), assoc_name, diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 22124ec67f5f3..b427420d57795 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -53,7 +53,7 @@ fn install_sh( } fn default_path(config: &Option, default: &str) -> PathBuf { - PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))) + config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)) } fn prepare_dir(mut path: PathBuf) -> String { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index d79c47bbe3de6..e20c84ba053f6 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -161,7 +161,7 @@ impl<'tcx> DocContext<'tcx> { } Entry::Occupied(e) => e.into_mut(), }; - *def_index = DefIndex::from(*def_index + 1); + *def_index = *def_index + 1; DefId { krate: crate_num, index: *def_index } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e2652ca378a81..b248fcdefbe7f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -182,7 +182,7 @@ fn from_clean_item_kind(item: clean::ItemKind, tcx: TyCtxt<'_>) -> ItemEnum { bounds: g.into_iter().map(Into::into).collect(), default: t.map(Into::into), }, - StrippedItem(inner) => from_clean_item_kind(*inner, tcx).into(), + StrippedItem(inner) => from_clean_item_kind(*inner, tcx), PrimitiveItem(_) | KeywordItem(_) => { panic!("{:?} is not supported for JSON output", item) } From 5ae392f3c6786d6aba065bcf94baedf5017a66c3 Mon Sep 17 00:00:00 2001 From: Jesus Rubio Date: Thu, 18 Feb 2021 06:53:01 +0100 Subject: [PATCH 15/20] Add long explanation for E0549 --- compiler/rustc_error_codes/src/error_codes.rs | 4 +- .../src/error_codes/E0549.md | 37 +++++++++++++++++++ .../stability-attribute-sanity.stderr | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0549.md diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 8944711f38f4f..c4330694504c3 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -290,6 +290,7 @@ E0543: include_str!("./error_codes/E0543.md"), E0545: include_str!("./error_codes/E0545.md"), E0546: include_str!("./error_codes/E0546.md"), E0547: include_str!("./error_codes/E0547.md"), +E0549: include_str!("./error_codes/E0549.md"), E0550: include_str!("./error_codes/E0550.md"), E0551: include_str!("./error_codes/E0551.md"), E0552: include_str!("./error_codes/E0552.md"), @@ -608,9 +609,6 @@ E0781: include_str!("./error_codes/E0781.md"), // E0540, // multiple rustc_deprecated attributes E0544, // multiple stability levels // E0548, // replaced with a generic attribute input check - // rustc_deprecated attribute must be paired with either stable or unstable - // attribute - E0549, E0553, // multiple rustc_const_unstable attributes // E0555, // replaced with a generic attribute input check // E0558, // replaced with a generic attribute input check diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md new file mode 100644 index 0000000000000..a5728dc20c8b8 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0549.md @@ -0,0 +1,37 @@ +The `rustc_deprecated` attribute must be paired with either `stable` or +`unstable`. + +Erroneous code example: + +```compile_fail,E0549 +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[rustc_deprecated( + since = "1.0.1", + reason = "explanation for deprecation" +)] // invalid +fn _deprecated_fn() {} +``` + +To fix this issue, you need to add also an attribute `stable` or `unstable`. +Example: + +``` +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "test")] + +#[stable(since = "1.0.0", feature = "test")] +#[rustc_deprecated( + since = "1.0.1", + reason = "explanation for deprecation" +)] // ok! +fn _deprecated_fn() {} +``` + +See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix +of the Book and the [Stability attributes][stability-attributes] section of the +Rustc Dev Guide for more details. + +[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html +[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 715eb00974ee2..03fb80bb90abc 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -116,5 +116,5 @@ LL | #[rustc_deprecated(since = "a", reason = "text")] error: aborting due to 19 previous errors -Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0550. +Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0546, E0547, E0549, E0550. For more information about an error, try `rustc --explain E0539`. From 5112cf0282e339af3e2f3bbe872fd32dfd69df56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rubio?= Date: Thu, 18 Feb 2021 09:23:21 +0100 Subject: [PATCH 16/20] Update compiler/rustc_error_codes/src/error_codes/E0549.md Co-authored-by: Guillaume Gomez --- compiler/rustc_error_codes/src/error_codes/E0549.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md index a5728dc20c8b8..0ae7b0a377fbc 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0549.md +++ b/compiler/rustc_error_codes/src/error_codes/E0549.md @@ -1,5 +1,5 @@ -The `rustc_deprecated` attribute must be paired with either `stable` or -`unstable`. +A `rustc_deprecated` attribute wasn't be paired with a `stable`/`unstable` +attribute. Erroneous code example: From 0e01c41c02d7d8ec4217e5ca9fa55281accd99a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rubio?= Date: Thu, 18 Feb 2021 09:38:42 +0100 Subject: [PATCH 17/20] Update compiler/rustc_error_codes/src/error_codes/E0549.md Co-authored-by: Guillaume Gomez --- compiler/rustc_error_codes/src/error_codes/E0549.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md index 0ae7b0a377fbc..3337b0964faeb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0549.md +++ b/compiler/rustc_error_codes/src/error_codes/E0549.md @@ -1,4 +1,4 @@ -A `rustc_deprecated` attribute wasn't be paired with a `stable`/`unstable` +A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable` attribute. Erroneous code example: From 3c4fe1e3dbc1f060d10c2dc974d2c496db4ed74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rubio?= Date: Thu, 18 Feb 2021 10:03:01 +0100 Subject: [PATCH 18/20] Update compiler/rustc_error_codes/src/error_codes/E0549.md Co-authored-by: Guillaume Gomez --- compiler/rustc_error_codes/src/error_codes/E0549.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md index 3337b0964faeb..d4b78e7e0d668 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0549.md +++ b/compiler/rustc_error_codes/src/error_codes/E0549.md @@ -1,5 +1,5 @@ A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable` -attribute. +attribute. Erroneous code example: From 6165d1cc72f8af55b3ef16ad81273b80876f9518 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 18 Feb 2021 14:13:38 +0200 Subject: [PATCH 19/20] Print -Ztime-passes (and misc stats/logs) on stderr, not stdout. --- .../rustc_data_structures/src/profiling.rs | 2 +- .../src/persist/file_format.rs | 2 +- compiler/rustc_incremental/src/persist/fs.rs | 4 +-- .../rustc_incremental/src/persist/load.rs | 2 +- compiler/rustc_interface/src/passes.rs | 6 ++-- compiler/rustc_metadata/src/rmeta/encoder.rs | 34 +++++++++---------- compiler/rustc_middle/src/ty/query/stats.rs | 22 ++++++------ .../rustc_mir/src/transform/coverage/tests.rs | 6 ++-- compiler/rustc_passes/src/hir_stats.rs | 12 +++---- .../rustc_query_system/src/dep_graph/graph.rs | 28 +++++++-------- compiler/rustc_session/src/session.rs | 8 ++--- compiler/rustc_span/src/source_map/tests.rs | 2 +- 12 files changed, 64 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index f0b413c795e9c..51f851dc9469f 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -608,7 +608,7 @@ pub fn print_time_passes_entry( (None, None) => String::new(), }; - println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what); + eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what); } // Hack up our own formatting for the duration to make it easier for scripts diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 087f83c24754a..374a9eb41e5c7 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -109,7 +109,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & debug!("read_file: {}", message); if report_incremental_info { - println!( + eprintln!( "[incremental] ignoring cache artifact `{}`: {}", file.file_name().unwrap().to_string_lossy(), message diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 7a1976bed4b3b..c7a6c1195c503 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -440,12 +440,12 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result DepGraphFuture { if prev_commandline_args_hash != expected_hash { if report_incremental_info { - println!( + eprintln!( "[incremental] completely ignoring cache because of \ differing commandline arguments" ); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 544da4cd9aa7d..ed5061125ba9e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -64,8 +64,8 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { } if sess.opts.debugging_opts.input_stats { - println!("Lines of code: {}", sess.source_map().count_lines()); - println!("Pre-expansion node count: {}", count_nodes(&krate)); + eprintln!("Lines of code: {}", sess.source_map().count_lines()); + eprintln!("Pre-expansion node count: {}", count_nodes(&krate)); } if let Some(ref s) = sess.opts.debugging_opts.show_span { @@ -394,7 +394,7 @@ fn configure_and_expand_inner<'a>( // Done with macro expansion! if sess.opts.debugging_opts.input_stats { - println!("Post-expansion node count: {}", count_nodes(&krate)); + eprintln!("Post-expansion node count: {}", count_nodes(&krate)); } if sess.opts.debugging_opts.hir_stats { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3314385dbf0a3..61265d7204c0b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -695,23 +695,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - println!("metadata stats:"); - println!(" dep bytes: {}", dep_bytes); - println!(" lib feature bytes: {}", lib_feature_bytes); - println!(" lang item bytes: {}", lang_item_bytes); - println!(" diagnostic item bytes: {}", diagnostic_item_bytes); - println!(" native bytes: {}", native_lib_bytes); - println!(" source_map bytes: {}", source_map_bytes); - println!(" impl bytes: {}", impl_bytes); - println!(" exp. symbols bytes: {}", exported_symbols_bytes); - println!(" def-path table bytes: {}", def_path_table_bytes); - println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes); - println!(" mir bytes: {}", mir_bytes); - println!(" item bytes: {}", item_bytes); - println!(" table bytes: {}", tables_bytes); - println!(" hygiene bytes: {}", hygiene_bytes); - println!(" zero bytes: {}", zero_bytes); - println!(" total bytes: {}", total_bytes); + eprintln!("metadata stats:"); + eprintln!(" dep bytes: {}", dep_bytes); + eprintln!(" lib feature bytes: {}", lib_feature_bytes); + eprintln!(" lang item bytes: {}", lang_item_bytes); + eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes); + eprintln!(" native bytes: {}", native_lib_bytes); + eprintln!(" source_map bytes: {}", source_map_bytes); + eprintln!(" impl bytes: {}", impl_bytes); + eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes); + eprintln!(" def-path table bytes: {}", def_path_table_bytes); + eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes); + eprintln!(" mir bytes: {}", mir_bytes); + eprintln!(" item bytes: {}", item_bytes); + eprintln!(" table bytes: {}", tables_bytes); + eprintln!(" hygiene bytes: {}", hygiene_bytes); + eprintln!(" zero bytes: {}", zero_bytes); + eprintln!(" total bytes: {}", total_bytes); } root diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs index c885a10f80595..29ec9c132a89c 100644 --- a/compiler/rustc_middle/src/ty/query/stats.rs +++ b/compiler/rustc_middle/src/ty/query/stats.rs @@ -67,29 +67,29 @@ pub fn print_stats(tcx: TyCtxt<'_>) { if cfg!(debug_assertions) { let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); let results: usize = queries.iter().map(|s| s.entry_count).sum(); - println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); + eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); } let mut query_key_sizes = queries.clone(); query_key_sizes.sort_by_key(|q| q.key_size); - println!("\nLarge query keys:"); + eprintln!("\nLarge query keys:"); for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) { - println!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type); + eprintln!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type); } let mut query_value_sizes = queries.clone(); query_value_sizes.sort_by_key(|q| q.value_size); - println!("\nLarge query values:"); + eprintln!("\nLarge query values:"); for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) { - println!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); + eprintln!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); } if cfg!(debug_assertions) { let mut query_cache_hits = queries.clone(); query_cache_hits.sort_by_key(|q| q.cache_hits); - println!("\nQuery cache hits:"); + eprintln!("\nQuery cache hits:"); for q in query_cache_hits.iter().rev() { - println!( + eprintln!( " {} - {} ({}%)", q.name, q.cache_hits, @@ -100,19 +100,19 @@ pub fn print_stats(tcx: TyCtxt<'_>) { let mut query_value_count = queries.clone(); query_value_count.sort_by_key(|q| q.entry_count); - println!("\nQuery value count:"); + eprintln!("\nQuery value count:"); for q in query_value_count.iter().rev() { - println!(" {} - {}", q.name, q.entry_count); + eprintln!(" {} - {}", q.name, q.entry_count); } let mut def_id_density: Vec<_> = queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect(); def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap()); - println!("\nLocal DefId density:"); + eprintln!("\nLocal DefId density:"); let total = tcx.hir().definitions().def_index_count() as f64; for q in def_id_density.iter().rev() { let local = q.local_def_id_keys.unwrap(); - println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total); + eprintln!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total); } } diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs index d36f1b8e5f670..7a9bfaad88367 100644 --- a/compiler/rustc_mir/src/transform/coverage/tests.rs +++ b/compiler/rustc_mir/src/transform/coverage/tests.rs @@ -327,7 +327,7 @@ macro_rules! assert_successors { fn test_covgraph_goto_switchint() { let mir_body = goto_switchint(); if false { - println!("basic_blocks = {}", debug_basic_blocks(&mir_body)); + eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body)); } let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks); @@ -583,11 +583,11 @@ fn test_find_loop_backedges_none() { let mir_body = goto_switchint(); let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); if false { - println!( + eprintln!( "basic_coverage_blocks = {:?}", basic_coverage_blocks.iter_enumerated().collect::>() ); - println!("successors = {:?}", basic_coverage_blocks.successors); + eprintln!("successors = {:?}", basic_coverage_blocks.successors); } let backedges = graph::find_loop_backedges(&basic_coverage_blocks); assert_eq!( diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e35ad10968d33..8d5a5bdf6b712 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -66,13 +66,13 @@ impl<'k> StatCollector<'k> { let mut total_size = 0; - println!("\n{}\n", title); + eprintln!("\n{}\n", title); - println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size"); - println!("----------------------------------------------------------------"); + eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size"); + eprintln!("----------------------------------------------------------------"); for (label, data) in stats { - println!( + eprintln!( "{:<18}{:>18}{:>14}{:>14}", label, to_readable_str(data.count * data.size), @@ -82,8 +82,8 @@ impl<'k> StatCollector<'k> { total_size += data.count * data.size; } - println!("----------------------------------------------------------------"); - println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size)); + eprintln!("----------------------------------------------------------------"); + eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size)); } } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 4fb3a683ea225..b13aa2f6ccbac 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -964,29 +964,29 @@ impl DepGraph { ----------------------------------------------\ ------------"; - println!("[incremental]"); - println!("[incremental] DepGraph Statistics"); - println!("{}", SEPARATOR); - println!("[incremental]"); - println!("[incremental] Total Node Count: {}", total_node_count); - println!("[incremental] Total Edge Count: {}", total_edge_count); + eprintln!("[incremental]"); + eprintln!("[incremental] DepGraph Statistics"); + eprintln!("{}", SEPARATOR); + eprintln!("[incremental]"); + eprintln!("[incremental] Total Node Count: {}", total_node_count); + eprintln!("[incremental] Total Edge Count: {}", total_edge_count); if cfg!(debug_assertions) { let total_edge_reads = current.total_read_count.load(Relaxed); let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed); - println!("[incremental] Total Edge Reads: {}", total_edge_reads); - println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads); + eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads); + eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads); } - println!("[incremental]"); + eprintln!("[incremental]"); - println!( + eprintln!( "[incremental] {:<36}| {:<17}| {:<12}| {:<17}|", "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count" ); - println!( + eprintln!( "[incremental] -------------------------------------\ |------------------\ |-------------\ @@ -997,7 +997,7 @@ impl DepGraph { let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64); let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64); - println!( + eprintln!( "[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |", format!("{:?}", stat.kind), node_kind_ratio, @@ -1006,8 +1006,8 @@ impl DepGraph { ); } - println!("{}", SEPARATOR); - println!("[incremental]"); + eprintln!("{}", SEPARATOR); + eprintln!("[incremental]"); } fn next_virtual_depnode_index(&self) -> DepNodeIndex { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a7ceb9e06a519..823aa61c4705d 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -959,19 +959,19 @@ impl Session { } pub fn print_perf_stats(&self) { - println!( + eprintln!( "Total time spent computing symbol hashes: {}", duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock()) ); - println!( + eprintln!( "Total queries canonicalized: {}", self.perf_stats.queries_canonicalized.load(Ordering::Relaxed) ); - println!( + eprintln!( "normalize_generic_arg_after_erasing_regions: {}", self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed) ); - println!( + eprintln!( "normalize_projection_ty: {}", self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed) ); diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 3f22829b049fe..0aca677248b72 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -243,7 +243,7 @@ impl SourceMapExtension for SourceMap { substring: &str, n: usize, ) -> Span { - println!( + eprintln!( "span_substr(file={:?}/{:?}, substring={:?}, n={})", file.name, file.start_pos, substring, n ); From 8a5c5681da3695e1c2e3f23bee43a7ebfdce6161 Mon Sep 17 00:00:00 2001 From: Nathan Nguyen Date: Wed, 17 Feb 2021 23:44:37 -0600 Subject: [PATCH 20/20] nhwn: optimize counting digits in line numbers --- compiler/rustc_errors/src/emitter.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index ea62e21523028..42c3d5e48fe86 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1713,7 +1713,18 @@ impl EmitterWriter { let max_line_num_len = if self.ui_testing { ANONYMIZED_LINE_NUM.len() } else { - self.get_max_line_num(span, children).to_string().len() + // Instead of using .to_string().len(), we iteratively count the + // number of digits to avoid allocation. This strategy has sizable + // performance gains over the old string strategy. + let mut n = self.get_max_line_num(span, children); + let mut num_digits = 0; + loop { + num_digits += 1; + n /= 10; + if n == 0 { + break num_digits; + } + } }; match self.emit_message_default(span, message, code, level, max_line_num_len, false) {