Skip to content

Commit b52414f

Browse files
committed
integrate the sub_free_regions code so we have only one copy of it
1 parent 03b2fff commit b52414f

File tree

5 files changed

+106
-94
lines changed

5 files changed

+106
-94
lines changed

src/librustc/infer/lexical_region_resolve/mod.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -420,12 +420,34 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
420420

421421
/// True if `a <= b`, but not defined over inference variables.
422422
fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
423+
let tcx = self.tcx();
424+
let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);
425+
426+
// Check for the case where we know that `'b: 'static` -- in that case,
427+
// `a <= b` for all `a`.
428+
let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b);
429+
if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
430+
return true;
431+
}
432+
433+
// If both a and b are free, consult the declared
434+
// relationships. Note that this can be more precise than the
435+
// `lub` relationship defined below, since sometimes the "lub"
436+
// is actually the `postdom_upper_bound` (see
437+
// `TransitiveRelation` for more details).
438+
let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a);
439+
if a_free_or_static && b_free_or_static {
440+
return sub_free_regions(a, b);
441+
}
442+
443+
// For other cases, leverage the LUB code to find the LUB and
444+
// check if it is equal to b.
423445
self.lub_concrete_regions(a, b) == b
424446
}
425447

426448
/// Returns the smallest region `c` such that `a <= c` and `b <= c`.
427449
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
428-
match (a, b) {
450+
let r = match (a, b) {
429451
(&ty::ReClosureBound(..), _)
430452
| (_, &ty::ReClosureBound(..))
431453
| (&ReLateBound(..), _)
@@ -509,7 +531,11 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
509531
self.tcx().lifetimes.re_static
510532
}
511533
}
512-
}
534+
};
535+
536+
debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r);
537+
538+
r
513539
}
514540

515541
/// After expansion is complete, go and check upper bounds (i.e.,
@@ -528,7 +554,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
528554
}
529555

530556
Constraint::RegSubReg(sub, sup) => {
531-
if self.region_rels.is_subregion_of(sub, sup) {
557+
if self.sub_concrete_regions(sub, sup) {
532558
continue;
533559
}
534560

@@ -557,7 +583,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
557583
// Do not report these errors immediately:
558584
// instead, set the variable value to error and
559585
// collect them later.
560-
if !self.region_rels.is_subregion_of(a_region, b_region) {
586+
if !self.sub_concrete_regions(a_region, b_region) {
561587
debug!(
562588
"collect_errors: region error at {:?}: \
563589
cannot verify that {:?}={:?} <= {:?}",
@@ -754,7 +780,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
754780
};
755781

756782
for upper_bound in &upper_bounds {
757-
if !self.region_rels.is_subregion_of(effective_lower_bound, upper_bound.region) {
783+
if !self.sub_concrete_regions(effective_lower_bound, upper_bound.region) {
758784
let origin = self.var_infos[node_idx].origin;
759785
debug!(
760786
"region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \
@@ -884,7 +910,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
884910
}
885911

886912
VerifyBound::OutlivedBy(r) => {
887-
self.region_rels.is_subregion_of(min, var_values.normalize(self.tcx(), r))
913+
self.sub_concrete_regions(min, var_values.normalize(self.tcx(), r))
888914
}
889915

890916
VerifyBound::IsEmpty => {

src/librustc/infer/opaque_types/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
384384
match least_region {
385385
None => least_region = Some(subst_arg),
386386
Some(lr) => {
387-
if free_region_relations.sub_free_regions(lr, subst_arg) {
387+
if free_region_relations.sub_free_regions(self.tcx, lr, subst_arg) {
388388
// keep the current least region
389-
} else if free_region_relations.sub_free_regions(subst_arg, lr) {
389+
} else if free_region_relations.sub_free_regions(self.tcx, subst_arg, lr) {
390390
// switch to `subst_arg`
391391
least_region = Some(subst_arg);
392392
} else {

src/librustc/middle/free_region.rs

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
//! and use that to decide when one free region outlives another, and so forth.
55
66
use crate::middle::region;
7-
use crate::ty::free_region_map::{FreeRegionMap, FreeRegionRelations};
8-
use crate::ty::{self, Region, TyCtxt};
7+
use crate::ty::free_region_map::FreeRegionMap;
8+
use crate::ty::{Region, TyCtxt};
99
use rustc_hir::def_id::DefId;
1010

1111
/// Combines a `region::ScopeTree` (which governs relationships between
@@ -38,62 +38,6 @@ impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
3838
Self { tcx, context, region_scope_tree, free_regions }
3939
}
4040

41-
/// Determines whether one region is a subregion of another. This is intended to run *after
42-
/// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
43-
pub fn is_subregion_of(
44-
&self,
45-
sub_region: ty::Region<'tcx>,
46-
super_region: ty::Region<'tcx>,
47-
) -> bool {
48-
let result = sub_region == super_region || {
49-
match (sub_region, super_region) {
50-
(ty::ReEmpty, _) | (_, ty::ReStatic) => true,
51-
52-
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
53-
self.region_scope_tree.is_subscope_of(*sub_scope, *super_scope)
54-
}
55-
56-
(ty::ReScope(sub_scope), ty::ReEarlyBound(ref br)) => {
57-
let fr_scope = self.region_scope_tree.early_free_scope(self.tcx, br);
58-
self.region_scope_tree.is_subscope_of(*sub_scope, fr_scope)
59-
}
60-
61-
(ty::ReScope(sub_scope), ty::ReFree(fr)) => {
62-
let fr_scope = self.region_scope_tree.free_scope(self.tcx, fr);
63-
self.region_scope_tree.is_subscope_of(*sub_scope, fr_scope)
64-
}
65-
66-
(ty::ReEarlyBound(_), ty::ReEarlyBound(_))
67-
| (ty::ReFree(_), ty::ReEarlyBound(_))
68-
| (ty::ReEarlyBound(_), ty::ReFree(_))
69-
| (ty::ReFree(_), ty::ReFree(_)) => {
70-
self.free_regions.sub_free_regions(sub_region, super_region)
71-
}
72-
73-
_ => false,
74-
}
75-
};
76-
let result = result || self.is_static(super_region);
77-
debug!(
78-
"is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}",
79-
sub_region, super_region, result
80-
);
81-
result
82-
}
83-
84-
/// Determines whether this free region is required to be `'static`.
85-
fn is_static(&self, super_region: ty::Region<'tcx>) -> bool {
86-
debug!("is_static(super_region={:?})", super_region);
87-
match *super_region {
88-
ty::ReStatic => true,
89-
ty::ReEarlyBound(_) | ty::ReFree(_) => {
90-
let re_static = self.tcx.mk_region(ty::ReStatic);
91-
self.free_regions.sub_free_regions(&re_static, &super_region)
92-
}
93-
_ => false,
94-
}
95-
}
96-
9741
pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> {
9842
self.free_regions.lub_free_regions(self.tcx, r_a, r_b)
9943
}

src/librustc/ty/free_region_map.rs

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,61 @@ impl<'tcx> FreeRegionMap<'tcx> {
2323
// (with the exception that `'static: 'x` is not notable)
2424
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
2525
debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
26-
if is_free_or_static(sub) && is_free(sup) {
26+
if self.is_free_or_static(sub) && self.is_free(sup) {
2727
self.relation.add(sub, sup)
2828
}
2929
}
3030

31+
/// Tests whether `r_a <= r_b`.
32+
///
33+
/// Both regions must meet `is_free_or_static`.
34+
///
35+
/// Subtle: one tricky case that this code gets correct is as
36+
/// follows. If we know that `r_b: 'static`, then this function
37+
/// will return true, even though we don't know anything that
38+
/// directly relates `r_a` and `r_b`.
39+
///
40+
/// Also available through the `FreeRegionRelations` trait below.
41+
pub fn sub_free_regions(
42+
&self,
43+
tcx: TyCtxt<'tcx>,
44+
r_a: Region<'tcx>,
45+
r_b: Region<'tcx>,
46+
) -> bool {
47+
assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b));
48+
let re_static = tcx.lifetimes.re_static;
49+
if self.check_relation(re_static, r_b) {
50+
// `'a <= 'static` is always true, and not stored in the
51+
// relation explicitly, so check if `'b` is `'static` (or
52+
// equivalent to it)
53+
true
54+
} else {
55+
self.check_relation(r_a, r_b)
56+
}
57+
}
58+
59+
/// Check whether `r_a <= r_b` is found in the relation
60+
fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
61+
r_a == r_b || self.relation.contains(&r_a, &r_b)
62+
}
63+
64+
/// True for free regions other than `'static`.
65+
pub fn is_free(&self, r: Region<'_>) -> bool {
66+
match *r {
67+
ty::ReEarlyBound(_) | ty::ReFree(_) => true,
68+
_ => false,
69+
}
70+
}
71+
72+
/// True if `r` is a free region or static of the sort that this
73+
/// free region map can be used with.
74+
pub fn is_free_or_static(&self, r: Region<'_>) -> bool {
75+
match *r {
76+
ty::ReStatic => true,
77+
_ => self.is_free(r),
78+
}
79+
}
80+
3181
/// Computes the least-upper-bound of two free regions. In some
3282
/// cases, this is more conservative than necessary, in order to
3383
/// avoid making arbitrary choices. See
@@ -39,13 +89,13 @@ impl<'tcx> FreeRegionMap<'tcx> {
3989
r_b: Region<'tcx>,
4090
) -> Region<'tcx> {
4191
debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
42-
assert!(is_free(r_a));
43-
assert!(is_free(r_b));
92+
assert!(self.is_free(r_a));
93+
assert!(self.is_free(r_b));
4494
let result = if r_a == r_b {
4595
r_a
4696
} else {
4797
match self.relation.postdom_upper_bound(&r_a, &r_b) {
48-
None => tcx.mk_region(ty::ReStatic),
98+
None => tcx.lifetimes.re_static,
4999
Some(r) => *r,
50100
}
51101
};
@@ -60,31 +110,18 @@ impl<'tcx> FreeRegionMap<'tcx> {
60110
pub trait FreeRegionRelations<'tcx> {
61111
/// Tests whether `r_a <= r_b`. Both must be free regions or
62112
/// `'static`.
63-
fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool;
113+
fn sub_free_regions(
114+
&self,
115+
tcx: TyCtxt<'tcx>,
116+
shorter: ty::Region<'tcx>,
117+
longer: ty::Region<'tcx>,
118+
) -> bool;
64119
}
65120

66121
impl<'tcx> FreeRegionRelations<'tcx> for FreeRegionMap<'tcx> {
67-
fn sub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
68-
assert!(is_free_or_static(r_a) && is_free_or_static(r_b));
69-
if let ty::ReStatic = r_b {
70-
true // `'a <= 'static` is just always true, and not stored in the relation explicitly
71-
} else {
72-
r_a == r_b || self.relation.contains(&r_a, &r_b)
73-
}
74-
}
75-
}
76-
77-
fn is_free(r: Region<'_>) -> bool {
78-
match *r {
79-
ty::ReEarlyBound(_) | ty::ReFree(_) => true,
80-
_ => false,
81-
}
82-
}
83-
84-
fn is_free_or_static(r: Region<'_>) -> bool {
85-
match *r {
86-
ty::ReStatic => true,
87-
_ => is_free(r),
122+
fn sub_free_regions(&self, tcx: TyCtxt<'tcx>, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
123+
// invoke the "inherent method"
124+
self.sub_free_regions(tcx, r_a, r_b)
88125
}
89126
}
90127

src/librustc_mir/borrow_check/type_check/free_region_relations.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc::mir::ConstraintCategory;
55
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
66
use rustc::traits::query::type_op::{self, TypeOp};
77
use rustc::ty::free_region_map::FreeRegionRelations;
8-
use rustc::ty::{self, RegionVid, Ty};
8+
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
99
use rustc_data_structures::transitive_relation::TransitiveRelation;
1010
use rustc_span::DUMMY_SP;
1111
use std::rc::Rc;
@@ -359,7 +359,12 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
359359
/// over the `FreeRegionMap` from lexical regions and
360360
/// `UniversalRegions` (from NLL)`.
361361
impl<'tcx> FreeRegionRelations<'tcx> for UniversalRegionRelations<'tcx> {
362-
fn sub_free_regions(&self, shorter: ty::Region<'tcx>, longer: ty::Region<'tcx>) -> bool {
362+
fn sub_free_regions(
363+
&self,
364+
_tcx: TyCtxt<'tcx>,
365+
shorter: ty::Region<'tcx>,
366+
longer: ty::Region<'tcx>,
367+
) -> bool {
363368
let shorter = shorter.to_region_vid();
364369
assert!(self.universal_regions.is_universal_region(shorter));
365370
let longer = longer.to_region_vid();

0 commit comments

Comments
 (0)