Skip to content

A few fixes for lifetime parameters #26831

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

Merged
merged 3 commits into from
Jul 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions src/librustc/middle/free_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@
use middle::implicator::Implication;
use middle::ty::{self, FreeRegion};
use util::common::can_reach;
use util::nodemap::FnvHashMap;
use util::nodemap::{FnvHashMap, FnvHashSet};

#[derive(Clone)]
pub struct FreeRegionMap {
/// `free_region_map` maps from a free region `a` to a list of
/// `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>
}

impl FreeRegionMap {
pub fn new() -> FreeRegionMap {
FreeRegionMap { map: FnvHashMap() }
FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() }
}

pub fn relate_free_regions_from_implications<'tcx>(&mut self,
Expand Down Expand Up @@ -59,6 +62,8 @@ impl FreeRegionMap {
}
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
match (r_a, r_b) {
(ty::ReStatic, ty::ReFree(_)) => {},
(ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a),
(ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
// Record that `'a:'b`. Or, put another way, `'b <= 'a`.
self.relate_free_regions(fr_b, fr_a);
Expand All @@ -76,8 +81,12 @@ impl FreeRegionMap {
}
}

pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
let mut sups = self.map.entry(sub).or_insert(Vec::new());
fn relate_to_static(&mut self, sup: FreeRegion) {
self.statics.insert(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);
}
Expand All @@ -88,7 +97,7 @@ impl FreeRegionMap {
/// 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)
can_reach(&self.map, sub, sup) || self.is_static(&sup)
}

/// Determines whether one region is a subregion of another. This is intended to run *after
Expand Down Expand Up @@ -116,10 +125,17 @@ impl FreeRegionMap {
(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),

_ =>
false,
}
}
}
}

/// Determines whether this free-region is required to be 'static
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))
}
}
3 changes: 2 additions & 1 deletion src/librustc/middle/infer/region_inference/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
// is the scope `s_id`. Otherwise, as we do not know
// big the free region is precisely, the GLB is undefined.
let fr_scope = fr.scope.to_code_extent();
if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope {
if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope ||
free_regions.is_static(fr) {
Ok(s)
} else {
Err(TypeError::RegionsNoOverlap(b, a))
Expand Down
10 changes: 6 additions & 4 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,11 +905,13 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let vtable = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable);
let vtable = erase_regions(tcx,
&drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable)
);

info!("Cache miss: {:?}", trait_ref);
ccx.trait_cache().borrow_mut().insert(trait_ref,
vtable.clone());
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);

ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone());

vtable
}
Expand Down
30 changes: 12 additions & 18 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt,
// any ambiguity.
fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>,
ty_param_node_id: ast::NodeId,
ty_param_name: Option<ast::Name>,
ty_param_name: ast::Name,
assoc_name: ast::Name,
span: Span)
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
Expand All @@ -1138,21 +1138,11 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>,
.filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name))
.collect();

if let Some(s) = ty_param_name {
// borrowck doesn't like this any other way
one_bound_for_assoc_type(tcx,
suitable_bounds,
&token::get_name(s),
&token::get_name(assoc_name),
span)
} else {
one_bound_for_assoc_type(tcx,
suitable_bounds,
"Self",
&token::get_name(assoc_name),
span)

}
one_bound_for_assoc_type(tcx,
suitable_bounds,
&token::get_name(ty_param_name),
&token::get_name(assoc_name),
span)
}


Expand Down Expand Up @@ -1251,7 +1241,11 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
}
(&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => {
assert_eq!(trait_did.krate, ast::LOCAL_CRATE);
match find_bound_for_assoc_item(this, trait_did.node, None, assoc_name, span) {
match find_bound_for_assoc_item(this,
trait_did.node,
token::special_idents::type_self.name,
assoc_name,
span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
Expand All @@ -1260,7 +1254,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
assert_eq!(param_did.krate, ast::LOCAL_CRATE);
match find_bound_for_assoc_item(this,
param_did.node,
Some(param_name),
param_name,
assoc_name,
span) {
Ok(bound) => bound,
Expand Down
24 changes: 24 additions & 0 deletions src/test/compile-fail/regions-static-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn static_id<'a,'b>(t: &'a ()) -> &'static ()
where 'a: 'static { t }
fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
where 'a: 'b, 'b: 'static { t }
fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
t //~ ERROR cannot infer an appropriate lifetime
}

fn error(u: &(), v: &()) {
static_id(&u); //~ ERROR cannot infer an appropriate lifetime
static_id_indirect(&v); //~ ERROR cannot infer an appropriate lifetime
}

fn main() {}
23 changes: 23 additions & 0 deletions src/test/run-pass/issue-26802.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait Foo<'a> {
fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 }
}

pub struct FooBar;
impl Foo<'static> for FooBar {}
fn test(foobar: FooBar) -> Box<Foo<'static>> {
Box::new(foobar)
}

fn main() {
assert_eq!(test(FooBar).bar(&4), 11);
}
28 changes: 28 additions & 0 deletions src/test/run-pass/regions-static-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a ()
where 'a: 'static { t }
fn static_id<'a>(t: &'a ()) -> &'static ()
where 'a: 'static { t }
fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
where 'a: 'b, 'b: 'static { t }
fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t }

static UNIT: () = ();

fn main()
{
let mut val : &'static () = &UNIT;
invariant_id(&mut val);
static_id(val);
static_id_indirect(val);
ref_id(val);
}