Rollup merge of #109367 - nnethercote:opt-fast-rejection, r=compiler-errors
Streamline fast rejection Some reworkings of this code that make it a little nicer. r? `@lcnr`
This commit is contained in:
commit
ba2164306a
6 changed files with 29 additions and 44 deletions
|
@ -1,6 +1,6 @@
|
|||
use crate::mir::Mutability;
|
||||
use crate::ty::subst::GenericArgKind;
|
||||
use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
@ -188,22 +188,24 @@ pub struct DeepRejectCtxt {
|
|||
}
|
||||
|
||||
impl DeepRejectCtxt {
|
||||
pub fn generic_args_may_unify<'tcx>(
|
||||
pub fn substs_refs_may_unify<'tcx>(
|
||||
self,
|
||||
obligation_arg: ty::GenericArg<'tcx>,
|
||||
impl_arg: ty::GenericArg<'tcx>,
|
||||
obligation_substs: SubstsRef<'tcx>,
|
||||
impl_substs: SubstsRef<'tcx>,
|
||||
) -> bool {
|
||||
match (obligation_arg.unpack(), impl_arg.unpack()) {
|
||||
// We don't fast reject based on regions for now.
|
||||
(GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
|
||||
(GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
|
||||
self.types_may_unify(obl, imp)
|
||||
iter::zip(obligation_substs, impl_substs).all(|(obl, imp)| {
|
||||
match (obl.unpack(), imp.unpack()) {
|
||||
// We don't fast reject based on regions for now.
|
||||
(GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true,
|
||||
(GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => {
|
||||
self.types_may_unify(obl, imp)
|
||||
}
|
||||
(GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
|
||||
self.consts_may_unify(obl, imp)
|
||||
}
|
||||
_ => bug!("kind mismatch: {obl} {imp}"),
|
||||
}
|
||||
(GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => {
|
||||
self.consts_may_unify(obl, imp)
|
||||
}
|
||||
_ => bug!("kind mismatch: {obligation_arg} {impl_arg}"),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool {
|
||||
|
@ -258,9 +260,7 @@ impl DeepRejectCtxt {
|
|||
},
|
||||
ty::Adt(obl_def, obl_substs) => match k {
|
||||
&ty::Adt(impl_def, impl_substs) => {
|
||||
obl_def == impl_def
|
||||
&& iter::zip(obl_substs, impl_substs)
|
||||
.all(|(obl, imp)| self.generic_args_may_unify(obl, imp))
|
||||
obl_def == impl_def && self.substs_refs_may_unify(obl_substs, impl_substs)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
|
|
|
@ -17,7 +17,6 @@ use rustc_middle::ty::ProjectionPredicate;
|
|||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
|
||||
use rustc_span::{sym, DUMMY_SP};
|
||||
use std::iter;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
|
@ -144,9 +143,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
if iter::zip(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs)
|
||||
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
|
||||
{
|
||||
if !drcx.substs_refs_may_unify(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use super::{assembly, EvalCtxt, SolverMode};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
|
@ -41,9 +39,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
if iter::zip(goal.predicate.trait_ref.substs, impl_trait_ref.skip_binder().substs)
|
||||
.any(|(goal, imp)| !drcx.generic_args_may_unify(goal, imp))
|
||||
{
|
||||
if !drcx.substs_refs_may_unify(
|
||||
goal.predicate.trait_ref.substs,
|
||||
impl_trait_ref.skip_binder().substs,
|
||||
) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
|
|
|
@ -79,8 +79,9 @@ pub fn overlapping_impls(
|
|||
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
|
||||
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
|
||||
let may_overlap = match (impl1_ref, impl2_ref) {
|
||||
(Some(a), Some(b)) => iter::zip(a.skip_binder().substs, b.skip_binder().substs)
|
||||
.all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
|
||||
(Some(a), Some(b)) => {
|
||||
drcx.substs_refs_may_unify(a.skip_binder().substs, b.skip_binder().substs)
|
||||
}
|
||||
(None, None) => {
|
||||
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
|
||||
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();
|
||||
|
|
|
@ -11,7 +11,7 @@ use hir::LangItem;
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
|
||||
use rustc_middle::ty::fast_reject::TreatProjections;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
|
||||
use crate::traits;
|
||||
|
@ -344,6 +344,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
let obligation_substs = obligation.predicate.skip_binder().trait_ref.substs;
|
||||
self.tcx().for_each_relevant_impl(
|
||||
obligation.predicate.def_id(),
|
||||
obligation.predicate.skip_binder().trait_ref.self_ty(),
|
||||
|
@ -352,7 +354,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// consider a "quick reject". This avoids creating more types
|
||||
// and so forth that we need to.
|
||||
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
|
||||
if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
|
||||
if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) {
|
||||
return;
|
||||
}
|
||||
if self.reject_fn_ptr_impls(
|
||||
|
|
|
@ -45,7 +45,6 @@ use rustc_infer::traits::TraitEngineExt;
|
|||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::SubstsRef;
|
||||
|
@ -2533,19 +2532,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||
Ok(Normalized { value: impl_substs, obligations: nested_obligations })
|
||||
}
|
||||
|
||||
fn fast_reject_trait_refs(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
impl_trait_ref: &ty::TraitRef<'tcx>,
|
||||
) -> bool {
|
||||
// We can avoid creating type variables and doing the full
|
||||
// substitution if we find that any of the input types, when
|
||||
// simplified, do not match.
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs)
|
||||
.any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp))
|
||||
}
|
||||
|
||||
/// Normalize `where_clause_trait_ref` and try to match it against
|
||||
/// `obligation`. If successful, return any predicates that
|
||||
/// result from the normalization.
|
||||
|
|
Loading…
Add table
Reference in a new issue