Skip to content

Commit 0d42782

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`. This patch includes rewording of diagnostics.
1 parent 3f98535 commit 0d42782

66 files changed

Lines changed: 707 additions & 406 deletions

File tree

Some content is hidden

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

compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
44

55
use std::marker::Unsize;
6-
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn};
6+
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
77

88
struct Ptr<T: ?Sized>(Box<T>);
99

@@ -14,6 +14,9 @@ impl<T: ?Sized> Deref for Ptr<T> {
1414
&*self.0
1515
}
1616
}
17+
impl<T: ?Sized> Receiver for Ptr<T> {
18+
type Target = T;
19+
}
1720

1821
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
1922
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
@@ -27,6 +30,9 @@ impl<T: ?Sized> Deref for Wrapper<T> {
2730
&self.0
2831
}
2932
}
33+
impl<T: ?Sized> Receiver for Wrapper<T> {
34+
type Target = T;
35+
}
3036

3137
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
3238
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}

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: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::cell::RefCell;
2+
3+
use rustc_data_structures::unord::UnordMap;
14
use rustc_hir::limit::Limit;
25
use rustc_infer::infer::InferCtxt;
36
use rustc_infer::traits::PredicateObligations;
@@ -26,6 +29,39 @@ struct AutoderefSnapshot<'tcx> {
2629
obligations: PredicateObligations<'tcx>,
2730
}
2831

32+
#[derive(Debug, Default)]
33+
pub struct AutoderefCache<'tcx> {
34+
next_deref: RefCell<UnordMap<Ty<'tcx>, (Ty<'tcx>, PredicateObligations<'tcx>)>>,
35+
next_receiver: RefCell<UnordMap<Ty<'tcx>, (Ty<'tcx>, PredicateObligations<'tcx>)>>,
36+
}
37+
38+
impl<'tcx> AutoderefCache<'tcx> {
39+
pub fn get(
40+
&self,
41+
use_receiver: bool,
42+
ty: Ty<'tcx>,
43+
) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> {
44+
if use_receiver {
45+
self.next_receiver.borrow().get(&ty).cloned()
46+
} else {
47+
self.next_deref.borrow().get(&ty).cloned()
48+
}
49+
}
50+
pub fn cache(
51+
&self,
52+
use_receiver: bool,
53+
ty: Ty<'tcx>,
54+
next: Ty<'tcx>,
55+
predicates: PredicateObligations<'tcx>,
56+
) {
57+
if use_receiver {
58+
self.next_receiver.borrow_mut().insert(ty, (next, predicates));
59+
} else {
60+
self.next_deref.borrow_mut().insert(ty, (next, predicates));
61+
}
62+
}
63+
}
64+
2965
/// Recursively dereference a type, considering both built-in
3066
/// dereferences (`*`) and the `Deref` trait.
3167
/// Although called `Autoderef` it can be configured to use the
@@ -36,6 +72,7 @@ pub struct Autoderef<'a, 'tcx> {
3672
span: Span,
3773
body_id: LocalDefId,
3874
param_env: ty::ParamEnv<'tcx>,
75+
cache: Option<&'a AutoderefCache<'tcx>>,
3976

4077
// Current state:
4178
state: AutoderefSnapshot<'tcx>,
@@ -80,16 +117,19 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
80117
}
81118

82119
// 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.
120+
// NOTE: in the case of self.use_receiver_trait = true,
121+
// Autoderef works only with Receiver trait.
122+
// Caller is expecting us to expand the Receiver chain only.
87123
let (kind, new_ty) =
88124
if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
89125
debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
90126
// NOTE: we may still need to normalize the built-in deref in case
91127
// we have some type like `&<Ty as Trait>::Assoc`, since users of
92128
// autoderef expect this type to have been structurally normalized.
129+
// NOTE: even when we follow Receiver chain we still unwrap
130+
// references and pointers here, but this is only symbolic and
131+
// we are not going to really dereferences any references or pointers.
132+
// That happens when autoderef is chasing the Deref chain.
93133
if self.infcx.next_trait_solver()
94134
&& let ty::Alias(..) = ty.kind()
95135
{
@@ -122,13 +162,15 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
122162
impl<'a, 'tcx> Autoderef<'a, 'tcx> {
123163
pub fn new(
124164
infcx: &'a InferCtxt<'tcx>,
165+
cache: Option<&'a AutoderefCache<'tcx>>,
125166
param_env: ty::ParamEnv<'tcx>,
126167
body_def_id: LocalDefId,
127168
span: Span,
128169
base_ty: Ty<'tcx>,
129170
) -> Self {
130171
Autoderef {
131172
infcx,
173+
cache,
132174
span,
133175
body_id: body_def_id,
134176
param_env,
@@ -145,13 +187,19 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
145187
}
146188
}
147189

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

152194
if ty.references_error() {
153195
return None;
154196
}
197+
if let Some(cache) = &self.cache
198+
&& let Some((ty, obligations)) = cache.get(self.use_receiver_trait, self.state.cur_ty)
199+
{
200+
self.state.obligations.extend(obligations);
201+
return Some(ty);
202+
}
155203

156204
// <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk.
157205
let (trait_def_id, trait_target_def_id) = if self.use_receiver_trait {
@@ -167,18 +215,23 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
167215
self.param_env,
168216
ty::Binder::dummy(trait_ref),
169217
);
170-
// We detect whether the self type implements `Deref` before trying to
218+
// We detect whether the self type implements `Deref`/`Receiver` before trying to
171219
// structurally normalize. We use `predicate_may_hold_opaque_types_jank`
172220
// to support not-yet-defined opaque types. It will succeed for `impl Deref`
173221
// but fail for `impl OtherTrait`.
174222
if !self.infcx.predicate_may_hold_opaque_types_jank(&obligation) {
175-
debug!("overloaded_deref_ty: cannot match obligation");
223+
debug!("cannot match obligation");
176224
return None;
177225
}
178226

179227
let (normalized_ty, obligations) =
180228
self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
181-
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
229+
debug!(?ty, ?normalized_ty, ?obligations);
230+
if matches!(ty.kind(), ty::Adt(..))
231+
&& let Some(cache) = &self.cache
232+
{
233+
cache.cache(self.use_receiver_trait, ty, normalized_ty, obligations.clone());
234+
}
182235
self.state.obligations.extend(obligations);
183236

184237
Some(self.infcx.resolve_vars_if_possible(normalized_ty))
@@ -255,11 +308,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
255308
/// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as
256309
/// the trait and associated type to iterate, instead of
257310
/// `core::ops::Deref` and `core::ops::Deref::Target`
258-
pub fn use_receiver_trait(mut self) -> Self {
311+
pub fn follow_receiver_chain(mut self) -> Self {
259312
self.use_receiver_trait = true;
260313
self
261314
}
262-
263315
pub fn silence_errors(mut self) -> Self {
264316
self.silence_errors = true;
265317
self

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,9 @@ fn check_method_receiver<'tcx>(
17991799
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
18001800
{
18011801
match receiver_validity_err {
1802-
ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => {
1802+
ReceiverValidityError::DoesNotReceive
1803+
if arbitrary_self_types_level.is_some() =>
1804+
{
18031805
let hint = match receiver_ty
18041806
.builtin_deref(false)
18051807
.unwrap_or(receiver_ty)
@@ -1813,7 +1815,7 @@ fn check_method_receiver<'tcx>(
18131815

18141816
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint })
18151817
}
1816-
ReceiverValidityError::DoesNotDeref => {
1818+
ReceiverValidityError::DoesNotReceive => {
18171819
tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes {
18181820
span,
18191821
receiver_ty,
@@ -1835,7 +1837,7 @@ fn check_method_receiver<'tcx>(
18351837
enum ReceiverValidityError {
18361838
/// The self type does not get to the receiver type by following the
18371839
/// autoderef chain.
1838-
DoesNotDeref,
1840+
DoesNotReceive,
18391841
/// A type was found which is a method type parameter, and that's not allowed.
18401842
MethodGenericParamUsed,
18411843
}
@@ -1891,17 +1893,21 @@ fn receiver_is_valid<'tcx>(
18911893

18921894
confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?;
18931895

1894-
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
1896+
let cache = Default::default();
1897+
let mut autoderef =
1898+
Autoderef::new(infcx, Some(&cache), wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
18951899

18961900
// The `arbitrary_self_types` feature allows custom smart pointer
1897-
// types to be method receivers, as identified by following the Receiver<Target=T>
1901+
// types to be method receivers, as identified by following the Receiver<Target = T>
18981902
// chain.
18991903
if arbitrary_self_types_enabled.is_some() {
1900-
autoderef = autoderef.use_receiver_trait();
1904+
// We are in the wf check, so we would like to deref the references in the type head.
1905+
// However, we do not want to walk `Deref` chain.
1906+
autoderef = autoderef.follow_receiver_chain();
19011907
}
19021908

19031909
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
1904-
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
1910+
if matches!(arbitrary_self_types_enabled, Some(ArbitrarySelfTypesLevel::WithPointers)) {
19051911
autoderef = autoderef.include_raw_pointers();
19061912
}
19071913

@@ -1955,7 +1961,7 @@ fn receiver_is_valid<'tcx>(
19551961
}
19561962

19571963
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
1958-
Err(ReceiverValidityError::DoesNotDeref)
1964+
Err(ReceiverValidityError::DoesNotReceive)
19591965
}
19601966

19611967
fn legacy_receiver_is_implemented<'tcx>(

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1723,7 +1723,8 @@ pub(crate) enum InvalidReceiverTyHint {
17231723
#[diag("invalid `self` parameter type: `{$receiver_ty}`", code = E0307)]
17241724
#[note("type of `self` must be `Self` or a type that dereferences to it")]
17251725
#[help(
1726-
"consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)"
1726+
"consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` where P is one of the previous types except `Self`; \
1727+
alternatively, consider implement `Receiver` trait on the type of `self`, where applicable"
17271728
)]
17281729
pub(crate) struct InvalidReceiverTyNoArbitrarySelfTypes<'tcx> {
17291730
#[primary_span]

compiler/rustc_hir_typeck/src/autoderef.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use super::{FnCtxt, PlaceOp};
1515

1616
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1717
pub(crate) fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
18-
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
18+
Autoderef::new(self, None, self.param_env, self.body_id, span, base_ty)
1919
}
2020

2121
pub(crate) fn try_overloaded_deref(

compiler/rustc_hir_typeck/src/method/confirm.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::fmt::Debug;
2+
use std::marker::PhantomData;
23
use std::ops::Deref;
34

45
use rustc_hir as hir;
@@ -356,18 +357,37 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
356357
// yield an object-type (e.g., `&Object` or `Box<Object>`
357358
// etc).
358359

359-
let mut autoderef = self.fcx.autoderef(self.span, self_ty);
360+
let fcx = self.fcx;
361+
let span = self.span;
362+
let autoderef = fcx.autoderef(span, self_ty);
360363

361364
// We don't need to gate this behind arbitrary self types
362365
// per se, but it does make things a bit more gated.
363-
if self.tcx.features().arbitrary_self_types()
364-
|| self.tcx.features().arbitrary_self_types_pointers()
365-
{
366-
autoderef = autoderef.use_receiver_trait();
367-
}
366+
let follow_receiver_chain = self.tcx.features().arbitrary_self_types()
367+
|| self.tcx.features().arbitrary_self_types_pointers();
368368

369369
autoderef
370370
.include_raw_pointers()
371+
.flat_map(|(ty, derefs)| {
372+
enum EitherIter<A, B, C> {
373+
A(A, PhantomData<fn() -> C>),
374+
B(B),
375+
}
376+
impl<A: Iterator<Item = C>, B: Iterator<Item = C>, C> Iterator for EitherIter<A, B, C> {
377+
type Item = C;
378+
fn next(&mut self) -> Option<Self::Item> {
379+
match self {
380+
EitherIter::A(a, _) => a.next(),
381+
EitherIter::B(b) => b.next(),
382+
}
383+
}
384+
}
385+
if follow_receiver_chain {
386+
EitherIter::A(fcx.autoderef(span, ty).follow_receiver_chain(), PhantomData)
387+
} else {
388+
EitherIter::B([(ty, derefs)].into_iter())
389+
}
390+
})
371391
.find_map(|(ty, _)| match ty.kind() {
372392
ty::Dynamic(data, ..) => Some(closure(
373393
self,

0 commit comments

Comments
 (0)