1
Fork 0

Treat associated types the same as type parameters when it comes to region bounding. Fixes #20303.

Strictly speaking, this is a [breaking-change] (if you are using
associated types). You are no longer free to wantonly violate the type
system rules by closing associated types into objects without any form
of region bound. Instead you should add region bounds like `T::X :
'a`, just as you would with a normal type parameter.
This commit is contained in:
Niko Matsakis 2015-01-03 04:40:33 -05:00
parent 8e83af6e87
commit c8868942e8
7 changed files with 275 additions and 104 deletions

View file

@ -66,7 +66,8 @@ use super::region_inference::RegionResolutionError;
use super::region_inference::ConcreteFailure; use super::region_inference::ConcreteFailure;
use super::region_inference::SubSupConflict; use super::region_inference::SubSupConflict;
use super::region_inference::SupSupConflict; use super::region_inference::SupSupConflict;
use super::region_inference::ParamBoundFailure; use super::region_inference::GenericBoundFailure;
use super::region_inference::GenericKind;
use super::region_inference::ProcessedErrors; use super::region_inference::ProcessedErrors;
use super::region_inference::SameRegions; use super::region_inference::SameRegions;
@ -120,9 +121,9 @@ pub trait ErrorReporting<'tcx> {
sub: Region, sub: Region,
sup: Region); sup: Region);
fn report_param_bound_failure(&self, fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>, origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy, kind: GenericKind<'tcx>,
sub: Region, sub: Region,
sups: Vec<Region>); sups: Vec<Region>);
@ -175,8 +176,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
self.report_concrete_failure(origin, sub, sup); self.report_concrete_failure(origin, sub, sup);
} }
ParamBoundFailure(origin, param_ty, sub, sups) => { GenericBoundFailure(kind, param_ty, sub, sups) => {
self.report_param_bound_failure(origin, param_ty, sub, sups); self.report_generic_bound_failure(kind, param_ty, sub, sups);
} }
SubSupConflict(var_origin, SubSupConflict(var_origin,
@ -421,30 +422,35 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
found.user_string(self.tcx))) found.user_string(self.tcx)))
} }
fn report_param_bound_failure(&self, fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>, origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy, bound_kind: GenericKind<'tcx>,
sub: Region, sub: Region,
_sups: Vec<Region>) { _sups: Vec<Region>)
{
// FIXME: it would be better to report the first error message // FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span // with the span of the parameter itself, rather than the span
// where the error was detected. But that span is not readily // where the error was detected. But that span is not readily
// accessible. // accessible.
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) =>
format!("the parameter type `{}`", p.user_string(self.tcx)),
GenericKind::Projection(ref p) =>
format!("the associated type `{}`", p.user_string(self.tcx)),
};
match sub { match sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print? // Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err( self.tcx.sess.span_err(
origin.span(), origin.span(),
format!( format!("{} may not live long enough", labeled_user_string)[]);
"the parameter type `{}` may not live long enough",
param_ty.user_string(self.tcx))[]);
self.tcx.sess.span_help( self.tcx.sess.span_help(
origin.span(), origin.span(),
format!( format!(
"consider adding an explicit lifetime bound `{}: {}`...", "consider adding an explicit lifetime bound `{}: {}`...",
param_ty.user_string(self.tcx), bound_kind.user_string(self.tcx),
sub.user_string(self.tcx))[]); sub.user_string(self.tcx))[]);
} }
@ -452,14 +458,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
// Does the required lifetime have a nice name we can print? // Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err( self.tcx.sess.span_err(
origin.span(), origin.span(),
format!( format!("{} may not live long enough", labeled_user_string)[]);
"the parameter type `{}` may not live long enough",
param_ty.user_string(self.tcx))[]);
self.tcx.sess.span_help( self.tcx.sess.span_help(
origin.span(), origin.span(),
format!( format!(
"consider adding an explicit lifetime bound `{}: 'static`...", "consider adding an explicit lifetime bound `{}: 'static`...",
param_ty.user_string(self.tcx))[]); bound_kind.user_string(self.tcx))[]);
} }
_ => { _ => {
@ -467,17 +471,16 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
self.tcx.sess.span_err( self.tcx.sess.span_err(
origin.span(), origin.span(),
format!( format!(
"the parameter type `{}` may not live long enough", "{} may not live long enough",
param_ty.user_string(self.tcx))[]); labeled_user_string)[]);
self.tcx.sess.span_help( self.tcx.sess.span_help(
origin.span(), origin.span(),
format!( format!(
"consider adding an explicit lifetime bound to `{}`", "consider adding an explicit lifetime bound for `{}`",
param_ty.user_string(self.tcx))[]); bound_kind.user_string(self.tcx))[]);
note_and_explain_region( note_and_explain_region(
self.tcx, self.tcx,
format!("the parameter type `{}` must be valid for ", format!("{} must be valid for ", labeled_user_string)[],
param_ty.user_string(self.tcx))[],
sub, sub,
"..."); "...");
} }

View file

@ -20,6 +20,7 @@ pub use self::ValuePairs::*;
pub use self::fixup_err::*; pub use self::fixup_err::*;
pub use middle::ty::IntVarValue; pub use middle::ty::IntVarValue;
pub use self::freshen::TypeFreshener; pub use self::freshen::TypeFreshener;
pub use self::region_inference::GenericKind;
use middle::subst; use middle::subst;
use middle::subst::Substs; use middle::subst::Substs;
@ -382,19 +383,6 @@ pub fn mk_subr<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
cx.region_vars.commit(snapshot); cx.region_vars.commit(snapshot);
} }
pub fn verify_param_bound<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy,
a: ty::Region,
bs: Vec<ty::Region>) {
debug!("verify_param_bound({}, {} <: {})",
param_ty.repr(cx.tcx),
a.repr(cx.tcx),
bs.repr(cx.tcx));
cx.region_vars.verify_param_bound(origin, param_ty, a, bs);
}
pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a_is_expected: bool, a_is_expected: bool,
origin: TypeOrigin, origin: TypeOrigin,
@ -1070,6 +1058,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
value, value,
|br, _| self.next_region_var(LateBoundRegion(span, br, lbrct))) |br, _| self.next_region_var(LateBoundRegion(span, br, lbrct)))
} }
/// See `verify_generic_bound` method in `region_inference`
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
a: ty::Region,
bs: Vec<ty::Region>) {
debug!("verify_generic_bound({}, {} <: {})",
kind.repr(self.tcx),
a.repr(self.tcx),
bs.repr(self.tcx));
self.region_vars.verify_generic_bound(origin, kind, a, bs);
}
} }
impl<'tcx> TypeTrace<'tcx> { impl<'tcx> TypeTrace<'tcx> {

View file

@ -22,7 +22,7 @@ use super::cres;
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use middle::region; use middle::region;
use middle::ty; use middle::ty::{mod, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
@ -30,7 +30,7 @@ use middle::graph;
use middle::graph::{Direction, NodeIndex}; use middle::graph::{Direction, NodeIndex};
use util::common::indenter; use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet}; use util::nodemap::{FnvHashMap, FnvHashSet};
use util::ppaux::Repr; use util::ppaux::{Repr, UserString};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::cmp::Ordering::{self, Less, Greater, Equal};
@ -61,12 +61,18 @@ pub enum Verify<'tcx> {
// `b` are inference variables. // `b` are inference variables.
VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region), VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region),
// VerifyParamBound(T, _, R, RS): The parameter type `T` must // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
// outlive the region `R`. `T` is known to outlive `RS`. Therefore // associated type) must outlive the region `R`. `T` is known to
// verify that `R <= RS[i]` for some `i`. Inference variables may // outlive `RS`. Therefore verify that `R <= RS[i]` for some
// be involved (but this verification step doesn't influence // `i`. Inference variables may be involved (but this verification
// inference). // step doesn't influence inference).
VerifyParamBound(ty::ParamTy, SubregionOrigin<'tcx>, Region, Vec<Region>), VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
}
#[deriving(Clone, Show, PartialEq, Eq)]
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
} }
#[derive(Copy, PartialEq, Eq, Hash)] #[derive(Copy, PartialEq, Eq, Hash)]
@ -98,12 +104,12 @@ pub enum RegionResolutionError<'tcx> {
/// `o` requires that `a <= b`, but this does not hold /// `o` requires that `a <= b`, but this does not hold
ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
/// `ParamBoundFailure(p, s, a, bs) /// `GenericBoundFailure(p, s, a, bs)
/// ///
/// The parameter type `p` must be known to outlive the lifetime /// The parameter/assocated-type `p` must be known to outlive the lifetime
/// `a`, but it is only known to outlive `bs` (and none of the /// `a`, but it is only known to outlive `bs` (and none of the
/// regions in `bs` outlive `a`). /// regions in `bs` outlive `a`).
ParamBoundFailure(SubregionOrigin<'tcx>, ty::ParamTy, Region, Vec<Region>), GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec<Region>),
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
/// ///
@ -489,12 +495,13 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
} }
} }
pub fn verify_param_bound(&self, /// See `Verify::VerifyGenericBound`
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>, origin: SubregionOrigin<'tcx>,
param_ty: ty::ParamTy, kind: GenericKind<'tcx>,
sub: Region, sub: Region,
sups: Vec<Region>) { sups: Vec<Region>) {
self.add_verify(VerifyParamBound(param_ty, origin, sub, sups)); self.add_verify(VerifyGenericBound(kind, origin, sub, sups));
} }
pub fn lub_regions(&self, pub fn lub_regions(&self,
@ -660,7 +667,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
&mut result_set, r, &mut result_set, r,
a, b); a, b);
} }
VerifyParamBound(_, _, a, ref bs) => { VerifyGenericBound(_, _, a, ref bs) => {
for &b in bs.iter() { for &b in bs.iter() {
consider_adding_bidirectional_edges( consider_adding_bidirectional_edges(
&mut result_set, r, &mut result_set, r,
@ -1211,7 +1218,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
errors.push(ConcreteFailure((*origin).clone(), sub, sup)); errors.push(ConcreteFailure((*origin).clone(), sub, sup));
} }
VerifyParamBound(ref param_ty, ref origin, sub, ref sups) => { VerifyGenericBound(ref kind, ref origin, sub, ref sups) => {
let sub = normalize(values, sub); let sub = normalize(values, sub);
if sups.iter() if sups.iter()
.map(|&sup| normalize(values, sup)) .map(|&sup| normalize(values, sup))
@ -1223,8 +1230,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
let sups = sups.iter().map(|&sup| normalize(values, sup)) let sups = sups.iter().map(|&sup| normalize(values, sup))
.collect(); .collect();
errors.push( errors.push(
ParamBoundFailure( GenericBoundFailure(
(*origin).clone(), *param_ty, sub, sups)); (*origin).clone(), kind.clone(), sub, sups));
} }
} }
} }
@ -1584,8 +1591,8 @@ impl<'tcx> Repr<'tcx> for Verify<'tcx> {
VerifyRegSubReg(_, ref a, ref b) => { VerifyRegSubReg(_, ref a, ref b) => {
format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx)) format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
} }
VerifyParamBound(_, ref p, ref a, ref bs) => { VerifyGenericBound(_, ref p, ref a, ref bs) => {
format!("VerifyParamBound({}, {}, {})", format!("VerifyGenericBound({}, {}, {})",
p.repr(tcx), a.repr(tcx), bs.repr(tcx)) p.repr(tcx), a.repr(tcx), bs.repr(tcx))
} }
} }
@ -1624,3 +1631,32 @@ impl<'tcx> Repr<'tcx> for RegionAndOrigin<'tcx> {
self.origin.repr(tcx)) self.origin.repr(tcx))
} }
} }
impl<'tcx> Repr<'tcx> for GenericKind<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
GenericKind::Param(ref p) => p.repr(tcx),
GenericKind::Projection(ref p) => p.repr(tcx),
}
}
}
impl<'tcx> UserString<'tcx> for GenericKind<'tcx> {
fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
GenericKind::Param(ref p) => p.user_string(tcx),
GenericKind::Projection(ref p) => p.user_string(tcx),
}
}
}
impl<'tcx> GenericKind<'tcx> {
pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match *self {
GenericKind::Param(ref p) =>
p.to_ty(tcx),
GenericKind::Projection(ref p) =>
ty::mk_projection(tcx, p.trait_ref.clone(), p.item_name),
}
}
}

View file

@ -92,7 +92,7 @@ use middle::region::CodeExtent;
use middle::traits; use middle::traits;
use middle::ty::{ReScope}; use middle::ty::{ReScope};
use middle::ty::{self, Ty, MethodCall}; use middle::ty::{self, Ty, MethodCall};
use middle::infer; use middle::infer::{mod, GenericKind};
use middle::pat_util; use middle::pat_util;
use util::ppaux::{ty_to_string, Repr}; use util::ppaux::{ty_to_string, Repr};
@ -164,7 +164,7 @@ pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
pub struct Rcx<'a, 'tcx: 'a> { pub struct Rcx<'a, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'tcx>, fcx: &'a FnCtxt<'a, 'tcx>,
region_param_pairs: Vec<(ty::Region, ty::ParamTy)>, region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
// id of innermost fn or loop // id of innermost fn or loop
repeating_scope: ast::NodeId, repeating_scope: ast::NodeId,
@ -205,7 +205,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
Rcx { fcx: fcx, Rcx { fcx: fcx,
repeating_scope: initial_repeating_scope, repeating_scope: initial_repeating_scope,
subject: subject, subject: subject,
region_param_pairs: Vec::new() } region_bound_pairs: Vec::new() }
} }
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
@ -286,12 +286,12 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
} }
}; };
let len = self.region_param_pairs.len(); let len = self.region_bound_pairs.len();
self.relate_free_regions(fn_sig[], body.id); self.relate_free_regions(fn_sig[], body.id);
link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs[]); link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs[]);
self.visit_block(body); self.visit_block(body);
self.visit_region_obligations(body.id); self.visit_region_obligations(body.id);
self.region_param_pairs.truncate(len); self.region_bound_pairs.truncate(len);
} }
fn visit_region_obligations(&mut self, node_id: ast::NodeId) fn visit_region_obligations(&mut self, node_id: ast::NodeId)
@ -357,11 +357,11 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
// relationship that arises here, but // relationship that arises here, but
// presently we do not.) // presently we do not.)
} }
regionmanip::RegionSubParamConstraint(_, r_a, p_b) => { regionmanip::RegionSubGenericConstraint(_, r_a, ref generic_b) => {
debug!("RegionSubParamConstraint: {} <= {}", debug!("RegionSubGenericConstraint: {} <= {}",
r_a.repr(tcx), p_b.repr(tcx)); r_a.repr(tcx), generic_b.repr(tcx));
self.region_param_pairs.push((r_a, p_b)); self.region_bound_pairs.push((r_a, generic_b.clone()));
} }
} }
} }
@ -1477,31 +1477,31 @@ fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
rcx.fcx.mk_subr(o1, r_a, r_b); rcx.fcx.mk_subr(o1, r_a, r_b);
} }
regionmanip::RegionSubParamConstraint(None, r_a, param_b) => { regionmanip::RegionSubGenericConstraint(None, r_a, ref generic_b) => {
param_must_outlive(rcx, origin.clone(), r_a, param_b); generic_must_outlive(rcx, origin.clone(), r_a, generic_b);
} }
regionmanip::RegionSubParamConstraint(Some(ty), r_a, param_b) => { regionmanip::RegionSubGenericConstraint(Some(ty), r_a, ref generic_b) => {
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
param_must_outlive(rcx, o1, r_a, param_b); generic_must_outlive(rcx, o1, r_a, generic_b);
} }
} }
} }
} }
fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
origin: infer::SubregionOrigin<'tcx>, origin: infer::SubregionOrigin<'tcx>,
region: ty::Region, region: ty::Region,
param_ty: ty::ParamTy) { generic: &GenericKind<'tcx>) {
let param_env = &rcx.fcx.inh.param_env; let param_env = &rcx.fcx.inh.param_env;
debug!("param_must_outlive(region={}, param_ty={})", debug!("param_must_outlive(region={}, generic={})",
region.repr(rcx.tcx()), region.repr(rcx.tcx()),
param_ty.repr(rcx.tcx())); generic.repr(rcx.tcx()));
// To start, collect bounds from user: // To start, collect bounds from user:
let mut param_bounds = let mut param_bounds =
ty::required_region_bounds(rcx.tcx(), ty::required_region_bounds(rcx.tcx(),
param_ty.to_ty(rcx.tcx()), generic.to_ty(rcx.tcx()),
param_env.caller_bounds.predicates.as_slice().to_vec()); param_env.caller_bounds.predicates.as_slice().to_vec());
// Add in the default bound of fn body that applies to all in // Add in the default bound of fn body that applies to all in
@ -1517,22 +1517,21 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
// fn foo<'a, A>(x: &'a A) { x.bar() } // fn foo<'a, A>(x: &'a A) { x.bar() }
// //
// The problem is that the type of `x` is `&'a A`. To be // The problem is that the type of `x` is `&'a A`. To be
// well-formed, then, A must be lower-bounded by `'a`, but we // well-formed, then, A must be lower-generic by `'a`, but we
// don't know that this holds from first principles. // don't know that this holds from first principles.
for &(ref r, ref p) in rcx.region_param_pairs.iter() { for &(ref r, ref p) in rcx.region_bound_pairs.iter() {
debug!("param_ty={} p={}", debug!("generic={} p={}",
param_ty.repr(rcx.tcx()), generic.repr(rcx.tcx()),
p.repr(rcx.tcx())); p.repr(rcx.tcx()));
if param_ty == *p { if generic == p {
param_bounds.push(*r); param_bounds.push(*r);
} }
} }
// Inform region inference that this parameter type must be // Inform region inference that this generic must be properly
// properly bounded. // bounded.
infer::verify_param_bound(rcx.fcx.infcx(), rcx.fcx.infcx().verify_generic_bound(origin,
origin, generic.clone(),
param_ty,
region, region,
param_bounds); param_bounds);
} }

View file

@ -12,6 +12,7 @@
pub use self::WfConstraint::*; pub use self::WfConstraint::*;
use middle::infer::GenericKind;
use middle::subst::{ParamSpace, Subst, Substs}; use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder}; use middle::ty_fold::{TypeFolder};
@ -24,7 +25,7 @@ use util::ppaux::Repr;
pub enum WfConstraint<'tcx> { pub enum WfConstraint<'tcx> {
RegionSubRegionConstraint(Option<Ty<'tcx>>, ty::Region, ty::Region), RegionSubRegionConstraint(Option<Ty<'tcx>>, ty::Region, ty::Region),
RegionSubParamConstraint(Option<Ty<'tcx>>, ty::Region, ty::ParamTy), RegionSubGenericConstraint(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
} }
struct Wf<'a, 'tcx: 'a> { struct Wf<'a, 'tcx: 'a> {
@ -125,8 +126,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
ty::ty_projection(ref data) => { ty::ty_projection(ref data) => {
// `<T as TraitRef<..>>::Name` // `<T as TraitRef<..>>::Name`
// FIXME(#20303) -- gain ability to require that ty_projection : in-scope region, self.push_projection_constraint_from_top(data);
// like a type parameter
// this seems like a minimal requirement: // this seems like a minimal requirement:
let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id); let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
@ -215,12 +215,21 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
self.push_param_constraint(region, opt_ty, param_ty); self.push_param_constraint(region, opt_ty, param_ty);
} }
/// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
fn push_projection_constraint_from_top(&mut self,
projection_ty: &ty::ProjectionTy<'tcx>) {
let &(region, opt_ty) = self.stack.last().unwrap();
self.out.push(RegionSubGenericConstraint(
opt_ty, region, GenericKind::Projection(projection_ty.clone())));
}
/// Pushes a constraint that `region <= param_ty`, due to `opt_ty` /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
fn push_param_constraint(&mut self, fn push_param_constraint(&mut self,
region: ty::Region, region: ty::Region,
opt_ty: Option<Ty<'tcx>>, opt_ty: Option<Ty<'tcx>>,
param_ty: ty::ParamTy) { param_ty: ty::ParamTy) {
self.out.push(RegionSubParamConstraint(opt_ty, region, param_ty)); self.out.push(RegionSubGenericConstraint(
opt_ty, region, GenericKind::Param(param_ty)));
} }
fn accumulate_from_adt(&mut self, fn accumulate_from_adt(&mut self,
@ -393,16 +402,16 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
} }
impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> { impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> {
fn repr(&self, tcx: &ty::ctxt) -> String { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self { match *self {
RegionSubRegionConstraint(_, r_a, r_b) => { RegionSubRegionConstraint(_, ref r_a, ref r_b) => {
format!("RegionSubRegionConstraint({}, {})", format!("RegionSubRegionConstraint({}, {})",
r_a.repr(tcx), r_a.repr(tcx),
r_b.repr(tcx)) r_b.repr(tcx))
} }
RegionSubParamConstraint(_, r, p) => { RegionSubGenericConstraint(_, ref r, ref p) => {
format!("RegionSubParamConstraint({}, {})", format!("RegionSubGenericConstraint({}, {})",
r.repr(tcx), r.repr(tcx),
p.repr(tcx)) p.repr(tcx))
} }

View file

@ -0,0 +1,83 @@
// 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(associated_types)]
trait X {}
trait Iter {
type Item: X;
fn into_item(self) -> Self::Item;
fn as_item(&self) -> &Self::Item;
}
fn bad1<T: Iter>(v: T) -> Box<X+'static>
{
let item = v.into_item();
box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
}
fn bad2<T: Iter>(v: T) -> Box<X+'static>
where Box<T::Item> : X
{
let item = box v.into_item();
box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
}
fn bad3<'a, T: Iter>(v: T) -> Box<X+'a>
{
let item = v.into_item();
box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
}
fn bad4<'a, T: Iter>(v: T) -> Box<X+'a>
where Box<T::Item> : X
{
let item = box v.into_item();
box item //~ ERROR associated type `<T as Iter>::Item` may not live long enough
}
fn ok1<'a, T: Iter>(v: T) -> Box<X+'a>
where T::Item : 'a
{
let item = v.into_item();
box item // OK, T::Item : 'a is declared
}
fn ok2<'a, T: Iter>(v: &T, w: &'a T::Item) -> Box<X+'a>
where T::Item : Clone
{
let item = Clone::clone(w);
box item // OK, T::Item : 'a is implied
}
fn ok3<'a, T: Iter>(v: &'a T) -> Box<X+'a>
where T::Item : Clone + 'a
{
let item = Clone::clone(v.as_item());
box item // OK, T::Item : 'a was declared
}
fn meh1<'a, T: Iter>(v: &'a T) -> Box<X+'a>
where T::Item : Clone
{
// This case is kind of interesting. It's the same as `ok3` but
// without the explicit declaration. In principle, it seems like
// we ought to be able to infer that `T::Item : 'a` because we
// invoked `v.as_self()` which yielded a value of type `&'a
// T::Item`. But we're not that smart at present.
let item = Clone::clone(v.as_item());
box item //~ ERROR associated type `<T as Iter>::Item` may not live
}
fn main() {}

View file

@ -0,0 +1,39 @@
// 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.
trait X {}
fn p1<T>(v: T) -> Box<X+'static>
where T : X
{
box v //~ ERROR parameter type `T` may not live long enough
}
fn p2<T>(v: Box<T>) -> Box<X+'static>
where Box<T> : X
{
box v //~ ERROR parameter type `T` may not live long enough
}
fn p3<'a,T>(v: T) -> Box<X+'a>
where T : X
{
box v //~ ERROR parameter type `T` may not live long enough
}
fn p4<'a,T>(v: Box<T>) -> Box<X+'a>
where Box<T> : X
{
box v //~ ERROR parameter type `T` may not live long enough
}
fn main() {}