Skip to content

Commit 8122ce8

Browse files
committed
Accept quantification of lifetimes outside the self type in where clauses.
Closes #20022
1 parent 012e964 commit 8122ce8

File tree

10 files changed

+100
-27
lines changed

10 files changed

+100
-27
lines changed

src/librustc/diagnostics.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ register_diagnostics! {
126126
E0312, // lifetime of reference outlives lifetime of borrowed content
127127
E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
128128
E0314, // closure outlives stack frame
129-
E0315 // cannot invoke closure outside of its lifetime
129+
E0315, // cannot invoke closure outside of its lifetime
130+
E0316 // nested quantification of lifetimes
130131
}
131132

132133
__build_diagnostic_array! { DIAGNOSTICS }

src/librustc/middle/infer/error_reporting.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
10761076
trait_ref: ast::TraitRef {
10771077
path: new_path,
10781078
ref_id: tr.ref_id,
1079-
}
1079+
},
1080+
span: poly_tr.span,
10801081
}, modifier)
10811082
}
10821083
}

src/librustc/middle/resolve_lifetime.rs

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,31 @@ pub enum DefRegion {
4545
/* lifetime decl */ ast::NodeId),
4646
}
4747

48-
// maps the id of each lifetime reference to the lifetime decl
49-
// that it corresponds to
48+
// Maps the id of each lifetime reference to the lifetime decl
49+
// that it corresponds to.
5050
pub type NamedRegionMap = NodeMap<DefRegion>;
5151

5252
struct LifetimeContext<'a> {
5353
sess: &'a Session,
5454
named_region_map: &'a mut NamedRegionMap,
5555
scope: Scope<'a>,
5656
def_map: &'a DefMap,
57+
// Deep breath. Our representation for poly trait refs contains a single
58+
// binder and thus we only allow a single level of quantification. However,
59+
// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
60+
// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
61+
// correct when representing these constraints, we should only introduce one
62+
// scope. However, we want to support both locations for the quantifier and
63+
// during lifetime resolution we want precise information (so we can't
64+
// desugar in an earlier phase).
65+
66+
// SO, if we encounter a quantifier at the outer scope, we set
67+
// trait_ref_hack to true (and introduce a scope), and then if we encounter
68+
// a quantifier at the inner scope, we error. If trait_ref_hack is false,
69+
// then we introduce the scope at the inner quantifier.
70+
71+
// I'm sorry.
72+
trait_ref_hack: bool,
5773
}
5874

5975
enum ScopeChain<'a> {
@@ -80,6 +96,7 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio
8096
named_region_map: &mut named_region_map,
8197
scope: &ROOT_SCOPE,
8298
def_map: def_map,
99+
trait_ref_hack: false,
83100
}, krate);
84101
sess.abort_if_errors();
85102
named_region_map
@@ -198,9 +215,22 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
198215
match predicate {
199216
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
200217
ref bounds,
218+
ref bound_lifetimes,
201219
.. }) => {
202-
self.visit_ty(&**bounded_ty);
203-
visit::walk_ty_param_bounds_helper(self, bounds);
220+
if bound_lifetimes.len() > 0 {
221+
self.trait_ref_hack = true;
222+
let result = self.with(LateScope(bound_lifetimes, self.scope),
223+
|old_scope, this| {
224+
this.check_lifetime_defs(old_scope, bound_lifetimes);
225+
this.visit_ty(&**bounded_ty);
226+
visit::walk_ty_param_bounds_helper(this, bounds);
227+
});
228+
self.trait_ref_hack = false;
229+
result
230+
} else {
231+
self.visit_ty(&**bounded_ty);
232+
visit::walk_ty_param_bounds_helper(self, bounds);
233+
}
204234
}
205235
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
206236
ref bounds,
@@ -222,18 +252,27 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
222252
}
223253
}
224254

225-
fn visit_poly_trait_ref(&mut self, trait_ref:
226-
&ast::PolyTraitRef,
255+
fn visit_poly_trait_ref(&mut self,
256+
trait_ref: &ast::PolyTraitRef,
227257
_modifier: &ast::TraitBoundModifier) {
228258
debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref);
229259

230-
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
231-
this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
232-
for lifetime in &trait_ref.bound_lifetimes {
233-
this.visit_lifetime_def(lifetime);
260+
if !self.trait_ref_hack || trait_ref.bound_lifetimes.len() > 0 {
261+
if self.trait_ref_hack {
262+
println!("{:?}", trait_ref.span);
263+
span_err!(self.sess, trait_ref.span, E0316,
264+
"nested quantification of lifetimes");
234265
}
235-
this.visit_trait_ref(&trait_ref.trait_ref)
236-
})
266+
self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| {
267+
this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes);
268+
for lifetime in &trait_ref.bound_lifetimes {
269+
this.visit_lifetime_def(lifetime);
270+
}
271+
this.visit_trait_ref(&trait_ref.trait_ref)
272+
})
273+
} else {
274+
self.visit_trait_ref(&trait_ref.trait_ref)
275+
}
237276
}
238277

239278
fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
@@ -251,6 +290,7 @@ impl<'a> LifetimeContext<'a> {
251290
named_region_map: *named_region_map,
252291
scope: &wrap_scope,
253292
def_map: self.def_map,
293+
trait_ref_hack: self.trait_ref_hack,
254294
};
255295
debug!("entering scope {:?}", this.scope);
256296
f(self.scope, &mut this);

src/librustc/middle/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
14781478
/// compiler's representation for things like `for<'a> Fn(&'a int)`
14791479
/// (which would be represented by the type `PolyTraitRef ==
14801480
/// Binder<TraitRef>`). Note that when we skolemize, instantiate,
1481-
/// erase, or otherwise "discharge" these bound reons, we change the
1481+
/// erase, or otherwise "discharge" these bound regions, we change the
14821482
/// type from `Binder<T>` to just `T` (see
14831483
/// e.g. `liberate_late_bound_regions`).
14841484
#[derive(Clone, PartialEq, Eq, Hash, Debug)]

src/librustc_typeck/astconv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ pub fn instantiate_poly_trait_ref<'tcx>(
526526
{
527527
let mut projections = Vec::new();
528528

529-
// the trait reference introduces a binding level here, so
529+
// The trait reference introduces a binding level here, so
530530
// we need to shift the `rscope`. It'd be nice if we could
531531
// do away with this rscope stuff and work this knowledge
532532
// into resolve_lifetimes, as we do with non-omitted

src/libsyntax/ast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ pub enum WherePredicate {
443443
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
444444
pub struct WhereBoundPredicate {
445445
pub span: Span,
446+
pub bound_lifetimes: Vec<LifetimeDef>,
446447
pub bounded_ty: P<Ty>,
447448
pub bounds: OwnedSlice<TyParamBound>,
448449
}
@@ -1535,6 +1536,8 @@ pub struct PolyTraitRef {
15351536

15361537
/// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
15371538
pub trait_ref: TraitRef,
1539+
1540+
pub span: Span,
15381541
}
15391542

15401543
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]

src/libsyntax/ext/build.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub trait AstBuilder {
7070
default: Option<P<ast::Ty>>) -> ast::TyParam;
7171

7272
fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
73-
fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef;
73+
fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef;
7474
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
7575
fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
7676
fn lifetime_def(&self,
@@ -442,15 +442,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
442442
}
443443
}
444444

445-
fn poly_trait_ref(&self, path: ast::Path) -> ast::PolyTraitRef {
445+
fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
446446
ast::PolyTraitRef {
447447
bound_lifetimes: Vec::new(),
448-
trait_ref: self.trait_ref(path)
448+
trait_ref: self.trait_ref(path),
449+
span: span,
449450
}
450451
}
451452

452453
fn typarambound(&self, path: ast::Path) -> ast::TyParamBound {
453-
ast::TraitTyParamBound(self.poly_trait_ref(path), ast::TraitBoundModifier::None)
454+
ast::TraitTyParamBound(self.poly_trait_ref(path.span, path), ast::TraitBoundModifier::None)
454455
}
455456

456457
fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {

src/libsyntax/ext/deriving/generic/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ impl<'a> TraitDef<'a> {
443443
ast::WherePredicate::BoundPredicate(ref wb) => {
444444
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
445445
span: self.span,
446+
bound_lifetimes: wb.bound_lifetimes.clone(),
446447
bounded_ty: wb.bounded_ty.clone(),
447448
bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
448449
})

src/libsyntax/fold.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,10 +806,12 @@ pub fn noop_fold_where_predicate<T: Folder>(
806806
fld: &mut T)
807807
-> WherePredicate {
808808
match pred {
809-
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bounded_ty,
809+
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bound_lifetimes,
810+
bounded_ty,
810811
bounds,
811812
span}) => {
812813
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
814+
bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
813815
bounded_ty: fld.fold_ty(bounded_ty),
814816
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
815817
span: fld.new_span(span)
@@ -895,7 +897,8 @@ pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
895897
pub fn noop_fold_poly_trait_ref<T: Folder>(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef {
896898
ast::PolyTraitRef {
897899
bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes),
898-
trait_ref: fld.fold_trait_ref(p.trait_ref)
900+
trait_ref: fld.fold_trait_ref(p.trait_ref),
901+
span: fld.new_span(p.span),
899902
}
900903
}
901904

src/libsyntax/parse/parser.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,8 @@ impl<'a> Parser<'a> {
10361036
*/
10371037

10381038
// parse <'lt>
1039+
let lo = self.span.lo;
1040+
10391041
let lifetime_defs = self.parse_late_bound_lifetime_defs();
10401042

10411043
// examine next token to decide to do
@@ -1047,9 +1049,11 @@ impl<'a> Parser<'a> {
10471049
self.token.is_ident() ||
10481050
self.token.is_path()
10491051
{
1052+
let hi = self.span.hi;
10501053
let trait_ref = self.parse_trait_ref();
10511054
let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs,
1052-
trait_ref: trait_ref };
1055+
trait_ref: trait_ref,
1056+
span: mk_sp(lo, hi)};
10531057
let other_bounds = if self.eat(&token::BinOp(token::Plus)) {
10541058
self.parse_ty_param_bounds(BoundParsingMode::Bare)
10551059
} else {
@@ -4070,7 +4074,8 @@ impl<'a> Parser<'a> {
40704074
if let Some(unbound) = unbound {
40714075
let mut bounds_as_vec = bounds.into_vec();
40724076
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
4073-
trait_ref: unbound },
4077+
trait_ref: unbound,
4078+
span: span },
40744079
TraitBoundModifier::Maybe));
40754080
bounds = OwnedSlice::from_vec(bounds_as_vec);
40764081
};
@@ -4223,6 +4228,16 @@ impl<'a> Parser<'a> {
42234228
}
42244229

42254230
_ => {
4231+
let bound_lifetimes = if self.eat_keyword(keywords::For) {
4232+
// Higher ranked constraint.
4233+
self.expect(&token::Lt);
4234+
let lifetime_defs = self.parse_lifetime_defs();
4235+
self.expect_gt();
4236+
lifetime_defs
4237+
} else {
4238+
vec![]
4239+
};
4240+
42264241
let bounded_ty = self.parse_ty();
42274242

42284243
if self.eat(&token::Colon) {
@@ -4233,12 +4248,13 @@ impl<'a> Parser<'a> {
42334248
if bounds.len() == 0 {
42344249
self.span_err(span,
42354250
"each predicate in a `where` clause must have \
4236-
at least one bound in it");
4251+
at least one bound in it");
42374252
}
42384253

42394254
generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
42404255
ast::WhereBoundPredicate {
42414256
span: span,
4257+
bound_lifetimes: bound_lifetimes,
42424258
bounded_ty: bounded_ty,
42434259
bounds: bounds,
42444260
}));
@@ -4674,8 +4690,12 @@ impl<'a> Parser<'a> {
46744690

46754691
/// Parse trait Foo { ... }
46764692
fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo {
4693+
46774694
let ident = self.parse_ident();
46784695
let mut tps = self.parse_generics();
4696+
// This is not very accurate, but since unbound only exists to catch
4697+
// obsolete syntax, the span is unlikely to ever be used.
4698+
let unbound_span = self.span;
46794699
let unbound = self.parse_for_sized();
46804700

46814701
// Parse supertrait bounds.
@@ -4684,7 +4704,8 @@ impl<'a> Parser<'a> {
46844704
if let Some(unbound) = unbound {
46854705
let mut bounds_as_vec = bounds.into_vec();
46864706
bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![],
4687-
trait_ref: unbound },
4707+
trait_ref: unbound,
4708+
span: unbound_span },
46884709
TraitBoundModifier::Maybe));
46894710
bounds = OwnedSlice::from_vec(bounds_as_vec);
46904711
};
@@ -4803,11 +4824,13 @@ impl<'a> Parser<'a> {
48034824

48044825
/// Parse for<'l> a::B<String,i32>
48054826
fn parse_poly_trait_ref(&mut self) -> PolyTraitRef {
4827+
let lo = self.span.lo;
48064828
let lifetime_defs = self.parse_late_bound_lifetime_defs();
48074829

48084830
ast::PolyTraitRef {
48094831
bound_lifetimes: lifetime_defs,
4810-
trait_ref: self.parse_trait_ref()
4832+
trait_ref: self.parse_trait_ref(),
4833+
span: mk_sp(lo, self.last_span.hi),
48114834
}
48124835
}
48134836

0 commit comments

Comments
 (0)