integrate the sub_free_regions code so we have only one copy of it
This commit is contained in:
parent
03b2fff40e
commit
b52414fede
5 changed files with 106 additions and 94 deletions
|
|
@ -420,12 +420,34 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
|
||||
/// True if `a <= b`, but not defined over inference variables.
|
||||
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);
|
||||
|
||||
// Check for the case where we know that `'b: 'static` -- in that case,
|
||||
// `a <= b` for all `a`.
|
||||
let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b);
|
||||
if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If both a and b are free, consult the declared
|
||||
// relationships. Note that this can be more precise than the
|
||||
// `lub` relationship defined below, since sometimes the "lub"
|
||||
// is actually the `postdom_upper_bound` (see
|
||||
// `TransitiveRelation` for more details).
|
||||
let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a);
|
||||
if a_free_or_static && b_free_or_static {
|
||||
return sub_free_regions(a, b);
|
||||
}
|
||||
|
||||
// For other cases, leverage the LUB code to find the LUB and
|
||||
// check if it is equal to b.
|
||||
self.lub_concrete_regions(a, b) == b
|
||||
}
|
||||
|
||||
/// Returns the smallest region `c` such that `a <= c` and `b <= c`.
|
||||
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
|
||||
match (a, b) {
|
||||
let r = match (a, b) {
|
||||
(&ty::ReClosureBound(..), _)
|
||||
| (_, &ty::ReClosureBound(..))
|
||||
| (&ReLateBound(..), _)
|
||||
|
|
@ -509,7 +531,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
self.tcx().lifetimes.re_static
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r);
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
/// After expansion is complete, go and check upper bounds (i.e.,
|
||||
|
|
@ -528,7 +554,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
Constraint::RegSubReg(sub, sup) => {
|
||||
if self.region_rels.is_subregion_of(sub, sup) {
|
||||
if self.sub_concrete_regions(sub, sup) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +583,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
// Do not report these errors immediately:
|
||||
// instead, set the variable value to error and
|
||||
// collect them later.
|
||||
if !self.region_rels.is_subregion_of(a_region, b_region) {
|
||||
if !self.sub_concrete_regions(a_region, b_region) {
|
||||
debug!(
|
||||
"collect_errors: region error at {:?}: \
|
||||
cannot verify that {:?}={:?} <= {:?}",
|
||||
|
|
@ -754,7 +780,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
for upper_bound in &upper_bounds {
|
||||
if !self.region_rels.is_subregion_of(effective_lower_bound, upper_bound.region) {
|
||||
if !self.sub_concrete_regions(effective_lower_bound, upper_bound.region) {
|
||||
let origin = self.var_infos[node_idx].origin;
|
||||
debug!(
|
||||
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
|
||||
|
|
@ -884,7 +910,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
VerifyBound::OutlivedBy(r) => {
|
||||
self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
|
||||
self.sub_concrete_regions(min, var_values.normalize(self.tcx(), r))
|
||||
}
|
||||
|
||||
VerifyBound::IsEmpty => {
|
||||
|
|
|
|||
|
|
@ -384,9 +384,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
match least_region {
|
||||
None => least_region = Some(subst_arg),
|
||||
Some(lr) => {
|
||||
if free_region_relations.sub_free_regions(lr, subst_arg) {
|
||||
if free_region_relations.sub_free_regions(self.tcx, lr, subst_arg) {
|
||||
// keep the current least region
|
||||
} else if free_region_relations.sub_free_regions(subst_arg, lr) {
|
||||
} else if free_region_relations.sub_free_regions(self.tcx, subst_arg, lr) {
|
||||
// switch to `subst_arg`
|
||||
least_region = Some(subst_arg);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
//! and use that to decide when one free region outlives another, and so forth.
|
||||
|
||||
use crate::middle::region;
|
||||
use crate::ty::free_region_map::{FreeRegionMap, FreeRegionRelations};
|
||||
use crate::ty::{self, Region, TyCtxt};
|
||||
use crate::ty::free_region_map::FreeRegionMap;
|
||||
use crate::ty::{Region, TyCtxt};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
/// Combines a `region::ScopeTree` (which governs relationships between
|
||||
|
|
@ -38,62 +38,6 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
|
|||
Self { tcx, context, region_scope_tree, free_regions }
|
||||
}
|
||||
|
||||
/// Determines whether one region is a subregion of another. This is intended to run *after
|
||||
/// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
|
||||
pub fn is_subregion_of(
|
||||
&self,
|
||||
sub_region: ty::Region<'tcx>,
|
||||
super_region: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
let result = sub_region == super_region || {
|
||||
match (sub_region, super_region) {
|
||||
(ty::ReEmpty, _) | (_, ty::ReStatic) => true,
|
||||
|
||||
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
|
||||
self.region_scope_tree.is_subscope_of(*sub_scope, *super_scope)
|
||||
}
|
||||
|
||||
(ty::ReScope(sub_scope), ty::ReEarlyBound(ref br)) => {
|
||||
let fr_scope = self.region_scope_tree.early_free_scope(self.tcx, br);
|
||||
self.region_scope_tree.is_subscope_of(*sub_scope, fr_scope)
|
||||
}
|
||||
|
||||
(ty::ReScope(sub_scope), ty::ReFree(fr)) => {
|
||||
let fr_scope = self.region_scope_tree.free_scope(self.tcx, fr);
|
||||
self.region_scope_tree.is_subscope_of(*sub_scope, fr_scope)
|
||||
}
|
||||
|
||||
(ty::ReEarlyBound(_), ty::ReEarlyBound(_))
|
||||
| (ty::ReFree(_), ty::ReEarlyBound(_))
|
||||
| (ty::ReEarlyBound(_), ty::ReFree(_))
|
||||
| (ty::ReFree(_), ty::ReFree(_)) => {
|
||||
self.free_regions.sub_free_regions(sub_region, super_region)
|
||||
}
|
||||
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
let result = result || self.is_static(super_region);
|
||||
debug!(
|
||||
"is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
|
||||
sub_region, super_region, result
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
/// Determines whether this free region is required to be `'static`.
|
||||
fn is_static(&self, super_region: ty::Region<'tcx>) -> bool {
|
||||
debug!("is_static(super_region={:?})", super_region);
|
||||
match *super_region {
|
||||
ty::ReStatic => true,
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => {
|
||||
let re_static = self.tcx.mk_region(ty::ReStatic);
|
||||
self.free_regions.sub_free_regions(&re_static, &super_region)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> {
|
||||
self.free_regions.lub_free_regions(self.tcx, r_a, r_b)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,61 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
// (with the exception that `'static: 'x` is not notable)
|
||||
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
|
||||
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
|
||||
if is_free_or_static(sub) && is_free(sup) {
|
||||
if self.is_free_or_static(sub) && self.is_free(sup) {
|
||||
self.relation.add(sub, sup)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests whether `r_a <= r_b`.
|
||||
///
|
||||
/// Both regions must meet `is_free_or_static`.
|
||||
///
|
||||
/// Subtle: one tricky case that this code gets correct is as
|
||||
/// 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>,
|
||||
r_a: Region<'tcx>,
|
||||
r_b: Region<'tcx>,
|
||||
) -> bool {
|
||||
assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b));
|
||||
let re_static = tcx.lifetimes.re_static;
|
||||
if self.check_relation(re_static, r_b) {
|
||||
// `'a <= 'static` is always true, and not stored in the
|
||||
// relation explicitly, so check if `'b` is `'static` (or
|
||||
// equivalent to it)
|
||||
true
|
||||
} else {
|
||||
self.check_relation(r_a, r_b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether `r_a <= r_b` is found in the relation
|
||||
fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
|
||||
r_a == r_b || self.relation.contains(&r_a, &r_b)
|
||||
}
|
||||
|
||||
/// True for free regions other than `'static`.
|
||||
pub fn is_free(&self, r: Region<'_>) -> bool {
|
||||
match *r {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// True if `r` is a free region or static of the sort that this
|
||||
/// free region map can be used with.
|
||||
pub fn is_free_or_static(&self, r: Region<'_>) -> bool {
|
||||
match *r {
|
||||
ty::ReStatic => true,
|
||||
_ => self.is_free(r),
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the least-upper-bound of two free regions. In some
|
||||
/// cases, this is more conservative than necessary, in order to
|
||||
/// avoid making arbitrary choices. See
|
||||
|
|
@ -39,13 +89,13 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
r_b: Region<'tcx>,
|
||||
) -> Region<'tcx> {
|
||||
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
|
||||
assert!(is_free(r_a));
|
||||
assert!(is_free(r_b));
|
||||
assert!(self.is_free(r_a));
|
||||
assert!(self.is_free(r_b));
|
||||
let result = if r_a == r_b {
|
||||
r_a
|
||||
} else {
|
||||
match self.relation.postdom_upper_bound(&r_a, &r_b) {
|
||||
None => tcx.mk_region(ty::ReStatic),
|
||||
None => tcx.lifetimes.re_static,
|
||||
Some(r) => *r,
|
||||
}
|
||||
};
|
||||
|
|
@ -60,31 +110,18 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||
pub trait FreeRegionRelations<'tcx> {
|
||||
/// Tests whether `r_a <= r_b`. Both must be free regions or
|
||||
/// `'static`.
|
||||
fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
|
||||
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, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
|
||||
assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
|
||||
if let ty::ReStatic = r_b {
|
||||
true // `'a <= 'static` is just always true, and not stored in the relation explicitly
|
||||
} else {
|
||||
r_a == r_b || self.relation.contains(&r_a, &r_b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_free(r: Region<'_>) -> bool {
|
||||
match *r {
|
||||
ty::ReEarlyBound(_) | ty::ReFree(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_free_or_static(r: Region<'_>) -> bool {
|
||||
match *r {
|
||||
ty::ReStatic => true,
|
||||
_ => is_free(r),
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc::mir::ConstraintCategory;
|
|||
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use rustc::traits::query::type_op::{self, TypeOp};
|
||||
use rustc::ty::free_region_map::FreeRegionRelations;
|
||||
use rustc::ty::{self, RegionVid, Ty};
|
||||
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -359,7 +359,12 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
|||
/// over the `FreeRegionMap` from lexical regions and
|
||||
/// `UniversalRegions` (from NLL)`.
|
||||
impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
|
||||
fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool {
|
||||
fn sub_free_regions(
|
||||
&self,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
shorter: ty::Region<'tcx>,
|
||||
longer: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
let shorter = shorter.to_region_vid();
|
||||
assert!(self.universal_regions.is_universal_region(shorter));
|
||||
let longer = longer.to_region_vid();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue