Skip to content

Commit 369adaf

Browse files
committed
Implement the rules for RFC 599, and add various tests.
Fixes rust-lang#22211.
1 parent ab57988 commit 369adaf

26 files changed

+542
-68
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -438,23 +438,25 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
438438
{
439439
let regions: Vec<_> =
440440
data.lifetimes.iter()
441-
.map(|l| ast_region_to_region(this.tcx(), l))
442-
.collect();
441+
.map(|l| ast_region_to_region(this.tcx(), l))
442+
.collect();
443443

444444
let region_substs =
445445
create_region_substs(this, rscope, span, decl_generics, regions);
446446

447447
let types: Vec<_> =
448448
data.types.iter()
449-
.map(|t| ast_ty_to_ty(this, rscope, &**t))
450-
.collect();
449+
.enumerate()
450+
.map(|(i,t)| ast_ty_arg_to_ty(this, rscope, decl_generics,
451+
i, &region_substs, t))
452+
.collect();
451453

452454
let assoc_bindings: Vec<_> =
453455
data.bindings.iter()
454-
.map(|b| ConvertedBinding { item_name: b.ident.name,
455-
ty: ast_ty_to_ty(this, rscope, &*b.ty),
456-
span: b.span })
457-
.collect();
456+
.map(|b| ConvertedBinding { item_name: b.ident.name,
457+
ty: ast_ty_to_ty(this, rscope, &*b.ty),
458+
span: b.span })
459+
.collect();
458460

459461
(region_substs, types, assoc_bindings)
460462
}
@@ -525,9 +527,11 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
525527
create_region_substs(this, rscope, span, decl_generics, Vec::new());
526528

527529
let binding_rscope = BindingRscope::new();
528-
let inputs = data.inputs.iter()
529-
.map(|a_t| ast_ty_to_ty(this, &binding_rscope, &**a_t))
530-
.collect::<Vec<Ty<'tcx>>>();
530+
let inputs =
531+
data.inputs.iter()
532+
.map(|a_t| ast_ty_arg_to_ty(this, &binding_rscope, decl_generics,
533+
0, &region_substs, a_t))
534+
.collect::<Vec<Ty<'tcx>>>();
531535

532536
let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect();
533537
let (implied_output_region,
@@ -655,7 +659,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
655659

656660
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
657661
ast::AngleBracketedParameters(ref data) => {
658-
// For now, require that parenthetical5D notation be used
662+
// For now, require that parenthetical notation be used
659663
// only with `Fn()` etc.
660664
if !this.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar {
661665
span_err!(this.tcx().sess, path.span, E0215,
@@ -1070,10 +1074,45 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
10701074
qpath.item_path.identifier.name);
10711075
}
10721076

1073-
// Parses the programmer's textual representation of a type into our
1074-
// internal notion of a type.
1075-
pub fn ast_ty_to_ty<'tcx>(
1076-
this: &AstConv<'tcx>, rscope: &RegionScope, ast_ty: &ast::Ty) -> Ty<'tcx>
1077+
/// Convert a type supplied as value for a type argument from AST into our
1078+
/// our internal representation. This is the same as `ast_ty_to_ty` but that
1079+
/// it applies the object lifetime default.
1080+
///
1081+
/// # Parameters
1082+
///
1083+
/// * `this`, `rscope`: the surrounding context
1084+
/// * `decl_generics`: the generics of the struct/enum/trait declaration being
1085+
/// referenced
1086+
/// * `index`: the index of the type parameter being instantiated from the list
1087+
/// (we assume it is in the `TypeSpace`)
1088+
/// * `region_substs`: a partial substitution consisting of
1089+
/// only the region type parameters being supplied to this type.
1090+
/// * `ast_ty`: the ast representation of the type being supplied
1091+
pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>,
1092+
rscope: &RegionScope,
1093+
decl_generics: &ty::Generics<'tcx>,
1094+
index: usize,
1095+
region_substs: &Substs<'tcx>,
1096+
ast_ty: &ast::Ty)
1097+
-> Ty<'tcx>
1098+
{
1099+
let tcx = this.tcx();
1100+
1101+
if let Some(def) = decl_generics.types.opt_get(TypeSpace, index) {
1102+
let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs);
1103+
let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default);
1104+
ast_ty_to_ty(this, rscope1, ast_ty)
1105+
} else {
1106+
ast_ty_to_ty(this, rscope, ast_ty)
1107+
}
1108+
}
1109+
1110+
/// Parses the programmer's textual representation of a type into our
1111+
/// internal notion of a type.
1112+
pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
1113+
rscope: &RegionScope,
1114+
ast_ty: &ast::Ty)
1115+
-> Ty<'tcx>
10771116
{
10781117
debug!("ast_ty_to_ty(ast_ty={})",
10791118
ast_ty.repr(this.tcx()));

src/test/compile-fail/issue-11374.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::old_io;
1212
use std::vec;
1313

1414
pub struct Container<'a> {
15-
reader: &'a mut Reader //~ ERROR explicit lifetime bound required
15+
reader: &'a mut Reader
1616
}
1717

1818
impl<'a> Container<'a> {
@@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> {
3333
fn main() {
3434
let mut c = for_stdin();
3535
let mut v = Vec::new();
36-
c.read_to(v);
36+
c.read_to(v); //~ ERROR mismatched types
3737
}

src/test/compile-fail/issue-5216.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
// except according to those terms.
1010

1111
fn f() { }
12-
struct S(Box<FnMut()>); //~ ERROR explicit lifetime bound required
13-
pub static C: S = S(f);
12+
struct S(Box<FnMut()>);
13+
pub static C: S = S(f); //~ ERROR mismatched types
1414

1515

1616
fn g() { }
17-
type T = Box<FnMut()>; //~ ERROR explicit lifetime bound required
18-
pub static D: T = g;
17+
type T = Box<FnMut()>;
18+
pub static D: T = g; //~ ERROR mismatched types
1919

2020
fn main() {}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
// Test that if a struct declares multiple region bounds for a given
12+
// type parameter, an explicit lifetime bound is required on object
13+
// lifetimes within.
14+
15+
#![allow(dead_code)]
16+
17+
trait Test {
18+
fn foo(&self) { }
19+
}
20+
21+
struct Ref0<T:?Sized> {
22+
r: *mut T
23+
}
24+
25+
struct Ref1<'a,T:'a+?Sized> {
26+
r: &'a T
27+
}
28+
29+
struct Ref2<'a,'b:'a,T:'a+'b+?Sized> {
30+
r: &'a &'b T
31+
}
32+
33+
fn a<'a,'b>(t: Ref2<'a,'b,Test>) {
34+
//~^ ERROR lifetime bound for this object type cannot be deduced from context
35+
}
36+
37+
fn b(t: Ref2<Test>) {
38+
//~^ ERROR lifetime bound for this object type cannot be deduced from context
39+
}
40+
41+
fn c(t: Ref2<&Test>) {
42+
// In this case, the &'a overrides.
43+
}
44+
45+
fn d(t: Ref2<Ref1<Test>>) {
46+
// In this case, the lifetime parameter from the Ref1 overrides.
47+
}
48+
49+
fn e(t: Ref2<Ref0<Test>>) {
50+
//~^ ERROR lifetime bound for this object type cannot be deduced from context
51+
//
52+
// In this case, Ref0 just inherits.
53+
}
54+
55+
fn f(t: &Ref2<Test>) {
56+
//~^ ERROR lifetime bound for this object type cannot be deduced from context
57+
}
58+
59+
fn main() {
60+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
// Test various cases where the old rules under lifetime elision
12+
// yield slightly different results than the new rules.
13+
14+
#![allow(dead_code)]
15+
16+
trait SomeTrait {
17+
fn dummy(&self) { }
18+
}
19+
20+
struct SomeStruct<'a> {
21+
r: Box<SomeTrait+'a>
22+
}
23+
24+
fn deref<T>(ss: &T) -> T {
25+
// produces the type of a deref without worrying about whether a
26+
// move out would actually be legal
27+
loop { }
28+
}
29+
30+
fn load0<'a>(ss: &'a Box<SomeTrait>) -> Box<SomeTrait> {
31+
// Under old rules, the fully elaborated types of input/output were:
32+
//
33+
// for<'a,'b> fn(&'a Box<SomeTrait+'b>) -> Box<SomeTrait+'a>
34+
//
35+
// Under new rules the result is:
36+
//
37+
// for<'a> fn(&'a Box<SomeTrait+'a>) -> Box<SomeTrait+'static>
38+
//
39+
// Therefore, we get a type error attempting to return `deref(ss)`
40+
// since `SomeTrait+'a <: SomeTrait+'static` does not hold.
41+
42+
deref(ss)
43+
//~^ ERROR cannot infer
44+
}
45+
46+
fn load1(ss: &SomeTrait) -> &SomeTrait {
47+
// Under old rules, the fully elaborated types of input/output were:
48+
//
49+
// for<'a,'b> fn(&'a (SomeTrait+'b)) -> &'a (SomeTrait+'a)
50+
//
51+
// Under new rules the result is:
52+
//
53+
// for<'a> fn(&'a (SomeTrait+'a)) -> &'a (SomeTrait+'a)
54+
//
55+
// In both cases, returning `ss` is legal.
56+
57+
ss
58+
}
59+
60+
fn load2<'a>(ss: &'a SomeTrait) -> &SomeTrait {
61+
// Same as `load1` but with an explicit name thrown in for fun.
62+
63+
ss
64+
}
65+
66+
fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
67+
// Under old rules, the fully elaborated types of input/output were:
68+
//
69+
// for<'a,'b,'c>fn(&'a (SomeTrait+'c)) -> &'b (SomeTrait+'a)
70+
//
71+
// Based on the input/output types, the compiler could infer that
72+
// 'c : 'a
73+
// 'b : 'a
74+
// must hold, and therefore it permitted `&'a (Sometrait+'c)` to be
75+
// coerced to `&'b (SomeTrait+'a)`.
76+
//
77+
// Under the newer defaults, though, we get:
78+
//
79+
// for<'a,'b> fn(&'a (SomeTrait+'a)) -> &'b (SomeTrait+'b)
80+
//
81+
// which fails to type check.
82+
83+
ss
84+
//~^ ERROR cannot infer
85+
//~| ERROR mismatched types
86+
}
87+
88+
fn main() {
89+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
// Test various cases where the defaults should lead to errors being
12+
// reported.
13+
14+
#![allow(dead_code)]
15+
16+
trait SomeTrait {
17+
fn dummy(&self) { }
18+
}
19+
20+
struct SomeStruct<'a> {
21+
r: Box<SomeTrait+'a>
22+
}
23+
24+
fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
25+
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
26+
// is illegal.
27+
28+
ss.r //~ ERROR mismatched types
29+
}
30+
31+
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
32+
// No error: b is bounded by 'static which outlives the
33+
// (anonymous) lifetime on the struct.
34+
35+
ss.r = b;
36+
}
37+
38+
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
39+
// Here we override the lifetimes explicitly, and so naturally we get an error.
40+
41+
ss.r = b; //~ ERROR mismatched types
42+
}
43+
44+
fn main() {
45+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// Test a "pass-through" object-lifetime-default that produces errors.
12+
13+
#![allow(dead_code)]
14+
15+
trait SomeTrait {
16+
fn dummy(&self) { }
17+
}
18+
19+
struct MyBox<T:?Sized> {
20+
r: Box<T>
21+
}
22+
23+
fn deref<T>(ss: &T) -> T {
24+
// produces the type of a deref without worrying about whether a
25+
// move out would actually be legal
26+
loop { }
27+
}
28+
29+
fn load0(ss: &MyBox<SomeTrait>) -> MyBox<SomeTrait> {
30+
deref(ss) //~ ERROR cannot infer
31+
}
32+
33+
fn load1<'a,'b>(a: &'a MyBox<SomeTrait>,
34+
b: &'b MyBox<SomeTrait>)
35+
-> &'b MyBox<SomeTrait>
36+
{
37+
a
38+
//~^ ERROR cannot infer
39+
//~| ERROR mismatched types
40+
//~| ERROR mismatched types
41+
}
42+
43+
fn main() {
44+
}

src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct Foo<'a,'b,'c> {
2525
c: Box<Is<'a>>,
2626
d: Box<IsSend>,
2727
e: Box<Is<'a>+Send>, // we can derive two bounds, but one is 'static, so ok
28-
f: Box<SomeTrait>, //~ ERROR explicit lifetime bound required
28+
f: Box<SomeTrait>, // OK, defaults to 'static due to RFC 599.
2929
g: Box<SomeTrait+'a>,
3030

3131
z: Box<Is<'a>+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted

0 commit comments

Comments
 (0)