Skip to content

Commit a832190

Browse files
committed
refine the warnings to consider projection inputs
1 parent dcbe887 commit a832190

File tree

3 files changed

+109
-8
lines changed

3 files changed

+109
-8
lines changed

src/librustc/ty/fold.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,30 @@ impl<'tcx> TyCtxt<'tcx> {
394394
}
395395
}
396396

397-
pub fn collect_late_bound_regions<T>(&self, value: &Binder<T>)
398-
-> FnvHashSet<ty::BoundRegion>
397+
/// Returns a set of all late-bound regions that are constrained
398+
/// by `value`, meaning that if we instantiate those LBR with
399+
/// variables and equate `value` with something else, those
400+
/// variables will also be equated.
401+
pub fn collect_constrained_late_bound_regions<T>(&self, value: &Binder<T>)
402+
-> FnvHashSet<ty::BoundRegion>
399403
where T : TypeFoldable<'tcx>
400404
{
401-
let mut collector = LateBoundRegionsCollector::new();
405+
self.collect_late_bound_regions(value, true)
406+
}
407+
408+
/// Returns a set of all late-bound regions that appear in `value` anywhere.
409+
pub fn collect_referenced_late_bound_regions<T>(&self, value: &Binder<T>)
410+
-> FnvHashSet<ty::BoundRegion>
411+
where T : TypeFoldable<'tcx>
412+
{
413+
self.collect_late_bound_regions(value, false)
414+
}
415+
416+
fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool)
417+
-> FnvHashSet<ty::BoundRegion>
418+
where T : TypeFoldable<'tcx>
419+
{
420+
let mut collector = LateBoundRegionsCollector::new(just_constraint);
402421
let result = value.skip_binder().visit_with(&mut collector);
403422
assert!(!result); // should never have stopped early
404423
collector.regions
@@ -655,13 +674,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
655674
struct LateBoundRegionsCollector {
656675
current_depth: u32,
657676
regions: FnvHashSet<ty::BoundRegion>,
677+
just_constrained: bool,
658678
}
659679

660680
impl LateBoundRegionsCollector {
661-
fn new() -> Self {
681+
fn new(just_constrained: bool) -> Self {
662682
LateBoundRegionsCollector {
663683
current_depth: 1,
664684
regions: FnvHashSet(),
685+
just_constrained: just_constrained,
665686
}
666687
}
667688
}
@@ -675,6 +696,20 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
675696
self.current_depth -= 1;
676697
}
677698

699+
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
700+
// if we are only looking for "constrained" region, we have to
701+
// ignore the inputs to a projection, as they may not appear
702+
// in the normalized form
703+
if self.just_constrained {
704+
match t.sty {
705+
ty::TyProjection(..) => { return false; }
706+
_ => { }
707+
}
708+
}
709+
710+
t.super_visit_with(self)
711+
}
712+
678713
fn visit_region(&mut self, r: ty::Region) -> bool {
679714
match r {
680715
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {

src/librustc_typeck/astconv.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -922,8 +922,8 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>(
922922
//
923923
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
924924
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
925-
let late_bound_in_trait_ref = tcx.collect_late_bound_regions(&trait_ref);
926-
let late_bound_in_ty = tcx.collect_late_bound_regions(&ty::Binder(binding.ty));
925+
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
926+
let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
927927
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
928928
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
929929
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
@@ -1702,9 +1702,9 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
17021702
// checking for here would be considered early bound
17031703
// anyway.)
17041704
let inputs = bare_fn_ty.sig.inputs();
1705-
let late_bound_in_args = this.tcx().collect_late_bound_regions(&inputs);
1705+
let late_bound_in_args = this.tcx().collect_constrained_late_bound_regions(&inputs);
17061706
let output = bare_fn_ty.sig.output();
1707-
let late_bound_in_ret = this.tcx().collect_late_bound_regions(&output);
1707+
let late_bound_in_ret = this.tcx().collect_referenced_late_bound_regions(&output);
17081708
for br in late_bound_in_ret.difference(&late_bound_in_args) {
17091709
let br_name = match *br {
17101710
ty::BrNamed(_, name) => name,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: func object clause
12+
13+
#![allow(dead_code)]
14+
#![feature(rustc_attrs)]
15+
#![feature(unboxed_closures)]
16+
#![deny(hr_lifetime_in_assoc_type)]
17+
18+
trait Foo<'a> {
19+
type Item;
20+
}
21+
22+
impl<'a> Foo<'a> for() {
23+
type Item = ();
24+
}
25+
26+
// Check that appearing in a projection input in the argument is not enough:
27+
#[cfg(func)]
28+
fn func1(_: for<'a> fn(<() as Foo<'a>>::Item) -> &'a i32) {
29+
//[func]~^ ERROR return type references lifetime `'a`
30+
//[func]~| WARNING previously accepted
31+
}
32+
33+
// Check that appearing in a projection input in the return still
34+
// causes an error:
35+
#[cfg(func)]
36+
fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) {
37+
//[func]~^ ERROR return type references lifetime `'a`
38+
//[func]~| WARNING previously accepted
39+
}
40+
41+
#[cfg(object)]
42+
fn object1(_: Box<for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32>) {
43+
//[object]~^ ERROR return type references lifetime `'a`
44+
//[object]~| WARNING previously accepted
45+
}
46+
47+
#[cfg(object)]
48+
fn object2(_: Box<for<'a> Fn() -> <() as Foo<'a>>::Item>) {
49+
//[object]~^ ERROR return type references lifetime `'a`
50+
//[object]~| WARNING previously accepted
51+
}
52+
53+
#[cfg(clause)]
54+
fn clause1<T>() where T: for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32 {
55+
//[clause]~^ ERROR return type references lifetime `'a`
56+
//[clause]~| WARNING previously accepted
57+
}
58+
59+
#[cfg(clause)]
60+
fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item {
61+
//[clause]~^ ERROR return type references lifetime `'a`
62+
//[clause]~| WARNING previously accepted
63+
}
64+
65+
#[rustc_error]
66+
fn main() { } //[ok]~ ERROR compilation successful

0 commit comments

Comments
 (0)