Skip to content

Commit 5676f60

Browse files
committed
Rollup merge of rust-lang#22301 - nikomatsakis:object-safe-sized-methods, r=huonw
RFC 817 is not yet accepted, but I wanted to put this code up so people can see how it works. And to be ready lest it should be accepted. cc rust-lang/rfcs#817
2 parents 8e88762 + fd9f7da commit 5676f60

14 files changed

+252
-66
lines changed

src/librustc/middle/traits/object_safety.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ pub enum ObjectSafetyViolation<'tcx> {
4242
/// Reasons a method might not be object-safe.
4343
#[derive(Copy,Clone,Debug)]
4444
pub enum MethodViolationCode {
45-
/// e.g., `fn(self)`
46-
ByValueSelf,
47-
4845
/// e.g., `fn foo()`
4946
StaticMethod,
5047

@@ -157,19 +154,25 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
157154
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
158155
trait_def_id: ast::DefId)
159156
-> bool
157+
{
158+
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
159+
let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
160+
generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates)
161+
}
162+
163+
fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
164+
generics: &ty::Generics<'tcx>,
165+
predicates: &ty::GenericPredicates<'tcx>)
166+
-> bool
160167
{
161168
let sized_def_id = match tcx.lang_items.sized_trait() {
162169
Some(def_id) => def_id,
163170
None => { return false; /* No Sized trait, can't require it! */ }
164171
};
165172

166173
// Search for a predicate like `Self : Sized` amongst the trait bounds.
167-
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
168-
let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID);
169-
170-
let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
171-
let predicates = trait_predicates.instantiate(tcx, &free_substs).predicates.into_vec();
172-
174+
let free_substs = ty::construct_free_substs(tcx, generics, ast::DUMMY_NODE_ID);
175+
let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
173176
elaborate_predicates(tcx, predicates)
174177
.any(|predicate| {
175178
match predicate {
@@ -192,17 +195,21 @@ fn object_safety_violations_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
192195
method: &ty::Method<'tcx>)
193196
-> Option<MethodViolationCode>
194197
{
195-
// The method's first parameter must be something that derefs to
196-
// `&self`. For now, we only accept `&self` and `Box<Self>`.
197-
match method.explicit_self {
198-
ty::ByValueExplicitSelfCategory => {
199-
return Some(MethodViolationCode::ByValueSelf);
200-
}
198+
// Any method that has a `Self : Sized` requisite is otherwise
199+
// exempt from the regulations.
200+
if generics_require_sized_self(tcx, &method.generics, &method.predicates) {
201+
return None;
202+
}
201203

204+
// The method's first parameter must be something that derefs (or
205+
// autorefs) to `&self`. For now, we only accept `self`, `&self`
206+
// and `Box<Self>`.
207+
match method.explicit_self {
202208
ty::StaticExplicitSelfCategory => {
203209
return Some(MethodViolationCode::StaticMethod);
204210
}
205211

212+
ty::ByValueExplicitSelfCategory |
206213
ty::ByReferenceExplicitSelfCategory(..) |
207214
ty::ByBoxExplicitSelfCategory => {
208215
}

src/librustc_trans/trans/meth.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -818,9 +818,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
818818
param_substs,
819819
substs.clone()).val;
820820

821-
// currently, at least, by-value self is not object safe
822-
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
823-
824821
Some(fn_ref).into_iter()
825822
}
826823
}

src/librustc_typeck/check/method/confirm.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -404,26 +404,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
404404
all_substs.repr(self.tcx()));
405405

406406
// Instantiate the bounds on the method with the
407-
// type/early-bound-regions substitutions performed. The only
408-
// late-bound-regions that can appear in bounds are from the
409-
// impl, and those were already instantiated above.
410-
//
411-
// FIXME(DST). Super hack. For a method on a trait object
412-
// `Trait`, the generic signature requires that
413-
// `Self:Trait`. Since, for an object, we bind `Self` to the
414-
// type `Trait`, this leads to an obligation
415-
// `Trait:Trait`. Until such time we DST is fully implemented,
416-
// that obligation is not necessarily satisfied. (In the
417-
// future, it would be.) But we know that the true `Self` DOES implement
418-
// the trait. So we just delete this requirement. Hack hack hack.
419-
let mut method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
420-
match pick.kind {
421-
probe::ObjectPick(..) => {
422-
assert_eq!(method_predicates.predicates.get_slice(subst::SelfSpace).len(), 1);
423-
method_predicates.predicates.pop(subst::SelfSpace);
424-
}
425-
_ => { }
426-
}
407+
// type/early-bound-regions substitutions performed. There can
408+
// be no late-bound regions appearing here.
409+
let method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
427410
let method_predicates = self.fcx.normalize_associated_types_in(self.span,
428411
&method_predicates);
429412

src/librustc_typeck/check/vtable.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,6 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
133133
in the supertrait listing");
134134
}
135135

136-
ObjectSafetyViolation::Method(method, MethodViolationCode::ByValueSelf) => {
137-
tcx.sess.span_note(
138-
span,
139-
&format!("method `{}` has a receiver type of `Self`, \
140-
which cannot be used with a trait object",
141-
method.name.user_string(tcx)));
142-
}
143-
144136
ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => {
145137
tcx.sess.span_note(
146138
span,

src/test/compile-fail/fn-trait-formatting.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ fn needs_fn<F>(x: F) where F: Fn(isize) -> isize {}
1515

1616
fn main() {
1717
let _: () = (box |_: isize| {}) as Box<FnOnce(isize)>;
18-
//~^ ERROR object-safe
19-
//~| ERROR mismatched types
18+
//~^ ERROR mismatched types
2019
//~| expected `()`
2120
//~| found `Box<core::ops::FnOnce(isize)>`
2221
//~| expected ()

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ impl Foo for Thing {
1717
fn foo<T>(&self, _: &T) {}
1818
}
1919

20-
#[inline(never)] fn foo(b: &Bar) { b.foo(&0_usize) }
20+
#[inline(never)]
21+
fn foo(b: &Bar) {
22+
b.foo(&0usize)
23+
//~^ ERROR the trait `Foo` is not implemented for the type `Bar`
24+
}
2125

2226
fn main() {
2327
let mut thing = Thing;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2014 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+
// Check that while a trait with by-value self is object-safe, we
12+
// can't actually invoke it from an object (yet...?).
13+
14+
#![feature(rustc_attrs)]
15+
16+
trait Bar {
17+
fn bar(self);
18+
}
19+
20+
trait Baz {
21+
fn baz(self: Self);
22+
}
23+
24+
fn use_bar(t: Box<Bar>) {
25+
t.bar() //~ ERROR cannot move a value of type Bar
26+
}
27+
28+
fn main() { }
29+

src/test/compile-fail/object-safety-by-value-self.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// Check that we correctly prevent users from making trait objects
12-
// from traits with a `fn(self)` method.
11+
// Check that a trait with by-value self is considered object-safe.
12+
13+
#![feature(rustc_attrs)]
14+
#![allow(dead_code)]
1315

1416
trait Bar {
1517
fn bar(self);
@@ -19,29 +21,35 @@ trait Baz {
1921
fn baz(self: Self);
2022
}
2123

24+
trait Quux {
25+
// Legal because of the where clause:
26+
fn baz(self: Self) where Self : Sized;
27+
}
28+
2229
fn make_bar<T:Bar>(t: &T) -> &Bar {
23-
t
24-
//~^ ERROR `Bar` is not object-safe
25-
//~| NOTE method `bar` has a receiver type of `Self`
30+
t // legal
2631
}
2732

2833
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
29-
t as &Bar
30-
//~^ ERROR `Bar` is not object-safe
31-
//~| NOTE method `bar` has a receiver type of `Self`
34+
t as &Bar // legal
3235
}
3336

3437
fn make_baz<T:Baz>(t: &T) -> &Baz {
35-
t
36-
//~^ ERROR `Baz` is not object-safe
37-
//~| NOTE method `baz` has a receiver type of `Self`
38+
t // legal
3839
}
3940

4041
fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
41-
t as &Baz
42-
//~^ ERROR `Baz` is not object-safe
43-
//~| NOTE method `baz` has a receiver type of `Self`
42+
t as &Baz // legal
43+
}
44+
45+
fn make_quux<T:Quux>(t: &T) -> &Quux {
46+
t
47+
}
48+
49+
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
50+
t as &Quux
4451
}
4552

46-
fn main() {
53+
#[rustc_error]
54+
fn main() { //~ ERROR compilation successful
4755
}

src/test/compile-fail/object-safety-generics.rs

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

1111
// Check that we correctly prevent users from making trait objects
12-
// from traits with generic methods.
12+
// from traits with generic methods, unless `where Self : Sized` is
13+
// present.
1314

1415
trait Bar {
1516
fn bar<T>(&self, t: T);
1617
}
1718

19+
trait Quux {
20+
fn bar<T>(&self, t: T)
21+
where Self : Sized;
22+
}
23+
1824
fn make_bar<T:Bar>(t: &T) -> &Bar {
1925
t
2026
//~^ ERROR `Bar` is not object-safe
@@ -27,5 +33,13 @@ fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
2733
//~| NOTE method `bar` has generic type parameters
2834
}
2935

36+
fn make_quux<T:Quux>(t: &T) -> &Quux {
37+
t
38+
}
39+
40+
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
41+
t as &Quux
42+
}
43+
3044
fn main() {
3145
}

src/test/compile-fail/object-safety-mentions-Self.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// except according to those terms.
1010

1111
// Check that we correctly prevent users from making trait objects
12-
// form traits that make use of `Self` in an argument or return position.
12+
// form traits that make use of `Self` in an argument or return
13+
// position, unless `where Self : Sized` is present..
1314

1415
trait Bar {
1516
fn bar(&self, x: &Self);
@@ -19,6 +20,10 @@ trait Baz {
1920
fn bar(&self) -> Self;
2021
}
2122

23+
trait Quux {
24+
fn get(&self, s: &Self) -> Self where Self : Sized;
25+
}
26+
2227
fn make_bar<T:Bar>(t: &T) -> &Bar {
2328
t
2429
//~^ ERROR `Bar` is not object-safe
@@ -43,5 +48,13 @@ fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
4348
//~| NOTE method `bar` references the `Self` type in its arguments or return type
4449
}
4550

51+
fn make_quux<T:Quux>(t: &T) -> &Quux {
52+
t
53+
}
54+
55+
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
56+
t as &Quux
57+
}
58+
4659
fn main() {
4760
}

src/test/compile-fail/trait-test-2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ fn main() {
1818
10.dup::<i32>(); //~ ERROR does not take type parameters
1919
10.blah::<i32, i32>(); //~ ERROR incorrect number of type parameters
2020
(box 10 as Box<bar>).dup(); //~ ERROR cannot convert to a trait object
21+
//~^ ERROR the trait `bar` is not implemented for the type `bar`
2122
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2014 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+
// Check that a trait is still object-safe (and usable) if it has
12+
// methods with by-value self so long as they require `Self : Sized`.
13+
14+
trait Counter {
15+
fn tick(&mut self) -> u32;
16+
fn get(self) -> u32 where Self : Sized;
17+
}
18+
19+
struct CCounter {
20+
c: u32
21+
}
22+
23+
impl Counter for CCounter {
24+
fn tick(&mut self) -> u32 { self.c += 1; self.c }
25+
fn get(self) -> u32 where Self : Sized { self.c }
26+
}
27+
28+
fn tick1<C:Counter>(mut c: C) -> u32 {
29+
tick2(&mut c);
30+
c.get()
31+
}
32+
33+
fn tick2(c: &mut Counter) {
34+
tick3(c);
35+
}
36+
37+
fn tick3<C:?Sized+Counter>(c: &mut C) {
38+
c.tick();
39+
c.tick();
40+
}
41+
42+
fn main() {
43+
let mut c = CCounter { c: 0 };
44+
let value = tick1(c);
45+
assert_eq!(value, 2);
46+
}

0 commit comments

Comments
 (0)