From 931a3c4f9df2fbf043bc30c0524bc93e1ffa397e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 16:37:36 -0500 Subject: [PATCH 1/8] Detect and store object-lifetime-defaults. --- src/librustc/metadata/tydecode.rs | 20 ++- src/librustc/metadata/tyencode.rs | 15 ++ src/librustc/middle/ty.rs | 25 ++++ src/librustc/middle/ty_fold.rs | 13 ++ src/librustc_typeck/collect.rs | 129 +++++++++++++++++- .../compile-fail/object-lifetime-default.rs | 32 +++++ 6 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/object-lifetime-default.rs diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 9962f49dfcf..94654b84922 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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 + 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") } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 640b9649286..e1e9d49dd05 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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) +{ + 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, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index e276683236f..6be16de9501 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1758,6 +1758,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, @@ -1766,6 +1781,7 @@ pub struct TypeParameterDef<'tcx> { pub index: u32, pub bounds: ParamBounds<'tcx>, pub default: Option>, + pub object_lifetime_default: Option, } #[derive(RustcEncodable, RustcDecodable, Clone, Debug)] @@ -7386,3 +7402,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), + } + } +} diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 645a7ab9440..5e46ce08e4f 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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>(&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)), } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8a1945c16a6..f26041dbbe1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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::>() + .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, ¶m.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 +{ + 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 + { + 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 + { + 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 diff --git a/src/test/compile-fail/object-lifetime-default.rs b/src/test/compile-fail/object-lifetime-default.rs new file mode 100644 index 00000000000..73f71751ee8 --- /dev/null +++ b/src/test/compile-fail/object-lifetime-default.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[rustc_object_lifetime_default] +struct A(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() { } From f5c6a23c9e4676964ea2dd0b2523cc2ae696da4b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 19:16:47 -0500 Subject: [PATCH 2/8] Various simplifications and renamings based on the fact that old-school closures are gone and type parameters can now have multiple region bounds (and hence use a different path). Should have no effect on the external behavior of the compiler. --- src/librustc/middle/ty.rs | 31 +----- src/librustc_typeck/astconv.rs | 134 ++++++++++++----------- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/regionmanip.rs | 3 +- src/librustc_typeck/rscope.rs | 37 ++++--- 5 files changed, 94 insertions(+), 113 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 6be16de9501..1c247f33818 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5896,42 +5896,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 -{ - // 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, ¶m_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. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1951d9946bc..ac892e64861 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ 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, +use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; use util::common::{ErrorReported, FN_OUTPUT_NAME}; @@ -465,7 +465,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 => { @@ -932,7 +932,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); @@ -1518,11 +1518,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>, // None for boxed closures + principal_trait_ref: ty::PolyTraitRef<'tcx>, projection_bounds: Vec>, ast_bounds: &[ast::TyParamBound]) -> ty::ExistentialBounds<'tcx> @@ -1546,15 +1546,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 +1565,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>, // None for boxed closures + principal_trait_ref: ty::PolyTraitRef<'tcx>, mut projection_bounds: Vec>, // Empty for boxed closures partitioned_bounds: PartitionedBounds) -> ty::ExistentialBounds<'tcx> @@ -1588,16 +1585,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, - ®ion_bounds, - principal_trait_ref, - builtin_bounds); + let region_bound = compute_object_lifetime_bound(this, + rscope, + span, + ®ion_bounds, + principal_trait_ref, + builtin_bounds); ty::sort_bounds_list(&mut projection_bounds); @@ -1608,17 +1604,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>, - builtin_bounds: ty::BuiltinBounds) - -> Option +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 +1633,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 +1667,36 @@ 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>, // None for closures - builtin_bounds: ty::BuiltinBounds) - -> ty::Region +pub fn object_region_bounds<'tcx>( + tcx: &ty::ctxt<'tcx>, + principal: &ty::PolyTraitRef<'tcx>, + others: ty::BuiltinBounds) + -> Vec { - 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, ¶m_bounds); + ty::required_region_bounds(tcx, open_ty, predicates) } pub struct PartitionedBounds<'a> { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d12b23187b8..874bd40ab9f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1890,7 +1890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { - fn default_region_bound(&self, span: Span) -> Option { + fn object_lifetime_default(&self, span: Span) -> Option { Some(self.infcx().next_region_var(infer::MiscVariable(span))) } diff --git a/src/librustc_typeck/check/regionmanip.rs b/src/librustc_typeck/check/regionmanip.rs index 4a0e2acc854..209570585d2 100644 --- a/src/librustc_typeck/check/regionmanip.rs +++ b/src/librustc_typeck/check/regionmanip.rs @@ -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) } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 60e969c4f99..c53fe91dc43 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -32,7 +32,10 @@ pub trait RegionScope { count: uint) -> Result, Option>>; - fn default_region_bound(&self, span: Span) -> Option; + /// 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; } // A scope in which all regions must be explicitly named. This is used @@ -41,7 +44,7 @@ pub trait RegionScope { pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { - fn default_region_bound(&self, _span: Span) -> Option { + fn object_lifetime_default(&self, _span: Span) -> Option { None } @@ -63,7 +66,7 @@ impl UnelidableRscope { } impl RegionScope for UnelidableRscope { - fn default_region_bound(&self, _span: Span) -> Option { + fn object_lifetime_default(&self, _span: Span) -> Option { None } @@ -76,21 +79,22 @@ 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 { +impl RegionScope for ElidableRscope { + fn object_lifetime_default(&self, _span: Span) -> Option { Some(self.default) } @@ -124,7 +128,7 @@ impl BindingRscope { } impl RegionScope for BindingRscope { - fn default_region_bound(&self, _span: Span) -> Option + fn object_lifetime_default(&self, _span: Span) -> Option { Some(self.next_region()) } @@ -151,9 +155,8 @@ impl<'r> ShiftedRscope<'r> { } impl<'r> RegionScope for ShiftedRscope<'r> { - fn default_region_bound(&self, span: Span) -> Option - { - self.base_scope.default_region_bound(span) + fn object_lifetime_default(&self, span: Span) -> Option { + self.base_scope.object_lifetime_default(span) .map(|r| ty_fold::shift_region(r, 1)) } From 80d1f14e7d54291773bf208e30c1ff4555f2178d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 11 Feb 2015 19:45:19 -0500 Subject: [PATCH 3/8] Implement the basic rules of RFC 599, but do not yet support custom types. --- src/librustc_typeck/astconv.rs | 8 ++- src/librustc_typeck/check/mod.rs | 6 +++ src/librustc_typeck/rscope.rs | 53 ++++++++++++++++--- ...ject-lifetime-default-default-to-static.rs | 42 +++++++++++++++ .../object-lifetime-default-from-rptr-box.rs | 42 +++++++++++++++ .../object-lifetime-default-from-rptr-mut.rs | 43 +++++++++++++++ ...bject-lifetime-default-from-rptr-struct.rs | 46 ++++++++++++++++ .../object-lifetime-default-from-rptr.rs | 43 +++++++++++++++ 8 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/object-lifetime-default-default-to-static.rs create mode 100644 src/test/run-pass/object-lifetime-default-from-rptr-box.rs create mode 100644 src/test/run-pass/object-lifetime-default-from-rptr-mut.rs create mode 100644 src/test/run-pass/object-lifetime-default-from-rptr-struct.rs create mode 100644 src/test/run-pass/object-lifetime-default-from-rptr.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ac892e64861..754ca643971 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -56,7 +56,7 @@ use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, - ShiftedRscope, BindingRscope}; + ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use TypeAndSubsts; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::DefIdMap; @@ -1084,7 +1084,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) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 874bd40ab9f..4c1fd7ea854 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1891,6 +1891,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { fn object_lifetime_default(&self, span: Span) -> Option { + // TODO. RFC #599 specifies that object lifetime defaults take + // precedence over other defaults. *However,* within a fn + // body, we typically use inference to allow users to elide + // lifetimes whenever they like, and then just infer it to + // whatever it must be. So I interpret that as applying only + // to fn sigs. Some(self.infcx().next_region_var(infer::MiscVariable(span))) } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index c53fe91dc43..b591209a638 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -45,7 +45,7 @@ pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { fn object_lifetime_default(&self, _span: Span) -> Option { - None + Some(ty::ReStatic) } fn anon_regions(&self, @@ -67,7 +67,7 @@ impl UnelidableRscope { impl RegionScope for UnelidableRscope { fn object_lifetime_default(&self, _span: Span) -> Option { - None + Some(ty::ReStatic) } fn anon_regions(&self, @@ -95,7 +95,10 @@ impl ElidableRscope { impl RegionScope for ElidableRscope { fn object_lifetime_default(&self, _span: Span) -> Option { - Some(self.default) + // 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, @@ -128,9 +131,11 @@ impl BindingRscope { } impl RegionScope for BindingRscope { - fn object_lifetime_default(&self, _span: Span) -> Option - { - Some(self.next_region()) + fn object_lifetime_default(&self, _span: Span) -> Option { + // 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, @@ -142,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, +} + +impl<'r> ObjectLifetimeDefaultRscope<'r> { + pub fn new(base_scope: &'r (RegionScope+'r), + default: Option) + -> ObjectLifetimeDefaultRscope<'r> + { + ObjectLifetimeDefaultRscope { + base_scope: base_scope, + default: default, + } + } +} + +impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { + fn object_lifetime_default(&self, span: Span) -> Option { + 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, Option>> + { + 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> { diff --git a/src/test/run-pass/object-lifetime-default-default-to-static.rs b/src/test/run-pass/object-lifetime-default-default-to-static.rs new file mode 100644 index 00000000000..c385a0195b6 --- /dev/null +++ b/src/test/run-pass/object-lifetime-default-default-to-static.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that `Box` is equivalent to `Box`, both in +// fields and fn arguments. + +#![allow(dead_code)] + +trait Test { + fn foo(&self) { } +} + +struct SomeStruct { + t: Box, + u: Box, +} + +fn a(t: Box, mut ss: SomeStruct) { + ss.t = t; +} + +fn b(t: Box, mut ss: SomeStruct) { + ss.t = t; +} + +fn c(t: Box, mut ss: SomeStruct) { + ss.u = t; +} + +fn d(t: Box, mut ss: SomeStruct) { + ss.u = t; +} + +fn main() { +} diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-box.rs b/src/test/run-pass/object-lifetime-default-from-rptr-box.rs new file mode 100644 index 00000000000..825800e1d44 --- /dev/null +++ b/src/test/run-pass/object-lifetime-default-from-rptr-box.rs @@ -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 or the MIT license +// , 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, + u: &'a Box, +} + +fn a<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { + ss.t = t; +} + +fn b<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { + ss.u = t; +} + +fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { + ss.t = t; +} + +fn d<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { + ss.u = t; +} + +fn main() { +} diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs b/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs new file mode 100644 index 00000000000..0f34d945c8f --- /dev/null +++ b/src/test/run-pass/object-lifetime-default-from-rptr-mut.rs @@ -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 or the MIT license +// , 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() { +} diff --git a/src/test/run-pass/object-lifetime-default-from-rptr-struct.rs b/src/test/run-pass/object-lifetime-default-from-rptr-struct.rs new file mode 100644 index 00000000000..9d5dac536f1 --- /dev/null +++ b/src/test/run-pass/object-lifetime-default-from-rptr-struct.rs @@ -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 or the MIT license +// , 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, + u: &'a MyBox, +} + +struct MyBox { + b: Box +} + +fn a<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { + ss.t = t; +} + +fn b<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { + ss.u = t; +} + +fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { + ss.t = t; +} + +fn d<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { + ss.u = t; +} + +fn main() { +} diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs new file mode 100644 index 00000000000..b7a28a5c524 --- /dev/null +++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs @@ -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 or the MIT license +// , 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() { +} From ab579883f27e511d6325f7b20dbc147ad0ecef6f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 12 Feb 2015 05:05:09 -0500 Subject: [PATCH 4/8] Factor out the "region substs" creation to occur earlier, so that the complete set of regions are available when converting types. --- src/librustc_typeck/astconv.rs | 125 +++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 43 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 754ca643971..d4252a92695 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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>, - types: Vec>, - regions: Vec) + regions_provided: Vec) -> 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>, + types_provided: Vec>, + 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,8 +429,10 @@ 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, + -> (Substs<'tcx>, Vec>, Vec>) { @@ -410,6 +441,9 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, .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)) @@ -422,7 +456,7 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>, span: b.span }) .collect(); - (regions, types, assoc_bindings) + (region_substs, types, assoc_bindings) } /// Returns the appropriate lifetime to use for any output lifetimes @@ -479,11 +513,17 @@ 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, + -> (Substs<'tcx>, Vec>, Vec>) { + 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)) @@ -514,7 +554,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>( @@ -626,7 +666,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 +680,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, From 369adaf5150877c124de99a1b9a94f7b522aade6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 12 Feb 2015 09:37:52 -0500 Subject: [PATCH 5/8] Implement the rules for RFC 599, and add various tests. Fixes #22211. --- src/librustc_typeck/astconv.rs | 71 +++++++++++---- src/test/compile-fail/issue-11374.rs | 4 +- src/test/compile-fail/issue-5216.rs | 8 +- .../object-lifetime-default-ambiguous.rs | 60 +++++++++++++ .../object-lifetime-default-elision.rs | 89 +++++++++++++++++++ .../object-lifetime-default-from-box-error.rs | 45 ++++++++++ .../object-lifetime-default-mybox.rs | 44 +++++++++ ...n-bounds-on-objects-and-type-parameters.rs | 2 +- .../compile-fail/region-object-lifetime-1.rs | 29 +----- .../compile-fail/region-object-lifetime-2.rs | 24 +++++ .../compile-fail/region-object-lifetime-3.rs | 28 ++++++ .../compile-fail/region-object-lifetime-4.rs | 26 ++++++ .../compile-fail/region-object-lifetime-5.rs | 25 ++++++ .../region-object-lifetime-in-coercion.rs | 4 +- ... => regions-close-object-into-object-1.rs} | 15 +--- .../regions-close-object-into-object-2.rs | 23 +++++ .../regions-close-object-into-object-3.rs | 25 ++++++ .../regions-close-object-into-object-4.rs | 24 +++++ src/test/compile-fail/seq-args.rs | 2 +- .../structure-constructor-type-mismatch.rs | 1 + .../compile-fail/trait-bounds-cant-coerce.rs | 2 +- src/test/compile-fail/trait-bounds-sugar.rs | 3 +- ...r-wrong-number-number-type-parameters-3.rs | 4 +- ...gar-wrong-number-number-type-parameters.rs | 4 +- .../unboxed-closure-sugar-wrong-trait.rs | 1 + ...object-lifetime-default-from-ref-struct.rs | 47 ++++++++++ 26 files changed, 542 insertions(+), 68 deletions(-) create mode 100644 src/test/compile-fail/object-lifetime-default-ambiguous.rs create mode 100644 src/test/compile-fail/object-lifetime-default-elision.rs create mode 100644 src/test/compile-fail/object-lifetime-default-from-box-error.rs create mode 100644 src/test/compile-fail/object-lifetime-default-mybox.rs create mode 100644 src/test/compile-fail/region-object-lifetime-2.rs create mode 100644 src/test/compile-fail/region-object-lifetime-3.rs create mode 100644 src/test/compile-fail/region-object-lifetime-4.rs create mode 100644 src/test/compile-fail/region-object-lifetime-5.rs rename src/test/compile-fail/{regions-close-object-into-object.rs => regions-close-object-into-object-1.rs} (67%) create mode 100644 src/test/compile-fail/regions-close-object-into-object-2.rs create mode 100644 src/test/compile-fail/regions-close-object-into-object-3.rs create mode 100644 src/test/compile-fail/regions-close-object-into-object-4.rs create mode 100644 src/test/run-pass/object-lifetime-default-from-ref-struct.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d4252a92695..dd814962c71 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -438,23 +438,25 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'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, ®ion_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(); (region_substs, types, assoc_bindings) } @@ -525,9 +527,11 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>, 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::>>(); + let inputs = + data.inputs.iter() + .map(|a_t| ast_ty_arg_to_ty(this, &binding_rscope, decl_generics, + 0, ®ion_substs, a_t)) + .collect::>>(); let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect(); let (implied_output_region, @@ -655,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, @@ -1070,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())); diff --git a/src/test/compile-fail/issue-11374.rs b/src/test/compile-fail/issue-11374.rs index 6dbea33d7d5..09d7293a3d0 100644 --- a/src/test/compile-fail/issue-11374.rs +++ b/src/test/compile-fail/issue-11374.rs @@ -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 } diff --git a/src/test/compile-fail/issue-5216.rs b/src/test/compile-fail/issue-5216.rs index fef414ce978..81424577d49 100644 --- a/src/test/compile-fail/issue-5216.rs +++ b/src/test/compile-fail/issue-5216.rs @@ -9,12 +9,12 @@ // except according to those terms. fn f() { } -struct S(Box); //~ ERROR explicit lifetime bound required -pub static C: S = S(f); +struct S(Box); +pub static C: S = S(f); //~ ERROR mismatched types fn g() { } -type T = Box; //~ ERROR explicit lifetime bound required -pub static D: T = g; +type T = Box; +pub static D: T = g; //~ ERROR mismatched types fn main() {} diff --git a/src/test/compile-fail/object-lifetime-default-ambiguous.rs b/src/test/compile-fail/object-lifetime-default-ambiguous.rs new file mode 100644 index 00000000000..c899232b733 --- /dev/null +++ b/src/test/compile-fail/object-lifetime-default-ambiguous.rs @@ -0,0 +1,60 @@ +// 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 or the MIT license +// , 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 { + 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) { + //~^ 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>) { + // In this case, the lifetime parameter from the Ref1 overrides. +} + +fn e(t: Ref2>) { + //~^ ERROR lifetime bound for this object type cannot be deduced from context + // + // In this case, Ref0 just inherits. +} + +fn f(t: &Ref2) { + //~^ ERROR lifetime bound for this object type cannot be deduced from context +} + +fn main() { +} diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs new file mode 100644 index 00000000000..0077d10e6ca --- /dev/null +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -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 or the MIT license +// , 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 +} + +fn deref(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) -> Box { + // Under old rules, the fully elaborated types of input/output were: + // + // for<'a,'b> fn(&'a Box) -> Box + // + // Under new rules the result is: + // + // for<'a> fn(&'a Box) -> Box + // + // 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() { +} diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs new file mode 100644 index 00000000000..70752cbfda1 --- /dev/null +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -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 or the MIT license +// , 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 +} + +fn load(ss: &mut SomeStruct) -> Box { + // `Box` defaults to a `'static` bound, so this return + // is illegal. + + ss.r //~ ERROR mismatched types +} + +fn store(ss: &mut SomeStruct, b: Box) { + // 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) { + // Here we override the lifetimes explicitly, and so naturally we get an error. + + ss.r = b; //~ ERROR mismatched types +} + +fn main() { +} diff --git a/src/test/compile-fail/object-lifetime-default-mybox.rs b/src/test/compile-fail/object-lifetime-default-mybox.rs new file mode 100644 index 00000000000..c107c8d131d --- /dev/null +++ b/src/test/compile-fail/object-lifetime-default-mybox.rs @@ -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 or the MIT license +// , 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 { + r: Box +} + +fn deref(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) -> MyBox { + deref(ss) //~ ERROR cannot infer +} + +fn load1<'a,'b>(a: &'a MyBox, + b: &'b MyBox) + -> &'b MyBox +{ + a + //~^ ERROR cannot infer + //~| ERROR mismatched types + //~| ERROR mismatched types +} + +fn main() { +} 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 6b3c92e0028..b8cbbdbe9ec 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 @@ -25,7 +25,7 @@ struct Foo<'a,'b,'c> { c: Box>, d: Box, e: Box+Send>, // we can derive two bounds, but one is 'static, so ok - f: Box, //~ ERROR explicit lifetime bound required + f: Box, // OK, defaults to 'static due to RFC 599. g: Box, z: Box+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted diff --git a/src/test/compile-fail/region-object-lifetime-1.rs b/src/test/compile-fail/region-object-lifetime-1.rs index 4758ce71fff..bb37d55fb08 100644 --- a/src/test/compile-fail/region-object-lifetime-1.rs +++ b/src/test/compile-fail/region-object-lifetime-1.rs @@ -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) -> &'static () { - x.borrowed() //~ ERROR cannot infer -} - -fn main() {} +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/region-object-lifetime-2.rs b/src/test/compile-fail/region-object-lifetime-2.rs new file mode 100644 index 00000000000..f9bf4e257b3 --- /dev/null +++ b/src/test/compile-fail/region-object-lifetime-2.rs @@ -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 or the MIT license +// , 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() {} + diff --git a/src/test/compile-fail/region-object-lifetime-3.rs b/src/test/compile-fail/region-object-lifetime-3.rs new file mode 100644 index 00000000000..7f00334f67e --- /dev/null +++ b/src/test/compile-fail/region-object-lifetime-3.rs @@ -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 or the MIT license +// , 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 + diff --git a/src/test/compile-fail/region-object-lifetime-4.rs b/src/test/compile-fail/region-object-lifetime-4.rs new file mode 100644 index 00000000000..fe0ff8dc3fe --- /dev/null +++ b/src/test/compile-fail/region-object-lifetime-4.rs @@ -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 or the MIT license +// , 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() {} + diff --git a/src/test/compile-fail/region-object-lifetime-5.rs b/src/test/compile-fail/region-object-lifetime-5.rs new file mode 100644 index 00000000000..f07f753d825 --- /dev/null +++ b/src/test/compile-fail/region-object-lifetime-5.rs @@ -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 or the MIT license +// , 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) -> &'static () { + x.borrowed() //~ ERROR `*x` does not live long enough +} + +fn main() {} + diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index e4521873a61..cf1e516901c 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -26,7 +26,9 @@ fn b(v: &[u8]) -> Box { } fn c(v: &[u8]) -> Box { - box v // OK thanks to lifetime elision + // same as previous case due to RFC 599 + + box v //~ ERROR declared lifetime bound not satisfied } fn d<'a,'b>(v: &'a [u8]) -> Box { diff --git a/src/test/compile-fail/regions-close-object-into-object.rs b/src/test/compile-fail/regions-close-object-into-object-1.rs similarity index 67% rename from src/test/compile-fail/regions-close-object-into-object.rs rename to src/test/compile-fail/regions-close-object-into-object-1.rs index 675f86b58f4..7a0e3cf4611 100644 --- a/src/test/compile-fail/regions-close-object-into-object.rs +++ b/src/test/compile-fail/regions-close-object-into-object-1.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(box_syntax)] +#![allow(warnings)] trait A {} struct B<'a, T>(&'a (A+'a)); @@ -17,19 +18,7 @@ trait X {} impl<'a, T> X for B<'a, T> {} fn f<'a, T, U>(v: Box+'static>) -> Box { - box B(&*v) as Box -} - -fn g<'a, T: 'static>(v: Box>) -> Box { - box B(&*v) as Box //~ ERROR cannot infer -} - -fn h<'a, T, U>(v: Box+'static>) -> Box { - box B(&*v) as Box -} - -fn i<'a, T, U>(v: Box>) -> Box { - box B(&*v) as Box //~ ERROR cannot infer + box B(&*v) as Box //~ ERROR `*v` does not live long enough } fn main() {} diff --git a/src/test/compile-fail/regions-close-object-into-object-2.rs b/src/test/compile-fail/regions-close-object-into-object-2.rs new file mode 100644 index 00000000000..7861fb95fef --- /dev/null +++ b/src/test/compile-fail/regions-close-object-into-object-2.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] + +trait A {} +struct B<'a, T>(&'a (A+'a)); + +trait X {} +impl<'a, T> X for B<'a, T> {} + +fn g<'a, T: 'static>(v: Box+'a>) -> Box { + box B(&*v) as Box //~ ERROR cannot infer +} + +fn main() { } diff --git a/src/test/compile-fail/regions-close-object-into-object-3.rs b/src/test/compile-fail/regions-close-object-into-object-3.rs new file mode 100644 index 00000000000..31354de2a27 --- /dev/null +++ b/src/test/compile-fail/regions-close-object-into-object-3.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] +#![allow(warnings)] + +trait A {} +struct B<'a, T>(&'a (A+'a)); + +trait X {} +impl<'a, T> X for B<'a, T> {} + +fn h<'a, T, U>(v: Box+'static>) -> Box { + box B(&*v) as Box //~ ERROR `*v` does not live long enough +} + +fn main() {} + diff --git a/src/test/compile-fail/regions-close-object-into-object-4.rs b/src/test/compile-fail/regions-close-object-into-object-4.rs new file mode 100644 index 00000000000..c60975f97e1 --- /dev/null +++ b/src/test/compile-fail/regions-close-object-into-object-4.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(box_syntax)] + +trait A {} +struct B<'a, T>(&'a (A+'a)); + +trait X {} +impl<'a, T> X for B<'a, T> {} + +fn i<'a, T, U>(v: Box+'a>) -> Box { + box B(&*v) as Box //~ ERROR cannot infer +} + +fn main() {} + diff --git a/src/test/compile-fail/seq-args.rs b/src/test/compile-fail/seq-args.rs index b4929eacf3d..44b049d6561 100644 --- a/src/test/compile-fail/seq-args.rs +++ b/src/test/compile-fail/seq-args.rs @@ -14,7 +14,7 @@ trait seq { } impl seq for Vec { //~ ERROR wrong number of type arguments /* ... */ } -impl seq for u32 { +impl seq for u32 { //~ ERROR wrong number of type arguments /* Treat the integer as a sequence of bits */ } diff --git a/src/test/compile-fail/structure-constructor-type-mismatch.rs b/src/test/compile-fail/structure-constructor-type-mismatch.rs index a82c05c72c3..c276228b18e 100644 --- a/src/test/compile-fail/structure-constructor-type-mismatch.rs +++ b/src/test/compile-fail/structure-constructor-type-mismatch.rs @@ -57,6 +57,7 @@ fn main() { let pt3 = PointF:: { //~^ ERROR wrong number of type arguments + //~| ERROR structure constructor specifies a structure of type x: 9i32, y: 10i32, }; diff --git a/src/test/compile-fail/trait-bounds-cant-coerce.rs b/src/test/compile-fail/trait-bounds-cant-coerce.rs index 79174552ae0..89e89cf8246 100644 --- a/src/test/compile-fail/trait-bounds-cant-coerce.rs +++ b/src/test/compile-fail/trait-bounds-cant-coerce.rs @@ -22,7 +22,7 @@ fn c(x: Box) { fn d(x: Box) { a(x); //~ ERROR mismatched types //~| expected `Box` - //~| found `Box` + //~| found `Box` //~| expected bounds `Send` //~| found no bounds } diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs index 4da496621d1..3d264e681a3 100644 --- a/src/test/compile-fail/trait-bounds-sugar.rs +++ b/src/test/compile-fail/trait-bounds-sugar.rs @@ -24,8 +24,7 @@ fn c(x: Box) { } fn d(x: &'static (Foo+Sync)) { - b(x); //~ ERROR cannot infer - //~^ ERROR mismatched types + b(x); } fn main() {} diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs index dcfcb7d4772..9f0682df3fe 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -12,7 +12,9 @@ trait Three { 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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs index a8ac62444aa..40635cf3ddd 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -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() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index e63f510b890..5810ffcf21a 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -14,6 +14,7 @@ trait Trait {} fn f isize>(x: F) {} //~^ ERROR wrong number of type arguments: expected 0, found 1 +//~| ERROR no associated type `Output` fn main() {} diff --git a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs new file mode 100644 index 00000000000..24da9603679 --- /dev/null +++ b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs @@ -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 or the MIT license +// , 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() { +} From f58a1bfa981eee4ba4d4c3c801f94772e4ab0019 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 12 Feb 2015 10:41:47 -0500 Subject: [PATCH 6/8] Fix fallout in libsyntax from RFC 599. Clarity and efficiency seems to be mostly improved, to my eye. Nonetheless, as this commit demonstrates, the previous commits was a [breaking-change]. In practice, breakage is focused on functions of this form: ```rust fn foo(..., object: Box) ```` where `FnMut()` could be any trait object type. The older scheme defaulted objects in argument position so that they were bounded by a fresh lifetime: ```rust fn foo<'a>(..., object: Box) ``` This meant that the object could contain borrowed data. The newer scheme defaults to a lifetime bound of `'static`: ```rust fn foo(..., object: Box) ``` This means that the object cannot contain borrowed data. In some cases, the best fix is to stop using `Box`: ```rust fn foo(..., object: &mut FnMut()) ``` but another option is to write an explicit annotation for the `'a` lifetime that used to be implicit. Both fixes are demonstrated in this commit. --- src/libsyntax/ext/base.rs | 6 +++--- src/libsyntax/ext/deriving/mod.rs | 4 ++-- src/libsyntax/ext/expand.rs | 9 +++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 64ae6162ef4..083039995ee 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -35,18 +35,18 @@ pub trait ItemDecorator { sp: Span, meta_item: &ast::MetaItem, item: &ast::Item, - push: Box)>); + push: &mut FnMut(P)); } impl ItemDecorator for F - where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, Box)>) + where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P)) { fn expand(&self, ecx: &mut ExtCtxt, sp: Span, meta_item: &ast::MetaItem, item: &ast::Item, - push: Box)>) { + push: &mut FnMut(P)) { (*self)(ecx, sp, meta_item, item, push) } } diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 9c3fa58ad09..0ed9e85e576 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -72,7 +72,7 @@ pub fn expand_deprecated_deriving(cx: &mut ExtCtxt, span: Span, _: &MetaItem, _: &Item, - _: Box)>) { + _: &mut FnMut(P)) { 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)>) { + push: &mut FnMut(P)) { match mitem.node { MetaNameValue(_, ref l) => { cx.span_err(l.span, "unexpected value in `derive`"); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 131bbc41005..fd98f42c2ab 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -363,7 +363,7 @@ fn expand_mac_invoc(mac: ast::Mac, span: codemap::Span, mark_thunk: G, fld: &mut MacroExpander) -> Option where - F: FnOnce(Box) -> Option, + F: for<'a> FnOnce(Box) -> Option, 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> = 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(); } From d0ef1664ca9bc885724e3a42d3194079ad0cf582 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 12 Feb 2015 13:34:50 -0500 Subject: [PATCH 7/8] Clarify and improve comment, removing a TODO. --- src/librustc_typeck/check/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4c1fd7ea854..828aed8b3ef 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1891,12 +1891,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { fn object_lifetime_default(&self, span: Span) -> Option { - // TODO. RFC #599 specifies that object lifetime defaults take - // precedence over other defaults. *However,* within a fn - // body, we typically use inference to allow users to elide - // lifetimes whenever they like, and then just infer it to - // whatever it must be. So I interpret that as applying only - // to fn sigs. + // 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))) } From 503e15b7c9095e11838c1bbb3f084232950aff18 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 16 Feb 2015 11:58:47 -0500 Subject: [PATCH 8/8] Address nits by @pnkfelix --- src/librustc/middle/infer/error_reporting.rs | 4 ++-- src/librustc_typeck/astconv.rs | 6 ++++++ src/librustc_typeck/check/regionck.rs | 4 ++-- src/test/compile-fail/builtin-superkinds-simple.rs | 2 +- src/test/compile-fail/kindck-impl-type-params.rs | 2 +- src/test/compile-fail/kindck-send-object1.rs | 2 +- src/test/compile-fail/kindck-send-owned.rs | 2 +- src/test/compile-fail/kindck-send-region-pointers.rs | 6 +++--- .../object-lifetime-default-ambiguous.rs | 3 ++- .../region-object-lifetime-in-coercion.rs | 8 ++++---- src/test/compile-fail/regions-bounded-by-send.rs | 10 +++++----- .../regions-bounded-by-trait-requiring-static.rs | 12 ++++++------ .../regions-bounded-method-type-parameters.rs | 2 +- 13 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 5d7a56ef0e6..23bd06b8f9b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -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 ", @@ -1629,7 +1629,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) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index dd814962c71..dd9b6dc132c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1754,6 +1754,12 @@ fn compute_object_lifetime_bound<'tcx>( return r; } +/// 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>, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bcb2ba6231d..17c259e674e 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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); } diff --git a/src/test/compile-fail/builtin-superkinds-simple.rs b/src/test/compile-fail/builtin-superkinds-simple.rs index 2c689f6909b..c7b75ade555 100644 --- a/src/test/compile-fail/builtin-superkinds-simple.rs +++ b/src/test/compile-fail/builtin-superkinds-simple.rs @@ -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() { } diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 5d090689415..de7639c6213 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -36,7 +36,7 @@ fn g(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>() { diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index c781fffff2d..3d47d33d7c3 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -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 diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs index 7025249fafb..266b6156656 100644 --- a/src/test/compile-fail/kindck-send-owned.rs +++ b/src/test/compile-fail/kindck-send-owned.rs @@ -19,7 +19,7 @@ fn test32() { assert_send:: >(); } // but not if they own a bad thing fn test40<'a>(_: &'a isize) { - assert_send::>(); //~ ERROR declared lifetime bound not satisfied + assert_send::>(); //~ ERROR does not fulfill the required lifetime } fn main() { } diff --git a/src/test/compile-fail/kindck-send-region-pointers.rs b/src/test/compile-fail/kindck-send-region-pointers.rs index c6987e89e3a..e2a5b0678a6 100644 --- a/src/test/compile-fail/kindck-send-region-pointers.rs +++ b/src/test/compile-fail/kindck-send-region-pointers.rs @@ -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() { } diff --git a/src/test/compile-fail/object-lifetime-default-ambiguous.rs b/src/test/compile-fail/object-lifetime-default-ambiguous.rs index c899232b733..322283a4ca9 100644 --- a/src/test/compile-fail/object-lifetime-default-ambiguous.rs +++ b/src/test/compile-fail/object-lifetime-default-ambiguous.rs @@ -49,7 +49,8 @@ fn d(t: Ref2>) { fn e(t: Ref2>) { //~^ ERROR lifetime bound for this object type cannot be deduced from context // - // In this case, Ref0 just inherits. + // In this case, Ref2 is ambiguous, and Ref0 inherits the + // ambiguity. } fn f(t: &Ref2) { diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index cf1e516901c..20cc624ab19 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -17,22 +17,22 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} fn a(v: &[u8]) -> Box { - let x: Box = box v; //~ ERROR declared lifetime bound not satisfied + let x: Box = box v; //~ ERROR does not fulfill the required lifetime x } fn b(v: &[u8]) -> Box { - box v //~ ERROR declared lifetime bound not satisfied + box v //~ ERROR does not fulfill the required lifetime } fn c(v: &[u8]) -> Box { // same as previous case due to RFC 599 - box v //~ ERROR declared lifetime bound not satisfied + box v //~ ERROR does not fulfill the required lifetime } fn d<'a,'b>(v: &'a [u8]) -> Box { - 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 { diff --git a/src/test/compile-fail/regions-bounded-by-send.rs b/src/test/compile-fail/regions-bounded-by-send.rs index e3f0d3bcdb6..71254e15d32 100644 --- a/src/test/compile-fail/regions-bounded-by-send.rs +++ b/src/test/compile-fail/regions-bounded-by-send.rs @@ -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::>(); //~ ERROR declared lifetime bound not satisfied + assert_send::>(); //~ 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 diff --git a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs index 8194af25d73..9e4c4e677cc 100644 --- a/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs +++ b/src/test/compile-fail/regions-bounded-by-trait-requiring-static.rs @@ -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::>(); //~ ERROR declared lifetime bound not satisfied + assert_send::>(); //~ 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() { diff --git a/src/test/compile-fail/regions-bounded-method-type-parameters.rs b/src/test/compile-fail/regions-bounded-method-type-parameters.rs index 9afacacd662..da4e8231a23 100644 --- a/src/test/compile-fail/regions-bounded-method-type-parameters.rs +++ b/src/test/compile-fail/regions-bounded-method-type-parameters.rs @@ -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() { }