use super::region_inference::ConcreteFailure;
use super::region_inference::SubSupConflict;
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::SameRegions;
sub: Region,
sup: Region);
- fn report_param_bound_failure(&self,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- sub: Region,
- sups: Vec<Region>);
+ fn report_generic_bound_failure(&self,
+ origin: SubregionOrigin<'tcx>,
+ kind: GenericKind<'tcx>,
+ sub: Region,
+ sups: Vec<Region>);
fn report_sub_sup_conflict(&self,
var_origin: RegionVariableOrigin,
self.report_concrete_failure(origin, sub, sup);
}
- ParamBoundFailure(origin, param_ty, sub, sups) => {
- self.report_param_bound_failure(origin, param_ty, sub, sups);
+ GenericBoundFailure(kind, param_ty, sub, sups) => {
+ self.report_generic_bound_failure(kind, param_ty, sub, sups);
}
SubSupConflict(var_origin,
found.user_string(self.tcx)))
}
- fn report_param_bound_failure(&self,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- sub: Region,
- _sups: Vec<Region>) {
-
+ fn report_generic_bound_failure(&self,
+ origin: SubregionOrigin<'tcx>,
+ bound_kind: GenericKind<'tcx>,
+ sub: Region,
+ _sups: Vec<Region>)
+ {
// FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span
// where the error was detected. But that span is not readily
// 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 {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
- format!(
- "the parameter type `{}` may not live long enough",
- param_ty.user_string(self.tcx))[]);
+ format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound `{}: {}`...",
- param_ty.user_string(self.tcx),
+ bound_kind.user_string(self.tcx),
sub.user_string(self.tcx))[]);
}
// Does the required lifetime have a nice name we can print?
self.tcx.sess.span_err(
origin.span(),
- format!(
- "the parameter type `{}` may not live long enough",
- param_ty.user_string(self.tcx))[]);
+ format!("{} may not live long enough", labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
"consider adding an explicit lifetime bound `{}: 'static`...",
- param_ty.user_string(self.tcx))[]);
+ bound_kind.user_string(self.tcx))[]);
}
_ => {
self.tcx.sess.span_err(
origin.span(),
format!(
- "the parameter type `{}` may not live long enough",
- param_ty.user_string(self.tcx))[]);
+ "{} may not live long enough",
+ labeled_user_string)[]);
self.tcx.sess.span_help(
origin.span(),
format!(
- "consider adding an explicit lifetime bound to `{}`",
- param_ty.user_string(self.tcx))[]);
+ "consider adding an explicit lifetime bound for `{}`",
+ bound_kind.user_string(self.tcx))[]);
note_and_explain_region(
self.tcx,
- format!("the parameter type `{}` must be valid for ",
- param_ty.user_string(self.tcx))[],
+ format!("{} must be valid for ", labeled_user_string)[],
sub,
"...");
}
pub use self::fixup_err::*;
pub use middle::ty::IntVarValue;
pub use self::freshen::TypeFreshener;
+pub use self::region_inference::GenericKind;
use middle::subst;
use middle::subst::Substs;
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>,
a_is_expected: bool,
origin: TypeOrigin,
value,
|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> {
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use middle::region;
-use middle::ty;
+use middle::ty::{mod, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
use middle::graph::{Direction, NodeIndex};
use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
use std::cell::{Cell, RefCell};
use std::cmp::Ordering::{self, Less, Greater, Equal};
// `b` are inference variables.
VerifyRegSubReg(SubregionOrigin<'tcx>, Region, Region),
- // VerifyParamBound(T, _, R, RS): The parameter type `T` must
- // outlive the region `R`. `T` is known to outlive `RS`. Therefore
- // verify that `R <= RS[i]` for some `i`. Inference variables may
- // be involved (but this verification step doesn't influence
- // inference).
- VerifyParamBound(ty::ParamTy, SubregionOrigin<'tcx>, Region, Vec<Region>),
+ // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
+ // associated type) must outlive the region `R`. `T` is known to
+ // outlive `RS`. Therefore verify that `R <= RS[i]` for some
+ // `i`. Inference variables may be involved (but this verification
+ // step doesn't influence inference).
+ 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)]
/// `o` requires that `a <= b`, but this does not hold
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
/// 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)`:
///
}
}
- pub fn verify_param_bound(&self,
- origin: SubregionOrigin<'tcx>,
- param_ty: ty::ParamTy,
- sub: Region,
- sups: Vec<Region>) {
- self.add_verify(VerifyParamBound(param_ty, origin, sub, sups));
+ /// See `Verify::VerifyGenericBound`
+ pub fn verify_generic_bound(&self,
+ origin: SubregionOrigin<'tcx>,
+ kind: GenericKind<'tcx>,
+ sub: Region,
+ sups: Vec<Region>) {
+ self.add_verify(VerifyGenericBound(kind, origin, sub, sups));
}
pub fn lub_regions(&self,
&mut result_set, r,
a, b);
}
- VerifyParamBound(_, _, a, ref bs) => {
+ VerifyGenericBound(_, _, a, ref bs) => {
for &b in bs.iter() {
consider_adding_bidirectional_edges(
&mut result_set, r,
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);
if sups.iter()
.map(|&sup| normalize(values, sup))
let sups = sups.iter().map(|&sup| normalize(values, sup))
.collect();
errors.push(
- ParamBoundFailure(
- (*origin).clone(), *param_ty, sub, sups));
+ GenericBoundFailure(
+ (*origin).clone(), kind.clone(), sub, sups));
}
}
}
VerifyRegSubReg(_, ref a, ref b) => {
format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
}
- VerifyParamBound(_, ref p, ref a, ref bs) => {
- format!("VerifyParamBound({}, {}, {})",
+ VerifyGenericBound(_, ref p, ref a, ref bs) => {
+ format!("VerifyGenericBound({}, {}, {})",
p.repr(tcx), a.repr(tcx), bs.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),
+ }
+ }
+}
use middle::traits;
use middle::ty::{ReScope};
use middle::ty::{self, Ty, MethodCall};
-use middle::infer;
+use middle::infer::{mod, GenericKind};
use middle::pat_util;
use util::ppaux::{ty_to_string, Repr};
pub struct Rcx<'a, 'tcx: 'a> {
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
repeating_scope: ast::NodeId,
Rcx { fcx: fcx,
repeating_scope: initial_repeating_scope,
subject: subject,
- region_param_pairs: Vec::new() }
+ region_bound_pairs: Vec::new() }
}
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
}
};
- let len = self.region_param_pairs.len();
+ let len = self.region_bound_pairs.len();
self.relate_free_regions(fn_sig[], body.id);
link_fn_args(self, CodeExtent::from_node_id(body.id), fn_decl.inputs[]);
self.visit_block(body);
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)
// relationship that arises here, but
// presently we do not.)
}
- regionmanip::RegionSubParamConstraint(_, r_a, p_b) => {
- debug!("RegionSubParamConstraint: {} <= {}",
- r_a.repr(tcx), p_b.repr(tcx));
+ regionmanip::RegionSubGenericConstraint(_, r_a, ref generic_b) => {
+ debug!("RegionSubGenericConstraint: {} <= {}",
+ 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()));
}
}
}
let o1 = infer::ReferenceOutlivesReferent(ty, origin.span());
rcx.fcx.mk_subr(o1, r_a, r_b);
}
- regionmanip::RegionSubParamConstraint(None, r_a, param_b) => {
- param_must_outlive(rcx, origin.clone(), r_a, param_b);
+ regionmanip::RegionSubGenericConstraint(None, r_a, ref generic_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());
- 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>,
- origin: infer::SubregionOrigin<'tcx>,
- region: ty::Region,
- param_ty: ty::ParamTy) {
+fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region,
+ generic: &GenericKind<'tcx>) {
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()),
- param_ty.repr(rcx.tcx()));
+ generic.repr(rcx.tcx()));
// To start, collect bounds from user:
let mut param_bounds =
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());
// Add in the default bound of fn body that applies to all in
// fn foo<'a, A>(x: &'a A) { x.bar() }
//
// 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.
- for &(ref r, ref p) in rcx.region_param_pairs.iter() {
- debug!("param_ty={} p={}",
- param_ty.repr(rcx.tcx()),
+ for &(ref r, ref p) in rcx.region_bound_pairs.iter() {
+ debug!("generic={} p={}",
+ generic.repr(rcx.tcx()),
p.repr(rcx.tcx()));
- if param_ty == *p {
+ if generic == p {
param_bounds.push(*r);
}
}
- // Inform region inference that this parameter type must be
- // properly bounded.
- infer::verify_param_bound(rcx.fcx.infcx(),
- origin,
- param_ty,
- region,
- param_bounds);
+ // Inform region inference that this generic must be properly
+ // bounded.
+ rcx.fcx.infcx().verify_generic_bound(origin,
+ generic.clone(),
+ region,
+ param_bounds);
}
pub use self::WfConstraint::*;
+use middle::infer::GenericKind;
use middle::subst::{ParamSpace, Subst, Substs};
use middle::ty::{self, Ty};
use middle::ty_fold::{TypeFolder};
pub enum WfConstraint<'tcx> {
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> {
ty::ty_projection(ref data) => {
// `<T as TraitRef<..>>::Name`
- // FIXME(#20303) -- gain ability to require that ty_projection : in-scope region,
- // like a type parameter
+ self.push_projection_constraint_from_top(data);
// this seems like a minimal requirement:
let trait_def = ty::lookup_trait_def(self.tcx, data.trait_ref.def_id);
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`
fn push_param_constraint(&mut self,
region: ty::Region,
opt_ty: Option<Ty<'tcx>>,
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,
}
impl<'tcx> Repr<'tcx> for WfConstraint<'tcx> {
- fn repr(&self, tcx: &ty::ctxt) -> String {
+ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
match *self {
- RegionSubRegionConstraint(_, r_a, r_b) => {
+ RegionSubRegionConstraint(_, ref r_a, ref r_b) => {
format!("RegionSubRegionConstraint({}, {})",
r_a.repr(tcx),
r_b.repr(tcx))
}
- RegionSubParamConstraint(_, r, p) => {
- format!("RegionSubParamConstraint({}, {})",
+ RegionSubGenericConstraint(_, ref r, ref p) => {
+ format!("RegionSubGenericConstraint({}, {})",
r.repr(tcx),
p.repr(tcx))
}
--- /dev/null
+// 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() {}
+
--- /dev/null
+// 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() {}
+