1
Fork 0

Change InferCtxtBuilder from enter to build

This commit is contained in:
Cameron Steffen 2022-09-19 22:03:59 -05:00
parent 91269fa5b8
commit 283abbf0e7
53 changed files with 1966 additions and 2182 deletions

View file

@ -177,18 +177,10 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
R: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
{
self.enter_with_canonical(
DUMMY_SP,
canonical_key,
|ref infcx, key, canonical_inference_vars| {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
let value = operation(infcx, &mut *fulfill_cx, key)?;
infcx.make_canonicalized_query_response(
canonical_inference_vars,
value,
&mut *fulfill_cx,
)
},
)
let (ref infcx, key, canonical_inference_vars) =
self.build_with_canonical(DUMMY_SP, canonical_key);
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
let value = operation(infcx, &mut *fulfill_cx, key)?;
infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx)
}
}

View file

@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{Region, RegionVid};
use rustc_middle::ty::{PolyTraitRef, Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -90,143 +90,105 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let trait_pred = ty::Binder::dummy(trait_ref);
let bail_out = tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
let result = selcx.select(&Obligation::new(
ObligationCause::dummy(),
orig_env,
trait_pred.to_poly_trait_predicate(),
));
match result {
Ok(Some(ImplSource::UserDefined(_))) => {
debug!(
"find_auto_trait_generics({:?}): \
manual impl found, bailing out",
trait_ref
);
return true;
}
_ => {}
let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
for f in [
PolyTraitRef::to_poly_trait_predicate,
PolyTraitRef::to_poly_trait_predicate_negative_polarity,
] {
let result =
selcx.select(&Obligation::new(ObligationCause::dummy(), orig_env, f(&trait_pred)));
if let Ok(Some(ImplSource::UserDefined(_))) = result {
debug!(
"find_auto_trait_generics({:?}): \
manual impl found, bailing out",
trait_ref
);
// If an explicit impl exists, it always takes priority over an auto impl
return AutoTraitResult::ExplicitImpl;
}
let result = selcx.select(&Obligation::new(
ObligationCause::dummy(),
orig_env,
trait_pred.to_poly_trait_predicate_negative_polarity(),
));
match result {
Ok(Some(ImplSource::UserDefined(_))) => {
debug!(
"find_auto_trait_generics({:?}): \
manual impl found, bailing out",
trait_ref
);
true
}
_ => false,
}
});
// If an explicit impl exists, it always takes priority over an auto impl
if bail_out {
return AutoTraitResult::ExplicitImpl;
}
tcx.infer_ctxt().enter(|infcx| {
let mut fresh_preds = FxHashSet::default();
let infcx = tcx.infer_ctxt().build();
let mut fresh_preds = FxHashSet::default();
// Due to the way projections are handled by SelectionContext, we need to run
// evaluate_predicates twice: once on the original param env, and once on the result of
// the first evaluate_predicates call.
//
// The problem is this: most of rustc, including SelectionContext and traits::project,
// are designed to work with a concrete usage of a type (e.g., Vec<u8>
// fn<T>() { Vec<T> }. This information will generally never change - given
// the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
// If we're unable to prove that 'T' implements a particular trait, we're done -
// there's nothing left to do but error out.
//
// However, synthesizing an auto trait impl works differently. Here, we start out with
// a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
// with - and progressively discover the conditions we need to fulfill for it to
// implement a certain auto trait. This ends up breaking two assumptions made by trait
// selection and projection:
//
// * We can always cache the result of a particular trait selection for the lifetime of
// an InfCtxt
// * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
// SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
//
// We fix the first assumption by manually clearing out all of the InferCtxt's caches
// in between calls to SelectionContext.select. This allows us to keep all of the
// intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
// them between calls.
//
// We fix the second assumption by reprocessing the result of our first call to
// evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
// pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
// traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
// SelectionContext to return it back to us.
// Due to the way projections are handled by SelectionContext, we need to run
// evaluate_predicates twice: once on the original param env, and once on the result of
// the first evaluate_predicates call.
//
// The problem is this: most of rustc, including SelectionContext and traits::project,
// are designed to work with a concrete usage of a type (e.g., Vec<u8>
// fn<T>() { Vec<T> }. This information will generally never change - given
// the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
// If we're unable to prove that 'T' implements a particular trait, we're done -
// there's nothing left to do but error out.
//
// However, synthesizing an auto trait impl works differently. Here, we start out with
// a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
// with - and progressively discover the conditions we need to fulfill for it to
// implement a certain auto trait. This ends up breaking two assumptions made by trait
// selection and projection:
//
// * We can always cache the result of a particular trait selection for the lifetime of
// an InfCtxt
// * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
// SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
//
// We fix the first assumption by manually clearing out all of the InferCtxt's caches
// in between calls to SelectionContext.select. This allows us to keep all of the
// intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
// them between calls.
//
// We fix the second assumption by reprocessing the result of our first call to
// evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
// pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
// traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
// SelectionContext to return it back to us.
let Some((new_env, user_env)) = self.evaluate_predicates(
&infcx,
trait_did,
ty,
orig_env,
orig_env,
&mut fresh_preds,
false,
) else {
return AutoTraitResult::NegativeImpl;
};
let Some((new_env, user_env)) = self.evaluate_predicates(
&infcx,
trait_did,
ty,
orig_env,
orig_env,
&mut fresh_preds,
false,
) else {
return AutoTraitResult::NegativeImpl;
};
let (full_env, full_user_env) = self
.evaluate_predicates(
&infcx,
trait_did,
ty,
new_env,
user_env,
&mut fresh_preds,
true,
)
.unwrap_or_else(|| {
panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
});
let (full_env, full_user_env) = self
.evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true)
.unwrap_or_else(|| {
panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
});
debug!(
"find_auto_trait_generics({:?}): fulfilling \
with {:?}",
trait_ref, full_env
);
infcx.clear_caches();
debug!(
"find_auto_trait_generics({:?}): fulfilling \
with {:?}",
trait_ref, full_env
);
infcx.clear_caches();
// 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);
if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}
// 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);
if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}
infcx.process_registered_region_obligations(&Default::default(), full_env);
infcx.process_registered_region_obligations(&Default::default(), full_env);
let region_data = infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
.region_constraint_data()
.clone();
let region_data =
infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
let vid_to_region = self.map_vid_to_region(&region_data);
let vid_to_region = self.map_vid_to_region(&region_data);
let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
AutoTraitResult::PositiveImpl(auto_trait_callback(info))
})
AutoTraitResult::PositiveImpl(auto_trait_callback(info))
}
}

View file

@ -29,60 +29,61 @@ pub fn codegen_select_candidate<'tcx>(
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
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);
let infcx = tcx
.infer_ctxt()
.ignoring_regions()
.with_opaque_type_inference(DefiningAnchor::Bubble)
.build();
//~^ HACK `Bubble` is required for
// this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
let mut selcx = SelectionContext::new(&infcx);
let obligation_cause = ObligationCause::dummy();
let obligation =
Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
let obligation_cause = ObligationCause::dummy();
let obligation =
Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => return Err(CodegenObligationError::Ambiguity),
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
Err(e) => {
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}
};
debug!(?selection);
// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
let impl_source = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
// In principle, we only need to do this so long as `impl_source`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
// `rustc_monomorphize::collector` assumes there are no type errors.
// Cycle errors are the only post-monomorphization errors possible; emit them now so
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
for err in errors {
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
infcx.err_ctxt().report_overflow_error_cycle(&cycle);
}
}
return Err(CodegenObligationError::FulfillmentError);
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
Ok(None) => return Err(CodegenObligationError::Ambiguity),
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
Err(e) => {
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}
};
let impl_source = infcx.resolve_vars_if_possible(impl_source);
let impl_source = infcx.tcx.erase_regions(impl_source);
debug!(?selection);
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
// as they will get constrained elsewhere, too.
// (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
let impl_source = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
Ok(&*tcx.arena.alloc(impl_source))
})
// In principle, we only need to do this so long as `impl_source`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
// `rustc_monomorphize::collector` assumes there are no type errors.
// Cycle errors are the only post-monomorphization errors possible; emit them now so
// `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization.
for err in errors {
if let FulfillmentErrorCode::CodeCycle(cycle) = err.code {
infcx.err_ctxt().report_overflow_error_cycle(&cycle);
}
}
return Err(CodegenObligationError::FulfillmentError);
}
let impl_source = infcx.resolve_vars_if_possible(impl_source);
let impl_source = infcx.tcx.erase_regions(impl_source);
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
// as they will get constrained elsewhere, too.
// (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
Ok(&*tcx.arena.alloc(impl_source))
}

View file

@ -100,11 +100,10 @@ where
return no_overlap();
}
let overlaps = tcx.infer_ctxt().enter(|infcx| {
let selcx = &mut SelectionContext::intercrate(&infcx);
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
});
let infcx = tcx.infer_ctxt().build();
let selcx = &mut SelectionContext::intercrate(&infcx);
let overlaps =
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some();
if !overlaps {
return no_overlap();
}
@ -112,13 +111,10 @@ where
// In the case where we detect an error, run the check again, but
// this time tracking intercrate ambiguity causes for better
// diagnostics. (These take time and can lead to false errors.)
tcx.infer_ctxt().enter(|infcx| {
let selcx = &mut SelectionContext::intercrate(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
on_overlap(
overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
)
})
let infcx = tcx.infer_ctxt().build();
let selcx = &mut SelectionContext::intercrate(&infcx);
selcx.enable_tracking_intercrate_ambiguity_causes();
on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap())
}
fn with_fresh_ty_vars<'cx, 'tcx>(
@ -298,33 +294,32 @@ fn negative_impl<'cx, 'tcx>(
let tcx = selcx.infcx().tcx;
// Create an infcx, taking the predicates of impl1 as assumptions:
tcx.infer_ctxt().enter(|infcx| {
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
let impl_env = tcx.param_env(impl1_def_id);
let subject1 = match traits::fully_normalize(
&infcx,
ObligationCause::dummy(),
impl_env,
tcx.impl_subject(impl1_def_id),
) {
Ok(s) => s,
Err(err) => {
tcx.sess.delay_span_bug(
tcx.def_span(impl1_def_id),
format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
);
return false;
}
};
let infcx = tcx.infer_ctxt().build();
// create a parameter environment corresponding to a (placeholder) instantiation of impl1
let impl_env = tcx.param_env(impl1_def_id);
let subject1 = match traits::fully_normalize(
&infcx,
ObligationCause::dummy(),
impl_env,
tcx.impl_subject(impl1_def_id),
) {
Ok(s) => s,
Err(err) => {
tcx.sess.delay_span_bug(
tcx.def_span(impl1_def_id),
format!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
);
return false;
}
};
// Attempt to prove that impl2 applies, given all of the above.
let selcx = &mut SelectionContext::new(&infcx);
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
let (subject2, obligations) =
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
// Attempt to prove that impl2 applies, given all of the above.
let selcx = &mut SelectionContext::new(&infcx);
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
let (subject2, obligations) =
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
})
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
}
fn equate<'tcx>(

View file

@ -1930,16 +1930,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
let normalize = |candidate| {
self.tcx.infer_ctxt().enter(|ref infcx| {
let normalized = infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.normalize(candidate)
.ok();
match normalized {
Some(normalized) => normalized.value,
None => candidate,
}
})
let infcx = self.tcx.infer_ctxt().build();
infcx
.at(&ObligationCause::dummy(), ty::ParamEnv::empty())
.normalize(candidate)
.map_or(candidate, |normalized| normalized.value)
};
// Sort impl candidates so that ordering is consistent for UI tests.

View file

@ -23,65 +23,64 @@ pub fn can_type_implement_copy<'tcx>(
parent_cause: ObligationCause<'tcx>,
) -> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
let (adt, substs) = match self_type.kind() {
// These types used to have a builtin impl.
// Now libcore provides that impl.
ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Float(_)
| ty::Char
| ty::RawPtr(..)
| ty::Never
| ty::Ref(_, _, hir::Mutability::Not)
| ty::Array(..) => return Ok(()),
let infcx = tcx.infer_ctxt().build();
let (adt, substs) = match self_type.kind() {
// These types used to have a builtin impl.
// Now libcore provides that impl.
ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Float(_)
| ty::Char
| ty::RawPtr(..)
| ty::Never
| ty::Ref(_, _, hir::Mutability::Not)
| ty::Array(..) => return Ok(()),
ty::Adt(adt, substs) => (adt, substs),
ty::Adt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
};
_ => return Err(CopyImplementationError::NotAnAdt),
};
let mut infringing = Vec::new();
for variant in adt.variants() {
for field in &variant.fields {
let ty = field.ty(tcx, substs);
if ty.references_error() {
continue;
}
let span = tcx.def_span(field.did);
// FIXME(compiler-errors): This gives us better spans for bad
// projection types like in issue-50480.
// If the ADT has substs, point to the cause we are given.
// If it does not, then this field probably doesn't normalize
// to begin with, and point to the bad field's span instead.
let cause = if field
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
.has_non_region_param()
{
parent_cause.clone()
} else {
ObligationCause::dummy_with_span(span)
};
match traits::fully_normalize(&infcx, cause, param_env, ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
infringing.push((field, ty));
}
}
Err(errors) => {
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
}
};
let mut infringing = Vec::new();
for variant in adt.variants() {
for field in &variant.fields {
let ty = field.ty(tcx, substs);
if ty.references_error() {
continue;
}
let span = tcx.def_span(field.did);
// FIXME(compiler-errors): This gives us better spans for bad
// projection types like in issue-50480.
// If the ADT has substs, point to the cause we are given.
// If it does not, then this field probably doesn't normalize
// to begin with, and point to the bad field's span instead.
let cause = if field
.ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
.has_non_region_param()
{
parent_cause.clone()
} else {
ObligationCause::dummy_with_span(span)
};
match traits::fully_normalize(&infcx, cause, param_env, ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
infringing.push((field, ty));
}
}
Err(errors) => {
infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
}
};
}
if !infringing.is_empty() {
return Err(CopyImplementationError::InfrigingFields(infringing));
}
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
}
if !infringing.is_empty() {
return Err(CopyImplementationError::InfrigingFields(infringing));
}
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
Ok(())
})
Ok(())
}

View file

@ -234,54 +234,51 @@ fn do_normalize_predicates<'tcx>(
// 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 predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
return Err(reported);
}
};
let infcx = tcx.infer_ctxt().ignoring_regions().build();
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
return Err(reported);
}
};
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
// We can use the `elaborated_env` here; the region code only
// cares about declarations like `'a: 'b`.
let outlives_env = OutlivesEnvironment::new(elaborated_env);
// We can use the `elaborated_env` here; the region code only
// cares about declarations like `'a: 'b`.
let outlives_env = OutlivesEnvironment::new(elaborated_env);
// FIXME: It's very weird that we ignore region obligations but apparently
// still need to use `resolve_regions` as we need the resolved regions in
// the normalized predicates.
let errors = infcx.resolve_regions(&outlives_env);
if !errors.is_empty() {
tcx.sess.delay_span_bug(
// FIXME: It's very weird that we ignore region obligations but apparently
// still need to use `resolve_regions` as we need the resolved regions in
// the normalized predicates.
let errors = infcx.resolve_regions(&outlives_env);
if !errors.is_empty() {
tcx.sess.delay_span_bug(
span,
format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
);
}
match infcx.fully_resolve(predicates) {
Ok(predicates) => Ok(predicates),
Err(fixup_err) => {
// If we encounter a fixup error, it means that some type
// variable wound up unconstrained. I actually don't know
// if this can happen, and I certainly don't expect it to
// happen often, but if it did happen it probably
// represents a legitimate failure due to some kind of
// unconstrained variable.
//
// @lcnr: Let's still ICE here for now. I want a test case
// for that.
span_bug!(
span,
format!(
"failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
),
"inference variables in normalized parameter environment: {}",
fixup_err
);
}
match infcx.fully_resolve(predicates) {
Ok(predicates) => Ok(predicates),
Err(fixup_err) => {
// If we encounter a fixup error, it means that some type
// variable wound up unconstrained. I actually don't know
// if this can happen, and I certainly don't expect it to
// happen often, but if it did happen it probably
// represents a legitimate failure due to some kind of
// unconstrained variable.
//
// @lcnr: Let's still ICE here for now. I want a test case
// for that.
span_bug!(
span,
"inference variables in normalized parameter environment: {}",
fixup_err
);
}
}
})
}
}
// FIXME: this is gonna need to be removed ...
@ -473,21 +470,20 @@ pub fn impossible_predicates<'tcx>(
) -> bool {
debug!("impossible_predicates(predicates={:?})", predicates);
let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::reveal_all();
let ocx = ObligationCtxt::new(&infcx);
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
for predicate in predicates {
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
ocx.register_obligation(obligation);
}
let errors = ocx.select_all_or_error();
let infcx = tcx.infer_ctxt().build();
let param_env = ty::ParamEnv::reveal_all();
let ocx = ObligationCtxt::new(&infcx);
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
for predicate in predicates {
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
ocx.register_obligation(obligation);
}
let errors = ocx.select_all_or_error();
// Clean up after ourselves
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
// Clean up after ourselves
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
!errors.is_empty()
});
let result = !errors.is_empty();
debug!("impossible_predicates = {:?}", result);
result
}
@ -578,18 +574,16 @@ fn is_impossible_method<'tcx>(
}
});
tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
for obligation in predicates_for_trait {
// Ignore overflow error, to be conservative.
if let Ok(result) = infcx.evaluate_obligation(&obligation)
&& !result.may_apply()
{
return true;
}
let infcx = tcx.infer_ctxt().ignoring_regions().build();
for obligation in predicates_for_trait {
// Ignore overflow error, to be conservative.
if let Ok(result) = infcx.evaluate_obligation(&obligation)
&& !result.may_apply()
{
return true;
}
false
})
}
false
}
#[derive(Clone, Debug)]
@ -952,10 +946,9 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
}),
);
let implsrc = tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation).unwrap()
});
let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
let implsrc = selcx.select(&obligation).unwrap();
let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
bug!();

View file

@ -734,10 +734,9 @@ fn receiver_is_dispatchable<'tcx>(
Obligation::new(ObligationCause::dummy(), param_env, predicate)
};
tcx.infer_ctxt().enter(|ref infcx| {
// the receiver is dispatchable iff the obligation holds
infcx.predicate_must_hold_modulo_regions(&obligation)
})
let infcx = tcx.infer_ctxt().build();
// the receiver is dispatchable iff the obligation holds
infcx.predicate_must_hold_modulo_regions(&obligation)
}
fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(

View file

@ -149,13 +149,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
// Create an infcx, taking the predicates of impl1 as assumptions:
tcx.infer_ctxt().enter(|infcx| {
let impl1_trait_ref = match traits::fully_normalize(
&infcx,
ObligationCause::dummy(),
penv,
impl1_trait_ref,
) {
let infcx = tcx.infer_ctxt().build();
let impl1_trait_ref =
match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
Ok(impl1_trait_ref) => impl1_trait_ref,
Err(_errors) => {
tcx.sess.delay_span_bug(
@ -166,9 +162,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
}
};
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
})
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
}
/// Attempt to fulfill all obligations of `target_impl` after unification with

View file

@ -265,9 +265,8 @@ impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
pub fn provide(providers: &mut Providers) {
providers.has_structural_eq_impls = |tcx, ty| {
tcx.infer_ctxt().enter(|infcx| {
let cause = ObligationCause::dummy();
type_marked_structural(&infcx, ty, cause)
})
let infcx = tcx.infer_ctxt().build();
let cause = ObligationCause::dummy();
type_marked_structural(&infcx, ty, cause)
};
}