mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
move considering_regions
to the infcx
This commit is contained in:
parent
ceeb5ade20
commit
608625dae9
@ -65,6 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
Self {
|
||||
tcx: self.tcx,
|
||||
defining_use_anchor: self.defining_use_anchor,
|
||||
considering_regions: self.considering_regions,
|
||||
in_progress_typeck_results: self.in_progress_typeck_results,
|
||||
inner: self.inner.clone(),
|
||||
skip_leak_check: self.skip_leak_check.clone(),
|
||||
|
@ -265,6 +265,11 @@ pub struct InferCtxt<'a, 'tcx> {
|
||||
/// might come up during inference or typeck.
|
||||
pub defining_use_anchor: DefiningAnchor,
|
||||
|
||||
/// Whether this inference context should care about region obligations in
|
||||
/// the root universe. Most notably, this is used during hir typeck as region
|
||||
/// solving is left to borrowck instead.
|
||||
pub considering_regions: bool,
|
||||
|
||||
/// During type-checking/inference of a body, `in_progress_typeck_results`
|
||||
/// contains a reference to the typeck results being built up, which are
|
||||
/// used for reading closure kinds/signatures as they are inferred,
|
||||
@ -539,8 +544,9 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
|
||||
/// without using `Rc` or something similar.
|
||||
pub struct InferCtxtBuilder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
|
||||
defining_use_anchor: DefiningAnchor,
|
||||
considering_regions: bool,
|
||||
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
|
||||
}
|
||||
|
||||
pub trait TyCtxtInferExt<'tcx> {
|
||||
@ -552,6 +558,7 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
|
||||
InferCtxtBuilder {
|
||||
tcx: self,
|
||||
defining_use_anchor: DefiningAnchor::Error,
|
||||
considering_regions: true,
|
||||
fresh_typeck_results: None,
|
||||
}
|
||||
}
|
||||
@ -577,6 +584,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn ignoring_regions(mut self) -> Self {
|
||||
self.considering_regions = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Given a canonical value `C` as a starting point, create an
|
||||
/// inference context that contains each of the bound values
|
||||
/// within instantiated as a fresh variable. The `f` closure is
|
||||
@ -601,11 +613,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
}
|
||||
|
||||
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
|
||||
let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
|
||||
let InferCtxtBuilder {
|
||||
tcx,
|
||||
defining_use_anchor,
|
||||
considering_regions,
|
||||
ref fresh_typeck_results,
|
||||
} = *self;
|
||||
let in_progress_typeck_results = fresh_typeck_results.as_ref();
|
||||
f(InferCtxt {
|
||||
tcx,
|
||||
defining_use_anchor,
|
||||
considering_regions,
|
||||
in_progress_typeck_results,
|
||||
inner: RefCell::new(InferCtxtInner::new()),
|
||||
lexical_region_resolutions: RefCell::new(None),
|
||||
|
@ -30,7 +30,9 @@ pub fn codegen_fulfill_obligation<'tcx>(
|
||||
|
||||
// Do the initial selection for the obligation. This yields the
|
||||
// shallow result we are looking for -- that is, what specific impl.
|
||||
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(|infcx| {
|
||||
let mut infcx_builder =
|
||||
tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
|
||||
infcx_builder.enter(|infcx| {
|
||||
//~^ HACK `Bubble` is required for
|
||||
// this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
|
@ -15,8 +15,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
pub trait TraitEngineExt<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
||||
|
||||
fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
||||
}
|
||||
|
||||
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||
@ -27,14 +25,6 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||
Box::new(FulfillmentContext::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ignoring_regions(tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||
if tcx.sess.opts.unstable_opts.chalk {
|
||||
Box::new(ChalkFulfillmentContext::new())
|
||||
} else {
|
||||
Box::new(FulfillmentContext::new_ignoring_regions())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used if you want to have pleasant experience when dealing
|
||||
|
@ -58,19 +58,6 @@ pub struct FulfillmentContext<'tcx> {
|
||||
|
||||
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
|
||||
|
||||
// Should this fulfillment context register type-lives-for-region
|
||||
// obligations on its parent infcx? In some cases, region
|
||||
// obligations are either already known to hold (normalization) or
|
||||
// hopefully verified elsewhere (type-impls-bound), and therefore
|
||||
// should not be checked.
|
||||
//
|
||||
// Note that if we are normalizing a type that we already
|
||||
// know is well-formed, there should be no harm setting this
|
||||
// to true - all the region variables should be determinable
|
||||
// using the RFC 447 rules, which don't depend on
|
||||
// type-lives-for-region constraints, and because the type
|
||||
// is well-formed, the constraints should hold.
|
||||
register_region_obligations: bool,
|
||||
// Is it OK to register obligations into this infcx inside
|
||||
// an infcx snapshot?
|
||||
//
|
||||
@ -103,7 +90,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
predicates: ObligationForest::new(),
|
||||
relationships: FxHashMap::default(),
|
||||
register_region_obligations: true,
|
||||
usable_in_snapshot: false,
|
||||
}
|
||||
}
|
||||
@ -112,30 +98,18 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
predicates: ObligationForest::new(),
|
||||
relationships: FxHashMap::default(),
|
||||
register_region_obligations: true,
|
||||
usable_in_snapshot: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
predicates: ObligationForest::new(),
|
||||
relationships: FxHashMap::default(),
|
||||
register_region_obligations: false,
|
||||
usable_in_snapshot: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to select obligations using `selcx`.
|
||||
fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
|
||||
let _enter = span.enter();
|
||||
|
||||
// Process pending obligations.
|
||||
let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor {
|
||||
selcx,
|
||||
register_region_obligations: self.register_region_obligations,
|
||||
});
|
||||
let outcome: Outcome<_, _> =
|
||||
self.predicates.process_obligations(&mut FulfillProcessor { selcx });
|
||||
|
||||
// FIXME: if we kept the original cache key, we could mark projection
|
||||
// obligations as complete for the projection cache here.
|
||||
@ -239,7 +213,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
|
||||
struct FulfillProcessor<'a, 'b, 'tcx> {
|
||||
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||
register_region_obligations: bool,
|
||||
}
|
||||
|
||||
fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
|
||||
@ -385,19 +358,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
ty::PredicateKind::RegionOutlives(data) => {
|
||||
match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) {
|
||||
Ok(()) => ProcessResult::Changed(vec![]),
|
||||
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
|
||||
if infcx.considering_regions || data.has_placeholders() {
|
||||
match infcx
|
||||
.region_outlives_predicate(&obligation.cause, Binder::dummy(data))
|
||||
{
|
||||
Ok(()) => ProcessResult::Changed(vec![]),
|
||||
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
|
||||
}
|
||||
} else {
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
|
||||
if self.register_region_obligations {
|
||||
self.selcx.infcx().register_region_obligation_with_cause(
|
||||
t_a,
|
||||
r_b,
|
||||
&obligation.cause,
|
||||
);
|
||||
if infcx.considering_regions {
|
||||
infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
|
||||
}
|
||||
ProcessResult::Changed(vec![])
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
|
||||
// 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 = FulfillmentContext::new_ignoring_regions();
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
|
||||
// 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
|
||||
@ -207,21 +207,21 @@ fn do_normalize_predicates<'tcx>(
|
||||
predicates: Vec<ty::Predicate<'tcx>>,
|
||||
) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> {
|
||||
let span = cause.span;
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
// FIXME. We should really... do something with these region
|
||||
// obligations. But this call just continues the older
|
||||
// behavior (i.e., doesn't cause any new bugs), and it would
|
||||
// take some further refactoring to actually solve them. In
|
||||
// particular, we would have to handle implied bounds
|
||||
// properly, and that code is currently largely confined to
|
||||
// regionck (though I made some efforts to extract it
|
||||
// out). -nmatsakis
|
||||
//
|
||||
// @arielby: In any case, these obligations are checked
|
||||
// by wfcheck anyway, so I'm not sure we have to check
|
||||
// them here too, and we will remove this function when
|
||||
// we move over to lazy normalization *anyway*.
|
||||
let fulfill_cx = FulfillmentContext::new_ignoring_regions();
|
||||
// FIXME. We should really... do something with these region
|
||||
// obligations. But this call just continues the older
|
||||
// behavior (i.e., doesn't cause any new bugs), and it would
|
||||
// take some further refactoring to actually solve them. In
|
||||
// particular, we would have to handle implied bounds
|
||||
// properly, and that code is currently largely confined to
|
||||
// regionck (though I made some efforts to extract it
|
||||
// out). -nmatsakis
|
||||
//
|
||||
// @arielby: In any case, these obligations are checked
|
||||
// by wfcheck anyway, so I'm not sure we have to check
|
||||
// them here too, and we will remove this function when
|
||||
// we move over to lazy normalization *anyway*.
|
||||
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
|
||||
let fulfill_cx = FulfillmentContext::new();
|
||||
let predicates =
|
||||
match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
|
||||
Ok(predicates) => predicates,
|
||||
|
@ -207,18 +207,7 @@ fn fulfill_implication<'a, 'tcx>(
|
||||
// (which are packed up in penv)
|
||||
|
||||
infcx.save_and_restore_in_snapshot_flag(|infcx| {
|
||||
// If we came from `translate_substs`, we already know that the
|
||||
// predicates for our impl hold (after all, we know that a more
|
||||
// specialized impl holds, so our impl must hold too), and
|
||||
// we only want to process the projections to determine the
|
||||
// the types in our substs using RFC 447, so we can safely
|
||||
// ignore region obligations, which allows us to avoid threading
|
||||
// a node-id to assign them with.
|
||||
//
|
||||
// If we came from specialization graph construction, then
|
||||
// we already make a mockery out of the region system, so
|
||||
// why not ignore them a bit earlier?
|
||||
let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
|
||||
let mut fulfill_cx = FulfillmentContext::new();
|
||||
for oblig in obligations.chain(more_obligations) {
|
||||
fulfill_cx.register_predicate_obligation(&infcx, oblig);
|
||||
}
|
||||
|
@ -86,7 +86,10 @@ impl<'tcx> Inherited<'_, 'tcx> {
|
||||
let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner;
|
||||
|
||||
InheritedBuilder {
|
||||
infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner),
|
||||
infcx: tcx
|
||||
.infer_ctxt()
|
||||
.ignoring_regions()
|
||||
.with_fresh_in_progress_typeck_results(hir_owner),
|
||||
def_id,
|
||||
}
|
||||
}
|
||||
@ -113,7 +116,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
maybe_typeck_results: infcx.in_progress_typeck_results,
|
||||
},
|
||||
infcx,
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new_ignoring_regions(tcx)),
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
|
||||
locals: RefCell::new(Default::default()),
|
||||
deferred_sized_obligations: RefCell::new(Vec::new()),
|
||||
deferred_call_resolutions: RefCell::new(Default::default()),
|
||||
|
@ -87,10 +87,10 @@ mod op;
|
||||
mod pat;
|
||||
mod place_op;
|
||||
mod region;
|
||||
mod regionck;
|
||||
pub mod regionck;
|
||||
pub mod rvalue_scopes;
|
||||
mod upvar;
|
||||
mod wfcheck;
|
||||
pub mod wfcheck;
|
||||
pub mod writeback;
|
||||
|
||||
use check::{check_abi, check_fn, check_mod_item_types};
|
||||
|
@ -1913,7 +1913,7 @@ impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn impl_implied_bounds<'tcx>(
|
||||
pub fn impl_implied_bounds<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
impl_def_id: LocalDefId,
|
||||
|
@ -116,8 +116,8 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
|
||||
// why this field does not implement Copy. This is useful because sometimes
|
||||
// it is not immediately clear why Copy is not implemented for a field, since
|
||||
// all we point at is the field itself.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new_ignoring_regions();
|
||||
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
|
||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
||||
fulfill_cx.register_bound(
|
||||
&infcx,
|
||||
param_env,
|
||||
|
@ -65,6 +65,8 @@
|
||||
//! cause use after frees with purely safe code in the same way as specializing
|
||||
//! on traits with methods can.
|
||||
|
||||
use crate::check::regionck::OutlivesEnvironmentExt;
|
||||
use crate::check::wfcheck::impl_implied_bounds;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::errors::SubstsOnOverriddenImpl;
|
||||
|
||||
@ -148,8 +150,15 @@ fn get_impl_substs<'tcx>(
|
||||
let impl2_substs =
|
||||
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
|
||||
|
||||
// Conservatively use an empty `ParamEnv`.
|
||||
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
|
||||
let mut outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let implied_bounds =
|
||||
impl_implied_bounds(infcx.tcx, param_env, impl1_def_id, tcx.def_span(impl1_def_id));
|
||||
outlives_env.add_implied_bounds(
|
||||
infcx,
|
||||
implied_bounds,
|
||||
tcx.hir().local_def_id_to_hir_id(impl1_def_id),
|
||||
);
|
||||
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
|
||||
infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
|
||||
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
||||
let span = tcx.def_span(impl1_def_id);
|
||||
|
Loading…
Reference in New Issue
Block a user