Change InferCtxtBuilder from enter to build
This commit is contained in:
parent
91269fa5b8
commit
283abbf0e7
53 changed files with 1966 additions and 2182 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(®ion_data);
|
||||
let vid_to_region = self.map_vid_to_region(®ion_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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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!();
|
||||
|
|
|
@ -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>>(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue