1
Fork 0

Auto merge of #89229 - oli-obk:i_love_inferctxt, r=jackh726

Remove redundant member-constraint check

impl trait will, for each lifetime in the hidden type, register a "member constraint" that says the lifetime must be equal or outlive one of the lifetimes of the impl trait. These member constraints will be solved by borrowck

But, as you can see in the big red block of removed code, there was an ad-hoc check for member constraints happening at the site where they get registered. This check had some minor effects on diagnostics, but will fall down on its feet with my big type alias impl trait refactor. So we removed it and I pulled the removal out into a (hopefully) reviewable PR that works on master directly.
This commit is contained in:
bors 2021-10-18 23:02:53 +00:00
commit ec724ac075
38 changed files with 277 additions and 708 deletions

View file

@ -386,21 +386,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
}
RegionResolutionError::MemberConstraintFailure {
hidden_ty,
member_region,
span,
} => {
let hidden_ty = self.resolve_vars_if_possible(hidden_ty);
unexpected_hidden_region_diagnostic(
self.tcx,
span,
hidden_ty,
member_region,
)
.emit();
}
}
}
}
@ -438,8 +423,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
RegionResolutionError::GenericBoundFailure(..) => true,
RegionResolutionError::ConcreteFailure(..)
| RegionResolutionError::SubSupConflict(..)
| RegionResolutionError::UpperBoundUniverseConflict(..)
| RegionResolutionError::MemberConstraintFailure { .. } => false,
| RegionResolutionError::UpperBoundUniverseConflict(..) => false,
};
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
@ -454,7 +438,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
RegionResolutionError::MemberConstraintFailure { span, .. } => span,
});
errors
}

View file

@ -53,9 +53,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::RelateObjectBound(span) => {
label_or_note(span, "...so that it can be closed over into an object");
}
infer::CallReturn(span) => {
label_or_note(span, "...so that return value is valid for the call");
}
infer::DataBorrowed(ty, span) => {
label_or_note(
span,
@ -281,23 +278,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
err
}
infer::CallReturn(span) => {
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0482,
"lifetime of return value does not outlive the function call"
);
note_and_explain_region(
self.tcx,
&mut err,
"the return value is only valid for ",
sup,
"",
None,
);
err
}
infer::DataBorrowed(ty, span) => {
let mut err = struct_span_err!(
self.tcx.sess,

View file

@ -66,8 +66,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
/// follows. If we know that `r_b: 'static`, then this function
/// will return true, even though we don't know anything that
/// directly relates `r_a` and `r_b`.
///
/// Also available through the `FreeRegionRelations` trait below.
pub fn sub_free_regions(
&self,
tcx: TyCtxt<'tcx>,
@ -131,27 +129,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
}
}
/// The NLL region handling code represents free region relations in a
/// slightly different way; this trait allows functions to be abstract
/// over which version is in use.
pub trait FreeRegionRelations<'tcx> {
/// Tests whether `r_a <= r_b`. Both must be free regions or
/// `'static`.
fn sub_free_regions(
&self,
tcx: TyCtxt<'tcx>,
shorter: ty::Region<'tcx>,
longer: ty::Region<'tcx>,
) -> bool;
}
impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
// invoke the "inherent method"
self.sub_free_regions(tcx, r_a, r_b)
}
}
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
type Lifted = FreeRegionMap<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {

View file

@ -2,7 +2,6 @@
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;
@ -20,7 +19,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
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
@ -28,13 +26,13 @@ use std::fmt;
/// 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 {
@ -109,11 +107,6 @@ pub enum RegionResolutionError<'tcx> {
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> {
@ -150,12 +143,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, '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
@ -233,120 +221,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
/// 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();
@ -461,6 +335,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
/// 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);
@ -492,6 +367,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
///
/// 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) => {
@ -562,13 +438,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
/// 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.
@ -580,7 +457,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
debug!(
"collect_errors: region error at {:?}: \
"region error at {:?}: \
cannot verify that {:?} <= {:?}",
origin, sub, sup
);
@ -606,7 +483,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// 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
);
@ -616,23 +493,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
// 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);

View file

@ -417,9 +417,6 @@ pub enum SubregionOrigin<'tcx> {
/// (&'a &'b T) where a >= b
ReferenceOutlivesReferent(Ty<'tcx>, Span),
/// Region in return type of invoked fn must enclose call
CallReturn(Span),
/// Comparing the signature and requirements of an impl method against
/// the containing trait.
CompareImplMethodObligation {
@ -1803,7 +1800,6 @@ impl<'tcx> SubregionOrigin<'tcx> {
ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
CallReturn(a) => a,
CompareImplMethodObligation { span, .. } => span,
CompareImplTypeObligation { span, .. } => span,
}