Auto merge of #22230 - nikomatsakis:object-lifetime-defaults-2, r=pnkfelix
Implement rules described in rust-lang/rfcs#599. Fixes https://github.com/rust-lang/rust/issues/22211. ~~Based atop PR https://github.com/rust-lang/rust/pull/22182, so the first few commits (up to and including "Pacify the mercilous nrc") have already been reviewed.~~
This commit is contained in:
commit
81bce5290f
@ -824,6 +824,7 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||
assert_eq!(next(st), '|');
|
||||
let bounds = parse_bounds_(st, conv);
|
||||
let default = parse_opt(st, |st| parse_ty_(st, conv));
|
||||
let object_lifetime_default = parse_object_lifetime_default(st, conv);
|
||||
|
||||
ty::TypeParameterDef {
|
||||
name: name,
|
||||
@ -831,7 +832,24 @@ fn parse_type_param_def_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
|
||||
space: space,
|
||||
index: index,
|
||||
bounds: bounds,
|
||||
default: default
|
||||
default: default,
|
||||
object_lifetime_default: object_lifetime_default,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
|
||||
conv: &mut F)
|
||||
-> Option<ty::ObjectLifetimeDefault>
|
||||
where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
|
||||
{
|
||||
match next(st) {
|
||||
'n' => None,
|
||||
'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
|
||||
's' => {
|
||||
let region = parse_region_(st, conv);
|
||||
Some(ty::ObjectLifetimeDefault::Specific(region))
|
||||
}
|
||||
_ => panic!("parse_object_lifetime_default: bad input")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,6 +414,21 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tc
|
||||
v.space.to_uint(), v.index);
|
||||
enc_bounds(w, cx, &v.bounds);
|
||||
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
|
||||
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
|
||||
}
|
||||
|
||||
fn enc_object_lifetime_default<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
cx: &ctxt<'a, 'tcx>,
|
||||
default: Option<ty::ObjectLifetimeDefault>)
|
||||
{
|
||||
match default {
|
||||
None => mywrite!(w, "n"),
|
||||
Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
|
||||
Some(ty::ObjectLifetimeDefault::Specific(r)) => {
|
||||
mywrite!(w, "s");
|
||||
enc_region(w, cx, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enc_predicate<'a, 'tcx>(w: &mut SeekableMemWriter,
|
||||
|
@ -619,7 +619,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
infer::RelateRegionParamBound(span) => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
"declared lifetime bound not satisfied");
|
||||
"lifetime bound not satisfied");
|
||||
note_and_explain_region(
|
||||
self.tcx,
|
||||
"lifetime parameter instantiated with ",
|
||||
@ -1628,7 +1628,7 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
&format!("...so that the type `{}` \
|
||||
will meet the declared lifetime bounds",
|
||||
will meet its required lifetime bounds",
|
||||
self.ty_to_string(t))[]);
|
||||
}
|
||||
infer::RelateDefaultParamBound(span, t) => {
|
||||
|
@ -1762,6 +1762,21 @@ impl fmt::Debug for IntVarValue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Default region to use for the bound of objects that are
|
||||
/// supplied as the value for this type parameter. This is derived
|
||||
/// from `T:'a` annotations appearing in the type definition. If
|
||||
/// this is `None`, then the default is inherited from the
|
||||
/// surrounding context. See RFC #599 for details.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ObjectLifetimeDefault {
|
||||
/// Require an explicit annotation. Occurs when multiple
|
||||
/// `T:'a` constraints are found.
|
||||
Ambiguous,
|
||||
|
||||
/// Use the given region as the default.
|
||||
Specific(Region),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TypeParameterDef<'tcx> {
|
||||
pub name: ast::Name,
|
||||
@ -1770,6 +1785,7 @@ pub struct TypeParameterDef<'tcx> {
|
||||
pub index: u32,
|
||||
pub bounds: ParamBounds<'tcx>,
|
||||
pub default: Option<Ty<'tcx>>,
|
||||
pub object_lifetime_default: Option<ObjectLifetimeDefault>,
|
||||
}
|
||||
|
||||
#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
|
||||
@ -5884,42 +5900,13 @@ pub fn each_bound_trait_and_supertraits<'tcx, F>(tcx: &ctxt<'tcx>,
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn object_region_bounds<'tcx>(
|
||||
tcx: &ctxt<'tcx>,
|
||||
opt_principal: Option<&PolyTraitRef<'tcx>>, // None for closures
|
||||
others: BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
// Since we don't actually *know* the self type for an object,
|
||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||
// a skolemized type.
|
||||
let open_ty = ty::mk_infer(tcx, FreshTy(0));
|
||||
|
||||
let opt_trait_ref = opt_principal.map_or(Vec::new(), |principal| {
|
||||
// Note that we preserve the overall binding levels here.
|
||||
assert!(!open_ty.has_escaping_regions());
|
||||
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
|
||||
vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))))
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: others,
|
||||
trait_bounds: opt_trait_ref,
|
||||
projection_bounds: Vec::new(), // not relevant to computing region bounds
|
||||
};
|
||||
|
||||
let predicates = ty::predicates(tcx, open_ty, ¶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.
|
||||
@ -7390,3 +7377,12 @@ impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
|
||||
self.caller_bounds.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ObjectLifetimeDefault {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
ObjectLifetimeDefault::Ambiguous => format!("Ambiguous"),
|
||||
ObjectLifetimeDefault::Specific(ref r) => r.repr(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,6 +379,19 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
|
||||
index: self.index,
|
||||
bounds: self.bounds.fold_with(folder),
|
||||
default: self.default.fold_with(folder),
|
||||
object_lifetime_default: self.object_lifetime_default.fold_with(folder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
|
||||
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ObjectLifetimeDefault {
|
||||
match *self {
|
||||
ty::ObjectLifetimeDefault::Ambiguous =>
|
||||
ty::ObjectLifetimeDefault::Ambiguous,
|
||||
|
||||
ty::ObjectLifetimeDefault::Specific(r) =>
|
||||
ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,8 +55,8 @@ use middle::resolve_lifetime as rl;
|
||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||
use middle::traits;
|
||||
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
|
||||
ShiftedRscope, BindingRscope};
|
||||
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
|
||||
use TypeAndSubsts;
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
use util::nodemap::DefIdMap;
|
||||
@ -264,19 +264,18 @@ pub fn ast_path_substs_for_ty<'tcx>(
|
||||
|
||||
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
|
||||
ast::AngleBracketedParameters(ref data) => {
|
||||
convert_angle_bracketed_parameters(this, rscope, data)
|
||||
convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
|
||||
}
|
||||
ast::ParenthesizedParameters(ref data) => {
|
||||
span_err!(tcx.sess, path.span, E0214,
|
||||
"parenthesized parameters may only be used with a trait");
|
||||
convert_parenthesized_parameters(this, data)
|
||||
convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
|
||||
}
|
||||
};
|
||||
|
||||
prohibit_projections(this.tcx(), &assoc_bindings);
|
||||
|
||||
create_substs_for_ast_path(this,
|
||||
rscope,
|
||||
path.span,
|
||||
decl_generics,
|
||||
None,
|
||||
@ -284,14 +283,12 @@ pub fn ast_path_substs_for_ty<'tcx>(
|
||||
regions)
|
||||
}
|
||||
|
||||
fn create_substs_for_ast_path<'tcx>(
|
||||
fn create_region_substs<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
types: Vec<Ty<'tcx>>,
|
||||
regions: Vec<ty::Region>)
|
||||
regions_provided: Vec<ty::Region>)
|
||||
-> Substs<'tcx>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
@ -300,9 +297,9 @@ fn create_substs_for_ast_path<'tcx>(
|
||||
// region with the current anon region binding (in other words,
|
||||
// whatever & would get replaced with).
|
||||
let expected_num_region_params = decl_generics.regions.len(TypeSpace);
|
||||
let supplied_num_region_params = regions.len();
|
||||
let supplied_num_region_params = regions_provided.len();
|
||||
let regions = if expected_num_region_params == supplied_num_region_params {
|
||||
regions
|
||||
regions_provided
|
||||
} else {
|
||||
let anon_regions =
|
||||
rscope.anon_regions(span, expected_num_region_params);
|
||||
@ -314,51 +311,82 @@ fn create_substs_for_ast_path<'tcx>(
|
||||
}
|
||||
|
||||
match anon_regions {
|
||||
Ok(v) => v.into_iter().collect(),
|
||||
Err(_) => (0..expected_num_region_params)
|
||||
.map(|_| ty::ReStatic).collect() // hokey
|
||||
Ok(anon_regions) => anon_regions,
|
||||
Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect()
|
||||
}
|
||||
};
|
||||
Substs::new_type(vec![], regions)
|
||||
}
|
||||
|
||||
/// Given the type/region arguments provided to some path (along with
|
||||
/// an implicit Self, if this is a trait reference) returns the complete
|
||||
/// set of substitutions. This may involve applying defaulted type parameters.
|
||||
///
|
||||
/// Note that the type listing given here is *exactly* what the user provided.
|
||||
///
|
||||
/// The `region_substs` should be the result of `create_region_substs`
|
||||
/// -- that is, a substitution with no types but the correct number of
|
||||
/// regions.
|
||||
fn create_substs_for_ast_path<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
span: Span,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
types_provided: Vec<Ty<'tcx>>,
|
||||
region_substs: Substs<'tcx>)
|
||||
-> Substs<'tcx>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
|
||||
debug!("create_substs_for_ast_path(decl_generics={}, self_ty={}, \
|
||||
types_provided={}, region_substs={}",
|
||||
decl_generics.repr(tcx), self_ty.repr(tcx), types_provided.repr(tcx),
|
||||
region_substs.repr(tcx));
|
||||
|
||||
assert_eq!(region_substs.regions().len(TypeSpace), decl_generics.regions.len(TypeSpace));
|
||||
assert!(region_substs.types.is_empty());
|
||||
|
||||
// Convert the type parameters supplied by the user.
|
||||
let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
|
||||
let supplied_ty_param_count = types.len();
|
||||
let formal_ty_param_count =
|
||||
ty_param_defs.iter()
|
||||
.take_while(|x| !ty::is_associated_type(tcx, x.def_id))
|
||||
.count();
|
||||
let required_ty_param_count =
|
||||
ty_param_defs.iter()
|
||||
.take_while(|x| {
|
||||
x.default.is_none() &&
|
||||
!ty::is_associated_type(tcx, x.def_id)
|
||||
})
|
||||
.count();
|
||||
let supplied_ty_param_count = types_provided.len();
|
||||
let formal_ty_param_count = ty_param_defs.len();
|
||||
let required_ty_param_count = ty_param_defs.iter()
|
||||
.take_while(|x| x.default.is_none())
|
||||
.count();
|
||||
|
||||
let mut type_substs = types_provided;
|
||||
if supplied_ty_param_count < required_ty_param_count {
|
||||
let expected = if required_ty_param_count < formal_ty_param_count {
|
||||
"expected at least"
|
||||
} else {
|
||||
"expected"
|
||||
};
|
||||
span_fatal!(this.tcx().sess, span, E0243,
|
||||
"wrong number of type arguments: {} {}, found {}",
|
||||
expected,
|
||||
required_ty_param_count,
|
||||
supplied_ty_param_count);
|
||||
span_err!(this.tcx().sess, span, E0243,
|
||||
"wrong number of type arguments: {} {}, found {}",
|
||||
expected,
|
||||
required_ty_param_count,
|
||||
supplied_ty_param_count);
|
||||
while type_substs.len() < required_ty_param_count {
|
||||
type_substs.push(tcx.types.err);
|
||||
}
|
||||
} else if supplied_ty_param_count > formal_ty_param_count {
|
||||
let expected = if required_ty_param_count < formal_ty_param_count {
|
||||
"expected at most"
|
||||
} else {
|
||||
"expected"
|
||||
};
|
||||
span_fatal!(this.tcx().sess, span, E0244,
|
||||
"wrong number of type arguments: {} {}, found {}",
|
||||
expected,
|
||||
formal_ty_param_count,
|
||||
supplied_ty_param_count);
|
||||
span_err!(this.tcx().sess, span, E0244,
|
||||
"wrong number of type arguments: {} {}, found {}",
|
||||
expected,
|
||||
formal_ty_param_count,
|
||||
supplied_ty_param_count);
|
||||
type_substs.truncate(formal_ty_param_count);
|
||||
}
|
||||
assert!(type_substs.len() >= required_ty_param_count &&
|
||||
type_substs.len() <= formal_ty_param_count);
|
||||
|
||||
let mut substs = Substs::new_type(types, regions);
|
||||
let mut substs = region_substs;
|
||||
substs.types.extend(TypeSpace, type_substs.into_iter());
|
||||
|
||||
match self_ty {
|
||||
None => {
|
||||
@ -374,7 +402,8 @@ fn create_substs_for_ast_path<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
for param in &ty_param_defs[supplied_ty_param_count..] {
|
||||
let actual_supplied_ty_param_count = substs.types.len(TypeSpace);
|
||||
for param in &ty_param_defs[actual_supplied_ty_param_count..] {
|
||||
match param.default {
|
||||
Some(default) => {
|
||||
// This is a default type parameter.
|
||||
@ -400,29 +429,36 @@ struct ConvertedBinding<'tcx> {
|
||||
|
||||
fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
data: &ast::AngleBracketedParameterData)
|
||||
-> (Vec<ty::Region>,
|
||||
-> (Substs<'tcx>,
|
||||
Vec<Ty<'tcx>>,
|
||||
Vec<ConvertedBinding<'tcx>>)
|
||||
{
|
||||
let regions: Vec<_> =
|
||||
data.lifetimes.iter()
|
||||
.map(|l| ast_region_to_region(this.tcx(), l))
|
||||
.collect();
|
||||
.map(|l| ast_region_to_region(this.tcx(), l))
|
||||
.collect();
|
||||
|
||||
let region_substs =
|
||||
create_region_substs(this, rscope, span, decl_generics, regions);
|
||||
|
||||
let types: Vec<_> =
|
||||
data.types.iter()
|
||||
.map(|t| ast_ty_to_ty(this, rscope, &**t))
|
||||
.collect();
|
||||
.enumerate()
|
||||
.map(|(i,t)| ast_ty_arg_to_ty(this, rscope, decl_generics,
|
||||
i, ®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();
|
||||
|
||||
(regions, types, assoc_bindings)
|
||||
(region_substs, types, assoc_bindings)
|
||||
}
|
||||
|
||||
/// Returns the appropriate lifetime to use for any output lifetimes
|
||||
@ -465,7 +501,7 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
|
||||
{
|
||||
match implied_output_region {
|
||||
Some(implied_output_region) => {
|
||||
let rb = SpecificRscope::new(implied_output_region);
|
||||
let rb = ElidableRscope::new(implied_output_region);
|
||||
ast_ty_to_ty(this, &rb, ty)
|
||||
}
|
||||
None => {
|
||||
@ -479,15 +515,23 @@ fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
|
||||
}
|
||||
|
||||
fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
data: &ast::ParenthesizedParameterData)
|
||||
-> (Vec<ty::Region>,
|
||||
-> (Substs<'tcx>,
|
||||
Vec<Ty<'tcx>>,
|
||||
Vec<ConvertedBinding<'tcx>>)
|
||||
{
|
||||
let region_substs =
|
||||
create_region_substs(this, rscope, span, decl_generics, Vec::new());
|
||||
|
||||
let binding_rscope = BindingRscope::new();
|
||||
let inputs = data.inputs.iter()
|
||||
.map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
|
||||
.collect::<Vec<Ty<'tcx>>>();
|
||||
let inputs =
|
||||
data.inputs.iter()
|
||||
.map(|a_t| ast_ty_arg_to_ty(this, &binding_rscope, decl_generics,
|
||||
0, ®ion_substs, a_t))
|
||||
.collect::<Vec<Ty<'tcx>>>();
|
||||
|
||||
let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect();
|
||||
let (implied_output_region,
|
||||
@ -514,7 +558,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
|
||||
span: output_span
|
||||
};
|
||||
|
||||
(vec![], vec![input_ty], vec![output_binding])
|
||||
(region_substs, vec![input_ty], vec![output_binding])
|
||||
}
|
||||
|
||||
pub fn instantiate_poly_trait_ref<'tcx>(
|
||||
@ -615,7 +659,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
|
||||
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
|
||||
ast::AngleBracketedParameters(ref data) => {
|
||||
// For now, require that parenthetical5D notation be used
|
||||
// For now, require that parenthetical notation be used
|
||||
// only with `Fn()` etc.
|
||||
if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
|
||||
span_err!(this.tcx().sess, path.span, E0215,
|
||||
@ -626,7 +670,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
the crate attributes to enable");
|
||||
}
|
||||
|
||||
convert_angle_bracketed_parameters(this, rscope, data)
|
||||
convert_angle_bracketed_parameters(this, rscope, path.span, &trait_def.generics, data)
|
||||
}
|
||||
ast::ParenthesizedParameters(ref data) => {
|
||||
// For now, require that parenthetical notation be used
|
||||
@ -640,12 +684,11 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
the crate attributes to enable");
|
||||
}
|
||||
|
||||
convert_parenthesized_parameters(this, data)
|
||||
convert_parenthesized_parameters(this, rscope, path.span, &trait_def.generics, data)
|
||||
}
|
||||
};
|
||||
|
||||
let substs = create_substs_for_ast_path(this,
|
||||
rscope,
|
||||
path.span,
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
@ -932,7 +975,7 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>,
|
||||
let existential_bounds = conv_existential_bounds(this,
|
||||
rscope,
|
||||
span,
|
||||
Some(trait_ref.clone()),
|
||||
trait_ref.clone(),
|
||||
projection_bounds,
|
||||
bounds);
|
||||
|
||||
@ -1031,10 +1074,45 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
qpath.item_path.identifier.name);
|
||||
}
|
||||
|
||||
// Parses the programmer's textual representation of a type into our
|
||||
// internal notion of a type.
|
||||
pub fn ast_ty_to_ty<'tcx>(
|
||||
this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx>
|
||||
/// Convert a type supplied as value for a type argument from AST into our
|
||||
/// our internal representation. This is the same as `ast_ty_to_ty` but that
|
||||
/// it applies the object lifetime default.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `this`, `rscope`: the surrounding context
|
||||
/// * `decl_generics`: the generics of the struct/enum/trait declaration being
|
||||
/// referenced
|
||||
/// * `index`: the index of the type parameter being instantiated from the list
|
||||
/// (we assume it is in the `TypeSpace`)
|
||||
/// * `region_substs`: a partial substitution consisting of
|
||||
/// only the region type parameters being supplied to this type.
|
||||
/// * `ast_ty`: the ast representation of the type being supplied
|
||||
pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
decl_generics: &ty::Generics<'tcx>,
|
||||
index: usize,
|
||||
region_substs: &Substs<'tcx>,
|
||||
ast_ty: &ast::Ty)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
|
||||
if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
|
||||
let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
|
||||
let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
|
||||
ast_ty_to_ty(this, rscope1, ast_ty)
|
||||
} else {
|
||||
ast_ty_to_ty(this, rscope, ast_ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the programmer's textual representation of a type into our
|
||||
/// internal notion of a type.
|
||||
pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
ast_ty: &ast::Ty)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
debug!("ast_ty_to_ty(ast_ty={})",
|
||||
ast_ty.repr(this.tcx()));
|
||||
@ -1084,7 +1162,11 @@ pub fn ast_ty_to_ty<'tcx>(
|
||||
ast::TyRptr(ref region, ref mt) => {
|
||||
let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
|
||||
debug!("ty_rptr r={}", r.repr(this.tcx()));
|
||||
let t = ast_ty_to_ty(this, rscope, &*mt.ty);
|
||||
let rscope1 =
|
||||
&ObjectLifetimeDefaultRscope::new(
|
||||
rscope,
|
||||
Some(ty::ObjectLifetimeDefault::Specific(r)));
|
||||
let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
|
||||
ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
|
||||
}
|
||||
ast::TyTup(ref fields) => {
|
||||
@ -1518,11 +1600,11 @@ pub fn ty_of_closure<'tcx>(
|
||||
/// `ExistentialBounds` struct. The `main_trait_refs` argument specifies the `Foo` -- it is absent
|
||||
/// for closures. Eventually this should all be normalized, I think, so that there is no "main
|
||||
/// trait ref" and instead we just have a flat list of bounds as the existential type.
|
||||
pub fn conv_existential_bounds<'tcx>(
|
||||
fn conv_existential_bounds<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
|
||||
ast_bounds: &[ast::TyParamBound])
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
@ -1546,15 +1628,15 @@ fn conv_ty_poly_trait_ref<'tcx>(
|
||||
let mut projection_bounds = Vec::new();
|
||||
let main_trait_bound = if !partitioned_bounds.trait_bounds.is_empty() {
|
||||
let trait_bound = partitioned_bounds.trait_bounds.remove(0);
|
||||
Some(instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
&mut projection_bounds))
|
||||
instantiate_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_bound,
|
||||
None,
|
||||
&mut projection_bounds)
|
||||
} else {
|
||||
span_err!(this.tcx().sess, span, E0224,
|
||||
"at least one non-builtin trait is required for an object type");
|
||||
None
|
||||
"at least one non-builtin trait is required for an object type");
|
||||
return this.tcx().types.err;
|
||||
};
|
||||
|
||||
let bounds =
|
||||
@ -1565,17 +1647,14 @@ fn conv_ty_poly_trait_ref<'tcx>(
|
||||
projection_bounds,
|
||||
partitioned_bounds);
|
||||
|
||||
match main_trait_bound {
|
||||
None => this.tcx().types.err,
|
||||
Some(principal) => ty::mk_trait(this.tcx(), principal, bounds)
|
||||
}
|
||||
ty::mk_trait(this.tcx(), main_trait_bound, bounds)
|
||||
}
|
||||
|
||||
pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for boxed closures
|
||||
principal_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
mut projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>, // Empty for boxed closures
|
||||
partitioned_bounds: PartitionedBounds)
|
||||
-> ty::ExistentialBounds<'tcx>
|
||||
@ -1588,16 +1667,15 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
|
||||
if !trait_bounds.is_empty() {
|
||||
let b = &trait_bounds[0];
|
||||
span_err!(this.tcx().sess, b.trait_ref.path.span, E0225,
|
||||
"only the builtin traits can be used \
|
||||
as closure or object bounds");
|
||||
"only the builtin traits can be used as closure or object bounds");
|
||||
}
|
||||
|
||||
let region_bound = compute_region_bound(this,
|
||||
rscope,
|
||||
span,
|
||||
®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 +1686,21 @@ pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the bounds on a type parameter / existential type, determines what single region bound
|
||||
/// Given the bounds on an object, determines what single region bound
|
||||
/// (if any) we can use to summarize this type. The basic idea is that we will use the bound the
|
||||
/// user provided, if they provided one, and otherwise search the supertypes of trait bounds for
|
||||
/// region bounds. It may be that we can derive no bound at all, in which case we return `None`.
|
||||
fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
span: Span,
|
||||
explicit_region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> Option<ty::Region>
|
||||
fn compute_object_lifetime_bound<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
explicit_region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
|
||||
debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
|
||||
principal_trait_ref={}, builtin_bounds={})",
|
||||
explicit_region_bounds,
|
||||
@ -1633,24 +1715,32 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
if explicit_region_bounds.len() != 0 {
|
||||
// Explicitly specified region bound. Use that.
|
||||
let r = explicit_region_bounds[0];
|
||||
return Some(ast_region_to_region(tcx, r));
|
||||
return ast_region_to_region(tcx, r);
|
||||
}
|
||||
|
||||
// No explicit region bound specified. Therefore, examine trait
|
||||
// bounds and see if we can derive region bounds from those.
|
||||
let derived_region_bounds =
|
||||
ty::object_region_bounds(tcx, principal_trait_ref.as_ref(), builtin_bounds);
|
||||
object_region_bounds(tcx, &principal_trait_ref, builtin_bounds);
|
||||
|
||||
// If there are no derived region bounds, then report back that we
|
||||
// can find no region bound.
|
||||
if derived_region_bounds.len() == 0 {
|
||||
return None;
|
||||
match rscope.object_lifetime_default(span) {
|
||||
Some(r) => { return r; }
|
||||
None => {
|
||||
span_err!(this.tcx().sess, span, E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound");
|
||||
return ty::ReStatic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If any of the derived region bounds are 'static, that is always
|
||||
// the best choice.
|
||||
if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
|
||||
return Some(ty::ReStatic);
|
||||
return ty::ReStatic;
|
||||
}
|
||||
|
||||
// Determine whether there is exactly one unique region in the set
|
||||
@ -1659,38 +1749,42 @@ fn compute_opt_region_bound<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
let r = derived_region_bounds[0];
|
||||
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
|
||||
span_err!(tcx.sess, span, E0227,
|
||||
"ambiguous lifetime bound, \
|
||||
explicit lifetime bound required");
|
||||
"ambiguous lifetime bound, explicit lifetime bound required");
|
||||
}
|
||||
return Some(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// A version of `compute_opt_region_bound` for use where some region bound is required
|
||||
/// (existential types, basically). Reports an error if no region bound can be derived and we are
|
||||
/// in an `rscope` that does not provide a default.
|
||||
fn compute_region_bound<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
region_bounds: &[&ast::Lifetime],
|
||||
principal_trait_ref: Option<ty::PolyTraitRef<'tcx>>, // None for closures
|
||||
builtin_bounds: ty::BuiltinBounds)
|
||||
-> ty::Region
|
||||
/// Given an object type like `SomeTrait+Send`, computes the lifetime
|
||||
/// bounds that must hold on the elided self type. These are derived
|
||||
/// from the declarations of `SomeTrait`, `Send`, and friends -- if
|
||||
/// they declare `trait SomeTrait : 'static`, for example, then
|
||||
/// `'static` would appear in the list. The hard work is done by
|
||||
/// `ty::required_region_bounds`, see that for more information.
|
||||
pub fn object_region_bounds<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
principal: &ty::PolyTraitRef<'tcx>,
|
||||
others: ty::BuiltinBounds)
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
match compute_opt_region_bound(this.tcx(), span, region_bounds,
|
||||
principal_trait_ref, builtin_bounds) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
match rscope.default_region_bound(span) {
|
||||
Some(r) => { r }
|
||||
None => {
|
||||
span_err!(this.tcx().sess, span, E0228,
|
||||
"explicit lifetime bound required");
|
||||
ty::ReStatic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Since we don't actually *know* the self type for an object,
|
||||
// this "open(err)" serves as a kind of dummy standin -- basically
|
||||
// a skolemized type.
|
||||
let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
|
||||
|
||||
// Note that we preserve the overall binding levels here.
|
||||
assert!(!open_ty.has_escaping_regions());
|
||||
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
|
||||
let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
region_bounds: Vec::new(),
|
||||
builtin_bounds: others,
|
||||
trait_bounds: trait_refs,
|
||||
projection_bounds: Vec::new(), // not relevant to computing region bounds
|
||||
};
|
||||
|
||||
let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
|
||||
ty::required_region_bounds(tcx, open_ty, predicates)
|
||||
}
|
||||
|
||||
pub struct PartitionedBounds<'a> {
|
||||
|
@ -1890,7 +1890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region> {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
// RFC #599 specifies that object lifetime defaults take
|
||||
// precedence over other defaults. But within a fn body we
|
||||
// don't have a *default* region, rather we use inference to
|
||||
// find the *correct* region, which is strictly more general
|
||||
// (and anyway, within a fn body the right region may not even
|
||||
// be something the user can write explicitly, since it might
|
||||
// be some expression).
|
||||
Some(self.infcx().next_region_var(infer::MiscVariable(span)))
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@ There are some shortcomings in this design:
|
||||
*/
|
||||
|
||||
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
|
||||
use middle::def;
|
||||
use middle::lang_items::SizedTraitLangItem;
|
||||
use middle::region;
|
||||
use middle::resolve_lifetime;
|
||||
@ -1199,8 +1200,23 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
|
||||
predicates.clone());
|
||||
assert!(prev_predicates.is_none());
|
||||
|
||||
return (scheme, predicates);
|
||||
// Debugging aid.
|
||||
if ty::has_attr(tcx, local_def(it.id), "rustc_object_lifetime_default") {
|
||||
let object_lifetime_default_reprs: String =
|
||||
scheme.generics.types.iter()
|
||||
.map(|t| match t.object_lifetime_default {
|
||||
Some(ty::ObjectLifetimeDefault::Specific(r)) =>
|
||||
r.user_string(tcx),
|
||||
d =>
|
||||
d.repr(ccx.tcx()),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.connect(",");
|
||||
|
||||
tcx.sess.span_err(it.span, &object_lifetime_default_reprs);
|
||||
}
|
||||
|
||||
return (scheme, predicates);
|
||||
}
|
||||
|
||||
fn type_scheme_of_foreign_item<'a, 'tcx>(
|
||||
@ -1269,6 +1285,7 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
|
||||
subst::TypeSpace,
|
||||
&generics.lifetimes[],
|
||||
&generics.ty_params[],
|
||||
&generics.where_clause,
|
||||
ty::Generics::empty())
|
||||
}
|
||||
|
||||
@ -1298,6 +1315,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
|
||||
subst::TypeSpace,
|
||||
&ast_generics.lifetimes[],
|
||||
&ast_generics.ty_params[],
|
||||
&ast_generics.where_clause,
|
||||
ty::Generics::empty());
|
||||
|
||||
// Add in the self type parameter.
|
||||
@ -1321,7 +1339,8 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
|
||||
trait_bounds: vec!(ty::Binder(self_trait_ref.clone())),
|
||||
projection_bounds: vec!(),
|
||||
},
|
||||
default: None
|
||||
default: None,
|
||||
object_lifetime_default: None,
|
||||
};
|
||||
|
||||
ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
|
||||
@ -1341,6 +1360,7 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
subst::FnSpace,
|
||||
&early_lifetimes[],
|
||||
&generics.ty_params[],
|
||||
&generics.where_clause,
|
||||
base_generics)
|
||||
}
|
||||
|
||||
@ -1487,6 +1507,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
space: subst::ParamSpace,
|
||||
lifetime_defs: &[ast::LifetimeDef],
|
||||
types: &[ast::TyParam],
|
||||
where_clause: &ast::WhereClause,
|
||||
base_generics: ty::Generics<'tcx>)
|
||||
-> ty::Generics<'tcx>
|
||||
{
|
||||
@ -1511,7 +1532,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
|
||||
// Now create the real type parameters.
|
||||
for (i, param) in types.iter().enumerate() {
|
||||
let def = get_or_create_type_parameter_def(ccx, space, param, i as u32);
|
||||
let def = get_or_create_type_parameter_def(ccx, space, param, i as u32, where_clause);
|
||||
debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
|
||||
result.types.push(space, def);
|
||||
}
|
||||
@ -1522,7 +1543,8 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
space: subst::ParamSpace,
|
||||
param: &ast::TyParam,
|
||||
index: u32)
|
||||
index: u32,
|
||||
where_clause: &ast::WhereClause)
|
||||
-> ty::TypeParameterDef<'tcx>
|
||||
{
|
||||
let tcx = ccx.tcx;
|
||||
@ -1558,13 +1580,17 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
}
|
||||
};
|
||||
|
||||
let object_lifetime_default =
|
||||
compute_object_lifetime_default(ccx, space, index, ¶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<ty::ObjectLifetimeDefault>
|
||||
{
|
||||
let inline_bounds = from_bounds(ccx, param_bounds);
|
||||
let where_bounds = from_predicates(ccx, space, index, &where_clause.predicates);
|
||||
let all_bounds: HashSet<_> = inline_bounds.into_iter()
|
||||
.chain(where_bounds.into_iter())
|
||||
.collect();
|
||||
return if all_bounds.len() > 1 {
|
||||
Some(ty::ObjectLifetimeDefault::Ambiguous)
|
||||
} else {
|
||||
all_bounds.into_iter()
|
||||
.next()
|
||||
.map(ty::ObjectLifetimeDefault::Specific)
|
||||
};
|
||||
|
||||
fn from_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
bounds: &[ast::TyParamBound])
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
bounds.iter()
|
||||
.filter_map(|bound| {
|
||||
match *bound {
|
||||
ast::TraitTyParamBound(..) =>
|
||||
None,
|
||||
ast::RegionTyParamBound(ref lifetime) =>
|
||||
Some(astconv::ast_region_to_region(ccx.tcx(), lifetime)),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn from_predicates<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
|
||||
space: subst::ParamSpace,
|
||||
index: u32,
|
||||
predicates: &[ast::WherePredicate])
|
||||
-> Vec<ty::Region>
|
||||
{
|
||||
predicates.iter()
|
||||
.flat_map(|predicate| {
|
||||
match *predicate {
|
||||
ast::WherePredicate::BoundPredicate(ref data) => {
|
||||
if data.bound_lifetimes.len() == 0 &&
|
||||
is_param(ccx, &data.bounded_ty, space, index)
|
||||
{
|
||||
from_bounds(ccx, &data.bounds).into_iter()
|
||||
} else {
|
||||
Vec::new().into_iter()
|
||||
}
|
||||
}
|
||||
ast::WherePredicate::RegionPredicate(..) |
|
||||
ast::WherePredicate::EqPredicate(..) => {
|
||||
Vec::new().into_iter()
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn is_param(ccx: &CollectCtxt,
|
||||
ast_ty: &ast::Ty,
|
||||
space: subst::ParamSpace,
|
||||
index: u32)
|
||||
-> bool
|
||||
{
|
||||
match ast_ty.node {
|
||||
ast::TyPath(_, id) => {
|
||||
match ccx.tcx.def_map.borrow()[id] {
|
||||
def::DefTyParam(s, i, _, _) => {
|
||||
space == s && index == i
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SizedByDefault { Yes, No }
|
||||
|
||||
/// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
|
||||
|
@ -32,7 +32,10 @@ pub trait RegionScope {
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>;
|
||||
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>;
|
||||
/// If an object omits any explicit lifetime bound, and none can
|
||||
/// be derived from the object traits, what should we use? If
|
||||
/// `None` is returned, an explicit annotation is required.
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
|
||||
}
|
||||
|
||||
// A scope in which all regions must be explicitly named. This is used
|
||||
@ -41,8 +44,8 @@ pub trait RegionScope {
|
||||
pub struct ExplicitRscope;
|
||||
|
||||
impl RegionScope for ExplicitRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
None
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
Some(ty::ReStatic)
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
@ -63,8 +66,8 @@ impl UnelidableRscope {
|
||||
}
|
||||
|
||||
impl RegionScope for UnelidableRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
None
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
Some(ty::ReStatic)
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
@ -76,22 +79,26 @@ impl RegionScope for UnelidableRscope {
|
||||
}
|
||||
}
|
||||
|
||||
// A scope in which any omitted region defaults to `default`. This is
|
||||
// used after the `->` in function signatures, but also for backwards
|
||||
// compatibility with object types. The latter use may go away.
|
||||
pub struct SpecificRscope {
|
||||
default: ty::Region
|
||||
// A scope in which omitted anonymous region defaults to
|
||||
// `default`. This is used after the `->` in function signatures. The
|
||||
// latter use may go away. Note that object-lifetime defaults work a
|
||||
// bit differently, as specified in RFC #599.
|
||||
pub struct ElidableRscope {
|
||||
default: ty::Region,
|
||||
}
|
||||
|
||||
impl SpecificRscope {
|
||||
pub fn new(r: ty::Region) -> SpecificRscope {
|
||||
SpecificRscope { default: r }
|
||||
impl ElidableRscope {
|
||||
pub fn new(r: ty::Region) -> ElidableRscope {
|
||||
ElidableRscope { default: r }
|
||||
}
|
||||
}
|
||||
|
||||
impl RegionScope for SpecificRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region> {
|
||||
Some(self.default)
|
||||
impl RegionScope for ElidableRscope {
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
// Per RFC #599, object-lifetimes default to 'static unless
|
||||
// overridden by context, and this takes precedence over
|
||||
// lifetime elision.
|
||||
Some(ty::ReStatic)
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
@ -124,9 +131,11 @@ impl BindingRscope {
|
||||
}
|
||||
|
||||
impl RegionScope for BindingRscope {
|
||||
fn default_region_bound(&self, _span: Span) -> Option<ty::Region>
|
||||
{
|
||||
Some(self.next_region())
|
||||
fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
|
||||
// Per RFC #599, object-lifetimes default to 'static unless
|
||||
// overridden by context, and this takes precedence over the
|
||||
// binding defaults.
|
||||
Some(ty::ReStatic)
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
@ -138,6 +147,42 @@ impl RegionScope for BindingRscope {
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope which overrides the default object lifetime but has no other effect.
|
||||
pub struct ObjectLifetimeDefaultRscope<'r> {
|
||||
base_scope: &'r (RegionScope+'r),
|
||||
default: Option<ty::ObjectLifetimeDefault>,
|
||||
}
|
||||
|
||||
impl<'r> ObjectLifetimeDefaultRscope<'r> {
|
||||
pub fn new(base_scope: &'r (RegionScope+'r),
|
||||
default: Option<ty::ObjectLifetimeDefault>)
|
||||
-> ObjectLifetimeDefaultRscope<'r>
|
||||
{
|
||||
ObjectLifetimeDefaultRscope {
|
||||
base_scope: base_scope,
|
||||
default: default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
match self.default {
|
||||
None => self.base_scope.object_lifetime_default(span),
|
||||
Some(ty::ObjectLifetimeDefault::Ambiguous) => None,
|
||||
Some(ty::ObjectLifetimeDefault::Specific(r)) => Some(r),
|
||||
}
|
||||
}
|
||||
|
||||
fn anon_regions(&self,
|
||||
span: Span,
|
||||
count: uint)
|
||||
-> Result<Vec<ty::Region>, Option<Vec<(String, uint)>>>
|
||||
{
|
||||
self.base_scope.anon_regions(span, count)
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope which simply shifts the Debruijn index of other scopes
|
||||
/// to account for binding levels.
|
||||
pub struct ShiftedRscope<'r> {
|
||||
@ -151,9 +196,8 @@ impl<'r> ShiftedRscope<'r> {
|
||||
}
|
||||
|
||||
impl<'r> RegionScope for ShiftedRscope<'r> {
|
||||
fn default_region_bound(&self, span: Span) -> Option<ty::Region>
|
||||
{
|
||||
self.base_scope.default_region_bound(span)
|
||||
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
|
||||
self.base_scope.object_lifetime_default(span)
|
||||
.map(|r| ty_fold::shift_region(r, 1))
|
||||
}
|
||||
|
||||
|
@ -35,18 +35,18 @@ pub trait ItemDecorator {
|
||||
sp: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: &ast::Item,
|
||||
push: Box<FnMut(P<ast::Item>)>);
|
||||
push: &mut FnMut(P<ast::Item>));
|
||||
}
|
||||
|
||||
impl<F> ItemDecorator for F
|
||||
where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, Box<FnMut(P<ast::Item>)>)
|
||||
where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, &mut FnMut(P<ast::Item>))
|
||||
{
|
||||
fn expand(&self,
|
||||
ecx: &mut ExtCtxt,
|
||||
sp: Span,
|
||||
meta_item: &ast::MetaItem,
|
||||
item: &ast::Item,
|
||||
push: Box<FnMut(P<ast::Item>)>) {
|
||||
push: &mut FnMut(P<ast::Item>)) {
|
||||
(*self)(ecx, sp, meta_item, item, push)
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ pub fn expand_deprecated_deriving(cx: &mut ExtCtxt,
|
||||
span: Span,
|
||||
_: &MetaItem,
|
||||
_: &Item,
|
||||
_: Box<FnMut(P<Item>)>) {
|
||||
_: &mut FnMut(P<Item>)) {
|
||||
cx.span_err(span, "`deriving` has been renamed to `derive`");
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ pub fn expand_meta_derive(cx: &mut ExtCtxt,
|
||||
_span: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Item,
|
||||
mut push: Box<FnMut(P<Item>)>) {
|
||||
push: &mut FnMut(P<Item>)) {
|
||||
match mitem.node {
|
||||
MetaNameValue(_, ref l) => {
|
||||
cx.span_err(l.span, "unexpected value in `derive`");
|
||||
|
@ -363,7 +363,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac, span: codemap::Span,
|
||||
mark_thunk: G,
|
||||
fld: &mut MacroExpander)
|
||||
-> Option<T> where
|
||||
F: FnOnce(Box<MacResult>) -> Option<T>,
|
||||
F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
|
||||
G: FnOnce(T, Mrk) -> T,
|
||||
{
|
||||
match mac.node {
|
||||
@ -1102,9 +1102,10 @@ fn expand_annotatable(a: Annotatable,
|
||||
// but that double-mut-borrows fld
|
||||
let mut items: SmallVector<P<ast::Item>> = SmallVector::zero();
|
||||
dec.expand(fld.cx, attr.span, &*attr.node.value, &**it,
|
||||
box |item| items.push(item));
|
||||
decorator_items.extend(items.into_iter()
|
||||
.flat_map(|item| expand_item(item, fld).into_iter()));
|
||||
&mut |item| items.push(item));
|
||||
decorator_items.extend(
|
||||
items.into_iter()
|
||||
.flat_map(|item| expand_item(item, fld).into_iter()));
|
||||
|
||||
fld.cx.bt_pop();
|
||||
}
|
||||
|
@ -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() { }
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -9,12 +9,12 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn f() { }
|
||||
struct S(Box<FnMut()>); //~ ERROR explicit lifetime bound required
|
||||
pub static C: S = S(f);
|
||||
struct S(Box<FnMut()>);
|
||||
pub static C: S = S(f); //~ ERROR mismatched types
|
||||
|
||||
|
||||
fn g() { }
|
||||
type T = Box<FnMut()>; //~ ERROR explicit lifetime bound required
|
||||
pub static D: T = g;
|
||||
type T = Box<FnMut()>;
|
||||
pub static D: T = g; //~ ERROR mismatched types
|
||||
|
||||
fn main() {}
|
||||
|
@ -36,7 +36,7 @@ fn g<T>(val: T) {
|
||||
fn foo<'a>() {
|
||||
let t: S<&'a isize> = S;
|
||||
let a = &t as &Gettable<&'a isize>;
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
//~^ ERROR the type `&'a isize` does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn foo2<'a>() {
|
||||
|
@ -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
|
||||
|
@ -19,7 +19,7 @@ fn test32() { assert_send::<Vec<isize> >(); }
|
||||
|
||||
// but not if they own a bad thing
|
||||
fn test40<'a>(_: &'a isize) {
|
||||
assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -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() { }
|
||||
|
61
src/test/compile-fail/object-lifetime-default-ambiguous.rs
Normal file
61
src/test/compile-fail/object-lifetime-default-ambiguous.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that if a struct declares multiple region bounds for a given
|
||||
// type parameter, an explicit lifetime bound is required on object
|
||||
// lifetimes within.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct Ref0<T:?Sized> {
|
||||
r: *mut T
|
||||
}
|
||||
|
||||
struct Ref1<'a,T:'a+?Sized> {
|
||||
r: &'a T
|
||||
}
|
||||
|
||||
struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
|
||||
r: &'a &'b T
|
||||
}
|
||||
|
||||
fn a<'a,'b>(t: Ref2<'a,'b,Test>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
}
|
||||
|
||||
fn b(t: Ref2<Test>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
}
|
||||
|
||||
fn c(t: Ref2<&Test>) {
|
||||
// In this case, the &'a overrides.
|
||||
}
|
||||
|
||||
fn d(t: Ref2<Ref1<Test>>) {
|
||||
// In this case, the lifetime parameter from the Ref1 overrides.
|
||||
}
|
||||
|
||||
fn e(t: Ref2<Ref0<Test>>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
//
|
||||
// In this case, Ref2 is ambiguous, and Ref0 inherits the
|
||||
// ambiguity.
|
||||
}
|
||||
|
||||
fn f(t: &Ref2<Test>) {
|
||||
//~^ ERROR lifetime bound for this object type cannot be deduced from context
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
89
src/test/compile-fail/object-lifetime-default-elision.rs
Normal file
89
src/test/compile-fail/object-lifetime-default-elision.rs
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test various cases where the old rules under lifetime elision
|
||||
// yield slightly different results than the new rules.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait SomeTrait {
|
||||
fn dummy(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
r: Box<SomeTrait+'a>
|
||||
}
|
||||
|
||||
fn deref<T>(ss: &T) -> T {
|
||||
// produces the type of a deref without worrying about whether a
|
||||
// move out would actually be legal
|
||||
loop { }
|
||||
}
|
||||
|
||||
fn load0<'a>(ss: &'a Box<SomeTrait>) -> Box<SomeTrait> {
|
||||
// Under old rules, the fully elaborated types of input/output were:
|
||||
//
|
||||
// for<'a,'b> fn(&'a Box<SomeTrait+'b>) -> Box<SomeTrait+'a>
|
||||
//
|
||||
// Under new rules the result is:
|
||||
//
|
||||
// for<'a> fn(&'a Box<SomeTrait+'a>) -> Box<SomeTrait+'static>
|
||||
//
|
||||
// Therefore, we get a type error attempting to return `deref(ss)`
|
||||
// since `SomeTrait+'a <: SomeTrait+'static` does not hold.
|
||||
|
||||
deref(ss)
|
||||
//~^ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn load1(ss: &SomeTrait) -> &SomeTrait {
|
||||
// Under old rules, the fully elaborated types of input/output were:
|
||||
//
|
||||
// for<'a,'b> fn(&'a (SomeTrait+'b)) -> &'a (SomeTrait+'a)
|
||||
//
|
||||
// Under new rules the result is:
|
||||
//
|
||||
// for<'a> fn(&'a (SomeTrait+'a)) -> &'a (SomeTrait+'a)
|
||||
//
|
||||
// In both cases, returning `ss` is legal.
|
||||
|
||||
ss
|
||||
}
|
||||
|
||||
fn load2<'a>(ss: &'a SomeTrait) -> &SomeTrait {
|
||||
// Same as `load1` but with an explicit name thrown in for fun.
|
||||
|
||||
ss
|
||||
}
|
||||
|
||||
fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
|
||||
// Under old rules, the fully elaborated types of input/output were:
|
||||
//
|
||||
// for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a)
|
||||
//
|
||||
// Based on the input/output types, the compiler could infer that
|
||||
// 'c : 'a
|
||||
// 'b : 'a
|
||||
// must hold, and therefore it permitted `&'a (Sometrait+'c)` to be
|
||||
// coerced to `&'b (SomeTrait+'a)`.
|
||||
//
|
||||
// Under the newer defaults, though, we get:
|
||||
//
|
||||
// for<'a,'b> fn(&'a (SomeTrait+'a)) -> &'b (SomeTrait+'b)
|
||||
//
|
||||
// which fails to type check.
|
||||
|
||||
ss
|
||||
//~^ ERROR cannot infer
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test various cases where the defaults should lead to errors being
|
||||
// reported.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait SomeTrait {
|
||||
fn dummy(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
r: Box<SomeTrait+'a>
|
||||
}
|
||||
|
||||
fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
|
||||
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
|
||||
// is illegal.
|
||||
|
||||
ss.r //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
|
||||
// No error: b is bounded by 'static which outlives the
|
||||
// (anonymous) lifetime on the struct.
|
||||
|
||||
ss.r = b;
|
||||
}
|
||||
|
||||
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
|
||||
// Here we override the lifetimes explicitly, and so naturally we get an error.
|
||||
|
||||
ss.r = b; //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
44
src/test/compile-fail/object-lifetime-default-mybox.rs
Normal file
44
src/test/compile-fail/object-lifetime-default-mybox.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test a "pass-through" object-lifetime-default that produces errors.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait SomeTrait {
|
||||
fn dummy(&self) { }
|
||||
}
|
||||
|
||||
struct MyBox<T:?Sized> {
|
||||
r: Box<T>
|
||||
}
|
||||
|
||||
fn deref<T>(ss: &T) -> T {
|
||||
// produces the type of a deref without worrying about whether a
|
||||
// move out would actually be legal
|
||||
loop { }
|
||||
}
|
||||
|
||||
fn load0(ss: &MyBox<SomeTrait>) -> MyBox<SomeTrait> {
|
||||
deref(ss) //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn load1<'a,'b>(a: &'a MyBox<SomeTrait>,
|
||||
b: &'b MyBox<SomeTrait>)
|
||||
-> &'b MyBox<SomeTrait>
|
||||
{
|
||||
a
|
||||
//~^ ERROR cannot infer
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
32
src/test/compile-fail/object-lifetime-default.rs
Normal file
32
src/test/compile-fail/object-lifetime-default.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct A<T>(T); //~ ERROR None
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct B<'a,T>(&'a (), T); //~ ERROR None
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct C<'a,T:'a>(&'a T); //~ ERROR 'a
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b
|
||||
|
||||
#[rustc_object_lifetime_default]
|
||||
struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous
|
||||
|
||||
fn main() { }
|
@ -25,7 +25,7 @@ struct Foo<'a,'b,'c> {
|
||||
c: Box<Is<'a>>,
|
||||
d: Box<IsSend>,
|
||||
e: Box<Is<'a>+Send>, // we can derive two bounds, but one is 'static, so ok
|
||||
f: Box<SomeTrait>, //~ ERROR explicit lifetime bound required
|
||||
f: Box<SomeTrait>, // OK, defaults to 'static due to RFC 599.
|
||||
g: Box<SomeTrait+'a>,
|
||||
|
||||
z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted
|
||||
|
@ -11,6 +11,8 @@
|
||||
// Various tests related to testing how region inference works
|
||||
// with respect to the object receivers.
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
trait Foo {
|
||||
fn borrowed<'a>(&'a self) -> &'a ();
|
||||
}
|
||||
@ -21,29 +23,6 @@ fn borrowed_receiver_same_lifetime<'a>(x: &'a Foo) -> &'a () {
|
||||
x.borrowed()
|
||||
}
|
||||
|
||||
// Borrowed receiver but two distinct lifetimes, we get an error.
|
||||
fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
|
||||
x.borrowed() //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
// Borrowed receiver with two distinct lifetimes, but we know that
|
||||
// 'b:'a, hence &'a () is permitted.
|
||||
fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (Foo+'b)) -> &'a () {
|
||||
x.borrowed()
|
||||
}
|
||||
|
||||
// Here we have two distinct lifetimes, but we try to return a pointer
|
||||
// with the longer lifetime when (from the signature) we only know
|
||||
// that it lives as long as the shorter lifetime. Therefore, error.
|
||||
fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () {
|
||||
x.borrowed() //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
// Here, the object is bounded by an anonymous lifetime and returned
|
||||
// as `&'static`, so you get an error.
|
||||
fn owned_receiver(x: Box<Foo>) -> &'static () {
|
||||
x.borrowed() //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
||||
|
||||
|
24
src/test/compile-fail/region-object-lifetime-2.rs
Normal file
24
src/test/compile-fail/region-object-lifetime-2.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Various tests related to testing how region inference works
|
||||
// with respect to the object receivers.
|
||||
|
||||
trait Foo {
|
||||
fn borrowed<'a>(&'a self) -> &'a ();
|
||||
}
|
||||
|
||||
// Borrowed receiver but two distinct lifetimes, we get an error.
|
||||
fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a Foo) -> &'b () {
|
||||
x.borrowed() //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
28
src/test/compile-fail/region-object-lifetime-3.rs
Normal file
28
src/test/compile-fail/region-object-lifetime-3.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Various tests related to testing how region inference works
|
||||
// with respect to the object receivers.
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
trait Foo {
|
||||
fn borrowed<'a>(&'a self) -> &'a ();
|
||||
}
|
||||
|
||||
// Borrowed receiver with two distinct lifetimes, but we know that
|
||||
// 'b:'a, hence &'a () is permitted.
|
||||
fn borrowed_receiver_related_lifetimes<'a,'b>(x: &'a (Foo+'b)) -> &'a () {
|
||||
x.borrowed()
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
||||
|
26
src/test/compile-fail/region-object-lifetime-4.rs
Normal file
26
src/test/compile-fail/region-object-lifetime-4.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Various tests related to testing how region inference works
|
||||
// with respect to the object receivers.
|
||||
|
||||
trait Foo {
|
||||
fn borrowed<'a>(&'a self) -> &'a ();
|
||||
}
|
||||
|
||||
// Here we have two distinct lifetimes, but we try to return a pointer
|
||||
// with the longer lifetime when (from the signature) we only know
|
||||
// that it lives as long as the shorter lifetime. Therefore, error.
|
||||
fn borrowed_receiver_related_lifetimes2<'a,'b>(x: &'a (Foo+'b)) -> &'b () {
|
||||
x.borrowed() //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
25
src/test/compile-fail/region-object-lifetime-5.rs
Normal file
25
src/test/compile-fail/region-object-lifetime-5.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Various tests related to testing how region inference works
|
||||
// with respect to the object receivers.
|
||||
|
||||
trait Foo {
|
||||
fn borrowed<'a>(&'a self) -> &'a ();
|
||||
}
|
||||
|
||||
// Here, the object is bounded by an anonymous lifetime and returned
|
||||
// as `&'static`, so you get an error.
|
||||
fn owned_receiver(x: Box<Foo>) -> &'static () {
|
||||
x.borrowed() //~ ERROR `*x` does not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -17,20 +17,22 @@ trait Foo {}
|
||||
impl<'a> Foo for &'a [u8] {}
|
||||
|
||||
fn a(v: &[u8]) -> Box<Foo + 'static> {
|
||||
let x: Box<Foo + 'static> = box v; //~ ERROR declared lifetime bound not satisfied
|
||||
let x: Box<Foo + 'static> = box v; //~ ERROR does not fulfill the required lifetime
|
||||
x
|
||||
}
|
||||
|
||||
fn b(v: &[u8]) -> Box<Foo + 'static> {
|
||||
box v //~ ERROR declared lifetime bound not satisfied
|
||||
box v //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn c(v: &[u8]) -> Box<Foo> {
|
||||
box v // OK thanks to lifetime elision
|
||||
// same as previous case due to RFC 599
|
||||
|
||||
box v //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
|
||||
box v //~ ERROR declared lifetime bound not satisfied
|
||||
box v //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn e<'a:'b,'b>(v: &'a [u8]) -> Box<Foo+'b> {
|
||||
|
@ -32,15 +32,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
|
||||
// otherwise lifetime pointers are not ok
|
||||
|
||||
fn param_not_ok<'a>(x: &'a isize) {
|
||||
assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn param_not_ok1<'a>(_: &'a isize) {
|
||||
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn param_not_ok2<'a>(_: &'a isize) {
|
||||
assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
// boxes are ok
|
||||
@ -54,7 +54,7 @@ fn box_ok() {
|
||||
// but not if they own a bad thing
|
||||
|
||||
fn box_with_region_not_ok<'a>() {
|
||||
assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
// objects with insufficient bounds no ok
|
||||
@ -66,7 +66,7 @@ fn object_with_random_bound_not_ok<'a>() {
|
||||
|
||||
fn object_with_send_bound_not_ok<'a>() {
|
||||
assert_send::<&'a (Dummy+Send)>();
|
||||
//~^ ERROR declared lifetime bound not satisfied
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
// unsafe pointers are ok unless they point at unsendable things
|
||||
|
@ -29,15 +29,15 @@ fn static_lifime_ok<'a,T,U:Send>(_: &'a isize) {
|
||||
// otherwise lifetime pointers are not ok
|
||||
|
||||
fn param_not_ok<'a>(x: &'a isize) {
|
||||
assert_send::<&'a isize>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<&'a isize>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn param_not_ok1<'a>(_: &'a isize) {
|
||||
assert_send::<&'a str>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn param_not_ok2<'a>(_: &'a isize) {
|
||||
assert_send::<&'a [isize]>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<&'a [isize]>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
// boxes are ok
|
||||
@ -51,7 +51,7 @@ fn box_ok() {
|
||||
// but not if they own a bad thing
|
||||
|
||||
fn box_with_region_not_ok<'a>() {
|
||||
assert_send::<Box<&'a isize>>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
// unsafe pointers are ok unless they point at unsendable things
|
||||
@ -62,11 +62,11 @@ fn unsafe_ok1<'a>(_: &'a isize) {
|
||||
}
|
||||
|
||||
fn unsafe_ok2<'a>(_: &'a isize) {
|
||||
assert_send::<*const &'a isize>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<*const &'a isize>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn unsafe_ok3<'a>(_: &'a isize) {
|
||||
assert_send::<*mut &'a isize>(); //~ ERROR declared lifetime bound not satisfied
|
||||
assert_send::<*mut &'a isize>(); //~ ERROR does not fulfill the required lifetime
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -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() { }
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![allow(warnings)]
|
||||
|
||||
trait A<T> {}
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
@ -17,19 +18,7 @@ trait X {}
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn f<'a, T, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X>
|
||||
}
|
||||
|
||||
fn g<'a, T: 'static>(v: Box<A<T>>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X> //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X>
|
||||
}
|
||||
|
||||
fn i<'a, T, U>(v: Box<A<U>>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X> //~ ERROR cannot infer
|
||||
box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
23
src/test/compile-fail/regions-close-object-into-object-2.rs
Normal file
23
src/test/compile-fail/regions-close-object-into-object-2.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
trait A<T> {}
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X {}
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn g<'a, T: 'static>(v: Box<A<T>+'a>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X> //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() { }
|
25
src/test/compile-fail/regions-close-object-into-object-3.rs
Normal file
25
src/test/compile-fail/regions-close-object-into-object-3.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![allow(warnings)]
|
||||
|
||||
trait A<T> {}
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X {}
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn h<'a, T, U>(v: Box<A<U>+'static>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X> //~ ERROR `*v` does not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
24
src/test/compile-fail/regions-close-object-into-object-4.rs
Normal file
24
src/test/compile-fail/regions-close-object-into-object-4.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
||||
trait A<T> {}
|
||||
struct B<'a, T>(&'a (A<T>+'a));
|
||||
|
||||
trait X {}
|
||||
impl<'a, T> X for B<'a, T> {}
|
||||
|
||||
fn i<'a, T, U>(v: Box<A<U>+'a>) -> Box<X+'static> {
|
||||
box B(&*v) as Box<X> //~ ERROR cannot infer
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,7 +14,7 @@ trait seq { }
|
||||
impl<T> seq<T> for Vec<T> { //~ ERROR wrong number of type arguments
|
||||
/* ... */
|
||||
}
|
||||
impl seq<bool> for u32 {
|
||||
impl seq<bool> for u32 { //~ ERROR wrong number of type arguments
|
||||
/* Treat the integer as a sequence of bits */
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,7 @@ fn main() {
|
||||
|
||||
let pt3 = PointF::<i32> {
|
||||
//~^ ERROR wrong number of type arguments
|
||||
//~| ERROR structure constructor specifies a structure of type
|
||||
x: 9i32,
|
||||
y: 10i32,
|
||||
};
|
||||
|
@ -22,7 +22,7 @@ fn c(x: Box<Foo+Sync+Send>) {
|
||||
fn d(x: Box<Foo>) {
|
||||
a(x); //~ ERROR mismatched types
|
||||
//~| expected `Box<Foo + Send>`
|
||||
//~| found `Box<Foo>`
|
||||
//~| found `Box<Foo + 'static>`
|
||||
//~| expected bounds `Send`
|
||||
//~| found no bounds
|
||||
}
|
||||
|
@ -24,8 +24,7 @@ fn c(x: Box<Foo+Sync>) {
|
||||
}
|
||||
|
||||
fn d(x: &'static (Foo+Sync)) {
|
||||
b(x); //~ ERROR cannot infer
|
||||
//~^ ERROR mismatched types
|
||||
b(x);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -12,7 +12,9 @@
|
||||
|
||||
trait Three<A,B,C> { fn dummy(&self) -> (A,B,C); }
|
||||
|
||||
fn foo(_: &Three()) //~ ERROR wrong number of type arguments
|
||||
fn foo(_: &Three())
|
||||
//~^ ERROR wrong number of type arguments
|
||||
//~| ERROR no associated type `Output`
|
||||
{}
|
||||
|
||||
fn main() { }
|
||||
|
@ -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() { }
|
||||
|
@ -14,6 +14,7 @@ trait Trait {}
|
||||
|
||||
fn f<F:Trait(isize) -> isize>(x: F) {}
|
||||
//~^ ERROR wrong number of type arguments: expected 0, found 1
|
||||
//~| ERROR no associated type `Output`
|
||||
|
||||
fn main() {}
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that `Box<Test>` is equivalent to `Box<Test+'static>`, both in
|
||||
// fields and fn arguments.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct {
|
||||
t: Box<Test>,
|
||||
u: Box<Test+'static>,
|
||||
}
|
||||
|
||||
fn a(t: Box<Test>, mut ss: SomeStruct) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn b(t: Box<Test+'static>, mut ss: SomeStruct) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn c(t: Box<Test>, mut ss: SomeStruct) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn d(t: Box<Test+'static>, mut ss: SomeStruct) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
47
src/test/run-pass/object-lifetime-default-from-ref-struct.rs
Normal file
47
src/test/run-pass/object-lifetime-default-from-ref-struct.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the lifetime of the enclosing `&` is used for the object
|
||||
// lifetime bound.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct Ref<'a,T:'a+?Sized> {
|
||||
r: &'a T
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
t: Ref<'a,Test>,
|
||||
u: Ref<'a,Test+'a>,
|
||||
}
|
||||
|
||||
fn a<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn b<'a>(t: Ref<'a,Test>, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn c<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
}
|
42
src/test/run-pass/object-lifetime-default-from-rptr-box.rs
Normal file
42
src/test/run-pass/object-lifetime-default-from-rptr-box.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the lifetime from the enclosing `&` is "inherited"
|
||||
// through the `Box` struct.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
t: &'a Box<Test>,
|
||||
u: &'a Box<Test+'a>,
|
||||
}
|
||||
|
||||
fn a<'a>(t: &'a Box<Test>, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn b<'a>(t: &'a Box<Test>, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn c<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn d<'a>(t: &'a Box<Test+'a>, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
43
src/test/run-pass/object-lifetime-default-from-rptr-mut.rs
Normal file
43
src/test/run-pass/object-lifetime-default-from-rptr-mut.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the lifetime of the enclosing `&` is used for the object
|
||||
// lifetime bound.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
t: &'a mut Test,
|
||||
u: &'a mut (Test+'a),
|
||||
}
|
||||
|
||||
fn a<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn b<'a>(t: &'a mut Test, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn c<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn d<'a>(t: &'a mut (Test+'a), mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the lifetime from the enclosing `&` is "inherited"
|
||||
// through the `MyBox` struct.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
t: &'a MyBox<Test>,
|
||||
u: &'a MyBox<Test+'a>,
|
||||
}
|
||||
|
||||
struct MyBox<T:?Sized> {
|
||||
b: Box<T>
|
||||
}
|
||||
|
||||
fn a<'a>(t: &'a MyBox<Test>, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn b<'a>(t: &'a MyBox<Test>, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn c<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn d<'a>(t: &'a MyBox<Test+'a>, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
43
src/test/run-pass/object-lifetime-default-from-rptr.rs
Normal file
43
src/test/run-pass/object-lifetime-default-from-rptr.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that the lifetime of the enclosing `&` is used for the object
|
||||
// lifetime bound.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Test {
|
||||
fn foo(&self) { }
|
||||
}
|
||||
|
||||
struct SomeStruct<'a> {
|
||||
t: &'a Test,
|
||||
u: &'a (Test+'a),
|
||||
}
|
||||
|
||||
fn a<'a>(t: &'a Test, mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn b<'a>(t: &'a Test, mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
fn c<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
|
||||
ss.t = t;
|
||||
}
|
||||
|
||||
fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) {
|
||||
ss.u = t;
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user