Extend object safety so that methods with Sized:Self are exempt.
This commit is contained in:
parent
f0f7ca27de
commit
8f5d225933
@ -157,6 +157,16 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||||||
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
trait_def_id: ast::DefId)
|
trait_def_id: ast::DefId)
|
||||||
-> bool
|
-> bool
|
||||||
|
{
|
||||||
|
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
||||||
|
let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
|
||||||
|
generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||||
|
generics: &ty::Generics<'tcx>,
|
||||||
|
predicates: &ty::GenericPredicates<'tcx>)
|
||||||
|
-> bool
|
||||||
{
|
{
|
||||||
let sized_def_id = match tcx.lang_items.sized_trait() {
|
let sized_def_id = match tcx.lang_items.sized_trait() {
|
||||||
Some(def_id) => def_id,
|
Some(def_id) => def_id,
|
||||||
@ -164,12 +174,8 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Search for a predicate like `Self : Sized` amongst the trait bounds.
|
// Search for a predicate like `Self : Sized` amongst the trait bounds.
|
||||||
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
|
let free_substs = ty::construct_free_substs(tcx, generics, ast::DUMMY_NODE_ID);
|
||||||
let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID);
|
let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
|
||||||
|
|
||||||
let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
|
|
||||||
let predicates = trait_predicates.instantiate(tcx, &free_substs).predicates.into_vec();
|
|
||||||
|
|
||||||
elaborate_predicates(tcx, predicates)
|
elaborate_predicates(tcx, predicates)
|
||||||
.any(|predicate| {
|
.any(|predicate| {
|
||||||
match predicate {
|
match predicate {
|
||||||
@ -192,6 +198,12 @@ fn object_safety_violations_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||||||
method: &ty::Method<'tcx>)
|
method: &ty::Method<'tcx>)
|
||||||
-> Option<MethodViolationCode>
|
-> Option<MethodViolationCode>
|
||||||
{
|
{
|
||||||
|
// Any method that has a `Self : Sized` requisite is otherwise
|
||||||
|
// exempt from the regulations.
|
||||||
|
if generics_require_sized_self(tcx, &method.generics, &method.predicates) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// The method's first parameter must be something that derefs to
|
// The method's first parameter must be something that derefs to
|
||||||
// `&self`. For now, we only accept `&self` and `Box<Self>`.
|
// `&self`. For now, we only accept `&self` and `Box<Self>`.
|
||||||
match method.explicit_self {
|
match method.explicit_self {
|
||||||
|
@ -815,9 +815,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
param_substs,
|
param_substs,
|
||||||
substs.clone()).val;
|
substs.clone()).val;
|
||||||
|
|
||||||
// currently, at least, by-value self is not object safe
|
|
||||||
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
|
|
||||||
|
|
||||||
Some(fn_ref).into_iter()
|
Some(fn_ref).into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// Check that we correctly prevent users from making trait objects
|
// Check that we correctly prevent users from making trait objects
|
||||||
// from traits with a `fn(self)` method.
|
// from traits with a `fn(self)` method, unless `where Self : Sized`
|
||||||
|
// is present on the method.
|
||||||
|
|
||||||
trait Bar {
|
trait Bar {
|
||||||
fn bar(self);
|
fn bar(self);
|
||||||
@ -19,6 +20,11 @@ trait Baz {
|
|||||||
fn baz(self: Self);
|
fn baz(self: Self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Quux {
|
||||||
|
// Legal because of the where clause:
|
||||||
|
fn baz(self: Self) where Self : Sized;
|
||||||
|
}
|
||||||
|
|
||||||
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
t
|
t
|
||||||
//~^ ERROR `Bar` is not object-safe
|
//~^ ERROR `Bar` is not object-safe
|
||||||
@ -43,5 +49,13 @@ fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
|
|||||||
//~| NOTE method `baz` has a receiver type of `Self`
|
//~| NOTE method `baz` has a receiver type of `Self`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_quux<T:Quux>(t: &T) -> &Quux {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
|
||||||
|
t as &Quux
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,18 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// Check that we correctly prevent users from making trait objects
|
// Check that we correctly prevent users from making trait objects
|
||||||
// from traits with generic methods.
|
// from traits with generic methods, unless `where Self : Sized` is
|
||||||
|
// present.
|
||||||
|
|
||||||
trait Bar {
|
trait Bar {
|
||||||
fn bar<T>(&self, t: T);
|
fn bar<T>(&self, t: T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Quux {
|
||||||
|
fn bar<T>(&self, t: T)
|
||||||
|
where Self : Sized;
|
||||||
|
}
|
||||||
|
|
||||||
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
t
|
t
|
||||||
//~^ ERROR `Bar` is not object-safe
|
//~^ ERROR `Bar` is not object-safe
|
||||||
@ -27,5 +33,13 @@ fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
|
|||||||
//~| NOTE method `bar` has generic type parameters
|
//~| NOTE method `bar` has generic type parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_quux<T:Quux>(t: &T) -> &Quux {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
|
||||||
|
t as &Quux
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// Check that we correctly prevent users from making trait objects
|
// Check that we correctly prevent users from making trait objects
|
||||||
// form traits that make use of `Self` in an argument or return position.
|
// form traits that make use of `Self` in an argument or return
|
||||||
|
// position, unless `where Self : Sized` is present..
|
||||||
|
|
||||||
trait Bar {
|
trait Bar {
|
||||||
fn bar(&self, x: &Self);
|
fn bar(&self, x: &Self);
|
||||||
@ -19,6 +20,10 @@ trait Baz {
|
|||||||
fn bar(&self) -> Self;
|
fn bar(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Quux {
|
||||||
|
fn get(&self, s: &Self) -> Self where Self : Sized;
|
||||||
|
}
|
||||||
|
|
||||||
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
fn make_bar<T:Bar>(t: &T) -> &Bar {
|
||||||
t
|
t
|
||||||
//~^ ERROR `Bar` is not object-safe
|
//~^ ERROR `Bar` is not object-safe
|
||||||
@ -43,5 +48,13 @@ fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
|
|||||||
//~| NOTE method `bar` references the `Self` type in its arguments or return type
|
//~| NOTE method `bar` references the `Self` type in its arguments or return type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_quux<T:Quux>(t: &T) -> &Quux {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
|
||||||
|
t as &Quux
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
46
src/test/run-pass/object-safety-sized-self-by-value-self.rs
Normal file
46
src/test/run-pass/object-safety-sized-self-by-value-self.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that a trait is still object-safe (and usable) if it has
|
||||||
|
// methods with by-value self so long as they require `Self : Sized`.
|
||||||
|
|
||||||
|
trait Counter {
|
||||||
|
fn tick(&mut self) -> u32;
|
||||||
|
fn get(self) -> u32 where Self : Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CCounter {
|
||||||
|
c: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Counter for CCounter {
|
||||||
|
fn tick(&mut self) -> u32 { self.c += 1; self.c }
|
||||||
|
fn get(self) -> u32 where Self : Sized { self.c }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick1<C:Counter>(mut c: C) -> u32 {
|
||||||
|
tick2(&mut c);
|
||||||
|
c.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick2(c: &mut Counter) {
|
||||||
|
tick3(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick3<C:?Sized+Counter>(c: &mut C) {
|
||||||
|
c.tick();
|
||||||
|
c.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut c = CCounter { c: 0 };
|
||||||
|
let value = tick1(c);
|
||||||
|
assert_eq!(value, 2);
|
||||||
|
}
|
46
src/test/run-pass/object-safety-sized-self-generic-method.rs
Normal file
46
src/test/run-pass/object-safety-sized-self-generic-method.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that a trait is still object-safe (and usable) if it has
|
||||||
|
// generic methods so long as they require `Self : Sized`.
|
||||||
|
|
||||||
|
trait Counter {
|
||||||
|
fn tick(&mut self) -> u32;
|
||||||
|
fn with<F:FnOnce(u32)>(&self, f: F) where Self : Sized;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CCounter {
|
||||||
|
c: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Counter for CCounter {
|
||||||
|
fn tick(&mut self) -> u32 { self.c += 1; self.c }
|
||||||
|
fn with<F:FnOnce(u32)>(&self, f: F) { f(self.c); }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick1<C:Counter>(c: &mut C) {
|
||||||
|
tick2(c);
|
||||||
|
c.with(|i| ());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick2(c: &mut Counter) {
|
||||||
|
tick3(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick3<C:?Sized+Counter>(c: &mut C) {
|
||||||
|
c.tick();
|
||||||
|
c.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut c = CCounter { c: 0 };
|
||||||
|
tick1(&mut c);
|
||||||
|
assert_eq!(c.tick(), 3);
|
||||||
|
}
|
47
src/test/run-pass/object-safety-sized-self-return-Self.rs
Normal file
47
src/test/run-pass/object-safety-sized-self-return-Self.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that a trait is still object-safe (and usable) if it has
|
||||||
|
// methods that return `Self` so long as they require `Self : Sized`.
|
||||||
|
|
||||||
|
trait Counter {
|
||||||
|
fn new() -> Self where Self : Sized;
|
||||||
|
fn tick(&mut self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CCounter {
|
||||||
|
c: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Counter for CCounter {
|
||||||
|
fn new() -> CCounter { CCounter { c: 0 } }
|
||||||
|
fn tick(&mut self) -> u32 { self.c += 1; self.c }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preticked<C:Counter>() -> C {
|
||||||
|
let mut c: C = Counter::new();
|
||||||
|
tick(&mut c);
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(c: &mut Counter) {
|
||||||
|
tick_generic(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick_generic<C:?Sized+Counter>(c: &mut C) {
|
||||||
|
c.tick();
|
||||||
|
c.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut c = preticked::<CCounter>();
|
||||||
|
tick(&mut c);
|
||||||
|
assert_eq!(c.tick(), 5);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user