rust-lang / reference

The Rust Reference
https://doc.rust-lang.org/nightly/reference/
Apache License 2.0
1.24k stars 488 forks source link

Rule around non-dispatchable functions doesn't match the compiler behavior #1247

Open upsuper opened 2 years ago

upsuper commented 2 years ago

In the Object Safety section, it says:

  • Explicitly non-dispatchable functions require:
    • Have a where Self: Sized bound (receiver type of Self (i.e. self) implies this).

This implies that if you have any associated function with receiver of self should be counted as non-dispatchable function. However, it is not the case. See the following code:

trait Foo {
    fn a(self);
    // fn b(self, x: &Self);
    // fn c(self) -> Self;
}

fn test() -> Box<dyn Foo> { todo!() }

Uncommenting b or c would make the code fail to compile, unless explicit where Self: Sized is added, but the rule in the reference indicates that having a receiver self already implies that bound exists.

Not sure whether it's something that should be fixed in the reference or the compiler.

bjorn3 commented 2 years ago

a is actually dispatchable when the unstable #![feature(unsized_fn_params)] is enabled.

upsuper commented 2 years ago

Sounds like the reference should remove "receiver type of Self (i.e. self) implies this", and possibly mention that while self in receiver doesn't violate object safety, unsized_fn_params is required to actually use it as dispatchable.

Havvy commented 2 years ago

Okay, looking into this way too long, I think I understand what the original author meant by the parenthetical. Specifically, having a bound of Self: Sized is implied by having the receiver be self because it is a requirement that the programmer specify that Self: Sized on the method or it won't compile.

I don't like parentheticals at all and would rather it be a note using the note notation explaining it similarly to how I just wrote it. Though not exactly; the word "implied" should not be used at all since it is confusing as evidence by this issue.

We also have a policy of discussing Rust as it currently exists. We don't talk about unstable features. So any fix for this issue should not mention them.

upsuper commented 2 years ago

Specifically, having a bound of Self: Sized is implied by having the receiver be self because it is a requirement that the programmer specify that Self: Sized on the method or it won't compile.

However, this is not true. As the example shows, fn a(self); compiles totally fine in stable Rust, so the logic is more consistent if we understand it as a dispatchable rather than a (implied or not) non-dispatchable.

Havvy commented 2 years ago

Oh, yeah. I tried fn a(self) {} and that failed asking to add the Sized bound. And I can even create a value of Box<dyn Foo> but I get errors if I try to call a on it. So yeah, the entire parenthetical can just be removed then.