Row | Self | Case | Master | #61207 | Niko's take | notes |
---|---|---|---|---|---|---|
S1 | Foo |
fn(self: Pin<&mut Self>, f: &u8) -> &u8 |
f |
self |
+ | |
S2 | Foo |
fn(self: Pin<&mut Foo>, f: &u8) -> &u8 |
f |
self |
+ | |
S3 | Foo<'a> |
fn(self: Pin<&mut Self>, f: &u8) -> &u8 |
f |
self |
+ | |
S4 | Foo<'a> |
fn(self: Pin<&mut Foo>, f: &u8) -> &u8 |
f |
self |
+ | |
S5 | Foo<'a> |
fn(self: Self, f: &u8) -> &u8 |
f |
f |
? | lifetime inside self is ignored |
S6 | Foo<'a> |
fn(self: Foo<'a>, f: &u8) -> &u8 |
f |
f |
? | lifetime inside self is ignored |
S7 | Foo<'a> |
fn(self: Box<Foo<'a>>, f: &u8) -> &u8 |
f |
f |
? | lifetime inside self is ignored |
S8 | Foo<'a> |
fn(self: Box<Foo>, f: &u8) -> &u8 |
X | X | ||
S9 | Foo |
fn(self: &Alias, f: &u8) -> &u8 |
f |
f |
? | Alias is not recognized as self here |
N1 | Foo<'a> |
fn(self: Box<&Self>, f: &u8) -> &u8 |
f |
self |
+ | |
N2 | Foo<'a> |
fn(self: Box<Box<&Self>>, f: &u8) -> &u8 |
f |
self |
+ | |
N3 | Foo<'a> |
fn(self: Box<Pin<&Self>>, f: &u8) -> &u8 |
f |
self |
+ |
- Sn -- works on stable
- Nn -- works on nightly
+
-- behavior improved?
-- behavior unchanged, but questionable- assume
type Alias = Foo
- Each elided lifetime in the parameters becomes a distinct lifetime parameter.
- If there is exactly one lifetime used in the parameters (elided or not), that lifetime is assigned to all elided output lifetimes.
- In a method signature:
- Stable: If the receiver has the semantic type
&'lt mut? Self
, then 'lt is assigned to all elided output lifetime parameters. - 61207: In the receiver, if all mentions of the semantic type
&'lt mut? Self
use a unique lifetime'lt
, then'lt
is assigned to all elided output lifetime parameters.
- Stable: If the receiver has the semantic type
Current behavior on stable (and under the PR) does not meet this specification. For example case S7 does not.
Further, we do not look for a "precise match" for the Self
type but rather we look for "some instance of the current struct/enum/union".
Niko's take: This spec itself may not be the thing we want, but obviously we have backwards compatibility concerns to consider as well, so we may simply want to introduce deprecations.
- Cases marked with
?
above are in violation of the rule as stated - Do we want a purely syntactic rule? (e.g., match
Self
but not other things equivalent toSelf
) - What about
fn foo<'a>(x: &'a self) -> &u32
? Can we deprecate this? (Elision expanding to a named lifetime) - What about
impl<'a> Foo<'a> { fn foo(&self) -> &u32 }
? In the past, people have complained about this. I'm inclined to keep it. -- Niko
The test for the "self" type is currently just checking if it is an instance of the same struct/enum/union that we are implementing on. This implies that in very strange cases like this one, you get ambiguity:
#![allow(dead_code)]
#![feature(arbitrary_self_types)]
use std::pin::Pin;
use std::ops::Deref;
struct Foo<T> { d: T }
struct Extra<A, B> {
data: (A, B)
}
impl<A, B> Deref for Extra<A, B> {
type Target = B;
fn deref(&self) -> &B {
panic!()
}
}
impl<T> Foo<T> {
fn and_self<'a, 'b>(self: Extra<&'a Foo<u32>, &'b Foo<T>>, a: &'a u8, b: &'b u8) -> &u8 {
a
}
}
fn main() {
}
convenience link to PR : rust-lang/rust#61207