Auto merge of #22230 - nikomatsakis:object-lifetime-defaults-2, r=pnkfelix

Implement rules described in rust-lang/rfcs#599.

Fixes https://github.com/rust-lang/rust/issues/22211.

~~Based atop PR https://github.com/rust-lang/rust/pull/22182, so the first few commits (up to and including "Pacify the mercilous nrc") have already been reviewed.~~
This commit is contained in:
bors 2015-02-16 20:31:15 +00:00
commit 81bce5290f
53 changed files with 1264 additions and 272 deletions

View File

@ -824,6 +824,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
assert_eq!(next(st), '|');
let bounds = parse_bounds_(st, conv);
let default = parse_opt(st, |st| parse_ty_(st, conv));
let object_lifetime_default = parse_object_lifetime_default(st, conv);
ty::TypeParameterDef {
name: name,
@ -831,7 +832,24 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
space: space,
index: index,
bounds: bounds,
default: default
default: default,
object_lifetime_default: object_lifetime_default,
}
}
fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
conv: &mut F)
-> Option<ty::ObjectLifetimeDefault>
where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
match next(st) {
'n' => None,
'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
's' => {
let region = parse_region_(st, conv);
Some(ty::ObjectLifetimeDefault::Specific(region))
}
_ => panic!("parse_object_lifetime_default: bad input")
}
}

View File

@ -414,6 +414,21 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
v.space.to_uint(), v.index);
enc_bounds(w, cx, &v.bounds);
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
}
fn enc_object_lifetime_default<'a, 'tcx>(w: &mut SeekableMemWriter,
cx: &ctxt<'a, 'tcx>,
default: Option<ty::ObjectLifetimeDefault>)
{
match default {
None => mywrite!(w, "n"),
Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
Some(ty::ObjectLifetimeDefault::Specific(r)) => {
mywrite!(w, "s");
enc_region(w, cx, r);
}
}
}
pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,

View File

@ -619,7 +619,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
infer::RelateRegionParamBound(span) => {
self.tcx.sess.span_err(
span,
"declared lifetime bound not satisfied");
"lifetime bound not satisfied");
note_and_explain_region(
self.tcx,
"lifetime parameter instantiated with ",
@ -1628,7 +1628,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
self.tcx.sess.span_note(
span,
&format!("...so that the type `{}` \
will meet the declared lifetime bounds",
will meet its required lifetime bounds",
self.ty_to_string(t))[]);
}
infer::RelateDefaultParamBound(span, t) => {

View File

@ -1762,6 +1762,21 @@ impl fmt::Debug for IntVarValue {
}
}
/// Default region to use for the bound of objects that are
/// supplied as the value for this type parameter. This is derived
/// from `T:'a` annotations appearing in the type definition. If
/// this is `None`, then the default is inherited from the
/// surrounding context. See RFC #599 for details.
#[derive(Copy, Clone, Debug)]
pub enum ObjectLifetimeDefault {
/// Require an explicit annotation. Occurs when multiple
/// `T:'a` constraints are found.
Ambiguous,
/// Use the given region as the default.
Specific(Region),
}
#[derive(Clone, Debug)]
pub struct TypeParameterDef<'tcx> {
pub name: ast::Name,
@ -1770,6 +1785,7 @@ pub struct TypeParameterDef<'tcx> {
pub index: u32,
pub bounds: ParamBounds<'tcx>,
pub default: Option<Ty<'tcx>>,
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
}
#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
@ -5884,42 +5900,13 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
return true;
}
pub fn object_region_bounds<'tcx>(
tcx: &ctxt<'tcx>,
opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures
others: BuiltinBounds)
-> Vec<ty::Region>
{
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
// a skolemized type.
let open_ty = ty::mk_infer(tcx, FreshTy(0));
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
// Note that we preserve the overall binding levels here.
assert!(!open_ty.has_escaping_regions());
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))))
});
let param_bounds = ty::ParamBounds {
region_bounds: Vec::new(),
builtin_bounds: others,
trait_bounds: opt_trait_ref,
projection_bounds: Vec::new(), // not relevant to computing region bounds
};
let predicates = ty::predicates(tcx, open_ty, &param_bounds);
ty::required_region_bounds(tcx, open_ty, predicates)
}
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
/// parameter `erased_self_ty` must be supplied to indicate what type
/// has been used to represent `Self` in the predicates
/// themselves. This should really be a unique type; `FreshTy(0)` is a
/// popular choice (see `object_region_bounds` above).
/// popular choice.
///
/// Requires that trait definitions have been processed so that we can
/// elaborate predicates and walk supertraits.
@ -7390,3 +7377,12 @@ impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
self.caller_bounds.repr(tcx))
}
}
impl<'tcx> Repr<'tcx> for ObjectLifetimeDefault {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
match *self {
ObjectLifetimeDefault::Ambiguous => format!("Ambiguous"),
ObjectLifetimeDefault::Specific(ref r) => r.repr(tcx),
}
}
}

View File

@ -379,6 +379,19 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
index: self.index,
bounds: self.bounds.fold_with(folder),
default: self.default.fold_with(folder),
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
match *self {
ty::ObjectLifetimeDefault::Ambiguous =>
ty::ObjectLifetimeDefault::Ambiguous,
ty::ObjectLifetimeDefault::Specific(r) =>
ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
}
}
}

View File

@ -55,8 +55,8 @@ use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::traits;
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
ShiftedRscope, BindingRscope};
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use TypeAndSubsts;
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::DefIdMap;
@ -264,19 +264,18 @@ pub fn ast_path_substs_for_ty<'tcx>(
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
convert_angle_bracketed_parameters(this, rscope, data)
convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
}
ast::ParenthesizedParameters(ref data) => {
span_err!(tcx.sess, path.span, E0214,
"parenthesized parameters may only be used with a trait");
convert_parenthesized_parameters(this, data)
convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
}
};
prohibit_projections(this.tcx(), &assoc_bindings);
create_substs_for_ast_path(this,
rscope,
path.span,
decl_generics,
None,
@ -284,14 +283,12 @@ pub fn ast_path_substs_for_ty<'tcx>(
regions)
}
fn create_substs_for_ast_path<'tcx>(
fn create_region_substs<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
types: Vec<Ty<'tcx>>,
regions: Vec<ty::Region>)
regions_provided: Vec<ty::Region>)
-> Substs<'tcx>
{
let tcx = this.tcx();
@ -300,9 +297,9 @@ fn create_substs_for_ast_path<'tcx>(
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
let expected_num_region_params = decl_generics.regions.len(TypeSpace);
let supplied_num_region_params = regions.len();
let supplied_num_region_params = regions_provided.len();
let regions = if expected_num_region_params == supplied_num_region_params {
regions
regions_provided
} else {
let anon_regions =
rscope.anon_regions(span, expected_num_region_params);
@ -314,51 +311,82 @@ fn create_substs_for_ast_path<'tcx>(
}
match anon_regions {
Ok(v) => v.into_iter().collect(),
Err(_) => (0..expected_num_region_params)
.map(|_| ty::ReStatic).collect() // hokey
Ok(anon_regions) => anon_regions,
Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
}
};
Substs::new_type(vec![], regions)
}
/// Given the type/region arguments provided to some path (along with
/// an implicit Self, if this is a trait reference) returns the complete
/// set of substitutions. This may involve applying defaulted type parameters.
///
/// Note that the type listing given here is *exactly* what the user provided.
///
/// The `region_substs` should be the result of `create_region_substs`
/// -- that is, a substitution with no types but the correct number of
/// regions.
fn create_substs_for_ast_path<'tcx>(
this: &AstConv<'tcx>,
span: Span,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
types_provided: Vec<Ty<'tcx>>,
region_substs: Substs<'tcx>)
-> Substs<'tcx>
{
let tcx = this.tcx();
debug!("create_substs_for_ast_path(decl_generics={}, self_ty={}, \
types_provided={}, region_substs={}",
decl_generics.repr(tcx), self_ty.repr(tcx), types_provided.repr(tcx),
region_substs.repr(tcx));
assert_eq!(region_substs.regions().len(TypeSpace), decl_generics.regions.len(TypeSpace));
assert!(region_substs.types.is_empty());
// Convert the type parameters supplied by the user.
let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
let supplied_ty_param_count = types.len();
let formal_ty_param_count =
ty_param_defs.iter()
.take_while(|x| !ty::is_associated_type(tcx, x.def_id))
.count();
let required_ty_param_count =
ty_param_defs.iter()
.take_while(|x| {
x.default.is_none() &&
!ty::is_associated_type(tcx, x.def_id)
})
.count();
let supplied_ty_param_count = types_provided.len();
let formal_ty_param_count = ty_param_defs.len();
let required_ty_param_count = ty_param_defs.iter()
.take_while(|x| x.default.is_none())
.count();
let mut type_substs = types_provided;
if supplied_ty_param_count < required_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count {
"expected at least"
} else {
"expected"
};
span_fatal!(this.tcx().sess, span, E0243,
"wrong number of type arguments: {} {}, found {}",
expected,
required_ty_param_count,
supplied_ty_param_count);
span_err!(this.tcx().sess, span, E0243,
"wrong number of type arguments: {} {}, found {}",
expected,
required_ty_param_count,
supplied_ty_param_count);
while type_substs.len() < required_ty_param_count {
type_substs.push(tcx.types.err);
}
} else if supplied_ty_param_count > formal_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count {
"expected at most"
} else {
"expected"
};
span_fatal!(this.tcx().sess, span, E0244,
"wrong number of type arguments: {} {}, found {}",
expected,
formal_ty_param_count,
supplied_ty_param_count);
span_err!(this.tcx().sess, span, E0244,
"wrong number of type arguments: {} {}, found {}",
expected,
formal_ty_param_count,
supplied_ty_param_count);
type_substs.truncate(formal_ty_param_count);
}
assert!(type_substs.len() >= required_ty_param_count &&
type_substs.len() <= formal_ty_param_count);
let mut substs = Substs::new_type(types, regions);
let mut substs = region_substs;
substs.types.extend(TypeSpace, type_substs.into_iter());
match self_ty {
None => {
@ -374,7 +402,8 @@ fn create_substs_for_ast_path<'tcx>(
}
}
for param in &ty_param_defs[supplied_ty_param_count..] {
let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
for param in &ty_param_defs[actual_supplied_ty_param_count..] {
match param.default {
Some(default) => {
// This is a default type parameter.
@ -400,29 +429,36 @@ struct ConvertedBinding<'tcx> {
fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
decl_generics: &ty::Generics<'tcx>,
data: &ast::AngleBracketedParameterData)
-> (Vec<ty::Region>,
-> (Substs<'tcx>,
Vec<Ty<'tcx>>,
Vec<ConvertedBinding<'tcx>>)
{
let regions: Vec<_> =
data.lifetimes.iter()
.map(|l| ast_region_to_region(this.tcx(), l))
.collect();
.map(|l| ast_region_to_region(this.tcx(), l))
.collect();
let region_substs =
create_region_substs(this, rscope, span, decl_generics, regions);
let types: Vec<_> =
data.types.iter()
.map(|t| ast_ty_to_ty(this, rscope, &**t))
.collect();
.enumerate()
.map(|(i,t)| ast_ty_arg_to_ty(this, rscope, decl_generics,
i, &region_substs, t))
.collect();
let assoc_bindings: Vec<_> =
data.bindings.iter()
.map(|b| ConvertedBinding { item_name: b.ident.name,
ty: ast_ty_to_ty(this, rscope, &*b.ty),
span: b.span })
.collect();
.map(|b| ConvertedBinding { item_name: b.ident.name,
ty: ast_ty_to_ty(this, rscope, &*b.ty),
span: b.span })
.collect();
(regions, types, assoc_bindings)
(region_substs, types, assoc_bindings)
}
/// Returns the appropriate lifetime to use for any output lifetimes
@ -465,7 +501,7 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
{
match implied_output_region {
Some(implied_output_region) => {
let rb = SpecificRscope::new(implied_output_region);
let rb = ElidableRscope::new(implied_output_region);
ast_ty_to_ty(this, &rb, ty)
}
None => {
@ -479,15 +515,23 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
}
fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
decl_generics: &ty::Generics<'tcx>,
data: &ast::ParenthesizedParameterData)
-> (Vec<ty::Region>,
-> (Substs<'tcx>,
Vec<Ty<'tcx>>,
Vec<ConvertedBinding<'tcx>>)
{
let region_substs =
create_region_substs(this, rscope, span, decl_generics, Vec::new());
let binding_rscope = BindingRscope::new();
let inputs = data.inputs.iter()
.map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
.collect::<Vec<Ty<'tcx>>>();
let inputs =
data.inputs.iter()
.map(|a_t| ast_ty_arg_to_ty(this, &binding_rscope, decl_generics,
0, &region_substs, a_t))
.collect::<Vec<Ty<'tcx>>>();
let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect();
let (implied_output_region,
@ -514,7 +558,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
span: output_span
};
(vec![], vec![input_ty], vec![output_binding])
(region_substs, vec![input_ty], vec![output_binding])
}
pub fn instantiate_poly_trait_ref<'tcx>(
@ -615,7 +659,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
// For now, require that parenthetical5D notation be used
// For now, require that parenthetical notation be used
// only with `Fn()` etc.
if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
span_err!(this.tcx().sess, path.span, E0215,
@ -626,7 +670,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
the crate attributes to enable");
}
convert_angle_bracketed_parameters(this, rscope, data)
convert_angle_bracketed_parameters(this, rscope, path.span, &trait_def.generics, data)
}
ast::ParenthesizedParameters(ref data) => {
// For now, require that parenthetical notation be used
@ -640,12 +684,11 @@ fn ast_path_to_trait_ref<'a,'tcx>(
the crate attributes to enable");
}
convert_parenthesized_parameters(this, data)
convert_parenthesized_parameters(this, rscope, path.span, &trait_def.generics, data)
}
};
let substs = create_substs_for_ast_path(this,
rscope,
path.span,
&trait_def.generics,
self_ty,
@ -932,7 +975,7 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
let existential_bounds = conv_existential_bounds(this,
rscope,
span,
Some(trait_ref.clone()),
trait_ref.clone(),
projection_bounds,
bounds);
@ -1031,10 +1074,45 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
qpath.item_path.identifier.name);
}
// Parses the programmer's textual representation of a type into our
// internal notion of a type.
pub fn ast_ty_to_ty<'tcx>(
this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx>
/// Convert a type supplied as value for a type argument from AST into our
/// our internal representation. This is the same as `ast_ty_to_ty` but that
/// it applies the object lifetime default.
///
/// # Parameters
///
/// * `this`, `rscope`: the surrounding context
/// * `decl_generics`: the generics of the struct/enum/trait declaration being
/// referenced
/// * `index`: the index of the type parameter being instantiated from the list
/// (we assume it is in the `TypeSpace`)
/// * `region_substs`: a partial substitution consisting of
/// only the region type parameters being supplied to this type.
/// * `ast_ty`: the ast representation of the type being supplied
pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
decl_generics: &ty::Generics<'tcx>,
index: usize,
region_substs: &Substs<'tcx>,
ast_ty: &ast::Ty)
-> Ty<'tcx>
{
let tcx = this.tcx();
if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
ast_ty_to_ty(this, rscope1, ast_ty)
} else {
ast_ty_to_ty(this, rscope, ast_ty)
}
}
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
ast_ty: &ast::Ty)
-> Ty<'tcx>
{
debug!("ast_ty_to_ty(ast_ty={})",
ast_ty.repr(this.tcx()));
@ -1084,7 +1162,11 @@ pub fn ast_ty_to_ty<'tcx>(
ast::TyRptr(ref region, ref mt) => {
let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
debug!("ty_rptr r={}", r.repr(this.tcx()));
let t = ast_ty_to_ty(this, rscope, &*mt.ty);
let rscope1 =
&ObjectLifetimeDefaultRscope::new(
rscope,
Some(ty::ObjectLifetimeDefault::Specific(r)));
let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
}
ast::TyTup(ref fields) => {
@ -1518,11 +1600,11 @@ pub fn ty_of_closure<'tcx>(
/// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent
/// for closures. Eventually this should all be normalized, I think, so that there is no "main
/// trait ref" and instead we just have a flat list of bounds as the existential type.
pub fn conv_existential_bounds<'tcx>(
fn conv_existential_bounds<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
principal_trait_ref: ty::PolyTraitRef<'tcx>,
projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
ast_bounds: &[ast::TyParamBound])
-> ty::ExistentialBounds<'tcx>
@ -1546,15 +1628,15 @@ fn conv_ty_poly_trait_ref<'tcx>(
let mut projection_bounds = Vec::new();
let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
let trait_bound = partitioned_bounds.trait_bounds.remove(0);
Some(instantiate_poly_trait_ref(this,
rscope,
trait_bound,
None,
&mut projection_bounds))
instantiate_poly_trait_ref(this,
rscope,
trait_bound,
None,
&mut projection_bounds)
} else {
span_err!(this.tcx().sess, span, E0224,
"at least one non-builtin trait is required for an object type");
None
"at least one non-builtin trait is required for an object type");
return this.tcx().types.err;
};
let bounds =
@ -1565,17 +1647,14 @@ fn conv_ty_poly_trait_ref<'tcx>(
projection_bounds,
partitioned_bounds);
match main_trait_bound {
None => this.tcx().types.err,
Some(principal) => ty::mk_trait(this.tcx(), principal, bounds)
}
ty::mk_trait(this.tcx(), main_trait_bound, bounds)
}
pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
principal_trait_ref: ty::PolyTraitRef<'tcx>,
mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
partitioned_bounds: PartitionedBounds)
-> ty::ExistentialBounds<'tcx>
@ -1588,16 +1667,15 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
if !trait_bounds.is_empty() {
let b = &trait_bounds[0];
span_err!(this.tcx().sess, b.trait_ref.path.span, E0225,
"only the builtin traits can be used \
as closure or object bounds");
"only the builtin traits can be used as closure or object bounds");
}
let region_bound = compute_region_bound(this,
rscope,
span,
&region_bounds,
principal_trait_ref,
builtin_bounds);
let region_bound = compute_object_lifetime_bound(this,
rscope,
span,
&region_bounds,
principal_trait_ref,
builtin_bounds);
ty::sort_bounds_list(&mut projection_bounds);
@ -1608,17 +1686,21 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
}
}
/// Given the bounds on a type parameter / existential type, determines what single region bound
/// Given the bounds on an object, determines what single region bound
/// (if any) we can use to summarize this type. The basic idea is that we will use the bound the
/// user provided, if they provided one, and otherwise search the supertypes of trait bounds for
/// region bounds. It may be that we can derive no bound at all, in which case we return `None`.
fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
explicit_region_bounds: &[&ast::Lifetime],
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
builtin_bounds: ty::BuiltinBounds)
-> Option<ty::Region>
fn compute_object_lifetime_bound<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
explicit_region_bounds: &[&ast::Lifetime],
principal_trait_ref: ty::PolyTraitRef<'tcx>,
builtin_bounds: ty::BuiltinBounds)
-> ty::Region
{
let tcx = this.tcx();
debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
principal_trait_ref={}, builtin_bounds={})",
explicit_region_bounds,
@ -1633,24 +1715,32 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
if explicit_region_bounds.len() != 0 {
// Explicitly specified region bound. Use that.
let r = explicit_region_bounds[0];
return Some(ast_region_to_region(tcx, r));
return ast_region_to_region(tcx, r);
}
// No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those.
let derived_region_bounds =
ty::object_region_bounds(tcx, principal_trait_ref.as_ref(), builtin_bounds);
object_region_bounds(tcx, &principal_trait_ref, builtin_bounds);
// If there are no derived region bounds, then report back that we
// can find no region bound.
if derived_region_bounds.len() == 0 {
return None;
match rscope.object_lifetime_default(span) {
Some(r) => { return r; }
None => {
span_err!(this.tcx().sess, span, E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound");
return ty::ReStatic;
}
}
}
// If any of the derived region bounds are 'static, that is always
// the best choice.
if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
return Some(ty::ReStatic);
return ty::ReStatic;
}
// Determine whether there is exactly one unique region in the set
@ -1659,38 +1749,42 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
let r = derived_region_bounds[0];
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
span_err!(tcx.sess, span, E0227,
"ambiguous lifetime bound, \
explicit lifetime bound required");
"ambiguous lifetime bound, explicit lifetime bound required");
}
return Some(r);
return r;
}
/// A version of `compute_opt_region_bound` for use where some region bound is required
/// (existential types, basically). Reports an error if no region bound can be derived and we are
/// in an `rscope` that does not provide a default.
fn compute_region_bound<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
region_bounds: &[&ast::Lifetime],
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
builtin_bounds: ty::BuiltinBounds)
-> ty::Region
/// Given an object type like `SomeTrait+Send`, computes the lifetime
/// bounds that must hold on the elided self type. These are derived
/// from the declarations of `SomeTrait`, `Send`, and friends -- if
/// they declare `trait SomeTrait : 'static`, for example, then
/// `'static` would appear in the list. The hard work is done by
/// `ty::required_region_bounds`, see that for more information.
pub fn object_region_bounds<'tcx>(
tcx: &ty::ctxt<'tcx>,
principal: &ty::PolyTraitRef<'tcx>,
others: ty::BuiltinBounds)
-> Vec<ty::Region>
{
match compute_opt_region_bound(this.tcx(), span, region_bounds,
principal_trait_ref, builtin_bounds) {
Some(r) => r,
None => {
match rscope.default_region_bound(span) {
Some(r) => { r }
None => {
span_err!(this.tcx().sess, span, E0228,
"explicit lifetime bound required");
ty::ReStatic
}
}
}
}
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
// a skolemized type.
let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
// Note that we preserve the overall binding levels here.
assert!(!open_ty.has_escaping_regions());
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
let param_bounds = ty::ParamBounds {
region_bounds: Vec::new(),
builtin_bounds: others,
trait_bounds: trait_refs,
projection_bounds: Vec::new(), // not relevant to computing region bounds
};
let predicates = ty::predicates(tcx, open_ty, &param_bounds);
ty::required_region_bounds(tcx, open_ty, predicates)
}
pub struct PartitionedBounds<'a> {

View File

@ -1890,7 +1890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
// RFC #599 specifies that object lifetime defaults take
// precedence over other defaults. But within a fn body we
// don't have a *default* region, rather we use inference to
// find the *correct* region, which is strictly more general
// (and anyway, within a fn body the right region may not even
// be something the user can write explicitly, since it might
// be some expression).
Some(self.infcx().next_region_var(infer::MiscVariable(span)))
}

View File

@ -154,7 +154,7 @@ pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// empty region is a subregion of all others, this can't fail
// unless the type does not meet the well-formedness
// requirements.
type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span),
type_must_outlive(&mut rcx, infer::RelateParamBound(span, component_ty),
component_ty, ty::ReEmpty);
}
}
@ -305,7 +305,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
debug!("visit_region_obligations: r_o={}",
r_o.repr(self.tcx()));
let sup_type = self.resolve_type(r_o.sup_type);
let origin = infer::RelateRegionParamBound(r_o.cause.span);
let origin = infer::RelateParamBound(r_o.cause.span, sup_type);
type_must_outlive(self, origin, sup_type, r_o.sub_region);
}

View File

@ -12,6 +12,7 @@
pub use self::WfConstraint::*;
use astconv::object_region_bounds;
use middle::infer::GenericKind;
use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty::{self, Ty};
@ -95,7 +96,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
ty::ty_trait(ref t) => {
let required_region_bounds =
ty::object_region_bounds(self.tcx, Some(&t.principal), t.bounds.builtin_bounds);
object_region_bounds(self.tcx, &t.principal, t.bounds.builtin_bounds);
self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
}

View File

@ -86,6 +86,7 @@ There are some shortcomings in this design:
*/
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
use middle::def;
use middle::lang_items::SizedTraitLangItem;
use middle::region;
use middle::resolve_lifetime;
@ -1199,8 +1200,23 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
predicates.clone());
assert!(prev_predicates.is_none());
return (scheme, predicates);
// Debugging aid.
if ty::has_attr(tcx, local_def(it.id), "rustc_object_lifetime_default") {
let object_lifetime_default_reprs: String =
scheme.generics.types.iter()
.map(|t| match t.object_lifetime_default {
Some(ty::ObjectLifetimeDefault::Specific(r)) =>
r.user_string(tcx),
d =>
d.repr(ccx.tcx()),
})
.collect::<Vec<String>>()
.connect(",");
tcx.sess.span_err(it.span, &object_lifetime_default_reprs);
}
return (scheme, predicates);
}
fn type_scheme_of_foreign_item<'a, 'tcx>(
@ -1269,6 +1285,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
subst::TypeSpace,
&generics.lifetimes[],
&generics.ty_params[],
&generics.where_clause,
ty::Generics::empty())
}
@ -1298,6 +1315,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
subst::TypeSpace,
&ast_generics.lifetimes[],
&ast_generics.ty_params[],
&ast_generics.where_clause,
ty::Generics::empty());
// Add in the self type parameter.
@ -1321,7 +1339,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
trait_bounds: vec!(ty::Binder(self_trait_ref.clone())),
projection_bounds: vec!(),
},
default: None
default: None,
object_lifetime_default: None,
};
ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
@ -1341,6 +1360,7 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
subst::FnSpace,
&early_lifetimes[],
&generics.ty_params[],
&generics.where_clause,
base_generics)
}
@ -1487,6 +1507,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
space: subst::ParamSpace,
lifetime_defs: &[ast::LifetimeDef],
types: &[ast::TyParam],
where_clause: &ast::WhereClause,
base_generics: ty::Generics<'tcx>)
-> ty::Generics<'tcx>
{
@ -1511,7 +1532,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
// Now create the real type parameters.
for (i, param) in types.iter().enumerate() {
let def = get_or_create_type_parameter_def(ccx, space, param, i as u32);
let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause);
debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
result.types.push(space, def);
}
@ -1522,7 +1543,8 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
space: subst::ParamSpace,
param: &ast::TyParam,
index: u32)
index: u32,
where_clause: &ast::WhereClause)
-> ty::TypeParameterDef<'tcx>
{
let tcx = ccx.tcx;
@ -1558,13 +1580,17 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
}
};
let object_lifetime_default =
compute_object_lifetime_default(ccx, space, index, &param.bounds, where_clause);
let def = ty::TypeParameterDef {
space: space,
index: index,
name: param.ident.name,
def_id: local_def(param.id),
bounds: bounds,
default: default
default: default,
object_lifetime_default: object_lifetime_default,
};
tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
@ -1572,6 +1598,99 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
def
}
/// Scan the bounds and where-clauses on a parameter to extract bounds
/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`.
/// This runs as part of computing the minimal type scheme, so we
/// intentionally avoid just asking astconv to convert all the where
/// clauses into a `ty::Predicate`. This is because that could induce
/// artificial cycles.
fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
space: subst::ParamSpace,
index: u32,
param_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
-> Option<ty::ObjectLifetimeDefault>
{
let inline_bounds = from_bounds(ccx, param_bounds);
let where_bounds = from_predicates(ccx, space, index, &where_clause.predicates);
let all_bounds: HashSet<_> = inline_bounds.into_iter()
.chain(where_bounds.into_iter())
.collect();
return if all_bounds.len() > 1 {
Some(ty::ObjectLifetimeDefault::Ambiguous)
} else {
all_bounds.into_iter()
.next()
.map(ty::ObjectLifetimeDefault::Specific)
};
fn from_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
bounds: &[ast::TyParamBound])
-> Vec<ty::Region>
{
bounds.iter()
.filter_map(|bound| {
match *bound {
ast::TraitTyParamBound(..) =>
None,
ast::RegionTyParamBound(ref lifetime) =>
Some(astconv::ast_region_to_region(ccx.tcx(), lifetime)),
}
})
.collect()
}
fn from_predicates<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
space: subst::ParamSpace,
index: u32,
predicates: &[ast::WherePredicate])
-> Vec<ty::Region>
{
predicates.iter()
.flat_map(|predicate| {
match *predicate {
ast::WherePredicate::BoundPredicate(ref data) => {
if data.bound_lifetimes.len() == 0 &&
is_param(ccx, &data.bounded_ty, space, index)
{
from_bounds(ccx, &data.bounds).into_iter()
} else {
Vec::new().into_iter()
}
}
ast::WherePredicate::RegionPredicate(..) |
ast::WherePredicate::EqPredicate(..) => {
Vec::new().into_iter()
}
}
})
.collect()
}
fn is_param(ccx: &CollectCtxt,
ast_ty: &ast::Ty,
space: subst::ParamSpace,
index: u32)
-> bool
{
match ast_ty.node {
ast::TyPath(_, id) => {
match ccx.tcx.def_map.borrow()[id] {
def::DefTyParam(s, i, _, _) => {
space == s && index == i
}
_ => {
false
}
}
}
_ => {
false
}
}
}
}
enum SizedByDefault { Yes, No }
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or

View File

@ -32,7 +32,10 @@ pub trait RegionScope {
count: uint)
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>;
fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
/// If an object omits any explicit lifetime bound, and none can
/// be derived from the object traits, what should we use? If
/// `None` is returned, an explicit annotation is required.
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
}
// A scope in which all regions must be explicitly named. This is used
@ -41,8 +44,8 @@ pub trait RegionScope {
pub struct ExplicitRscope;
impl RegionScope for ExplicitRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
None
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
Some(ty::ReStatic)
}
fn anon_regions(&self,
@ -63,8 +66,8 @@ impl UnelidableRscope {
}
impl RegionScope for UnelidableRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
None
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
Some(ty::ReStatic)
}
fn anon_regions(&self,
@ -76,22 +79,26 @@ impl RegionScope for UnelidableRscope {
}
}
// A scope in which any omitted region defaults to `default`. This is
// used after the `->` in function signatures, but also for backwards
// compatibility with object types. The latter use may go away.
pub struct SpecificRscope {
default: ty::Region
// A scope in which omitted anonymous region defaults to
// `default`. This is used after the `->` in function signatures. The
// latter use may go away. Note that object-lifetime defaults work a
// bit differently, as specified in RFC #599.
pub struct ElidableRscope {
default: ty::Region,
}
impl SpecificRscope {
pub fn new(r: ty::Region) -> SpecificRscope {
SpecificRscope { default: r }
impl ElidableRscope {
pub fn new(r: ty::Region) -> ElidableRscope {
ElidableRscope { default: r }
}
}
impl RegionScope for SpecificRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
Some(self.default)
impl RegionScope for ElidableRscope {
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
// Per RFC #599, object-lifetimes default to 'static unless
// overridden by context, and this takes precedence over
// lifetime elision.
Some(ty::ReStatic)
}
fn anon_regions(&self,
@ -124,9 +131,11 @@ impl BindingRscope {
}
impl RegionScope for BindingRscope {
fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
{
Some(self.next_region())
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
// Per RFC #599, object-lifetimes default to 'static unless
// overridden by context, and this takes precedence over the
// binding defaults.
Some(ty::ReStatic)
}
fn anon_regions(&self,
@ -138,6 +147,42 @@ impl RegionScope for BindingRscope {
}
}
/// A scope which overrides the default object lifetime but has no other effect.
pub struct ObjectLifetimeDefaultRscope<'r> {
base_scope: &'r (RegionScope+'r),
default: Option<ty::ObjectLifetimeDefault>,
}
impl<'r> ObjectLifetimeDefaultRscope<'r> {
pub fn new(base_scope: &'r (RegionScope+'r),
default: Option<ty::ObjectLifetimeDefault>)
-> ObjectLifetimeDefaultRscope<'r>
{
ObjectLifetimeDefaultRscope {
base_scope: base_scope,
default: default,
}
}
}
impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
match self.default {
None => self.base_scope.object_lifetime_default(span),
Some(ty::ObjectLifetimeDefault::Ambiguous) => None,
Some(ty::ObjectLifetimeDefault::Specific(r)) => Some(r),
}
}
fn anon_regions(&self,
span: Span,
count: uint)
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>
{
self.base_scope.anon_regions(span, count)
}
}
/// A scope which simply shifts the Debruijn index of other scopes
/// to account for binding levels.
pub struct ShiftedRscope<'r> {
@ -151,9 +196,8 @@ impl<'r> ShiftedRscope<'r> {
}
impl<'r> RegionScope for ShiftedRscope<'r> {
fn default_region_bound(&self, span: Span) -> Option<ty::Region>
{
self.base_scope.default_region_bound(span)
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
self.base_scope.object_lifetime_default(span)
.map(|r| ty_fold::shift_region(r, 1))
}

View File

@ -35,18 +35,18 @@ pub trait ItemDecorator {
sp: Span,
meta_item: &ast::MetaItem,
item: &ast::Item,
push: Box<FnMut(P<ast::Item>)>);
push: &mut FnMut(P<ast::Item>));
}
impl<F> ItemDecorator for F
where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, Box<FnMut(P<ast::Item>)>)
where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P<ast::Item>))
{
fn expand(&self,
ecx: &mut ExtCtxt,
sp: Span,
meta_item: &ast::MetaItem,
item: &ast::Item,
push: Box<FnMut(P<ast::Item>)>) {
push: &mut FnMut(P<ast::Item>)) {
(*self)(ecx, sp, meta_item, item, push)
}
}

View File

@ -72,7 +72,7 @@ pub fn expand_deprecated_deriving(cx: &mut ExtCtxt,
span: Span,
_: &MetaItem,
_: &Item,
_: Box<FnMut(P<Item>)>) {
_: &mut FnMut(P<Item>)) {
cx.span_err(span, "`deriving` has been renamed to `derive`");
}
@ -80,7 +80,7 @@ pub fn expand_meta_derive(cx: &mut ExtCtxt,
_span: Span,
mitem: &MetaItem,
item: &Item,
mut push: Box<FnMut(P<Item>)>) {
push: &mut FnMut(P<Item>)) {
match mitem.node {
MetaNameValue(_, ref l) => {
cx.span_err(l.span, "unexpected value in `derive`");

View File

@ -363,7 +363,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac, span: codemap::Span,
mark_thunk: G,
fld: &mut MacroExpander)
-> Option<T> where
F: FnOnce(Box<MacResult>) -> Option<T>,
F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
G: FnOnce(T, Mrk) -> T,
{
match mac.node {
@ -1102,9 +1102,10 @@ fn expand_annotatable(a: Annotatable,
// but that double-mut-borrows fld
let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
box |item| items.push(item));
decorator_items.extend(items.into_iter()
.flat_map(|item| expand_item(item, fld).into_iter()));
&mut |item| items.push(item));
decorator_items.extend(
items.into_iter()
.flat_map(|item| expand_item(item, fld).into_iter()));
fld.cx.bt_pop();
}

View File

@ -14,6 +14,6 @@
trait Foo : Send { }
impl <'a> Foo for &'a mut () { }
//~^ ERROR declared lifetime bound not satisfied
//~^ ERROR the type `&'a mut ()` does not fulfill the required lifetime
fn main() { }

View File

@ -12,7 +12,7 @@ use std::old_io;
use std::vec;
pub struct Container<'a> {
reader: &'a mut Reader //~ ERROR explicit lifetime bound required
reader: &'a mut Reader
}
impl<'a> Container<'a> {
@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
fn main() {
let mut c = for_stdin();
let mut v = Vec::new();
c.read_to(v);
c.read_to(v); //~ ERROR mismatched types
}

View File

@ -9,12 +9,12 @@
// except according to those terms.
fn f() { }
struct S(Box<FnMut()>); //~ ERROR explicit lifetime bound required
pub static C: S = S(f);
struct S(Box<FnMut()>);
pub static C: S = S(f); //~ ERROR mismatched types
fn g() { }
type T = Box<FnMut()>; //~ ERROR explicit lifetime bound required
pub static D: T = g;
type T = Box<FnMut()>;
pub static D: T = g; //~ ERROR mismatched types
fn main() {}

View File

@ -36,7 +36,7 @@ fn g<T>(val: T) {
fn foo<'a>() {
let t: S<&'a isize> = S;
let a = &t as &Gettable<&'a isize>;
//~^ ERROR declared lifetime bound not satisfied
//~^ ERROR the type `&'a isize` does not fulfill the required lifetime
}
fn foo2<'a>() {

View File

@ -22,7 +22,7 @@ fn test51<'a>() {
}
fn test52<'a>() {
assert_send::<&'a (Dummy+Send)>();
//~^ ERROR declared lifetime bound not satisfied
//~^ ERROR does not fulfill the required lifetime
}
// ...unless they are properly bounded

View File

@ -19,7 +19,7 @@ fn test32() { assert_send::<Vec<isize> >(); }
// but not if they own a bad thing
fn test40<'a>(_: &'a isize) {
assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
}
fn main() { }

View File

@ -22,13 +22,13 @@ fn test10() { assert_send::<&'static mut isize>(); }
// otherwise lifetime pointers are not ok
fn test20<'a>(_: &'a isize) {
assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
}
fn test21<'a>(_: &'a isize) {
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
}
fn test22<'a>(_: &'a isize) {
assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
}
fn main() { }

View File

@ -0,0 +1,61 @@
// 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.
// Test that if a struct declares multiple region bounds for a given
// type parameter, an explicit lifetime bound is required on object
// lifetimes within.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct Ref0<T:?Sized> {
r: *mut T
}
struct Ref1<'a,T:'a+?Sized> {
r: &'a T
}
struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
r: &'a &'b T
}
fn a<'a,'b>(t: Ref2<'a,'b,Test>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
}
fn b(t: Ref2<Test>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
}
fn c(t: Ref2<&Test>) {
// In this case, the &'a overrides.
}
fn d(t: Ref2<Ref1<Test>>) {
// In this case, the lifetime parameter from the Ref1 overrides.
}
fn e(t: Ref2<Ref0<Test>>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
//
// In this case, Ref2 is ambiguous, and Ref0 inherits the
// ambiguity.
}
fn f(t: &Ref2<Test>) {
//~^ ERROR lifetime bound for this object type cannot be deduced from context
}
fn main() {
}

View File

@ -0,0 +1,89 @@
// 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.
// Test various cases where the old rules under lifetime elision
// yield slightly different results than the new rules.
#![allow(dead_code)]
trait SomeTrait {
fn dummy(&self) { }
}
struct SomeStruct<'a> {
r: Box<SomeTrait+'a>
}
fn deref<T>(ss: &T) -> T {
// produces the type of a deref without worrying about whether a
// move out would actually be legal
loop { }
}
fn load0<'a>(ss: &'a Box<SomeTrait>) -> Box<SomeTrait> {
// Under old rules, the fully elaborated types of input/output were:
//
// for<'a,'b> fn(&'a Box<SomeTrait+'b>) -> Box<SomeTrait+'a>
//
// Under new rules the result is:
//
// for<'a> fn(&'a Box<SomeTrait+'a>) -> Box<SomeTrait+'static>
//
// Therefore, we get a type error attempting to return `deref(ss)`
// since `SomeTrait+'a <: SomeTrait+'static` does not hold.
deref(ss)
//~^ ERROR cannot infer
}
fn load1(ss: &SomeTrait) -> &SomeTrait {
// Under old rules, the fully elaborated types of input/output were:
//
// for<'a,'b> fn(&'a (SomeTrait+'b)) -> &'a (SomeTrait+'a)
//
// Under new rules the result is:
//
// for<'a> fn(&'a (SomeTrait+'a)) -> &'a (SomeTrait+'a)
//
// In both cases, returning `ss` is legal.
ss
}
fn load2<'a>(ss: &'a SomeTrait) -> &SomeTrait {
// Same as `load1` but with an explicit name thrown in for fun.
ss
}
fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
// Under old rules, the fully elaborated types of input/output were:
//
// for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a)
//
// Based on the input/output types, the compiler could infer that
// 'c : 'a
// 'b : 'a
// must hold, and therefore it permitted `&'a (Sometrait+'c)` to be
// coerced to `&'b (SomeTrait+'a)`.
//
// Under the newer defaults, though, we get:
//
// for<'a,'b> fn(&'a (SomeTrait+'a)) -> &'b (SomeTrait+'b)
//
// which fails to type check.
ss
//~^ ERROR cannot infer
//~| ERROR mismatched types
}
fn main() {
}

View File

@ -0,0 +1,45 @@
// 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.
// Test various cases where the defaults should lead to errors being
// reported.
#![allow(dead_code)]
trait SomeTrait {
fn dummy(&self) { }
}
struct SomeStruct<'a> {
r: Box<SomeTrait+'a>
}
fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal.
ss.r //~ ERROR mismatched types
}
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
// No error: b is bounded by 'static which outlives the
// (anonymous) lifetime on the struct.
ss.r = b;
}
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
// Here we override the lifetimes explicitly, and so naturally we get an error.
ss.r = b; //~ ERROR mismatched types
}
fn main() {
}

View File

@ -0,0 +1,44 @@
// 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.
// Test a "pass-through" object-lifetime-default that produces errors.
#![allow(dead_code)]
trait SomeTrait {
fn dummy(&self) { }
}
struct MyBox<T:?Sized> {
r: Box<T>
}
fn deref<T>(ss: &T) -> T {
// produces the type of a deref without worrying about whether a
// move out would actually be legal
loop { }
}
fn load0(ss: &MyBox<SomeTrait>) -> MyBox<SomeTrait> {
deref(ss) //~ ERROR cannot infer
}
fn load1<'a,'b>(a: &'a MyBox<SomeTrait>,
b: &'b MyBox<SomeTrait>)
-> &'b MyBox<SomeTrait>
{
a
//~^ ERROR cannot infer
//~| ERROR mismatched types
//~| ERROR mismatched types
}
fn main() {
}

View File

@ -0,0 +1,32 @@
// 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.
#[rustc_object_lifetime_default]
struct A<T>(T); //~ ERROR None
#[rustc_object_lifetime_default]
struct B<'a,T>(&'a (), T); //~ ERROR None
#[rustc_object_lifetime_default]
struct C<'a,T:'a>(&'a T); //~ ERROR 'a
#[rustc_object_lifetime_default]
struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous
#[rustc_object_lifetime_default]
struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b
#[rustc_object_lifetime_default]
struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b
#[rustc_object_lifetime_default]
struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous
fn main() { }

View File

@ -25,7 +25,7 @@ struct Foo<'a,'b,'c> {
c: Box<Is<'a>>,
d: Box<IsSend>,
e: Box<Is<'a>+Send>, // we can derive two bounds, but one is 'static, so ok
f: Box<SomeTrait>, //~ ERROR explicit lifetime bound required
f: Box<SomeTrait>, // OK, defaults to 'static due to RFC 599.
g: Box<SomeTrait+'a>,
z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted

View File

@ -11,6 +11,8 @@
// Various tests related to testing how region inference works
// with respect to the object receivers.
#![allow(warnings)]
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
@ -21,29 +23,6 @@ fn borrowed_receiver_same_lifetime<'a>(x: &'a Foo) -> &'a () {
x.borrowed()
}
// Borrowed receiver but two distinct lifetimes, we get an error.
fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
x.borrowed() //~ ERROR cannot infer
}
// Borrowed receiver with two distinct lifetimes, but we know that
// 'b:'a, hence &'a () is permitted.
fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (Foo+'b)) -> &'a () {
x.borrowed()
}
// Here we have two distinct lifetimes, but we try to return a pointer
// with the longer lifetime when (from the signature) we only know
// that it lives as long as the shorter lifetime. Therefore, error.
fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () {
x.borrowed() //~ ERROR cannot infer
}
// Here, the object is bounded by an anonymous lifetime and returned
// as `&'static`, so you get an error.
fn owned_receiver(x: Box<Foo>) -> &'static () {
x.borrowed() //~ ERROR cannot infer
}
fn main() {}
#[rustc_error]
fn main() {} //~ ERROR compilation successful

View File

@ -0,0 +1,24 @@
// Copyright 2012-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 related to testing how region inference works
// with respect to the object receivers.
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
// Borrowed receiver but two distinct lifetimes, we get an error.
fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
x.borrowed() //~ ERROR cannot infer
}
fn main() {}

View File

@ -0,0 +1,28 @@
// Copyright 2012-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 related to testing how region inference works
// with respect to the object receivers.
#![allow(warnings)]
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
// Borrowed receiver with two distinct lifetimes, but we know that
// 'b:'a, hence &'a () is permitted.
fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (Foo+'b)) -> &'a () {
x.borrowed()
}
#[rustc_error]
fn main() {} //~ ERROR compilation successful

View File

@ -0,0 +1,26 @@
// Copyright 2012-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 related to testing how region inference works
// with respect to the object receivers.
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
// Here we have two distinct lifetimes, but we try to return a pointer
// with the longer lifetime when (from the signature) we only know
// that it lives as long as the shorter lifetime. Therefore, error.
fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () {
x.borrowed() //~ ERROR cannot infer
}
fn main() {}

View File

@ -0,0 +1,25 @@
// Copyright 2012-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 related to testing how region inference works
// with respect to the object receivers.
trait Foo {
fn borrowed<'a>(&'a self) -> &'a ();
}
// Here, the object is bounded by an anonymous lifetime and returned
// as `&'static`, so you get an error.
fn owned_receiver(x: Box<Foo>) -> &'static () {
x.borrowed() //~ ERROR `*x` does not live long enough
}
fn main() {}

View File

@ -17,20 +17,22 @@ trait Foo {}
impl<'a> Foo for &'a [u8] {}
fn a(v: &[u8]) -> Box<Foo + 'static> {
let x: Box<Foo + 'static> = box v; //~ ERROR declared lifetime bound not satisfied
let x: Box<Foo + 'static> = box v; //~ ERROR does not fulfill the required lifetime
x
}
fn b(v: &[u8]) -> Box<Foo + 'static> {
box v //~ ERROR declared lifetime bound not satisfied
box v //~ ERROR does not fulfill the required lifetime
}
fn c(v: &[u8]) -> Box<Foo> {
box v // OK thanks to lifetime elision
// same as previous case due to RFC 599
box v //~ ERROR does not fulfill the required lifetime
}
fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
box v //~ ERROR declared lifetime bound not satisfied
box v //~ ERROR does not fulfill the required lifetime
}
fn e<'a:'b,'b>(v: &'a [u8]) -> Box<Foo+'b> {

View File

@ -32,15 +32,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
// otherwise lifetime pointers are not ok
fn param_not_ok<'a>(x: &'a isize) {
assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
}
fn param_not_ok1<'a>(_: &'a isize) {
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
}
fn param_not_ok2<'a>(_: &'a isize) {
assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
}
// boxes are ok
@ -54,7 +54,7 @@ fn box_ok() {
// but not if they own a bad thing
fn box_with_region_not_ok<'a>() {
assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
}
// objects with insufficient bounds no ok
@ -66,7 +66,7 @@ fn object_with_random_bound_not_ok<'a>() {
fn object_with_send_bound_not_ok<'a>() {
assert_send::<&'a (Dummy+Send)>();
//~^ ERROR declared lifetime bound not satisfied
//~^ ERROR does not fulfill the required lifetime
}
// unsafe pointers are ok unless they point at unsendable things

View File

@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
// otherwise lifetime pointers are not ok
fn param_not_ok<'a>(x: &'a isize) {
assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
}
fn param_not_ok1<'a>(_: &'a isize) {
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
}
fn param_not_ok2<'a>(_: &'a isize) {
assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
}
// boxes are ok
@ -51,7 +51,7 @@ fn box_ok() {
// but not if they own a bad thing
fn box_with_region_not_ok<'a>() {
assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
}
// unsafe pointers are ok unless they point at unsendable things
@ -62,11 +62,11 @@ fn unsafe_ok1<'a>(_: &'a isize) {
}
fn unsafe_ok2<'a>(_: &'a isize) {
assert_send::<*const &'a isize>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the required lifetime
}
fn unsafe_ok3<'a>(_: &'a isize) {
assert_send::<*mut &'a isize>(); //~ ERROR declared lifetime bound not satisfied
assert_send::<*mut &'a isize>(); //~ ERROR does not fulfill the required lifetime
}
fn main() {

View File

@ -20,7 +20,7 @@ impl Foo {
fn caller<'a>(x: &isize) {
Foo.some_method::<&'a isize>();
//~^ ERROR declared lifetime bound not satisfied
//~^ ERROR does not fulfill the required lifetime
}
fn main() { }

View File

@ -9,6 +9,7 @@
// except according to those terms.
#![feature(box_syntax)]
#![allow(warnings)]
trait A<T> {}
struct B<'a, T>(&'a (A<T>+'a));
@ -17,19 +18,7 @@ trait X {}
impl<'a, T> X for B<'a, T> {}
fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
box B(&*v) as Box<X>
}
fn g<'a, T: 'static>(v: Box<A<T>>) -> Box<X+'static> {
box B(&*v) as Box<X> //~ ERROR cannot infer
}
fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
box B(&*v) as Box<X>
}
fn i<'a, T, U>(v: Box<A<U>>) -> Box<X+'static> {
box B(&*v) as Box<X> //~ ERROR cannot infer
box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
}
fn main() {}

View File

@ -0,0 +1,23 @@
// 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.
#![feature(box_syntax)]
trait A<T> {}
struct B<'a, T>(&'a (A<T>+'a));
trait X {}
impl<'a, T> X for B<'a, T> {}
fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
box B(&*v) as Box<X> //~ ERROR cannot infer
}
fn main() { }

View File

@ -0,0 +1,25 @@
// 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.
#![feature(box_syntax)]
#![allow(warnings)]
trait A<T> {}
struct B<'a, T>(&'a (A<T>+'a));
trait X {}
impl<'a, T> X for B<'a, T> {}
fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
}
fn main() {}

View File

@ -0,0 +1,24 @@
// 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.
#![feature(box_syntax)]
trait A<T> {}
struct B<'a, T>(&'a (A<T>+'a));
trait X {}
impl<'a, T> X for B<'a, T> {}
fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
box B(&*v) as Box<X> //~ ERROR cannot infer
}
fn main() {}

View File

@ -14,7 +14,7 @@ trait seq { }
impl<T> seq<T> for Vec<T> { //~ ERROR wrong number of type arguments
/* ... */
}
impl seq<bool> for u32 {
impl seq<bool> for u32 { //~ ERROR wrong number of type arguments
/* Treat the integer as a sequence of bits */
}

View File

@ -57,6 +57,7 @@ fn main() {
let pt3 = PointF::<i32> {
//~^ ERROR wrong number of type arguments
//~| ERROR structure constructor specifies a structure of type
x: 9i32,
y: 10i32,
};

View File

@ -22,7 +22,7 @@ fn c(x: Box<Foo+Sync+Send>) {
fn d(x: Box<Foo>) {
a(x); //~ ERROR mismatched types
//~| expected `Box<Foo + Send>`
//~| found `Box<Foo>`
//~| found `Box<Foo + 'static>`
//~| expected bounds `Send`
//~| found no bounds
}

View File

@ -24,8 +24,7 @@ fn c(x: Box<Foo+Sync>) {
}
fn d(x: &'static (Foo+Sync)) {
b(x); //~ ERROR cannot infer
//~^ ERROR mismatched types
b(x);
}
fn main() {}

View File

@ -12,7 +12,9 @@
trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
fn foo(_: &Three()) //~ ERROR wrong number of type arguments
fn foo(_: &Three())
//~^ ERROR wrong number of type arguments
//~| ERROR no associated type `Output`
{}
fn main() { }

View File

@ -12,7 +12,9 @@
trait Zero { fn dummy(&self); }
fn foo(_: Zero()) //~ ERROR wrong number of type arguments
fn foo(_: Zero())
//~^ ERROR wrong number of type arguments
//~| ERROR no associated type `Output` defined in `Zero`
{}
fn main() { }

View File

@ -14,6 +14,7 @@ trait Trait {}
fn f<F:Trait(isize) -> isize>(x: F) {}
//~^ ERROR wrong number of type arguments: expected 0, found 1
//~| ERROR no associated type `Output`
fn main() {}

View File

@ -0,0 +1,42 @@
// 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.
// Test that `Box<Test>` is equivalent to `Box<Test+'static>`, both in
// fields and fn arguments.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct SomeStruct {
t: Box<Test>,
u: Box<Test+'static>,
}
fn a(t: Box<Test>, mut ss: SomeStruct) {
ss.t = t;
}
fn b(t: Box<Test+'static>, mut ss: SomeStruct) {
ss.t = t;
}
fn c(t: Box<Test>, mut ss: SomeStruct) {
ss.u = t;
}
fn d(t: Box<Test+'static>, mut ss: SomeStruct) {
ss.u = t;
}
fn main() {
}

View File

@ -0,0 +1,47 @@
// 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.
// Test that the lifetime of the enclosing `&` is used for the object
// lifetime bound.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct Ref<'a,T:'a+?Sized> {
r: &'a T
}
struct SomeStruct<'a> {
t: Ref<'a,Test>,
u: Ref<'a,Test+'a>,
}
fn a<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn b<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn c<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn main() {
}

View File

@ -0,0 +1,42 @@
// 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.
// Test that the lifetime from the enclosing `&` is "inherited"
// through the `Box` struct.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct SomeStruct<'a> {
t: &'a Box<Test>,
u: &'a Box<Test+'a>,
}
fn a<'a>(t: &'a Box<Test>, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn b<'a>(t: &'a Box<Test>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn c<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn d<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn main() {
}

View File

@ -0,0 +1,43 @@
// 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.
// Test that the lifetime of the enclosing `&` is used for the object
// lifetime bound.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct SomeStruct<'a> {
t: &'a mut Test,
u: &'a mut (Test+'a),
}
fn a<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn b<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn c<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn d<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn main() {
}

View File

@ -0,0 +1,46 @@
// 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.
// Test that the lifetime from the enclosing `&` is "inherited"
// through the `MyBox` struct.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct SomeStruct<'a> {
t: &'a MyBox<Test>,
u: &'a MyBox<Test+'a>,
}
struct MyBox<T:?Sized> {
b: Box<T>
}
fn a<'a>(t: &'a MyBox<Test>, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn b<'a>(t: &'a MyBox<Test>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn c<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn d<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn main() {
}

View File

@ -0,0 +1,43 @@
// 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.
// Test that the lifetime of the enclosing `&` is used for the object
// lifetime bound.
#![allow(dead_code)]
trait Test {
fn foo(&self) { }
}
struct SomeStruct<'a> {
t: &'a Test,
u: &'a (Test+'a),
}
fn a<'a>(t: &'a Test, mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn b<'a>(t: &'a Test, mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn c<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
ss.t = t;
}
fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
ss.u = t;
}
fn main() {
}