-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Be more careful when selecting LUB of free regions #27892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
5448de7
38df8c6
4756d4a
5e126e4
4b1d3b7
dcf6f08
d5b679b
36809bf
2a25876
aa469a9
10b8941
b247402
a54b91f
1630c79
63eedfc
57909f7
81eab1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,24 +10,18 @@ | |
|
||
//! This file defines | ||
|
||
use middle::ty::{self, FreeRegion, Region}; | ||
use middle::wf::ImpliedBound; | ||
use middle::ty::{self, FreeRegion}; | ||
use util::common::can_reach; | ||
use util::nodemap::{FnvHashMap, FnvHashSet}; | ||
use rustc_data_structures::transitive_relation::TransitiveRelation; | ||
|
||
#[derive(Clone)] | ||
pub struct FreeRegionMap { | ||
/// `map` maps from a free region `a` to a list of | ||
/// free regions `bs` such that `a <= b for all b in bs` | ||
map: FnvHashMap<FreeRegion, Vec<FreeRegion>>, | ||
/// regions that are required to outlive (and therefore be | ||
/// equal to) 'static. | ||
statics: FnvHashSet<FreeRegion> | ||
relation: TransitiveRelation<Region> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know the code is practically self-documenting, but it might be nice to at least state here what relation is encoded in this field. (Namely whether a relation |
||
} | ||
|
||
impl FreeRegionMap { | ||
pub fn new() -> FreeRegionMap { | ||
FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() } | ||
FreeRegionMap { relation: TransitiveRelation::new() } | ||
} | ||
|
||
pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self, | ||
|
@@ -84,22 +78,38 @@ impl FreeRegionMap { | |
} | ||
|
||
fn relate_to_static(&mut self, sup: FreeRegion) { | ||
self.statics.insert(sup); | ||
self.relation.add(ty::ReStatic, ty::ReFree(sup)); | ||
} | ||
|
||
fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { | ||
let mut sups = self.map.entry(sub).or_insert(Vec::new()); | ||
if !sups.contains(&sup) { | ||
sups.push(sup); | ||
} | ||
self.relation.add(ty::ReFree(sub), ty::ReFree(sup)) | ||
} | ||
|
||
/// Determines whether two free regions have a subregion relationship | ||
/// by walking the graph encoded in `map`. Note that | ||
/// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub` | ||
/// (that is, the user can give two different names to the same lifetime). | ||
pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool { | ||
can_reach(&self.map, sub, sup) || self.is_static(&sup) | ||
let result = sub == sup || { | ||
let sub = ty::ReFree(sub); | ||
let sup = ty::ReFree(sup); | ||
self.relation.contains(&sub, &sup) || self.relation.contains(&sup, &ty::ReStatic) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The right-hand disjunct,
(When I first read it, I thought that it was trying to capture some sort of reasoning like " There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Indeed, you'd think I should be able to make some sort of test that will fail here... or at least fail to compile when expected. I think it doesn't make everything go completely nuts simply because ty::ReStatic is usually not in the relation (and when it is, it never has incoming edges). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fn test<'a,'b>(x: &'a i32) -> &'b i32
where 'a: 'static
{
x
}
fn main() { } |
||
}; | ||
debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result); | ||
result | ||
} | ||
|
||
pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region { | ||
let r_a = ty::ReFree(fr_a); | ||
let r_b = ty::ReFree(fr_b); | ||
let result = if fr_a == fr_b { r_a } else { | ||
match self.relation.best_upper_bound(&r_a, &r_b) { | ||
None => ty::ReStatic, | ||
Some(r) => *r, | ||
} | ||
}; | ||
debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result); | ||
result | ||
} | ||
|
||
/// Determines whether one region is a subregion of another. This is intended to run *after | ||
|
@@ -109,10 +119,7 @@ impl FreeRegionMap { | |
sub_region: ty::Region, | ||
super_region: ty::Region) | ||
-> bool { | ||
debug!("is_subregion_of(sub_region={:?}, super_region={:?})", | ||
sub_region, super_region); | ||
|
||
sub_region == super_region || { | ||
let result = sub_region == super_region || { | ||
match (sub_region, super_region) { | ||
(ty::ReEmpty, _) | | ||
(_, ty::ReStatic) => | ||
|
@@ -121,23 +128,47 @@ impl FreeRegionMap { | |
(ty::ReScope(sub_scope), ty::ReScope(super_scope)) => | ||
tcx.region_maps.is_subscope_of(sub_scope, super_scope), | ||
|
||
(ty::ReScope(sub_scope), ty::ReFree(ref fr)) => | ||
tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()), | ||
(ty::ReScope(sub_scope), ty::ReFree(fr)) => | ||
tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()) || | ||
self.is_static(fr), | ||
|
||
(ty::ReFree(sub_fr), ty::ReFree(super_fr)) => | ||
self.sub_free_region(sub_fr, super_fr), | ||
|
||
(ty::ReStatic, ty::ReFree(ref sup_fr)) => self.is_static(sup_fr), | ||
(ty::ReStatic, ty::ReFree(sup_fr)) => | ||
self.is_static(sup_fr), | ||
|
||
_ => | ||
false, | ||
} | ||
} | ||
}; | ||
debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}", | ||
sub_region, super_region, result); | ||
result | ||
} | ||
|
||
/// Determines whether this free-region is required to be 'static | ||
pub fn is_static(&self, super_region: &ty::FreeRegion) -> bool { | ||
pub fn is_static(&self, super_region: ty::FreeRegion) -> bool { | ||
debug!("is_static(super_region={:?})", super_region); | ||
self.statics.iter().any(|s| can_reach(&self.map, *s, *super_region)) | ||
self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region)) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
fn free_region(index: u32) -> FreeRegion { | ||
use middle::region::DestructionScopeData; | ||
FreeRegion { scope: DestructionScopeData::new(0), | ||
bound_region: ty::BoundRegion::BrAnon(index) } | ||
} | ||
|
||
#[test] | ||
fn lub() { | ||
// a very VERY basic test, but see the tests in | ||
// TransitiveRelation, which are much more thorough. | ||
let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect(); | ||
let mut map = FreeRegionMap::new(); | ||
map.relate_free_regions(frs[0], frs[2]); | ||
map.relate_free_regions(frs[1], frs[2]); | ||
assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2])); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love