E0312, // lifetime of reference outlives lifetime of borrowed content
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
E0314, // closure outlives stack frame
- E0315 // cannot invoke closure outside of its lifetime
+ E0315, // cannot invoke closure outside of its lifetime
+ E0316 // nested quantification of lifetimes
}
__build_diagnostic_array! { DIAGNOSTICS }
trait_ref: ast::TraitRef {
path: new_path,
ref_id: tr.ref_id,
- }
+ },
+ span: poly_tr.span,
}, modifier)
}
}
/* lifetime decl */ ast::NodeId),
}
-// maps the id of each lifetime reference to the lifetime decl
-// that it corresponds to
+// Maps the id of each lifetime reference to the lifetime decl
+// that it corresponds to.
pub type NamedRegionMap = NodeMap<DefRegion>;
struct LifetimeContext<'a> {
named_region_map: &'a mut NamedRegionMap,
scope: Scope<'a>,
def_map: &'a DefMap,
+ // Deep breath. Our representation for poly trait refs contains a single
+ // binder and thus we only allow a single level of quantification. However,
+ // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
+ // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
+ // correct when representing these constraints, we should only introduce one
+ // scope. However, we want to support both locations for the quantifier and
+ // during lifetime resolution we want precise information (so we can't
+ // desugar in an earlier phase).
+
+ // SO, if we encounter a quantifier at the outer scope, we set
+ // trait_ref_hack to true (and introduce a scope), and then if we encounter
+ // a quantifier at the inner scope, we error. If trait_ref_hack is false,
+ // then we introduce the scope at the inner quantifier.
+
+ // I'm sorry.
+ trait_ref_hack: bool,
}
enum ScopeChain<'a> {
named_region_map: &mut named_region_map,
scope: &ROOT_SCOPE,
def_map: def_map,
+ trait_ref_hack: false,
}, krate);
sess.abort_if_errors();
named_region_map
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
ref bounds,
+ ref bound_lifetimes,
.. }) => {
- self.visit_ty(&**bounded_ty);
- visit::walk_ty_param_bounds_helper(self, bounds);
+ if bound_lifetimes.len() > 0 {
+ self.trait_ref_hack = true;
+ let result = self.with(LateScope(bound_lifetimes, self.scope),
+ |old_scope, this| {
+ this.check_lifetime_defs(old_scope, bound_lifetimes);
+ this.visit_ty(&**bounded_ty);
+ visit::walk_ty_param_bounds_helper(this, bounds);
+ });
+ self.trait_ref_hack = false;
+ result
+ } else {
+ self.visit_ty(&**bounded_ty);
+ visit::walk_ty_param_bounds_helper(self, bounds);
+ }
}
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
ref bounds,
}
}
- fn visit_poly_trait_ref(&mut self, trait_ref:
- &ast::PolyTraitRef,
+ fn visit_poly_trait_ref(&mut self,
+ trait_ref: &ast::PolyTraitRef,
_modifier: &ast::TraitBoundModifier) {
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
- self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
- this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
- for lifetime in &trait_ref.bound_lifetimes {
- this.visit_lifetime_def(lifetime);
+ if !self.trait_ref_hack || trait_ref.bound_lifetimes.len() > 0 {
+ if self.trait_ref_hack {
+ println!("{:?}", trait_ref.span);
+ span_err!(self.sess, trait_ref.span, E0316,
+ "nested quantification of lifetimes");
}
- this.visit_trait_ref(&trait_ref.trait_ref)
- })
+ self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
+ this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
+ for lifetime in &trait_ref.bound_lifetimes {
+ this.visit_lifetime_def(lifetime);
+ }
+ this.visit_trait_ref(&trait_ref.trait_ref)
+ })
+ } else {
+ self.visit_trait_ref(&trait_ref.trait_ref)
+ }
}
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
named_region_map: *named_region_map,
scope: &wrap_scope,
def_map: self.def_map,
+ trait_ref_hack: self.trait_ref_hack,
};
debug!("entering scope {:?}", this.scope);
f(self.scope, &mut this);
/// compiler's representation for things like `for<'a> Fn(&'a int)`
/// (which would be represented by the type `PolyTraitRef ==
/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
-/// erase, or otherwise "discharge" these bound reons, we change the
+/// erase, or otherwise "discharge" these bound regions, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g. `liberate_late_bound_regions`).
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
{
let mut projections = Vec::new();
- // the trait reference introduces a binding level here, so
+ // The trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
// into resolve_lifetimes, as we do with non-omitted
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct WhereBoundPredicate {
pub span: Span,
+ pub bound_lifetimes: Vec<LifetimeDef>,
pub bounded_ty: P<Ty>,
pub bounds: OwnedSlice<TyParamBound>,
}
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
pub trait_ref: TraitRef,
+
+ pub span: Span,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
default: Option<P<ast::Ty>>) -> ast::TyParam;
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
- fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef;
+ fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef;
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
fn lifetime_def(&self,
}
}
- fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef {
+ fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
ast::PolyTraitRef {
bound_lifetimes: Vec::new(),
- trait_ref: self.trait_ref(path)
+ trait_ref: self.trait_ref(path),
+ span: span,
}
}
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound {
- ast::TraitTyParamBound(self.poly_trait_ref(path), ast::TraitBoundModifier::None)
+ ast::TraitTyParamBound(self.poly_trait_ref(path.span, path), ast::TraitBoundModifier::None)
}
fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {
ast::WherePredicate::BoundPredicate(ref wb) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
span: self.span,
+ bound_lifetimes: wb.bound_lifetimes.clone(),
bounded_ty: wb.bounded_ty.clone(),
bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
})
fld: &mut T)
-> WherePredicate {
match pred {
- ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bounded_ty,
+ ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_lifetimes,
+ bounded_ty,
bounds,
span}) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+ bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
bounded_ty: fld.fold_ty(bounded_ty),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
span: fld.new_span(span)
pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
ast::PolyTraitRef {
bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
- trait_ref: fld.fold_trait_ref(p.trait_ref)
+ trait_ref: fld.fold_trait_ref(p.trait_ref),
+ span: fld.new_span(p.span),
}
}
*/
// parse <'lt>
+ let lo = self.span.lo;
+
let lifetime_defs = self.parse_late_bound_lifetime_defs();
// examine next token to decide to do
self.token.is_ident() ||
self.token.is_path()
{
+ let hi = self.span.hi;
let trait_ref = self.parse_trait_ref();
let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs,
- trait_ref: trait_ref };
+ trait_ref: trait_ref,
+ span: mk_sp(lo, hi)};
let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
self.parse_ty_param_bounds(BoundParsingMode::Bare)
} else {
if let Some(unbound) = unbound {
let mut bounds_as_vec = bounds.into_vec();
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
- trait_ref: unbound },
+ trait_ref: unbound,
+ span: span },
TraitBoundModifier::Maybe));
bounds = OwnedSlice::from_vec(bounds_as_vec);
};
}
_ => {
+ let bound_lifetimes = if self.eat_keyword(keywords::For) {
+ // Higher ranked constraint.
+ self.expect(&token::Lt);
+ let lifetime_defs = self.parse_lifetime_defs();
+ self.expect_gt();
+ lifetime_defs
+ } else {
+ vec![]
+ };
+
let bounded_ty = self.parse_ty();
if self.eat(&token::Colon) {
if bounds.len() == 0 {
self.span_err(span,
"each predicate in a `where` clause must have \
- at least one bound in it");
+ at least one bound in it");
}
generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
ast::WhereBoundPredicate {
span: span,
+ bound_lifetimes: bound_lifetimes,
bounded_ty: bounded_ty,
bounds: bounds,
}));
/// Parse trait Foo { ... }
fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
+
let ident = self.parse_ident();
let mut tps = self.parse_generics();
+ // This is not very accurate, but since unbound only exists to catch
+ // obsolete syntax, the span is unlikely to ever be used.
+ let unbound_span = self.span;
let unbound = self.parse_for_sized();
// Parse supertrait bounds.
if let Some(unbound) = unbound {
let mut bounds_as_vec = bounds.into_vec();
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
- trait_ref: unbound },
+ trait_ref: unbound,
+ span: unbound_span },
TraitBoundModifier::Maybe));
bounds = OwnedSlice::from_vec(bounds_as_vec);
};
/// Parse for<'l> a::B<String,i32>
fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
+ let lo = self.span.lo;
let lifetime_defs = self.parse_late_bound_lifetime_defs();
ast::PolyTraitRef {
bound_lifetimes: lifetime_defs,
- trait_ref: self.parse_trait_ref()
+ trait_ref: self.parse_trait_ref(),
+ span: mk_sp(lo, self.last_span.hi),
}
}