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
|
|
@ -12,38 +12,38 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
trait Foo {
|
||||
fn foo(self: Rc<Self>) -> usize;
|
||||
fn foo(self: &Rc<Self>) -> usize;
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn foo(self: Rc<Self>) -> usize where Self: Sized;
|
||||
fn bar(self: Box<Self>) -> usize;
|
||||
fn foo(self: &Rc<Self>) -> usize where Self: Sized;
|
||||
fn bar(self: Rc<Self>) -> usize;
|
||||
}
|
||||
|
||||
impl Foo for usize {
|
||||
fn foo(self: Rc<Self>) -> usize {
|
||||
*self
|
||||
fn foo(self: &Rc<Self>) -> usize {
|
||||
**self
|
||||
}
|
||||
}
|
||||
|
||||
impl Bar for usize {
|
||||
fn foo(self: Rc<Self>) -> usize {
|
||||
*self
|
||||
fn foo(self: &Rc<Self>) -> usize {
|
||||
**self
|
||||
}
|
||||
|
||||
fn bar(self: Box<Self>) -> usize {
|
||||
fn bar(self: Rc<Self>) -> usize {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
fn make_foo() {
|
||||
let x = Box::new(5usize) as Box<Foo>;
|
||||
let x = Rc::new(5usize) as Rc<Foo>;
|
||||
//~^ ERROR E0038
|
||||
//~| ERROR E0038
|
||||
}
|
||||
|
||||
fn make_bar() {
|
||||
let x = Box::new(5usize) as Box<Bar>;
|
||||
let x = Rc::new(5usize) as Rc<Bar>;
|
||||
x.bar();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/arbitrary-self-types-not-object-safe.rs:40:33
|
||||
--> $DIR/arbitrary-self-types-not-object-safe.rs:40:32
|
||||
|
|
||||
LL | let x = Box::new(5usize) as Box<Foo>;
|
||||
| ^^^^^^^^ the trait `Foo` cannot be made into an object
|
||||
LL | let x = Rc::new(5usize) as Rc<Foo>;
|
||||
| ^^^^^^^ the trait `Foo` cannot be made into an object
|
||||
|
|
||||
= note: method `foo` has a non-standard `self` type
|
||||
= note: method `foo`'s receiver cannot be dispatched on
|
||||
|
||||
error[E0038]: the trait `Foo` cannot be made into an object
|
||||
--> $DIR/arbitrary-self-types-not-object-safe.rs:40:13
|
||||
|
|
||||
LL | let x = Box::new(5usize) as Box<Foo>;
|
||||
| ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
||||
LL | let x = Rc::new(5usize) as Rc<Foo>;
|
||||
| ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
||||
|
|
||||
= note: method `foo` has a non-standard `self` type
|
||||
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<usize>`
|
||||
= note: method `foo`'s receiver cannot be dispatched on
|
||||
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
|
||||
|
|
||||
= note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
|
||||
= note: currently, 2 fields need coercions: b (T to U), c (U to T)
|
||||
= note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
52
src/test/ui/invalid_dispatch_from_dyn_impls.rs
Normal file
52
src/test/ui/invalid_dispatch_from_dyn_impls.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// 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(unsize, dispatch_from_dyn)]
|
||||
|
||||
use std::{
|
||||
ops::DispatchFromDyn,
|
||||
marker::{Unsize, PhantomData},
|
||||
};
|
||||
|
||||
struct WrapperWithExtraField<T>(T, i32);
|
||||
|
||||
impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
|
||||
where
|
||||
T: DispatchFromDyn<U>,
|
||||
{} //~^^^ ERROR [E0378]
|
||||
|
||||
|
||||
struct MultiplePointers<T: ?Sized>{
|
||||
ptr1: *const T,
|
||||
ptr2: *const T,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
|
||||
where
|
||||
T: Unsize<U>,
|
||||
{} //~^^^ ERROR [E0378]
|
||||
|
||||
|
||||
struct NothingToCoerce<T: ?Sized> {
|
||||
data: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
|
||||
//~^ ERROR [E0378]
|
||||
|
||||
#[repr(C)]
|
||||
struct HasReprC<T: ?Sized>(Box<T>);
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
|
||||
where
|
||||
T: Unsize<U>,
|
||||
{} //~^^^ ERROR [E0378]
|
||||
|
||||
fn main() {}
|
||||
41
src/test/ui/invalid_dispatch_from_dyn_impls.stderr
Normal file
41
src/test/ui/invalid_dispatch_from_dyn_impls.stderr
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, `PhantomData` fields, and nothing else
|
||||
--> $DIR/invalid_dispatch_from_dyn_impls.rs:20:1
|
||||
|
|
||||
LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
|
||||
LL | | where
|
||||
LL | | T: DispatchFromDyn<U>,
|
||||
LL | | {} //~^^^ ERROR [E0378]
|
||||
| |__^
|
||||
|
|
||||
= note: extra field `1` of type `i32` is not allowed
|
||||
|
||||
error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
|
||||
--> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1
|
||||
|
|
||||
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
|
||||
LL | | where
|
||||
LL | | T: Unsize<U>,
|
||||
LL | | {} //~^^^ ERROR [E0378]
|
||||
| |__^
|
||||
|
|
||||
= note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
|
||||
= note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`)
|
||||
|
||||
error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced, none found
|
||||
--> $DIR/invalid_dispatch_from_dyn_impls.rs:41:1
|
||||
|
|
||||
LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
|
||||
--> $DIR/invalid_dispatch_from_dyn_impls.rs:47:1
|
||||
|
|
||||
LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
|
||||
LL | | where
|
||||
LL | | T: Unsize<U>,
|
||||
LL | | {} //~^^^ ERROR [E0378]
|
||||
| |__^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0378`.
|
||||
|
|
@ -5,7 +5,7 @@ LL | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
|
||||
|
|
||||
= note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
|
||||
= note: currently, 2 fields need coercions: _ptr (*const T to *const U), _boo (NotPhantomData<T> to NotPhantomData<U>)
|
||||
= note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData<T>` to `NotPhantomData<U>`)
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -110,9 +110,7 @@ fn check_assoc_const() {
|
|||
// A, B, C are resolved as inherent items, their traits don't need to be in scope
|
||||
C::A; //~ ERROR associated constant `A` is private
|
||||
//~^ ERROR the trait `assoc_const::C` cannot be made into an object
|
||||
//~| ERROR the trait bound `dyn assoc_const::C: assoc_const::A` is not satisfied
|
||||
C::B; // ERROR the trait `assoc_const::C` cannot be made into an object
|
||||
//~^ ERROR the trait bound `dyn assoc_const::C: assoc_const::B` is not satisfied
|
||||
C::C; // OK
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,30 +100,6 @@ error[E0624]: associated constant `A` is private
|
|||
LL | C::A; //~ ERROR associated constant `A` is private
|
||||
| ^^^^
|
||||
|
||||
error[E0277]: the trait bound `dyn assoc_const::C: assoc_const::A` is not satisfied
|
||||
--> $DIR/trait-item-privacy.rs:111:5
|
||||
|
|
||||
LL | C::A; //~ ERROR associated constant `A` is private
|
||||
| ^^^^ the trait `assoc_const::A` is not implemented for `dyn assoc_const::C`
|
||||
|
|
||||
note: required by `assoc_const::A::A`
|
||||
--> $DIR/trait-item-privacy.rs:35:9
|
||||
|
|
||||
LL | const A: u8 = 0;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `dyn assoc_const::C: assoc_const::B` is not satisfied
|
||||
--> $DIR/trait-item-privacy.rs:114:5
|
||||
|
|
||||
LL | C::B; // ERROR the trait `assoc_const::C` cannot be made into an object
|
||||
| ^^^^ the trait `assoc_const::B` is not implemented for `dyn assoc_const::C`
|
||||
|
|
||||
note: required by `assoc_const::B::B`
|
||||
--> $DIR/trait-item-privacy.rs:39:9
|
||||
|
|
||||
LL | const B: u8 = 0;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0038]: the trait `assoc_const::C` cannot be made into an object
|
||||
--> $DIR/trait-item-privacy.rs:111:5
|
||||
|
|
||||
|
|
@ -135,36 +111,36 @@ LL | C::A; //~ ERROR associated constant `A` is private
|
|||
= note: the trait cannot contain associated consts like `A`
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/trait-item-privacy.rs:127:12
|
||||
--> $DIR/trait-item-privacy.rs:125:12
|
||||
|
|
||||
LL | let _: S::A; //~ ERROR ambiguous associated type
|
||||
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::A`
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/trait-item-privacy.rs:128:12
|
||||
--> $DIR/trait-item-privacy.rs:126:12
|
||||
|
|
||||
LL | let _: S::B; //~ ERROR ambiguous associated type
|
||||
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::B`
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/trait-item-privacy.rs:129:12
|
||||
--> $DIR/trait-item-privacy.rs:127:12
|
||||
|
|
||||
LL | let _: S::C; //~ ERROR ambiguous associated type
|
||||
| ^^^^ help: use fully-qualified syntax: `<S as Trait>::C`
|
||||
|
||||
error: associated type `A` is private
|
||||
--> $DIR/trait-item-privacy.rs:131:12
|
||||
--> $DIR/trait-item-privacy.rs:129:12
|
||||
|
|
||||
LL | let _: T::A; //~ ERROR associated type `A` is private
|
||||
| ^^^^
|
||||
|
||||
error: associated type `A` is private
|
||||
--> $DIR/trait-item-privacy.rs:140:9
|
||||
--> $DIR/trait-item-privacy.rs:138:9
|
||||
|
|
||||
LL | A = u8, //~ ERROR associated type `A` is private
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
Some errors occurred: E0038, E0223, E0277, E0599, E0624.
|
||||
Some errors occurred: E0038, E0223, E0599, E0624.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
||||
|
|
|
|||
|
|
@ -20,5 +20,4 @@ fn main() {
|
|||
(box 10 as Box<bar>).dup();
|
||||
//~^ ERROR E0038
|
||||
//~| ERROR E0038
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,6 @@ error[E0107]: wrong number of type arguments: expected 1, found 2
|
|||
LL | 10.blah::<i32, i32>(); //~ ERROR wrong number of type arguments: expected 1, found 2
|
||||
| ^^^ unexpected type argument
|
||||
|
||||
error[E0277]: the trait bound `dyn bar: bar` is not satisfied
|
||||
--> $DIR/trait-test-2.rs:20:26
|
||||
|
|
||||
LL | (box 10 as Box<bar>).dup();
|
||||
| ^^^ the trait `bar` is not implemented for `dyn bar`
|
||||
|
||||
error[E0038]: the trait `bar` cannot be made into an object
|
||||
--> $DIR/trait-test-2.rs:20:16
|
||||
|
|
||||
|
|
@ -35,7 +29,7 @@ LL | (box 10 as Box<bar>).dup();
|
|||
= note: method `blah` has generic type parameters
|
||||
= note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn bar>>` for `std::boxed::Box<{integer}>`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors occurred: E0038, E0107, E0277.
|
||||
Some errors occurred: E0038, E0107.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue