Skip to content

Commit 9b0480b

Browse files
committed
Name higher-ranked lifetimes properly while displaying
Now they don't shadow other lifetimes.
1 parent 108706f commit 9b0480b

5 files changed

+229
-21
lines changed

src/librustc/ty/context.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,10 @@ pub struct GlobalCtxt<'tcx> {
915915
/// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
916916
pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
917917

918+
pub display_used_late_bound_region_names: RefCell<Option<FxHashSet<Name>>>,
919+
920+
pub display_late_bound_region_index: Cell<usize>,
921+
918922
/// The definite name of the current crate after taking into account
919923
/// attributes, commandline parameters, etc.
920924
pub crate_name: Symbol,
@@ -1189,6 +1193,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11891193
selection_cache: traits::SelectionCache::new(),
11901194
evaluation_cache: traits::EvaluationCache::new(),
11911195
rvalue_promotable_to_static: RefCell::new(NodeMap()),
1196+
display_used_late_bound_region_names: RefCell::new(None),
1197+
display_late_bound_region_index: Cell::new(0),
11921198
crate_name: Symbol::intern(crate_name),
11931199
data_layout,
11941200
layout_interner: RefCell::new(FxHashSet()),

src/librustc/util/ppaux.rs

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
2020
use ty::{TyClosure, TyGenerator, TyProjection, TyAnon};
2121
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
2222
use ty::{self, Ty, TyCtxt, TypeFoldable};
23+
use util::nodemap::FxHashSet;
2324

2425
use std::cell::Cell;
2526
use std::fmt;
@@ -259,12 +260,34 @@ pub fn parameterized(f: &mut fmt::Formatter,
259260
Ok(())
260261
}
261262

263+
struct LateBoundRegionNameCollector(FxHashSet<Symbol>);
264+
265+
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector {
266+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
267+
match *r {
268+
ty::ReLateBound(_, ty::BrNamed(_, name)) => {
269+
self.0.insert(name);
270+
},
271+
_ => {},
272+
}
273+
r.super_visit_with(self)
274+
}
275+
}
276+
262277
fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
263278
tcx: TyCtxt<'a, 'gcx, 'tcx>,
264279
original: &ty::Binder<T>,
265280
lifted: Option<ty::Binder<U>>) -> fmt::Result
266281
where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx>
267282
{
283+
fn name_by_region_index(index: usize) -> Symbol {
284+
match index {
285+
0 => Symbol::intern("'r"),
286+
1 => Symbol::intern("'s"),
287+
i => Symbol::intern(&format!("'t{}", i-2)),
288+
}
289+
}
290+
268291
// Replace any anonymous late-bound regions with named
269292
// variants, using gensym'd identifiers, so that we can
270293
// clearly differentiate between named and unnamed regions in
@@ -286,27 +309,54 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter,
286309
}
287310
};
288311

289-
let new_value = tcx.replace_late_bound_regions(&value, |br| {
290-
let _ = start_or_continue(f, "for<", ", ");
291-
let br = match br {
292-
ty::BrNamed(_, name) => {
293-
let _ = write!(f, "{}", name);
294-
br
295-
}
296-
ty::BrAnon(_) |
297-
ty::BrFresh(_) |
298-
ty::BrEnv => {
299-
let name = Symbol::intern("'r");
300-
let _ = write!(f, "{}", name);
301-
ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID),
302-
name)
303-
}
304-
};
305-
tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
306-
}).0;
312+
// If displaying is just started, collect named late-bound regions.
313+
let display_just_started = tcx.display_used_late_bound_region_names.borrow().is_none();
314+
if display_just_started {
315+
let mut collector = LateBoundRegionNameCollector(FxHashSet());
316+
value.visit_with(&mut collector);
317+
*tcx.display_used_late_bound_region_names.borrow_mut() = Some(collector.0);
318+
}
307319

320+
let old_region_index = tcx.display_late_bound_region_index.get();
321+
let mut region_index = old_region_index;
322+
let new_value = {
323+
let used_region_names = tcx.display_used_late_bound_region_names.borrow();
324+
let used_region_names = used_region_names.as_ref().unwrap();
325+
tcx.replace_late_bound_regions(&value, |br| {
326+
let _ = start_or_continue(f, "for<", ", ");
327+
let br = match br {
328+
ty::BrNamed(_, name) => {
329+
let _ = write!(f, "{}", name);
330+
br
331+
}
332+
ty::BrAnon(_) |
333+
ty::BrFresh(_) |
334+
ty::BrEnv => {
335+
let name = loop {
336+
let name = name_by_region_index(region_index);
337+
region_index += 1;
338+
if !used_region_names.contains(&name) {
339+
break name;
340+
}
341+
};
342+
let _ = write!(f, "{}", name);
343+
ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID),
344+
name)
345+
}
346+
};
347+
tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
348+
}).0
349+
};
308350
start_or_continue(f, "", "> ")?;
309-
write!(f, "{}", new_value)
351+
352+
// Push current state to gcx, and restore after writing new_value.
353+
tcx.display_late_bound_region_index.set(region_index);
354+
write!(f, "{}", new_value)?;
355+
tcx.display_late_bound_region_index.set(old_region_index);
356+
if display_just_started {
357+
*tcx.display_used_late_bound_region_names.borrow_mut() = None;
358+
}
359+
Ok(())
310360
}
311361

312362
impl<'tcx> fmt::Display for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
@@ -782,7 +832,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
782832
write!(f, "}}")
783833
}
784834
TyFnPtr(ref bare_fn) => {
785-
write!(f, "{}", bare_fn.0)
835+
write!(f, "{}", bare_fn)
786836
}
787837
TyInfer(infer_ty) => write!(f, "{}", infer_ty),
788838
TyError => write!(f, "[type error]"),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2015 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+
fn main() {
12+
f1(|_: (), _: ()| {});
13+
f2(|_: (), _: ()| {});
14+
f3(|_: (), _: ()| {});
15+
f4(|_: (), _: ()| {});
16+
f5(|_: (), _: ()| {});
17+
g1(|_: (), _: ()| {});
18+
g2(|_: (), _: ()| {});
19+
g3(|_: (), _: ()| {});
20+
g4(|_: (), _: ()| {});
21+
h1(|_: (), _: (), _: (), _: ()| {});
22+
h2(|_: (), _: (), _: (), _: ()| {});
23+
}
24+
25+
// Basic
26+
fn f1<F>(_: F) where F: Fn(&(), &()) {}
27+
fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
28+
fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
29+
fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
30+
fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
31+
32+
// Nested
33+
fn g1<F>(_: F) where F: Fn(&(), Box<Fn(&())>) {}
34+
fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
35+
fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<Fn(&())>) {}
36+
fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
37+
38+
// Mixed
39+
fn h1<F>(_: F) where F: Fn(&(), Box<Fn(&())>, &(), fn(&(), &())) {}
40+
fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<Fn(&())>, &'t0 (), fn(&(), &())) {}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
error[E0631]: type mismatch in closure arguments
2+
--> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
3+
|
4+
12 | f1(|_: (), _: ()| {});
5+
| ^^ ----------------- found signature of `fn((), ()) -> _`
6+
| |
7+
| expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _`
8+
|
9+
= note: required by `f1`
10+
11+
error[E0631]: type mismatch in closure arguments
12+
--> $DIR/anonymous-higher-ranked-lifetime.rs:13:5
13+
|
14+
13 | f2(|_: (), _: ()| {});
15+
| ^^ ----------------- found signature of `fn((), ()) -> _`
16+
| |
17+
| expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _`
18+
|
19+
= note: required by `f2`
20+
21+
error[E0631]: type mismatch in closure arguments
22+
--> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
23+
|
24+
14 | f3(|_: (), _: ()| {});
25+
| ^^ ----------------- found signature of `fn((), ()) -> _`
26+
| |
27+
| expected signature of `for<'r> fn(&(), &'r ()) -> _`
28+
|
29+
= note: required by `f3`
30+
31+
error[E0631]: type mismatch in closure arguments
32+
--> $DIR/anonymous-higher-ranked-lifetime.rs:15:5
33+
|
34+
15 | f4(|_: (), _: ()| {});
35+
| ^^ ----------------- found signature of `fn((), ()) -> _`
36+
| |
37+
| expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _`
38+
|
39+
= note: required by `f4`
40+
41+
error[E0631]: type mismatch in closure arguments
42+
--> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
43+
|
44+
16 | f5(|_: (), _: ()| {});
45+
| ^^ ----------------- found signature of `fn((), ()) -> _`
46+
| |
47+
| expected signature of `for<'r> fn(&'r (), &'r ()) -> _`
48+
|
49+
= note: required by `f5`
50+
51+
error[E0631]: type mismatch in closure arguments
52+
--> $DIR/anonymous-higher-ranked-lifetime.rs:17:5
53+
|
54+
17 | g1(|_: (), _: ()| {});
55+
| ^^ ----------------- found signature of `fn((), ()) -> _`
56+
| |
57+
| expected signature of `for<'r> fn(&'r (), std::boxed::Box<for<'s> std::ops::Fn(&'s ()) + 'static>) -> _`
58+
|
59+
= note: required by `g1`
60+
61+
error[E0631]: type mismatch in closure arguments
62+
--> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
63+
|
64+
18 | g2(|_: (), _: ()| {});
65+
| ^^ ----------------- found signature of `fn((), ()) -> _`
66+
| |
67+
| expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _`
68+
|
69+
= note: required by `g2`
70+
71+
error[E0631]: type mismatch in closure arguments
72+
--> $DIR/anonymous-higher-ranked-lifetime.rs:19:5
73+
|
74+
19 | g3(|_: (), _: ()| {});
75+
| ^^ ----------------- found signature of `fn((), ()) -> _`
76+
| |
77+
| expected signature of `for<'s> fn(&'s (), std::boxed::Box<for<'r> std::ops::Fn(&'r ()) + 'static>) -> _`
78+
|
79+
= note: required by `g3`
80+
81+
error[E0631]: type mismatch in closure arguments
82+
--> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
83+
|
84+
20 | g4(|_: (), _: ()| {});
85+
| ^^ ----------------- found signature of `fn((), ()) -> _`
86+
| |
87+
| expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _`
88+
|
89+
= note: required by `g4`
90+
91+
error[E0631]: type mismatch in closure arguments
92+
--> $DIR/anonymous-higher-ranked-lifetime.rs:21:5
93+
|
94+
21 | h1(|_: (), _: (), _: (), _: ()| {});
95+
| ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _`
96+
| |
97+
| expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<for<'t0> std::ops::Fn(&'t0 ()) + 'static>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _`
98+
|
99+
= note: required by `h1`
100+
101+
error[E0631]: type mismatch in closure arguments
102+
--> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
103+
|
104+
22 | h2(|_: (), _: (), _: (), _: ()| {});
105+
| ^^ ------------------------------- found signature of `fn((), (), (), ()) -> _`
106+
| |
107+
| expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<for<'s> std::ops::Fn(&'s ()) + 'static>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _`
108+
|
109+
= note: required by `h2`
110+
111+
error: aborting due to 11 previous errors
112+

src/test/ui/regions-fn-subtyping-return-static.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
44
51 | want_F(bar); //~ ERROR E0308
55
| ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
66
|
7-
= note: expected type `fn(&'cx S) -> &'cx S`
7+
= note: expected type `for<'cx> fn(&'cx S) -> &'cx S`
88
found type `fn(&'a S) -> &S {bar::<'_>}`
99

1010
error: aborting due to previous error

0 commit comments

Comments
 (0)