remove some trait solver helpers

they add more complexity then they are worth. It's confusing
which of these helpers should be used in which context.
This commit is contained in:
lcnr 2023-03-14 14:19:06 +01:00
parent 84c47b8279
commit 791ce0b7b5
31 changed files with 199 additions and 289 deletions

View file

@ -8,26 +8,16 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes
use rustc_middle::traits::query::Fallible;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, ToPredicate};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::DUMMY_SP;
use std::fmt::Debug;
pub use rustc_infer::infer::*;
pub trait InferCtxtExt<'tcx> {
fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
fn type_is_sized_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool;
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
/// Check whether a `ty` implements given trait(trait_def_id).
/// The inputs are:
@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult;
}
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
if !(param_env, ty).needs_infer() {
@ -65,17 +51,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
}
fn type_is_sized_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
}
#[instrument(level = "debug", skip(self, params), ret)]

View file

@ -180,8 +180,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// At this point, we already have all of the bounds we need. FulfillmentContext is used
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
// an additional sanity check.
let errors =
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}

View file

@ -383,7 +383,10 @@ fn resolve_negative_obligation<'tcx>(
};
let param_env = o.param_env;
if !super::fully_solve_obligation(&infcx, o).is_empty() {
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligation(o);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
return false;
}

View file

@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_span::def_id::{DefId, CRATE_DEF_ID};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use std::fmt::Debug;
@ -63,9 +63,7 @@ pub use self::util::{
elaborate_trait_ref, elaborate_trait_refs,
};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{
get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
};
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
pub use self::util::{
supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
SupertraitDefIds, Supertraits,
@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span,
) -> bool {
let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty]));
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span)
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
}
#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)]
/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
///
/// Ping me on zulip if you want to use this method and need help with finding
/// an appropriate replacement.
#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
fn pred_known_to_hold_modulo_regions<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
span: Span,
) -> bool {
let has_non_region_infer = pred.has_non_region_infer();
let obligation = Obligation {
param_env,
// We can use a dummy node-id here because we won't pay any mind
// to region obligations that arise (there shouldn't really be any
// anyhow).
cause: ObligationCause::misc(span, CRATE_DEF_ID),
recursion_depth: 0,
predicate: pred.to_predicate(infcx.tcx),
};
let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
let result = infcx.evaluate_obligation_no_overflow(&obligation);
debug!(?result);
@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
// this function's result remains infallible, we must confirm
// that guess. While imperfect, I believe this is sound.
// FIXME(@lcnr): this function doesn't seem right.
//
// The handling of regions in this area of the code is terrible,
// see issue #29149. We should be able to improve on this with
// NLL.
let errors = fully_solve_obligation(infcx, obligation);
match &errors[..] {
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
match errors.as_slice() {
[] => true,
errors => {
debug!(?errors);
@ -389,43 +380,6 @@ where
Ok(resolved_value)
}
/// Process an obligation (and any nested obligations that come from it) to
/// completion, returning any errors
pub fn fully_solve_obligation<'tcx>(
infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
fully_solve_obligations(infcx, [obligation])
}
/// Process a set of obligations (and any nested obligations that come from them)
/// to completion
pub fn fully_solve_obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) -> Vec<FulfillmentError<'tcx>> {
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligations(obligations);
ocx.select_all_or_error()
}
/// Process a bound (and any nested obligations that come from it) to completion.
/// This is a convenience function for traits that have no generic arguments, such
/// as auto traits, and builtin traits like Copy or Sized.
pub fn fully_solve_bound<'tcx>(
infcx: &InferCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
bound: DefId,
) -> Vec<FulfillmentError<'tcx>> {
let tcx = infcx.tcx;
let trait_ref = tcx.mk_trait_ref(bound, [ty]);
let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
fully_solve_obligation(infcx, obligation)
}
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
/// returns true, then either normalize encountered an error or one of the predicates did not
/// hold. Used when creating vtables to check for unsatisfiable methods.

View file

@ -1,7 +1,7 @@
use crate::infer::InferCtxt;
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution;
use crate::traits::ObligationCause;
use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::{self, ParamEnv, Ty};
use rustc_span::def_id::LocalDefId;
@ -71,22 +71,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
if let Some(constraints) = constraints {
debug!(?constraints);
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
let cause = ObligationCause::misc(span, body_id);
let errors = super::fully_solve_obligations(
self,
constraints.outlives.iter().map(|constraint| {
self.query_outlives_constraint_to_obligation(
*constraint,
cause.clone(),
param_env,
)
}),
);
if !constraints.member_constraints.is_empty() {
span_bug!(span, "{:#?}", constraints.member_constraints);
}
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
let ocx = ObligationCtxt::new(self);
let cause = ObligationCause::misc(span, body_id);
for &constraint in &constraints.outlives {
ocx.register_obligation(self.query_outlives_constraint_to_obligation(
constraint,
cause.clone(),
param_env,
));
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,

View file

@ -1,8 +1,8 @@
use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk};
use crate::traits;
use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible;
use crate::traits::ObligationCtxt;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_span::source_map::DUMMY_SP;
@ -73,7 +73,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
);
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
let errors = traits::fully_solve_obligations(infcx, obligations);
let ocx = ObligationCtxt::new(infcx);
ocx.register_obligations(obligations);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
}
let region_obligations = infcx.take_registered_region_obligations();
let region_constraint_data = infcx.take_and_reset_region_constraints();
let region_constraints = query_response::make_query_region_constraints(
infcx.tcx,
region_obligations

View file

@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver;
use rustc_span::def_id::DefId;
use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::vtable::{
count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset,
VtblSegment,
@ -253,15 +253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
let cause = obligation.derived_cause(BuiltinDerivedObligation);
ensure_sufficient_stack(|| {
self.collect_predicates_for_types(
obligation.param_env,
cause,
obligation.recursion_depth + 1,
trait_def,
nested,
)
})
self.collect_predicates_for_types(
obligation.param_env,
cause,
obligation.recursion_depth + 1,
trait_def,
nested,
)
} else {
vec![]
};
@ -1118,14 +1116,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);
// Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
nested.push(predicate_for_trait_def(
let tail_unsize_obligation = obligation.with(
tcx,
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
[source_tail, target_tail],
));
tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]),
);
nested.push(tail_unsize_obligation);
}
// `(.., T)` -> `(.., U)`
@ -1147,17 +1142,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
// Construct the nested `T: Unsize<U>` predicate.
nested.push(ensure_sufficient_stack(|| {
predicate_for_trait_def(
tcx,
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
[a_last, b_last],
)
}));
// Add a nested `T: Unsize<U>` predicate.
let last_unsize_obligation = obligation
.with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last]));
nested.push(last_unsize_obligation);
}
_ => bug!("source: {source}, target: {target}"),

View file

@ -17,7 +17,7 @@ use super::project;
use super::project::normalize_with_depth_to;
use super::project::ProjectionTyObligation;
use super::util;
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
use super::util::closure_trait_ref_and_return_type;
use super::wf;
use super::{
ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
@ -2440,15 +2440,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
placeholder_ty,
)
});
let placeholder_obligation = predicate_for_trait_def(
let obligation = Obligation::new(
self.tcx(),
param_env,
cause.clone(),
trait_def_id,
recursion_depth,
[normalized_ty],
param_env,
self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]),
);
obligations.push(placeholder_obligation);
obligations.push(obligation);
obligations
})
.collect()

View file

@ -1,11 +1,11 @@
use super::NormalizeExt;
use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext};
use super::{ObligationCause, PredicateObligation, SelectionContext};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferOk;
use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, SubstsRef};
use rustc_span::Span;
use smallvec::SmallVec;
@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
(subject, impl_obligations)
}
pub fn predicate_for_trait_ref<'tcx>(
tcx: TyCtxt<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
recursion_depth: usize,
) -> PredicateObligation<'tcx> {
Obligation {
cause,
param_env,
recursion_depth,
predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
}
}
pub fn predicate_for_trait_def<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
) -> PredicateObligation<'tcx> {
let trait_ref = tcx.mk_trait_ref(trait_def_id, params);
predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
}
/// Casts a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.