Skip to content

Commit 32146f8

Browse files
arbitrary_self_types: split the Autoderef chain
Receiver chain has been an extension of Deref chain, but the consequence has been questioned as this would admit method signatures that are deemed dubious. It is also debatable that Receiver trait which determines applicable `Self` type should have anything to do with dereference operation in general. This patch separate the two traits and isolate their use in the language. This means that in method probing, we will chase down a Deref chain for an applicable type for the variable `self`, from which we additionally chase down a Receiver chain for an applicable `Self` type from a list of methods that accepts one of these possible types of `self`.
1 parent 99ca0ae commit 32146f8

File tree

52 files changed

+586
-365
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+586
-365
lines changed

compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
#![feature(rustc_attrs)]
55
#![allow(internal_features)]
66

7-
use std::{
8-
ops::{Deref, CoerceUnsized, DispatchFromDyn},
9-
marker::Unsize,
10-
};
7+
use std::marker::Unsize;
8+
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
119

1210
struct Ptr<T: ?Sized>(Box<T>);
1311

@@ -18,6 +16,9 @@ impl<T: ?Sized> Deref for Ptr<T> {
1816
&*self.0
1917
}
2018
}
19+
impl<T: ?Sized> Receiver for Ptr<T> {
20+
type Target = T;
21+
}
2122

2223
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
2324
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
@@ -31,11 +32,13 @@ impl<T: ?Sized> Deref for Wrapper<T> {
3132
&self.0
3233
}
3334
}
35+
impl<T: ?Sized> Receiver for Wrapper<T> {
36+
type Target = T;
37+
}
3438

3539
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
3640
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
3741

38-
3942
trait Trait {
4043
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
4144
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;

compiler/rustc_error_codes/src/error_codes/E0307.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,16 @@ impl Trait for Foo {
6767
The nightly feature [Arbitrary self types][AST] extends the accepted
6868
set of receiver types to also include any type that implements the
6969
`Receiver` trait and can follow its chain of `Target` types to `Self`.
70-
There's a blanket implementation of `Receiver` for `T: Deref`, so any
71-
type which dereferences to `Self` can be used.
7270

7371
```
7472
#![feature(arbitrary_self_types)]
7573
7674
struct Foo;
7775
struct Bar;
7876
79-
// Because you can dereference `Bar` into `Foo`...
80-
impl std::ops::Deref for Bar {
77+
// Because you can set `Bar` as method receiver for `Foo`...
78+
impl std::ops::Receiver for Bar {
8179
type Target = Foo;
82-
83-
fn deref(&self) -> &Foo {
84-
&Foo
85-
}
8680
}
8781
8882
impl Foo {

compiler/rustc_hir_analysis/src/autoderef.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,19 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
8080
}
8181

8282
// Otherwise, deref if type is derefable:
83-
// NOTE: in the case of self.use_receiver_trait = true, you might think it would
84-
// be better to skip this clause and use the Overloaded case only, since &T
85-
// and &mut T implement Receiver. But built-in derefs apply equally to Receiver
86-
// and Deref, and this has benefits for const and the emitted MIR.
83+
// NOTE: in the case of self.use_receiver_trait = true,
84+
// Autoderef works only with Receiver trait.
85+
// Caller is expecting us to expand the Receiver chain only.
8786
let (kind, new_ty) =
8887
if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
8988
debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
9089
// NOTE: we may still need to normalize the built-in deref in case
9190
// we have some type like `&<Ty as Trait>::Assoc`, since users of
9291
// autoderef expect this type to have been structurally normalized.
92+
// NOTE: even when we follow Receiver chain we still unwrap
93+
// references and pointers here, but this is only symbolic and
94+
// we are not going to really dereferences any references or pointers.
95+
// That happens when autoderef is chasing the Deref chain.
9396
if self.infcx.next_trait_solver()
9497
&& let ty::Alias(..) = ty.kind()
9598
{
@@ -145,8 +148,8 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
145148
}
146149
}
147150

151+
#[instrument(level = "debug", skip(self), ret)]
148152
fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
149-
debug!("overloaded_deref_ty({:?})", ty);
150153
let tcx = self.infcx.tcx;
151154

152155
if ty.references_error() {
@@ -172,13 +175,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
172175
// to support not-yet-defined opaque types. It will succeed for `impl Deref`
173176
// but fail for `impl OtherTrait`.
174177
if !self.infcx.predicate_may_hold_opaque_types_jank(&obligation) {
175-
debug!("overloaded_deref_ty: cannot match obligation");
178+
debug!("cannot match obligation");
176179
return None;
177180
}
178181

179182
let (normalized_ty, obligations) =
180183
self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
181-
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
184+
debug!(?ty, ?normalized_ty, ?obligations);
182185
self.state.obligations.extend(obligations);
183186

184187
Some(self.infcx.resolve_vars_if_possible(normalized_ty))
@@ -255,11 +258,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
255258
/// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as
256259
/// the trait and associated type to iterate, instead of
257260
/// `core::ops::Deref` and `core::ops::Deref::Target`
258-
pub fn use_receiver_trait(mut self) -> Self {
261+
pub fn follow_receiver_chain(mut self) -> Self {
259262
self.use_receiver_trait = true;
260263
self
261264
}
262-
263265
pub fn silence_errors(mut self) -> Self {
264266
self.silence_errors = true;
265267
self

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,7 +1722,9 @@ fn check_method_receiver<'tcx>(
17221722
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
17231723
{
17241724
match receiver_validity_err {
1725-
ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => {
1725+
ReceiverValidityError::DoesNotReceive
1726+
if arbitrary_self_types_level.is_some() =>
1727+
{
17261728
let hint = match receiver_ty
17271729
.builtin_deref(false)
17281730
.unwrap_or(receiver_ty)
@@ -1736,7 +1738,7 @@ fn check_method_receiver<'tcx>(
17361738

17371739
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint })
17381740
}
1739-
ReceiverValidityError::DoesNotDeref => {
1741+
ReceiverValidityError::DoesNotReceive => {
17401742
tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes {
17411743
span,
17421744
receiver_ty,
@@ -1758,7 +1760,7 @@ fn check_method_receiver<'tcx>(
17581760
enum ReceiverValidityError {
17591761
/// The self type does not get to the receiver type by following the
17601762
/// autoderef chain.
1761-
DoesNotDeref,
1763+
DoesNotReceive,
17621764
/// A type was found which is a method type parameter, and that's not allowed.
17631765
MethodGenericParamUsed,
17641766
}
@@ -1816,7 +1818,9 @@ fn receiver_is_valid<'tcx>(
18161818
// types to be method receivers, as identified by following the Receiver<Target=T>
18171819
// chain.
18181820
if arbitrary_self_types_enabled.is_some() {
1819-
autoderef = autoderef.use_receiver_trait();
1821+
// We are in the wf check, so we would like to deref the references in the type head.
1822+
// However, we do not want to walk `Deref` chain.
1823+
autoderef = autoderef.follow_receiver_chain();
18201824
}
18211825

18221826
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
@@ -1870,7 +1874,7 @@ fn receiver_is_valid<'tcx>(
18701874
}
18711875

18721876
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
1873-
Err(ReceiverValidityError::DoesNotDeref)
1877+
Err(ReceiverValidityError::DoesNotReceive)
18741878
}
18751879

18761880
fn legacy_receiver_is_implemented<'tcx>(

compiler/rustc_hir_typeck/src/method/confirm.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::marker::PhantomData;
12
use std::ops::Deref;
23

34
use rustc_hir as hir;
@@ -350,18 +351,37 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
350351
// yield an object-type (e.g., `&Object` or `Box<Object>`
351352
// etc).
352353

353-
let mut autoderef = self.fcx.autoderef(self.span, self_ty);
354+
let fcx = self.fcx;
355+
let span = self.span;
356+
let autoderef = fcx.autoderef(span, self_ty);
354357

355358
// We don't need to gate this behind arbitrary self types
356359
// per se, but it does make things a bit more gated.
357-
if self.tcx.features().arbitrary_self_types()
358-
|| self.tcx.features().arbitrary_self_types_pointers()
359-
{
360-
autoderef = autoderef.use_receiver_trait();
361-
}
360+
let follow_receiver_chain = self.tcx.features().arbitrary_self_types()
361+
|| self.tcx.features().arbitrary_self_types_pointers();
362362

363363
autoderef
364364
.include_raw_pointers()
365+
.flat_map(|(ty, derefs)| {
366+
enum EitherIter<A, B, C> {
367+
A(A, PhantomData<fn() -> C>),
368+
B(B, PhantomData<fn() -> C>),
369+
}
370+
impl<A: Iterator<Item = C>, B: Iterator<Item = C>, C> Iterator for EitherIter<A, B, C> {
371+
type Item = C;
372+
fn next(&mut self) -> Option<Self::Item> {
373+
match self {
374+
EitherIter::A(a, _) => a.next(),
375+
EitherIter::B(b, _) => b.next(),
376+
}
377+
}
378+
}
379+
if follow_receiver_chain {
380+
EitherIter::A(fcx.autoderef(span, ty).follow_receiver_chain(), PhantomData)
381+
} else {
382+
EitherIter::B([(ty, derefs)].into_iter(), PhantomData)
383+
}
384+
})
365385
.find_map(|(ty, _)| match ty.kind() {
366386
ty::Dynamic(data, ..) => Some(closure(
367387
self,

0 commit comments

Comments
 (0)