Skip to content

Commit

Permalink
Generalize lifetime bounds on type parameters to support multiple
Browse files Browse the repository at this point in the history
lifetime bounds. This doesn't really cause any difficulties, because
we already had to accommodate the fact that multiple implicit bounds
could accumulate. Object types still require precisely one lifetime
bound. This is a pre-step towards generalized where clauses (once you
have lifetime bounds in where clauses, it is harder to restrict them
to exactly one).
  • Loading branch information
nikomatsakis committed Sep 16, 2014
1 parent 946654a commit e86c87a
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 18 deletions.
4 changes: 2 additions & 2 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,14 +680,14 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
let builtin_bounds = parse_builtin_bounds(st, |x,y| conv(x,y));

let mut param_bounds = ty::ParamBounds {
opt_region_bound: None,
region_bounds: Vec::new(),
builtin_bounds: builtin_bounds,
trait_bounds: Vec::new()
};
loop {
match next(st) {
'R' => {
param_bounds.opt_region_bound = Some(parse_region(st, |x, y| conv (x, y)));
param_bounds.region_bounds.push(parse_region(st, |x, y| conv (x, y)));
}
'I' => {
param_bounds.trait_bounds.push(Rc::new(parse_trait_ref(st, |x,y| conv(x,y))));
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ pub fn enc_existential_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::Exi
pub fn enc_bounds(w: &mut SeekableMemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
enc_builtin_bounds(w, cx, &bs.builtin_bounds);

for &r in bs.opt_region_bound.iter() {
for &r in bs.region_bounds.iter() {
mywrite!(w, "R");
enc_region(w, cx, r);
}
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,15 +1008,16 @@ pub enum type_err {
/// as well as the existential type parameter in an object type.
#[deriving(PartialEq, Eq, Hash, Clone, Show)]
pub struct ParamBounds {
pub opt_region_bound: Option<ty::Region>,
pub region_bounds: Vec<ty::Region>,
pub builtin_bounds: BuiltinBounds,
pub trait_bounds: Vec<Rc<TraitRef>>
}

/// Bounds suitable for an existentially quantified type parameter
/// such as those that appear in object types or closure types. The
/// major difference between this case and `ParamBounds` is that
/// general purpose trait bounds are omitted.
/// general purpose trait bounds are omitted and there must be
/// *exactly one* region.
#[deriving(PartialEq, Eq, Hash, Clone, Show)]
pub struct ExistentialBounds {
pub region_bound: ty::Region,
Expand Down Expand Up @@ -4864,7 +4865,7 @@ pub fn required_region_bounds(tcx: &ctxt,
trait_bounds,
|trait_ref| {
let bounds = ty::bounds_for_trait_ref(tcx, &*trait_ref);
push_region_bounds(bounds.opt_region_bound.as_slice(),
push_region_bounds(bounds.region_bounds.as_slice(),
bounds.builtin_bounds,
&mut all_bounds);
debug!("from {}: bounds={} all_bounds={}",
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl TypeFoldable for ty::ExistentialBounds {
impl TypeFoldable for ty::ParamBounds {
fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParamBounds {
ty::ParamBounds {
opt_region_bound: self.opt_region_bound.fold_with(folder),
region_bounds: self.region_bounds.fold_with(folder),
builtin_bounds: self.builtin_bounds.fold_with(folder),
trait_bounds: self.trait_bounds.fold_with(folder),
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2005,7 +2005,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let region_bounds =
ty::required_region_bounds(
self.tcx(),
param_bound.opt_region_bound.as_slice(),
param_bound.region_bounds.as_slice(),
param_bound.builtin_bounds,
param_bound.trait_bounds.as_slice());
for &r in region_bounds.iter() {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@ fn param_must_outlive(rcx: &Rcx,
let param_bound = param_env.bounds.get(param_ty.space, param_ty.idx);
param_bounds =
ty::required_region_bounds(rcx.tcx(),
param_bound.opt_region_bound.as_slice(),
param_bound.region_bounds.as_slice(),
param_bound.builtin_bounds,
param_bound.trait_bounds.as_slice());

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/check/regionmanip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {

// Inspect bounds on this type parameter for any
// region bounds.
for &r in type_param_def.bounds.opt_region_bound.iter() {
for &r in type_param_def.bounds.region_bounds.iter() {
self.stack.push((r, Some(ty)));
self.accumulate_from_ty(type_param_ty);
self.stack.pop().unwrap();
Expand Down
12 changes: 6 additions & 6 deletions src/librustc/middle/typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
ident: special_idents::type_self,
def_id: local_def(param_id),
bounds: ty::ParamBounds {
opt_region_bound: None,
region_bounds: vec!(),
builtin_bounds: ty::empty_builtin_bounds(),
trait_bounds: vec!(self_trait_ref),
},
Expand Down Expand Up @@ -1280,12 +1280,12 @@ fn conv_param_bounds(ccx: &CrateCtxt,
.map(|b| instantiate_trait_ref(ccx, b, param_ty.to_ty(ccx.tcx)))
.chain(unboxed_fn_ty_bounds)
.collect();
let opt_region_bound =
astconv::compute_opt_region_bound(
ccx.tcx, span, builtin_bounds, region_bounds.as_slice(),
trait_bounds.as_slice());
let region_bounds: Vec<ty::Region> =
region_bounds.move_iter()
.map(|r| ast_region_to_region(ccx.tcx, r))
.collect();
ty::ParamBounds {
opt_region_bound: opt_region_bound,
region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ fn test<
'a,
'b,
A:IsStatic,
B:Is<'a>+Is2<'b>, //~ ERROR ambiguous lifetime bound
B:Is<'a>+Is2<'b>, // OK in a parameter, but not an object type.
C:'b+Is<'a>+Is2<'b>,
D:Is<'a>+Is2<'static>,
E:'a+'b //~ ERROR only a single explicit lifetime bound is permitted
E:'a+'b // OK in a parameter, but not an object type.
>() { }

fn main() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2014 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.

// Various tests where we over type parameters with multiple lifetime
// bounds.

trait SomeTrait { fn get(&self) -> int; }

fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'a> {
// A outlives 'a AND 'b...
box v as Box<SomeTrait+'a> // ...hence this type is safe.
}

fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
// A outlives 'a AND 'b...
box v as Box<SomeTrait+'b> // ...hence this type is safe.
}

fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
// A outlives 'a AND 'b...but not 'c.
box v as Box<SomeTrait+'a> //~ ERROR mismatched types
}

fn main() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2014 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.

// A test where we (successfully) close over a reference into
// an object.

trait SomeTrait { fn get(&self) -> int; }

impl<'a> SomeTrait for &'a int {
fn get(&self) -> int {
**self
}
}

fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box<SomeTrait+'a> {
box v as Box<SomeTrait+'a>
}

fn main() {
let i: int = 22;
let obj = make_object(&i);
assert_eq!(22, obj.get());
}

0 comments on commit e86c87a

Please sign in to comment.