Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for nested receivers. #724

Merged
merged 3 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 17 additions & 11 deletions src/items/associated-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,28 @@ Associated functions whose first parameter is named `self` are called *methods*
and may be invoked using the [method call operator], for example, `x.foo()`, as
well as the usual function call notation.

If the type of the `self` parameter is specified, it is limited to one of the
following types:
If the type of the `self` parameter is specified, it is limited to semantic
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's a "semantic type"? In the PL research community this has a very specific meaning (which you can read about e.g. in this paper), but I doubt that is what you mean.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it's not the "semantic type system" notion in PL research. Rather, this means to say that the Self here is not meant literally (as in those characters making up Self). So it could be a type alias to e.g. Rc<TheImplementingType>. Ideas for a better wording?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"unfolded type"? "fully expanded type"? "resolved type"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"resolved type" seems good.

types generated by the following grammar (where `'lt` denotes some arbitrary
lifetime):

- `Self`
- `&Self`
- `&mut Self`
- [`Box<Self>`]
- [`Rc<Self>`]
- [`Arc<Self>`]
- [`Pin<P>`] where `P` is one of the above types except `Self`.
```text
P = &'lt S | &'lt mut S | Box<S> | Rc<S> | Arc<S> | Pin<P>
S = Self | P
```

The `Self` term can be replaced with the type being implemented.
The `Self` terminal in this grammar is the semantic `Self` type and can be
replaced with the type being implemented, including type aliases or associated
type projections for the type.

```rust
# use std::rc::Rc;
# use std::sync::Arc;
# use std::pin::Pin;
// Examples of methods implemented on struct `Example`.
struct Example;
type Alias = Example;
Centril marked this conversation as resolved.
Show resolved Hide resolved
trait Trait { type Output; }
impl Trait for Example { type Output = Example; }
impl Example {
fn by_value(self: Self) {}
fn by_ref(self: &Self) {}
Expand All @@ -126,6 +130,8 @@ impl Example {
fn by_pin(self: Pin<&Self>) {}
fn explicit_type(self: Arc<Example>) {}
fn with_lifetime<'a>(self: &'a Self) {}
fn nested<'a>(self: &mut &'a Arc<Rc<Box<Alias>>>) {}
Centril marked this conversation as resolved.
Show resolved Hide resolved
fn via_projection(self: <Example as Trait>::Output) {}
}
```

Expand Down Expand Up @@ -360,4 +366,4 @@ fn main() {
[function item]: ../types/function-item.md
[method call operator]: ../expressions/method-call-expr.md
[path]: ../paths.md
[regular function parameters]: functions.md#attributes-on-function-parameters
[regular function parameters]: functions.md#attributes-on-function-parameters
96 changes: 96 additions & 0 deletions src/items/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,98 @@ Object safe traits can be the base trait of a [trait object]. A trait is
* It must not have any associated constants.
* All supertraits must also be object safe.

When there isn't a `Self: Sized` bound on a method, the type of a method
receiver must be one of the following types:

* `&Self`
* `&mut Self`
* [`Box<Self>`]
* [`Rc<Self>`]
* [`Arc<Self>`]
* [`Pin<P>`] where `P` is one of the types above

```rust
# use std::rc::Rc;
# use std::sync::Arc;
# use std::pin::Pin;
// Examples of object safe methods.
trait TraitMethods {
fn by_ref(self: &Self) {}
fn by_ref_mut(self: &mut Self) {}
fn by_box(self: Box<Self>) {}
fn by_rc(self: Rc<Self>) {}
fn by_arc(self: Arc<Self>) {}
fn by_pin(self: Pin<&Self>) {}
fn with_lifetime<'a>(self: &'a Self) {}
fn nested_pin(self: Pin<Arc<Self>>) {}
}
# struct S;
# impl TraitMethods for S {}
# let t: Box<dyn TraitMethods> = Box::new(S);
```

```rust,compile_fail
// This trait is object-safe, but these methods cannot be dispatched on a trait object.
trait NonDispatchable {
// Non-methods cannot be dispatched.
fn foo() where Self: Sized {}
// Self type isn't known until runtime.
fn returns(&self) -> Self where Self: Sized;
// `other` may be a different concrete type of the receiver.
fn param(&self, other: Self) where Self: Sized {}
ehuss marked this conversation as resolved.
Show resolved Hide resolved
// Generics are not compatible with vtables.
fn typed<T>(&self, x: T) where Self: Sized {}
}

struct S;
impl NonDispatchable for S {
fn returns(&self) -> Self where Self: Sized { S }
}
let obj: Box<dyn NonDispatchable> = Box::new(S);
obj.returns(); // ERROR: cannot call with Self return
obj.param(S); // ERROR: cannot call with Self parameter
obj.typed(1); // ERROR: cannot call with generic type
```

```rust,compile_fail
# use std::rc::Rc;
// Examples of non-object safe traits.
trait NotObjectSafe {
const CONST: i32 = 1; // ERROR: cannot have associated const

fn foo() {} // ERROR: associated function without Sized
fn returns(&self) -> Self; // ERROR: Self in return type
fn typed<T>(&self, x: T) {} // ERROR: has generic type parameters
fn nested(self: Rc<Box<Self>>) {} // ERROR: nested receiver not yet supported
}

struct S;
impl NotObjectSafe for S {
fn returns(&self) -> Self { S }
}
let obj: Box<dyn NotObjectSafe> = Box::new(S); // ERROR
```

```rust,compile_fail
// Self: Sized traits are not object-safe.
trait TraitWithSize where Self: Sized {}

struct S;
impl TraitWithSize for S {}
let obj: Box<dyn TraitWithSize> = Box::new(S); // ERROR
```

```rust,compile_fail
// Not object safe if `Self` is a type argument.
trait Super<A> {}
trait WithSelf: Super<Self> where Self: Sized {}

struct S;
impl<A> Super<A> for S {}
impl WithSelf for S {}
let obj: Box<dyn WithSelf> = Box::new(S); // ERROR: cannot use `Self` type parameter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how this falls out of the rules listed above. Is this an extra rule, or some combination I am not understanding?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like Niko hasn't had time to address this. Let's file an issue for now and then Niko can follow up on that one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, I wasn't expecting to fix it in this PR, I was just a little confused.

Filed #756.

```

## Supertraits

**Supertraits** are traits that are required to be implemented for a type to
Expand Down Expand Up @@ -268,3 +360,7 @@ fn main() {
[trait implementation]: implementations.md#trait-implementations
[`Send`]: ../special-types-and-traits.md#send
[`Sync`]: ../special-types-and-traits.md#sync
[`Arc<Self>`]: ../special-types-and-traits.md#arct
[`Box<Self>`]: ../special-types-and-traits.md#boxt
[`Pin<P>`]: ../special-types-and-traits.md#pinp
[`Rc<Self>`]: ../special-types-and-traits.md#rct