From e86c87a81e69de51cfed5719888840f25266a8d8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 14 Aug 2014 18:05:27 -0400 Subject: [PATCH] Generalize lifetime bounds on type parameters to support multiple 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). --- src/librustc/metadata/tydecode.rs | 4 +-- src/librustc/metadata/tyencode.rs | 2 +- src/librustc/middle/ty.rs | 7 ++-- src/librustc/middle/ty_fold.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 2 +- src/librustc/middle/typeck/check/regionck.rs | 2 +- .../middle/typeck/check/regionmanip.rs | 2 +- src/librustc/middle/typeck/collect.rs | 12 +++---- ...n-bounds-on-objects-and-type-parameters.rs | 4 +-- ...ions-close-over-type-parameter-multiple.rs | 32 +++++++++++++++++++ ...-close-over-type-parameter-successfully.rs | 30 +++++++++++++++++ 11 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/regions-close-over-type-parameter-multiple.rs create mode 100644 src/test/run-pass/regions-close-over-type-parameter-successfully.rs diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 53203663bb16e..0e888b39b8516 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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)))); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index cbf558b6b483e..3ef1d15cf5651 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index d0b94cb3abb8b..628665457cc91 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1008,7 +1008,7 @@ 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, + pub region_bounds: Vec, pub builtin_bounds: BuiltinBounds, pub trait_bounds: Vec> } @@ -1016,7 +1016,8 @@ pub struct ParamBounds { /// 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, @@ -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={}", diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 549f0daef8112..48fa6f823b0e5 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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), } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 20fe8186adf40..ec2c3d2d2efb2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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() { diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 45ffddf3fe80e..6926d9dd0e7e7 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -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()); diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index 60e502786ab3d..8bcbe4b792985 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -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(); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 581bd8acbc97e..74db36ff9ac37 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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), }, @@ -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 = + 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, } diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs index 40cff3e466b71..6b3c92e0028bf 100644 --- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs +++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs @@ -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() { } diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs new file mode 100644 index 0000000000000..cec785c6e9666 --- /dev/null +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -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 or the MIT license +// , 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 { + // A outlives 'a AND 'b... + box v as Box // ...hence this type is safe. +} + +fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { + // A outlives 'a AND 'b... + box v as Box // ...hence this type is safe. +} + +fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { + // A outlives 'a AND 'b...but not 'c. + box v as Box //~ ERROR mismatched types +} + +fn main() { +} diff --git a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs new file mode 100644 index 0000000000000..5dba80ad38a16 --- /dev/null +++ b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs @@ -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 or the MIT license +// , 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 { + box v as Box +} + +fn main() { + let i: int = 22; + let obj = make_object(&i); + assert_eq!(22, obj.get()); +}