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))));
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);
}
/// 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,
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={}",
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),
}
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() {
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());
// 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();
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),
},
.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,
}
'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() { }
--- /dev/null
+// 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() {
+}
--- /dev/null
+// 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());
+}