Add traits::fully_solve_obligation
that acts like traits::fully_normalize
It spawns up a trait engine, registers the single obligation, then fully solves it
This commit is contained in:
parent
3e48434cc7
commit
fe894756f8
10 changed files with 78 additions and 97 deletions
|
@ -205,10 +205,8 @@ 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 mut fulfill = <dyn TraitEngine<'tcx>>::new(tcx);
|
||||
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
|
||||
let errors = fulfill.select_all_or_error(&infcx);
|
||||
|
||||
let errors =
|
||||
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
|
||||
if !errors.is_empty() {
|
||||
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
|
||||
}
|
||||
|
|
|
@ -10,14 +10,14 @@ use crate::traits::select::IntercrateAmbiguityCause;
|
|||
use crate::traits::util::impl_subject_and_oblig;
|
||||
use crate::traits::SkipLeakCheck;
|
||||
use crate::traits::{
|
||||
self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
|
||||
PredicateObligations, SelectionContext, TraitEngineExt,
|
||||
self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
|
||||
SelectionContext,
|
||||
};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{util, TraitEngine};
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
|
@ -384,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
|
|||
return false;
|
||||
};
|
||||
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
fulfillment_cx.register_predicate_obligation(infcx, o);
|
||||
|
||||
let errors = fulfillment_cx.select_all_or_error(infcx);
|
||||
|
||||
let errors = super::fully_solve_obligation(infcx, o);
|
||||
if !errors.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME -- also add "assumed to be well formed" types into the `outlives_env`
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
|
@ -161,22 +162,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
|
|||
// this function's result remains infallible, we must confirm
|
||||
// that guess. While imperfect, I believe this is sound.
|
||||
|
||||
// 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 mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
|
||||
// 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).
|
||||
let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
|
||||
|
||||
fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
|
||||
// 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_bound(infcx, cause, param_env, ty, def_id);
|
||||
|
||||
// Note: we only assume something is `Copy` if we can
|
||||
// *definitively* show that it implements `Copy`. Otherwise,
|
||||
// assume it is move; linear is always ok.
|
||||
match fulfill_cx.select_all_or_error(infcx).as_slice() {
|
||||
match &errors[..] {
|
||||
[] => {
|
||||
debug!(
|
||||
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
|
||||
|
@ -413,6 +412,36 @@ where
|
|||
Ok(resolved_value)
|
||||
}
|
||||
|
||||
pub fn fully_solve_obligation<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
engine.register_predicate_obligation(infcx, obligation);
|
||||
engine.select_all_or_error(infcx)
|
||||
}
|
||||
|
||||
pub fn fully_solve_obligations<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
engine.register_predicate_obligations(infcx, obligations);
|
||||
engine.select_all_or_error(infcx)
|
||||
}
|
||||
|
||||
pub fn fully_solve_bound<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: DefId,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
engine.register_bound(infcx, param_env, ty, bound, cause);
|
||||
engine.select_all_or_error(infcx)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use crate::infer::canonical::query_response;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::engine::TraitEngineExt as _;
|
||||
use crate::traits;
|
||||
use crate::traits::query::type_op::TypeOpOutput;
|
||||
use crate::traits::query::Fallible;
|
||||
use crate::traits::TraitEngine;
|
||||
use rustc_infer::infer::region_constraints::RegionConstraintData;
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
||||
use std::fmt;
|
||||
|
@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
|||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
|
||||
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
|
||||
// During NLL, we expect that nobody will register region
|
||||
// obligations **except** as part of a custom type op (and, at the
|
||||
// end of each custom type op, we scrape out the region
|
||||
|
@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
|||
);
|
||||
|
||||
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||
let errors = fulfill_cx.select_all_or_error(infcx);
|
||||
let errors = traits::fully_solve_obligations(infcx, obligations);
|
||||
if !errors.is_empty() {
|
||||
infcx.tcx.sess.diagnostic().delay_span_bug(
|
||||
DUMMY_SP,
|
||||
|
|
|
@ -14,9 +14,7 @@ use specialization_graph::GraphExt;
|
|||
|
||||
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
use crate::traits::{
|
||||
self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt,
|
||||
};
|
||||
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
@ -26,8 +24,8 @@ use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
|
|||
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use super::util;
|
||||
use super::SelectionContext;
|
||||
use super::{util, FulfillmentContext};
|
||||
|
||||
/// Information pertinent to an overlapping impl error.
|
||||
#[derive(Debug)]
|
||||
|
@ -210,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>(
|
|||
// (which are packed up in penv)
|
||||
|
||||
infcx.save_and_restore_in_snapshot_flag(|infcx| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
|
||||
for oblig in obligations.chain(more_obligations) {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, oblig);
|
||||
}
|
||||
match fulfill_cx.select_all_or_error(infcx).as_slice() {
|
||||
let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
|
||||
match &errors[..] {
|
||||
[] => {
|
||||
debug!(
|
||||
"fulfill_implication: an impl for {:?} specializes {:?}",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue