From a4f6770d83cb5aa82f10d8e8441ca5708600b077 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 29 Sep 2023 11:34:50 +0200 Subject: [PATCH 1/2] a small wf and clause cleanup --- .../src/check/compare_impl_item.rs | 9 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 14 ++--- compiler/rustc_middle/src/ty/mod.rs | 25 ++++++--- compiler/rustc_middle/src/ty/sty.rs | 2 +- .../src/solve/project_goals.rs | 9 ++-- .../src/traits/project.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 52 ++++++++----------- compiler/rustc_ty_utils/src/ty.rs | 9 ++-- 8 files changed, 58 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d081b0e35c666..b5a3437c992cd 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -16,6 +16,7 @@ use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -2279,16 +2280,16 @@ pub(super) fn check_type_bounds<'tcx>( // // impl X for T where T: X { type Y = ::Y; } } - _ => predicates.push(ty::Clause::from_projection_clause( - tcx, + _ => predicates.push( ty::Binder::bind_with_vars( ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args), term: normalize_impl_ty.into(), }, bound_vars, - ), - )), + ) + .to_predicate(tcx), + ), }; ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing) }; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b7b162ce27bc8..a3dc6a857c242 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1105,11 +1105,11 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt let wf_obligations = bounds.instantiate_identity_iter_copied().flat_map(|(bound, bound_span)| { let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( + traits::wf::clause_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - normalized_bound.as_predicate(), + normalized_bound, bound_span, ) }); @@ -1209,7 +1209,7 @@ fn check_impl<'tcx>( wfcx.infcx, wfcx.param_env, wfcx.body_def_id, - &trait_pred, + trait_pred, ast_trait_ref.path.span, item, ); @@ -1418,13 +1418,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = predicates.into_iter().flat_map(|(p, sp)| { - traits::wf::predicate_obligations( - infcx, - wfcx.param_env, - wfcx.body_def_id, - p.as_predicate(), - sp, - ) + traits::wf::clause_obligations(infcx, wfcx.param_env, wfcx.body_def_id, p, sp) }); let obligations: Vec<_> = wf_obligations.chain(default_obligations).collect(); wfcx.register_obligations(obligations); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index aa1e7f216a069..783963589692c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -578,11 +578,6 @@ impl rustc_errors::IntoDiagnosticArg for Clause<'_> { pub struct Clause<'tcx>(Interned<'tcx, WithCachedTypeInfo>>>); impl<'tcx> Clause<'tcx> { - pub fn from_projection_clause(tcx: TyCtxt<'tcx>, pred: PolyProjectionPredicate<'tcx>) -> Self { - let pred: Predicate<'tcx> = pred.to_predicate(tcx); - pred.expect_clause() - } - pub fn as_predicate(self) -> Predicate<'tcx> { Predicate(self.0) } @@ -1296,12 +1291,25 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef } } +impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx) } } +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { let p: Predicate<'tcx> = self.to_predicate(tcx); @@ -1340,9 +1348,10 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> { } } -impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx) +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1e57392e0e7d9..e5f418bbb4b11 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -725,7 +725,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> { self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx) } ExistentialPredicate::Projection(p) => { - ty::Clause::from_projection_clause(tcx, self.rebind(p.with_self_ty(tcx, self_ty))) + self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) } ExistentialPredicate::AutoTrait(did) => { let generics = tcx.generics_of(did); diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 0f9d36342ad25..339a3e738467c 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -346,14 +346,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) }); - let pred = ty::Clause::from_projection_clause( - tcx, - tupled_inputs_and_output.map_bound(|(inputs, output)| ty::ProjectionPredicate { + let pred = tupled_inputs_and_output + .map_bound(|(inputs, output)| ty::ProjectionPredicate { projection_ty: tcx .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), term: output.into(), - }), - ); + }) + .to_predicate(tcx); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 154cc7a71416e..73c2ff3c53661 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1644,7 +1644,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( let env_predicates = data .projection_bounds() .filter(|bound| bound.item_def_id() == obligation.predicate.def_id) - .map(|p| ty::Clause::from_projection_clause(tcx, p.with_self_ty(tcx, object_ty))); + .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx)); assemble_candidates_from_predicates( selcx, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b04008d9ee561..060df7726138b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -105,13 +105,13 @@ pub fn unnormalized_obligations<'tcx>( /// Returns the obligations that make this trait reference /// well-formed. For example, if there is a trait `Set` defined like -/// `trait Set`, then the trait reference `Foo: Set` is WF +/// `trait Set`, then the trait bound `Foo: Set` is WF /// if `Bar: Eq`. pub fn trait_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, - trait_pred: &ty::TraitPredicate<'tcx>, + trait_pred: ty::TraitPredicate<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, ) -> Vec> { @@ -129,12 +129,17 @@ pub fn trait_obligations<'tcx>( wf.normalize(infcx) } +/// Returns the requirements for `clause` to be well-formed. +/// +/// For example, if there is a trait `Set` defined like +/// `trait Set`, then the trait bound `Foo: Set` is WF +/// if `Bar: Eq`. #[instrument(skip(infcx), ret)] -pub fn predicate_obligations<'tcx>( +pub fn clause_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, - predicate: ty::Predicate<'tcx>, + clause: ty::Clause<'tcx>, span: Span, ) -> Vec> { let mut wf = WfPredicates { @@ -148,45 +153,32 @@ pub fn predicate_obligations<'tcx>( }; // It's ok to skip the binder here because wf code is prepared for it - match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => { - wf.compute_trait_pred(&t, Elaborate::None); + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(t) => { + wf.compute_trait_pred(t, Elaborate::None); } - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {} - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - ty, - _reg, - ))) => { + ty::ClauseKind::RegionOutlives(..) => {} + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { wf.compute(ty.into()); } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(t)) => { + ty::ClauseKind::Projection(t) => { wf.compute_projection(t.projection_ty); wf.compute(match t.term.unpack() { ty::TermKind::Ty(ty) => ty.into(), ty::TermKind::Const(c) => c.into(), }) } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { + ty::ClauseKind::ConstArgHasType(ct, ty) => { wf.compute(ct.into()); wf.compute(ty.into()); } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + ty::ClauseKind::WellFormed(arg) => { wf.compute(arg); } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { + ty::ClauseKind::ConstEvaluatable(ct) => { wf.compute(ct.into()); } - - ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) => { - bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}") - } } wf.normalize(infcx) @@ -233,7 +225,7 @@ enum Elaborate { fn extend_cause_with_original_assoc_item_obligation<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, item: Option<&hir::Item<'tcx>>, cause: &mut traits::ObligationCause<'tcx>, pred: ty::Predicate<'tcx>, @@ -336,9 +328,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) { + fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) { let tcx = self.tcx(); - let trait_ref = &trait_pred.trait_ref; + let trait_ref = trait_pred.trait_ref; // Negative trait predicates don't require supertraits to hold, just // that their args are WF. @@ -411,7 +403,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // Compute the obligations that are required for `trait_ref` to be WF, // given that it is a *negative* trait predicate. - fn compute_negative_trait_pred(&mut self, trait_ref: &ty::TraitRef<'tcx>) { + fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) { for arg in trait_ref.args { self.compute(arg); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 4234e69e8546e..c22c67bd90750 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -3,9 +3,8 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; use rustc_middle::query::Providers; -use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, -}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable}; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; @@ -214,10 +213,10 @@ impl<'tcx> TypeVisitor> for ImplTraitInTraitFinder<'_, 'tcx> { // strategy, then just reinterpret the associated type like an opaque :^) let default_ty = self.tcx.type_of(shifted_alias_ty.def_id).instantiate(self.tcx, shifted_alias_ty.args); - self.predicates.push(ty::Clause::from_projection_clause(self.tcx, ty::Binder::bind_with_vars( + self.predicates.push(ty::Binder::bind_with_vars( ty::ProjectionPredicate { projection_ty: shifted_alias_ty, term: default_ty.into() }, self.bound_vars, - ))); + ).to_predicate(self.tcx)); // We walk the *un-shifted* alias ty, because we're tracking the de bruijn // binder depth, and if we were to walk `shifted_alias_ty` instead, we'd From aac29a0fc3b9ab7d3784a7d5b637cf51a01b0469 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 29 Sep 2023 11:47:42 +0200 Subject: [PATCH 2/2] specialization: use clause --- .../src/impl_wf_check/min_specialization.rs | 60 +++++++------------ 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 3760195a5e8ec..dbd38e1b1fe72 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -376,9 +376,9 @@ fn check_predicates<'tcx>( let always_applicable_traits = impl1_predicates .iter() .copied() - .filter(|(clause, _span)| { + .filter(|&(clause, _span)| { matches!( - trait_predicate_kind(tcx, clause.as_predicate()), + trait_specialization_kind(tcx, clause), Some(TraitSpecializationKind::AlwaysApplicable) ) }) @@ -402,7 +402,7 @@ fn check_predicates<'tcx>( .iter() .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) { - check_specialization_on(tcx, clause.as_predicate(), span) + check_specialization_on(tcx, clause, span) } } } @@ -441,19 +441,16 @@ fn trait_predicates_eq<'tcx>( } #[instrument(level = "debug", skip(tcx))] -fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) { - match predicate.kind().skip_binder() { +fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, span: Span) { + match clause.kind().skip_binder() { // Global predicates are either always true or always false, so we // are fine to specialize on. - _ if predicate.is_global() => (), + _ if clause.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: _, - })) => { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { if !matches!( - trait_predicate_kind(tcx, predicate), + trait_specialization_kind(tcx, clause), Some(TraitSpecializationKind::Marker) ) { tcx.sess @@ -467,10 +464,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc .emit(); } } - ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_ty, - term, - })) => { + ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { tcx.sess .struct_span_err( span, @@ -478,7 +472,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc ) .emit(); } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => { + ty::ClauseKind::ConstArgHasType(..) => { // FIXME(min_specialization), FIXME(const_generics): // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure // about the actual rules that would be sound. Can't just always error here because otherwise @@ -490,33 +484,25 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc } _ => { tcx.sess - .struct_span_err(span, format!("cannot specialize on predicate `{predicate}`")) + .struct_span_err(span, format!("cannot specialize on predicate `{clause}`")) .emit(); } } } -fn trait_predicate_kind<'tcx>( +fn trait_specialization_kind<'tcx>( tcx: TyCtxt<'tcx>, - predicate: ty::Predicate<'tcx>, + clause: ty::Clause<'tcx>, ) -> Option { - match predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate { - trait_ref, - polarity: _, - })) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind), - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous => None, + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => { + Some(tcx.trait_def(trait_ref.def_id).specialization_kind) + } + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::TypeOutlives(_) + | ty::ClauseKind::Projection(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(..) => None, } }