Auto merge of #54383 - mikeyhew:custom-receivers-object-safety, r=nikomatsakis
Take 2: Implement object-safety and dynamic dispatch for arbitrary_self_types This replaces #50173. Over the months that that PR was open, we made a lot of changes to the way this was going to be implemented, and the long, meandering comment thread and commit history would have been confusing to people reading it in the future. So I decided to package everything up with new, straighforward commits and open a new PR. Here are the main points. Please read the commit messages for details. - To simplify codegen, we only support receivers that have the ABI of a pointer. That means they are builtin pointer types, or newtypes thereof. - We introduce a new trait: `DispatchFromDyn<T>`, similar to `CoerceUnsized<T>`. `DispatchFromDyn` has extra requirements that `CoerceUnsized` does not: when you implement `DispatchFromDyn` for a struct, there cannot be any extra fields besides the field being coerced and `PhantomData` fields. This ensures that the struct's ABI is the same as a pointer. - For a method's receiver (e.g. `self: Rc<Self>`) to be object-safe, it needs to have the following property: - let `DynReceiver` be the receiver when `Self = dyn Trait` - let `ConcreteReceiver` be the receiver when `Self = T`, where `T` is some unknown `Sized` type that implements `Trait`, and is the erased type of the trait object. - `ConcreteReceiver` must implement `DispatchFromDyn<DynReceiver>` In the case of `Rc<Self>`, this requires `Rc<T>: DispatchFromDyn<Rc<dyn Trait>>` These rules are explained more thoroughly in the doc comment on `receiver_is_dispatchable` in object_safety.rs. r? @nikomatsakis and @eddyb cc @arielb1 @cramertj @withoutboats Special thanks to @nikomatsakis for getting me un-stuck when implementing the object-safety checks, and @eddyb for helping with the codegen parts. EDIT 2018-11-01: updated because CoerceSized has been replaced with DispatchFromDyn
This commit is contained in:
commit
3fc70e8d46
30 changed files with 904 additions and 128 deletions
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2017 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.
|
||||
#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::{
|
||||
ops::{Deref, CoerceUnsized, DispatchFromDyn},
|
||||
marker::Unsize,
|
||||
};
|
||||
|
||||
struct Ptr<T: ?Sized>(Box<T>);
|
||||
|
||||
impl<T: ?Sized> Deref for Ptr<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
|
||||
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
|
||||
|
||||
struct Wrapper<T: ?Sized>(T);
|
||||
|
||||
impl<T: ?Sized> Deref for Wrapper<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
|
||||
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
|
||||
|
||||
|
||||
trait Trait {
|
||||
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
|
||||
// without unsized_locals), but wrappers arond `Self` currently are not.
|
||||
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
|
||||
// fn wrapper(self: Wrapper<Self>) -> i32;
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
||||
}
|
||||
|
||||
impl Trait for i32 {
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 {
|
||||
**self
|
||||
}
|
||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
|
||||
**self
|
||||
}
|
||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
|
||||
***self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let pw = Ptr(Box::new(Wrapper(5))) as Ptr<Wrapper<dyn Trait>>;
|
||||
assert_eq!(pw.ptr_wrapper(), 5);
|
||||
|
||||
let wp = Wrapper(Ptr(Box::new(6))) as Wrapper<Ptr<dyn Trait>>;
|
||||
assert_eq!(wp.wrapper_ptr(), 6);
|
||||
|
||||
let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
|
||||
assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
|
||||
}
|
||||
56
src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs
Normal file
56
src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(pin)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::{
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
pin::Pin,
|
||||
};
|
||||
|
||||
trait Trait {
|
||||
fn by_rc(self: Rc<Self>) -> i64;
|
||||
fn by_arc(self: Arc<Self>) -> i64;
|
||||
fn by_pin_mut(self: Pin<&mut Self>) -> i64;
|
||||
fn by_pin_box(self: Pin<Box<Self>>) -> i64;
|
||||
}
|
||||
|
||||
impl Trait for i64 {
|
||||
fn by_rc(self: Rc<Self>) -> i64 {
|
||||
*self
|
||||
}
|
||||
fn by_arc(self: Arc<Self>) -> i64 {
|
||||
*self
|
||||
}
|
||||
fn by_pin_mut(self: Pin<&mut Self>) -> i64 {
|
||||
*self
|
||||
}
|
||||
fn by_pin_box(self: Pin<Box<Self>>) -> i64 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rc = Rc::new(1i64) as Rc<dyn Trait>;
|
||||
assert_eq!(1, rc.by_rc());
|
||||
|
||||
let arc = Arc::new(2i64) as Arc<dyn Trait>;
|
||||
assert_eq!(2, arc.by_arc());
|
||||
|
||||
let mut value = 3i64;
|
||||
let pin_mut = Pin::new(&mut value) as Pin<&mut dyn Trait>;
|
||||
assert_eq!(3, pin_mut.by_pin_mut());
|
||||
|
||||
let pin_box = Into::<Pin<Box<i64>>>::into(Box::new(4i64)) as Pin<Box<dyn Trait>>;
|
||||
assert_eq!(4, pin_box.by_pin_box());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue