Skip to content

Commit bee4e5b

Browse files
committed
rfc, self-in-typedefs: discuss the meaning of Self more
1 parent f9e6622 commit bee4e5b

File tree

1 file changed

+110
-4
lines changed

1 file changed

+110
-4
lines changed

text/0000-self-in-typedefs.md

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,12 @@ enum StackList<'a, T: 'a + InterestingTrait> {
386386

387387
[RFC 2102]: https://github.com/rust-lang/rfcs/pull/2102
388388

389-
## In relation to [RFC 2102]
389+
## In relation to [RFC 2102] and what `Self` refers to.
390390

391-
It should be noted that `Self` always refers to the top level type and not the
392-
inner unnamed `struct` or `union`. In other words:
393-
*Self always applies to the top level inside type definitions*.
391+
It should be noted that `Self` always refers to the top level type and not
392+
the inner unnamed `struct` or `union` because those are unnamed. Specifically,
393+
*Self always applies to the innermost nameable type*. In type definitions in
394+
particular, this is equivalent: *Self always applies to the top level type*.
394395

395396
## Error messages
396397

@@ -442,6 +443,111 @@ it removes exceptional cases especially in the users mental model.
442443
The rationale for this particular design is straightforward as it would be
443444
uneconomic, confusing, and inconsistent to use other keywords.
444445

446+
## The consistency of what `Self` refers to
447+
448+
As explained in the [reference-level explanation], we said that:
449+
> *Self always applies to the innermost nameable type*.
450+
451+
We arrive at this conclusion by examining a few different cases and what
452+
they have in common.
453+
454+
### Current Rust - Shadowing in `impl`s
455+
456+
First, let's take a look at shadowing in `impl`s.
457+
458+
```rust
459+
fn main() { Foo {}.foo(); }
460+
461+
#[derive(Debug)]
462+
struct Foo;
463+
464+
impl Foo {
465+
fn foo(&self) {
466+
// Prints "Foo", which is the innermost type.
467+
println!("{:?}", Self {});
468+
469+
#[derive(Debug)]
470+
struct Bar;
471+
472+
impl Bar {
473+
fn bar(&self) {
474+
// Prints "Bar", also the innermost type in this context.
475+
println!("{:?}", Self {});
476+
}
477+
}
478+
Bar {}.bar();
479+
}
480+
}
481+
```
482+
483+
Let's also consider trait impls instead of inherent impls:
484+
485+
```rust
486+
impl Trait for Foo {
487+
fn foo(&self) {
488+
impl Trait for Bar {
489+
// Self is shadowed here...
490+
}
491+
}
492+
}
493+
```
494+
495+
We see that the conclusion holds for both examples.
496+
497+
### In relation to [RFC 2102]
498+
499+
Let's consider a modified example from [RFC 2102]:
500+
501+
```rust
502+
#[repr(C)]
503+
struct S {
504+
a: u32,
505+
_: union {
506+
b: Box<Self>,
507+
c: f32,
508+
},
509+
d: u64,
510+
}
511+
```
512+
513+
In this example, the inner union is not nameable, and so `Self` refers to the
514+
only nameable introduced type `S`. Therefore, the conclusion holds.
515+
516+
### Type definitions inside `impl`s
517+
518+
If in the future we decide to permit type definitions inside `impl`s as in:
519+
520+
```rust
521+
impl Trait for Foo {
522+
struct Bar {
523+
head: u8,
524+
tail: Option<Box<Self>>,
525+
}
526+
}
527+
```
528+
529+
as sugar for:
530+
531+
```rust
532+
enum _Bar {
533+
head: u8,
534+
tail: Option<Box<Self>>,
535+
}
536+
impl Trait for Foo {
537+
type Bar = _Bar;
538+
}
539+
```
540+
541+
In the desugared example, we see that the only possible meaning of `Self` is
542+
that it refers to `_Bar` and not `Foo`. To be consistent with the desugared
543+
form, the sugared variant should have the same meaning and so `Self` refers
544+
to `Bar` there.
545+
546+
### Conclusion
547+
548+
We've now examined a few cases and seen that indeed, the meaning of `Self` is
549+
consistent in all of them as well as with what the meaning in in today's Rust.
550+
445551
## Doing nothing
446552

447553
One alternative to the changes proposed in this RFC is to simply not implement

0 commit comments

Comments
 (0)