Skip to content

Commit ccceab9

Browse files
committed
Add more tests and map regions in writeback
1 parent f32a666 commit ccceab9

File tree

5 files changed

+96
-31
lines changed

5 files changed

+96
-31
lines changed

src/librustc/hir/lowering.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -788,12 +788,18 @@ impl<'a> LoweringContext<'a> {
788788
let old_len = self.currently_bound_lifetimes.len();
789789

790790
// Record the introduction of 'a in `for<'a> ...`
791-
self.currently_bound_lifetimes
792-
.extend(polytr.bound_lifetimes.iter().filter_map(|lt_def|
793-
if let hir::LifetimeName::Name(name) = lt_def.lifetime.name {
794-
Some(name)
795-
} else { None }
796-
));
791+
for lt_def in &polytr.bound_lifetimes {
792+
// Introduce lifetimes one at a time so that we can handle
793+
// cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd> ...`
794+
if let hir::LifetimeName::Name(name) = lt_def.lifetime.name {
795+
self.currently_bound_lifetimes.push(name);
796+
}
797+
798+
// Visit the lifetime bounds
799+
for lt_bound in &lt_def.bounds {
800+
self.visit_lifetime(&lt_bound);
801+
}
802+
}
797803

798804
hir::intravisit::walk_trait_ref(self, &polytr.trait_ref);
799805

src/librustc_typeck/check/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
212212
// associated fresh inference variable. Writeback resolves these
213213
// variables to get the concrete type, which can be used to
214214
// deanonymize TyAnon, after typeck is done with all functions.
215-
anon_types: RefCell<NodeMap<Ty<'tcx>>>,
215+
anon_types: RefCell<DefIdMap<(&'tcx Substs<'tcx>, Ty<'tcx>)>>,
216216

217217
/// Each type parameter has an implicit region bound that
218218
/// indicates it must outlive at least the function body (the user
@@ -621,7 +621,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
621621
deferred_call_resolutions: RefCell::new(DefIdMap()),
622622
deferred_cast_checks: RefCell::new(Vec::new()),
623623
deferred_generator_interiors: RefCell::new(Vec::new()),
624-
anon_types: RefCell::new(NodeMap()),
624+
anon_types: RefCell::new(DefIdMap()),
625625
implicit_region_bound,
626626
body_id,
627627
}
@@ -1943,13 +1943,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
19431943

19441944
// Use the same type variable if the exact same TyAnon appears more
19451945
// than once in the return type (e.g. if it's passed to a type alias).
1946-
let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
1947-
if let Some(ty_var) = self.anon_types.borrow().get(&id) {
1946+
if let Some(&(_substs, ty_var)) = self.anon_types.borrow().get(&def_id) {
19481947
return ty_var;
19491948
}
19501949
let span = self.tcx.def_span(def_id);
19511950
let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
1952-
self.anon_types.borrow_mut().insert(id, ty_var);
1951+
self.anon_types.borrow_mut().insert(def_id, (substs, ty_var));
19531952
debug!("instantiate_anon_types: ty_var={:?}", ty_var);
19541953

19551954
let predicates_of = self.tcx.predicates_of(def_id);

src/librustc_typeck/check/writeback.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
1919
use rustc::infer::{InferCtxt};
2020
use rustc::ty::{self, Ty, TyCtxt};
2121
use rustc::ty::fold::{TypeFolder,TypeFoldable};
22-
use rustc::util::nodemap::DefIdSet;
22+
use rustc::ty::subst::{Kind, Substs};
23+
use rustc::util::nodemap::{DefIdSet, FxHashMap};
2324
use syntax::ast;
2425
use syntax_pos::Span;
2526
use std::mem;
@@ -285,35 +286,43 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
285286

286287
fn visit_anon_types(&mut self) {
287288
let gcx = self.tcx().global_tcx();
288-
for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
289+
for (&def_id, &(substs, concrete_ty)) in self.fcx.anon_types.borrow().iter() {
290+
let node_id = gcx.hir.as_local_node_id(def_id).unwrap();
289291
let inside_ty = self.resolve(&concrete_ty, &node_id);
290292

293+
// Use substs to build up a reverse map from regions
294+
// to their identity mappings.
295+
// This is necessary because of `impl Trait` lifetimes
296+
// are computed by replacing existing lifetimes with 'static
297+
// and remapping only those used in the `impl Trait` return type,
298+
// resulting in the parameters shifting.
299+
let id_substs = Substs::identity_for_item(gcx, def_id);
300+
let map: FxHashMap<Kind, Kind> =
301+
substs.iter().enumerate()
302+
.map(|(index, subst)| (*subst, id_substs[index]))
303+
.collect();
304+
291305
// Convert the type from the function into a type valid outside
292306
// the function, by replacing invalid regions with 'static,
293307
// after producing an error for each of them.
294308
let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
295309
match *r {
296310
// 'static and early-bound regions are valid.
297311
ty::ReStatic |
298-
ty::ReEarlyBound(_) |
299312
ty::ReEmpty => r,
300313

301-
ty::ReFree(_) |
302-
ty::ReLateBound(..) |
303-
ty::ReScope(_) |
304-
ty::ReSkolemized(..) => {
305-
let span = node_id.to_span(&self.fcx.tcx);
306-
span_err!(self.tcx().sess, span, E0564,
307-
"only named lifetimes are allowed in `impl Trait`, \
308-
but `{}` was found in the type `{}`", r, inside_ty);
309-
gcx.types.re_static
310-
}
311-
312-
ty::ReVar(_) |
313-
ty::ReErased => {
314-
let span = node_id.to_span(&self.fcx.tcx);
315-
span_bug!(span, "invalid region in impl Trait: {:?}", r);
316-
}
314+
// All other regions, we map them appropriately to their adjusted
315+
// indices, erroring if we find any lifetimes that were not mapped
316+
// into the new set.
317+
_ => if let Some(r1) =
318+
map.get(&Kind::from(r)).and_then(|k| k.as_region()) { r1 } else
319+
{
320+
let span = node_id.to_span(&self.fcx.tcx);
321+
span_err!(self.tcx().sess, span, E0564,
322+
"only named lifetimes are allowed in `impl Trait`, \
323+
but `{}` was found in the type `{}`", r, inside_ty);
324+
gcx.types.re_static
325+
},
317326
}
318327
});
319328

src/test/compile-fail/impl-trait/more_lifetimes.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,20 @@ fn foo_not_static() -> impl Debug + 'static {
2020
let mut x = 5;
2121
x += 5;
2222
foo(&x)
23-
//~^ ERROR cannot infer an appropriate lifetime
23+
//~^ ERROR `x` does not live long enough
24+
}
25+
26+
trait Any {}
27+
impl<T> Any for T {}
28+
29+
// Check that type parameters are captured and not considered 'static
30+
fn whatever<T>(x: T) -> impl Any + 'static {
31+
x
32+
//~^ ERROR the parameter type `T` may not live long enough
33+
}
34+
35+
fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
36+
move |_| println!("{}", y)
2437
}
2538

2639
fn main() {}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2017 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+
#![feature(conservative_impl_trait)]
12+
13+
use std::fmt::Debug;
14+
15+
fn any_lifetime<'a>() -> &'a u32 { &5 }
16+
17+
fn static_lifetime() -> &'static u32 { &5 }
18+
19+
fn any_lifetime_as_static_impl_trait() -> impl Debug {
20+
any_lifetime()
21+
}
22+
23+
fn lifetimes_as_static_impl_trait() -> impl Debug {
24+
static_lifetime()
25+
}
26+
27+
trait Foo<'a> {}
28+
impl<'a> Foo<'a> for u32 {}
29+
30+
fn foo<'b>() -> impl for<'a> Foo<'a> { 5 }
31+
32+
fn closure_hrtb() -> impl for<'a> Fn(&'a u32) { |_| () }
33+
34+
fn mixed_lifetimes<'a>() -> impl for<'b: 'a> Fn(&'b u32) { |_| () }
35+
36+
fn mixed_as_static() -> impl Fn(&'static u32) { mixed_lifetimes() }
37+
38+
fn main() {}

0 commit comments

Comments
 (0)