use crate::infer::region_constraints::Constraint;
use crate::infer::region_constraints::GenericKind;
-use crate::infer::region_constraints::MemberConstraint;
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::VarInfos;
use crate::infer::region_constraints::VerifyBound;
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
-use rustc_span::Span;
use std::fmt;
/// This function performs lexical region resolution given a complete
/// iteration to find region values which satisfy all constraints,
/// assuming such values can be found. It returns the final values of
/// all the variables as well as a set of errors that must be reported.
+#[instrument(level = "debug", skip(region_rels, var_infos, data))]
pub fn resolve<'tcx>(
region_rels: &RegionRelations<'_, 'tcx>,
var_infos: VarInfos,
data: RegionConstraintData<'tcx>,
mode: RegionckMode,
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
- debug!("RegionConstraintData: resolve_regions()");
let mut errors = vec![];
let mut resolver = LexicalResolver { region_rels, var_infos, data };
match mode {
SubregionOrigin<'tcx>, // cause of the constraint
Region<'tcx>, // the placeholder `'b`
),
-
- /// Indicates a failure of a `MemberConstraint`. These arise during
- /// impl trait processing explicitly -- basically, the impl trait's hidden type
- /// included some region that it was not supposed to.
- MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> },
}
struct RegionAndOrigin<'tcx> {
let graph = self.construct_graph();
self.expand_givens(&graph);
- loop {
- self.expansion(&mut var_data);
- if !self.enforce_member_constraints(&graph, &mut var_data) {
- break;
- }
- }
+ self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
var_data
}
}
- /// Enforce all member constraints and return true if anything
- /// changed. See `enforce_member_constraint` for more details.
- fn enforce_member_constraints(
- &self,
- graph: &RegionGraph<'tcx>,
- var_values: &mut LexicalRegionResolutions<'tcx>,
- ) -> bool {
- // Note: we don't use the `any` combinator because we don't
- // want to stop at the first constraint that makes a change.
- let mut any_changed = false;
- for member_constraint in &self.data.member_constraints {
- any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values);
- }
- any_changed
- }
-
- /// Enforce a constraint like
- ///
- /// ```
- /// 'r member of ['c...]
- /// ```
- ///
- /// We look for all choice regions from the list `'c...` that:
- ///
- /// (a) are greater than the current value of `'r` (which is a lower bound)
- ///
- /// and
- ///
- /// (b) are compatible with the upper bounds of `'r` that we can
- /// find by traversing the graph.
- ///
- /// From that list, we look for a *minimal* option `'c_min`. If we
- /// find one, then we can enforce that `'r: 'c_min`.
- fn enforce_member_constraint(
- &self,
- graph: &RegionGraph<'tcx>,
- member_constraint: &MemberConstraint<'tcx>,
- var_values: &mut LexicalRegionResolutions<'tcx>,
- ) -> bool {
- debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint);
-
- // The constraint is some inference variable (`vid`) which
- // must be equal to one of the options.
- let member_vid = match member_constraint.member_region {
- ty::ReVar(vid) => *vid,
- _ => return false,
- };
-
- // The current value of `vid` is a lower bound LB -- i.e., we
- // know that `LB <= vid` must be true.
- let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
- VarValue::ErrorValue => return false,
- VarValue::Value(r) => r,
- };
-
- // Find all the "upper bounds" -- that is, each region `b` such that
- // `r0 <= b` must hold.
- let (member_upper_bounds, ..) =
- self.collect_bounding_regions(graph, member_vid, OUTGOING, None);
-
- // Get an iterator over the *available choice* -- that is,
- // each choice region `c` where `lb <= c` and `c <= ub` for all the
- // upper bounds `ub`.
- debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds);
- let mut options = member_constraint.choice_regions.iter().filter(|option| {
- self.sub_concrete_regions(member_lower_bound, option)
- && member_upper_bounds
- .iter()
- .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
- });
-
- // If there is more than one option, we only make a choice if
- // there is a single *least* choice -- i.e., some available
- // region that is `<=` all the others.
- let mut least_choice: ty::Region<'tcx> = match options.next() {
- Some(&r) => r,
- None => return false,
- };
- debug!("enforce_member_constraint: least_choice={:?}", least_choice);
- for &option in options {
- debug!("enforce_member_constraint: option={:?}", option);
- if !self.sub_concrete_regions(least_choice, option) {
- if self.sub_concrete_regions(option, least_choice) {
- debug!("enforce_member_constraint: new least choice");
- least_choice = option;
- } else {
- debug!("enforce_member_constraint: no least choice");
- return false;
- }
- }
- }
-
- // (#72087) Different `ty::Regions` can be known to be equal, for
- // example, we know that `'a` and `'static` are equal in a function
- // with a parameter of type `&'static &'a ()`.
- //
- // When we have two equal regions like this `expansion` will use
- // `lub_concrete_regions` to pick a canonical representative. The same
- // choice is needed here so that we don't end up in a cycle of
- // `expansion` changing the region one way and the code here changing
- // it back.
- let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
- debug!(
- "enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
- least_choice, lub
- );
- if lub != member_lower_bound {
- *var_values.value_mut(member_vid) = VarValue::Value(least_choice);
- true
- } else {
- false
- }
- }
-
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
let mut changes = Vec::new();
}
/// True if `a <= b`, but not defined over inference variables.
+ #[instrument(level = "trace", skip(self))]
fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
let tcx = self.tcx();
let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);
///
/// Neither `a` nor `b` may be an inference variable (hence the
/// term "concrete regions").
+ #[instrument(level = "trace", skip(self))]
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let r = match (a, b) {
(&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
/// After expansion is complete, go and check upper bounds (i.e.,
/// cases where the region cannot grow larger than a fixed point)
/// and check that they are satisfied.
+ #[instrument(skip(self, var_data, errors))]
fn collect_errors(
&self,
var_data: &mut LexicalRegionResolutions<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
for (constraint, origin) in &self.data.constraints {
- debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin);
+ debug!(?constraint, ?origin);
match *constraint {
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
// Expansion will ensure that these constraints hold. Ignore.
}
debug!(
- "collect_errors: region error at {:?}: \
+ "region error at {:?}: \
cannot verify that {:?} <= {:?}",
origin, sub, sup
);
// collect them later.
if !self.sub_concrete_regions(a_region, b_region) {
debug!(
- "collect_errors: region error at {:?}: \
+ "region error at {:?}: \
cannot verify that {:?}={:?} <= {:?}",
origin, a_vid, a_region, b_region
);
}
}
- // Check that all member constraints are satisfied.
- for member_constraint in &self.data.member_constraints {
- let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
- let choice_regions = member_constraint
- .choice_regions
- .iter()
- .map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
- if !choice_regions.clone().any(|choice_region| member_region == choice_region) {
- let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
- errors.push(RegionResolutionError::MemberConstraintFailure {
- span,
- hidden_ty: member_constraint.hidden_ty,
- member_region,
- });
- }
- }
-
for verify in &self.data.verifys {
debug!("collect_errors: verify={:?}", verify);
let sub = var_data.normalize(self.tcx(), verify.region);