Accept quantification of lifetimes outside the self type in where clauses.
Closes #20022
This commit is contained in:
parent
012e9643e4
commit
8122ce81d0
10 changed files with 100 additions and 27 deletions
|
@ -126,7 +126,8 @@ register_diagnostics! {
|
||||||
E0312, // lifetime of reference outlives lifetime of borrowed content
|
E0312, // lifetime of reference outlives lifetime of borrowed content
|
||||||
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
|
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
|
||||||
E0314, // closure outlives stack frame
|
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 }
|
__build_diagnostic_array! { DIAGNOSTICS }
|
||||||
|
|
|
@ -1076,7 +1076,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
||||||
trait_ref: ast::TraitRef {
|
trait_ref: ast::TraitRef {
|
||||||
path: new_path,
|
path: new_path,
|
||||||
ref_id: tr.ref_id,
|
ref_id: tr.ref_id,
|
||||||
}
|
},
|
||||||
|
span: poly_tr.span,
|
||||||
}, modifier)
|
}, modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ pub enum DefRegion {
|
||||||
/* lifetime decl */ ast::NodeId),
|
/* lifetime decl */ ast::NodeId),
|
||||||
}
|
}
|
||||||
|
|
||||||
// maps the id of each lifetime reference to the lifetime decl
|
// Maps the id of each lifetime reference to the lifetime decl
|
||||||
// that it corresponds to
|
// that it corresponds to.
|
||||||
pub type NamedRegionMap = NodeMap<DefRegion>;
|
pub type NamedRegionMap = NodeMap<DefRegion>;
|
||||||
|
|
||||||
struct LifetimeContext<'a> {
|
struct LifetimeContext<'a> {
|
||||||
|
@ -54,6 +54,22 @@ struct LifetimeContext<'a> {
|
||||||
named_region_map: &'a mut NamedRegionMap,
|
named_region_map: &'a mut NamedRegionMap,
|
||||||
scope: Scope<'a>,
|
scope: Scope<'a>,
|
||||||
def_map: &'a DefMap,
|
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> {
|
enum ScopeChain<'a> {
|
||||||
|
@ -80,6 +96,7 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio
|
||||||
named_region_map: &mut named_region_map,
|
named_region_map: &mut named_region_map,
|
||||||
scope: &ROOT_SCOPE,
|
scope: &ROOT_SCOPE,
|
||||||
def_map: def_map,
|
def_map: def_map,
|
||||||
|
trait_ref_hack: false,
|
||||||
}, krate);
|
}, krate);
|
||||||
sess.abort_if_errors();
|
sess.abort_if_errors();
|
||||||
named_region_map
|
named_region_map
|
||||||
|
@ -198,9 +215,22 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||||
match predicate {
|
match predicate {
|
||||||
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
|
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
|
||||||
ref bounds,
|
ref bounds,
|
||||||
|
ref bound_lifetimes,
|
||||||
.. }) => {
|
.. }) => {
|
||||||
self.visit_ty(&**bounded_ty);
|
if bound_lifetimes.len() > 0 {
|
||||||
visit::walk_ty_param_bounds_helper(self, bounds);
|
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,
|
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
|
||||||
ref bounds,
|
ref bounds,
|
||||||
|
@ -222,18 +252,27 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_poly_trait_ref(&mut self, trait_ref:
|
fn visit_poly_trait_ref(&mut self,
|
||||||
&ast::PolyTraitRef,
|
trait_ref: &ast::PolyTraitRef,
|
||||||
_modifier: &ast::TraitBoundModifier) {
|
_modifier: &ast::TraitBoundModifier) {
|
||||||
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
|
||||||
|
|
||||||
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
|
if !self.trait_ref_hack || trait_ref.bound_lifetimes.len() > 0 {
|
||||||
this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
|
if self.trait_ref_hack {
|
||||||
for lifetime in &trait_ref.bound_lifetimes {
|
println!("{:?}", trait_ref.span);
|
||||||
this.visit_lifetime_def(lifetime);
|
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) {
|
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
|
||||||
|
@ -251,6 +290,7 @@ impl<'a> LifetimeContext<'a> {
|
||||||
named_region_map: *named_region_map,
|
named_region_map: *named_region_map,
|
||||||
scope: &wrap_scope,
|
scope: &wrap_scope,
|
||||||
def_map: self.def_map,
|
def_map: self.def_map,
|
||||||
|
trait_ref_hack: self.trait_ref_hack,
|
||||||
};
|
};
|
||||||
debug!("entering scope {:?}", this.scope);
|
debug!("entering scope {:?}", this.scope);
|
||||||
f(self.scope, &mut this);
|
f(self.scope, &mut this);
|
||||||
|
|
|
@ -1478,7 +1478,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
|
||||||
/// compiler's representation for things like `for<'a> Fn(&'a int)`
|
/// compiler's representation for things like `for<'a> Fn(&'a int)`
|
||||||
/// (which would be represented by the type `PolyTraitRef ==
|
/// (which would be represented by the type `PolyTraitRef ==
|
||||||
/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
|
/// 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
|
/// type from `Binder<T>` to just `T` (see
|
||||||
/// e.g. `liberate_late_bound_regions`).
|
/// e.g. `liberate_late_bound_regions`).
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
|
|
@ -526,7 +526,7 @@ pub fn instantiate_poly_trait_ref<'tcx>(
|
||||||
{
|
{
|
||||||
let mut projections = Vec::new();
|
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
|
// we need to shift the `rscope`. It'd be nice if we could
|
||||||
// do away with this rscope stuff and work this knowledge
|
// do away with this rscope stuff and work this knowledge
|
||||||
// into resolve_lifetimes, as we do with non-omitted
|
// into resolve_lifetimes, as we do with non-omitted
|
||||||
|
|
|
@ -443,6 +443,7 @@ pub enum WherePredicate {
|
||||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||||
pub struct WhereBoundPredicate {
|
pub struct WhereBoundPredicate {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub bound_lifetimes: Vec<LifetimeDef>,
|
||||||
pub bounded_ty: P<Ty>,
|
pub bounded_ty: P<Ty>,
|
||||||
pub bounds: OwnedSlice<TyParamBound>,
|
pub bounds: OwnedSlice<TyParamBound>,
|
||||||
}
|
}
|
||||||
|
@ -1535,6 +1536,8 @@ pub struct PolyTraitRef {
|
||||||
|
|
||||||
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
|
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
|
||||||
pub trait_ref: TraitRef,
|
pub trait_ref: TraitRef,
|
||||||
|
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub trait AstBuilder {
|
||||||
default: Option<P<ast::Ty>>) -> ast::TyParam;
|
default: Option<P<ast::Ty>>) -> ast::TyParam;
|
||||||
|
|
||||||
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
|
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 typarambound(&self, path: ast::Path) -> ast::TyParamBound;
|
||||||
fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
|
fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
|
||||||
fn lifetime_def(&self,
|
fn lifetime_def(&self,
|
||||||
|
@ -442,15 +442,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef {
|
fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
|
||||||
ast::PolyTraitRef {
|
ast::PolyTraitRef {
|
||||||
bound_lifetimes: Vec::new(),
|
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 {
|
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 {
|
fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {
|
||||||
|
|
|
@ -443,6 +443,7 @@ impl<'a> TraitDef<'a> {
|
||||||
ast::WherePredicate::BoundPredicate(ref wb) => {
|
ast::WherePredicate::BoundPredicate(ref wb) => {
|
||||||
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||||
span: self.span,
|
span: self.span,
|
||||||
|
bound_lifetimes: wb.bound_lifetimes.clone(),
|
||||||
bounded_ty: wb.bounded_ty.clone(),
|
bounded_ty: wb.bounded_ty.clone(),
|
||||||
bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
|
bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
|
||||||
})
|
})
|
||||||
|
|
|
@ -806,10 +806,12 @@ pub fn noop_fold_where_predicate<T: Folder>(
|
||||||
fld: &mut T)
|
fld: &mut T)
|
||||||
-> WherePredicate {
|
-> WherePredicate {
|
||||||
match pred {
|
match pred {
|
||||||
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bounded_ty,
|
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_lifetimes,
|
||||||
|
bounded_ty,
|
||||||
bounds,
|
bounds,
|
||||||
span}) => {
|
span}) => {
|
||||||
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||||
|
bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
|
||||||
bounded_ty: fld.fold_ty(bounded_ty),
|
bounded_ty: fld.fold_ty(bounded_ty),
|
||||||
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
|
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
|
||||||
span: fld.new_span(span)
|
span: fld.new_span(span)
|
||||||
|
@ -895,7 +897,8 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
|
||||||
pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
|
pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
|
||||||
ast::PolyTraitRef {
|
ast::PolyTraitRef {
|
||||||
bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1036,6 +1036,8 @@ impl<'a> Parser<'a> {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// parse <'lt>
|
// parse <'lt>
|
||||||
|
let lo = self.span.lo;
|
||||||
|
|
||||||
let lifetime_defs = self.parse_late_bound_lifetime_defs();
|
let lifetime_defs = self.parse_late_bound_lifetime_defs();
|
||||||
|
|
||||||
// examine next token to decide to do
|
// examine next token to decide to do
|
||||||
|
@ -1047,9 +1049,11 @@ impl<'a> Parser<'a> {
|
||||||
self.token.is_ident() ||
|
self.token.is_ident() ||
|
||||||
self.token.is_path()
|
self.token.is_path()
|
||||||
{
|
{
|
||||||
|
let hi = self.span.hi;
|
||||||
let trait_ref = self.parse_trait_ref();
|
let trait_ref = self.parse_trait_ref();
|
||||||
let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs,
|
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)) {
|
let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
|
||||||
self.parse_ty_param_bounds(BoundParsingMode::Bare)
|
self.parse_ty_param_bounds(BoundParsingMode::Bare)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4070,7 +4074,8 @@ impl<'a> Parser<'a> {
|
||||||
if let Some(unbound) = unbound {
|
if let Some(unbound) = unbound {
|
||||||
let mut bounds_as_vec = bounds.into_vec();
|
let mut bounds_as_vec = bounds.into_vec();
|
||||||
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
|
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
|
||||||
trait_ref: unbound },
|
trait_ref: unbound,
|
||||||
|
span: span },
|
||||||
TraitBoundModifier::Maybe));
|
TraitBoundModifier::Maybe));
|
||||||
bounds = OwnedSlice::from_vec(bounds_as_vec);
|
bounds = OwnedSlice::from_vec(bounds_as_vec);
|
||||||
};
|
};
|
||||||
|
@ -4223,6 +4228,16 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
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();
|
let bounded_ty = self.parse_ty();
|
||||||
|
|
||||||
if self.eat(&token::Colon) {
|
if self.eat(&token::Colon) {
|
||||||
|
@ -4233,12 +4248,13 @@ impl<'a> Parser<'a> {
|
||||||
if bounds.len() == 0 {
|
if bounds.len() == 0 {
|
||||||
self.span_err(span,
|
self.span_err(span,
|
||||||
"each predicate in a `where` clause must have \
|
"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(
|
generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
|
||||||
ast::WhereBoundPredicate {
|
ast::WhereBoundPredicate {
|
||||||
span: span,
|
span: span,
|
||||||
|
bound_lifetimes: bound_lifetimes,
|
||||||
bounded_ty: bounded_ty,
|
bounded_ty: bounded_ty,
|
||||||
bounds: bounds,
|
bounds: bounds,
|
||||||
}));
|
}));
|
||||||
|
@ -4674,8 +4690,12 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parse trait Foo { ... }
|
/// Parse trait Foo { ... }
|
||||||
fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
|
fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
|
||||||
|
|
||||||
let ident = self.parse_ident();
|
let ident = self.parse_ident();
|
||||||
let mut tps = self.parse_generics();
|
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();
|
let unbound = self.parse_for_sized();
|
||||||
|
|
||||||
// Parse supertrait bounds.
|
// Parse supertrait bounds.
|
||||||
|
@ -4684,7 +4704,8 @@ impl<'a> Parser<'a> {
|
||||||
if let Some(unbound) = unbound {
|
if let Some(unbound) = unbound {
|
||||||
let mut bounds_as_vec = bounds.into_vec();
|
let mut bounds_as_vec = bounds.into_vec();
|
||||||
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
|
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
|
||||||
trait_ref: unbound },
|
trait_ref: unbound,
|
||||||
|
span: unbound_span },
|
||||||
TraitBoundModifier::Maybe));
|
TraitBoundModifier::Maybe));
|
||||||
bounds = OwnedSlice::from_vec(bounds_as_vec);
|
bounds = OwnedSlice::from_vec(bounds_as_vec);
|
||||||
};
|
};
|
||||||
|
@ -4803,11 +4824,13 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parse for<'l> a::B<String,i32>
|
/// Parse for<'l> a::B<String,i32>
|
||||||
fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
|
fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
|
||||||
|
let lo = self.span.lo;
|
||||||
let lifetime_defs = self.parse_late_bound_lifetime_defs();
|
let lifetime_defs = self.parse_late_bound_lifetime_defs();
|
||||||
|
|
||||||
ast::PolyTraitRef {
|
ast::PolyTraitRef {
|
||||||
bound_lifetimes: lifetime_defs,
|
bound_lifetimes: lifetime_defs,
|
||||||
trait_ref: self.parse_trait_ref()
|
trait_ref: self.parse_trait_ref(),
|
||||||
|
span: mk_sp(lo, self.last_span.hi),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue