Cleanup free_region_relations a bit

This commit is contained in:
Jack Huey 2022-09-11 03:53:54 -04:00
parent 8996ea93b6
commit 1a663c0f53
6 changed files with 91 additions and 72 deletions

View File

@ -187,6 +187,7 @@ pub(crate) struct PlaceholderIndices {
} }
impl PlaceholderIndices { impl PlaceholderIndices {
/// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex { pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
let (index, _) = self.indices.insert_full(placeholder); let (index, _) = self.indices.insert_full(placeholder);
index.into() index.into()

View File

@ -8,6 +8,7 @@ use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory; use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_middle::ty::{self, RegionVid, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc; use std::rc::Rc;
use type_op::TypeOpOutput; use type_op::TypeOpOutput;
@ -217,65 +218,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.inverse_outlives.add(fr_b, fr_a); self.inverse_outlives.add(fr_b, fr_a);
} }
#[instrument(level = "debug", skip(self))]
pub(crate) fn create(mut self) -> CreateResult<'tcx> { pub(crate) fn create(mut self) -> CreateResult<'tcx> {
let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id()); let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
let unnormalized_input_output_tys = self
.universal_regions
.unnormalized_input_tys
.iter()
.cloned()
.chain(Some(self.universal_regions.unnormalized_output_ty));
// For each of the input/output types:
// - Normalize the type. This will create some region
// constraints, which we buffer up because we are
// not ready to process them yet.
// - Then compute the implied bounds. This will adjust
// the `region_bound_pairs` and so forth.
// - After this is done, we'll process the constraints, once
// the `relations` is built.
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty.
// See issue #87748
let constraints_implied1 = self.add_implied_bounds(ty);
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx)
.unwrap_or_else(|_| {
let reported = self
.infcx
.tcx
.sess
.delay_span_bug(span, &format!("failed to normalize {:?}", ty));
TypeOpOutput {
output: self.infcx.tcx.ty_error_with_guaranteed(reported),
constraints: None,
error_info: None,
}
});
// Note: we need this in examples like
// ```
// trait Foo {
// type Bar;
// fn foo(&self) -> &Self::Bar;
// }
// impl Foo for () {
// type Bar = ();
// fn foo(&self) -> &() {}
// }
// ```
// Both &Self::Bar and &() are WF
let constraints_implied2 =
if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
normalized_inputs_and_output.push(norm_ty);
constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
})
.collect();
// Insert the facts we know from the predicates. Why? Why not. // Insert the facts we know from the predicates. Why? Why not.
let param_env = self.param_env; let param_env = self.param_env;
@ -295,19 +240,69 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.relate_universal_regions(fr, fr_fn_body); self.relate_universal_regions(fr, fr_fn_body);
} }
for data in &constraint_sets { let unnormalized_input_output_tys = self
constraint_conversion::ConstraintConversion::new( .universal_regions
self.infcx, .unnormalized_input_tys
&self.universal_regions, .iter()
&self.region_bound_pairs, .cloned()
self.implicit_region_bound, .chain(Some(self.universal_regions.unnormalized_output_ty));
self.param_env,
Locations::All(span), // For each of the input/output types:
span, // - Normalize the type. This will create some region
ConstraintCategory::Internal, // constraints, which we buffer up because we are
&mut self.constraints, // not ready to process them yet.
) // - Then compute the implied bounds. This will adjust
.convert_all(data); // the `region_bound_pairs` and so forth.
// - After this is done, we'll process the constraints, once
// the `relations` is built.
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
let mut constraints = vec![];
for ty in unnormalized_input_output_tys {
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty.
// See issue #87748
let constraints_unnorm = self.add_implied_bounds(ty);
constraints_unnorm.map(|c| constraints.push(c));
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx)
.unwrap_or_else(|_| {
self.infcx
.tcx
.sess
.delay_span_bug(span, &format!("failed to normalize {:?}", ty));
TypeOpOutput {
output: self.infcx.tcx.ty_error(),
constraints: None,
error_info: None,
}
});
constraints_normalize.map(|c| constraints.push(c));
// Note: we need this in examples like
// ```
// trait Foo {
// type Bar;
// fn foo(&self) -> &Self::Bar;
// }
// impl Foo for () {
// type Bar = ();
// fn foo(&self) ->&() {}
// }
// ```
// Both &Self::Bar and &() are WF
if ty != norm_ty {
let constraints_norm = self.add_implied_bounds(norm_ty);
constraints_norm.map(|c| constraints.push(c));
}
normalized_inputs_and_output.push(norm_ty);
}
for c in constraints {
self.push_region_constraints(c, span);
} }
CreateResult { CreateResult {
@ -321,6 +316,24 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
} }
} }
#[instrument(skip(self, data), level = "debug")]
fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
debug!("constraints generated: {:#?}", data);
constraint_conversion::ConstraintConversion::new(
self.infcx,
&self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.param_env,
Locations::All(span),
span,
ConstraintCategory::Internal,
&mut self.constraints,
)
.convert_all(data);
}
/// Update the type of a single local, which should represent /// Update the type of a single local, which should represent
/// either the return type of the MIR or one of its arguments. At /// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come /// the same time, compute and add any implied bounds that come
@ -332,6 +345,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
.fully_perform(self.infcx) .fully_perform(self.infcx)
.unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty)); .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
debug!(?bounds, ?constraints);
self.add_outlives_bounds(bounds); self.add_outlives_bounds(bounds);
constraints constraints
} }

View File

@ -910,6 +910,8 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
} }
impl<'tcx> MirTypeckRegionConstraints<'tcx> { impl<'tcx> MirTypeckRegionConstraints<'tcx> {
/// Creates a `Region` that for a given `PlaceholderRegion`, or returns the
/// region that corresponds to a previously created one.
fn placeholder_region( fn placeholder_region(
&mut self, &mut self,
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,

View File

@ -207,6 +207,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// ///
/// In some cases, such as when `erased_ty` represents a `ty::Param`, however, /// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
/// the result is precise. /// the result is precise.
#[instrument(level = "debug", skip(self))]
fn declared_generic_bounds_from_env_for_erased_ty( fn declared_generic_bounds_from_env_for_erased_ty(
&self, &self,
erased_ty: Ty<'tcx>, erased_ty: Ty<'tcx>,

View File

@ -81,6 +81,7 @@ fn compute_implied_outlives_bounds<'tcx>(
// From the full set of obligations, just filter down to the // From the full set of obligations, just filter down to the
// region relationships. // region relationships.
outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| { outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
debug!(?obligation);
assert!(!obligation.has_escaping_bound_vars()); assert!(!obligation.has_escaping_bound_vars());
match obligation.predicate.kind().no_bound_vars() { match obligation.predicate.kind().no_bound_vars() {
None => None, None => None,

View File

@ -1,6 +1,6 @@
// Regression test for #52057. There is an implied bound // Regression test for #52057. There is an implied bound
// that `I: 'a` where `'a` is the lifetime of `self` in `parse_first`; // that `I: 'x` where `'x` is the lifetime of the reference `&mut Self::Input`
// but to observe that, one must normalize first. // in `parse_first`; but to observe that, one must normalize first.
// //
// run-pass // run-pass