Skip to content

Commit 3971c3c

Browse files
committed
Auto merge of rust-lang#132961 - adetaylor:arbitrary-self-types-the-big-bit, r=<try>
Arbitrary self types v2: main compiler changes This is the main PR in a series of PRs related to Arbitrary Self Types v2, tracked in rust-lang#44874. Specifically this is step 7 of the plan [described here](rust-lang#44874 (comment)), for [RFC 3519](rust-lang/rfcs#3519). Overall this PR: * Switches from the `Deref` trait to the new `Receiver` trait when the unstable `arbitrary_self_types` feature is enabled (the simple bit) * Introduces new algorithms to spot "shadowing"; that is, the case where a newly-added method in an outer smart pointer might end up overriding a pre-existing method in the pointee (the complex bit). Most of this bit was explored in [this earlier perf-testing PR](rust-lang#127812 (comment)). * Lots of tests This should not break compatibility for: * Stable users, where it should have no effect * Users of the existing `arbitrary_self_types` feature (because we implement `Receiver` for `T: Deref`) _unless_ those folks have added methods which may shadow methods in inner types, which we no longer want to allow Subsequent PRs will add better diagnostics. It's probably easiest to review this commit-by-commit. r? `@wesleywiser`
2 parents 42b4b9c + 560a529 commit 3971c3c

File tree

50 files changed

+1737
-196
lines changed

Some content is hidden

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

50 files changed

+1737
-196
lines changed

compiler/rustc_error_codes/src/error_codes/E0307.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,10 @@ impl Trait for Foo {
6565
```
6666

6767
The nightly feature [Arbitrary self types][AST] extends the accepted
68-
set of receiver types to also include any type that can dereference to
69-
`Self`:
68+
set of receiver types to also include any type that implements the
69+
`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.
7072

7173
```
7274
#![feature(arbitrary_self_types)]

compiler/rustc_hir_analysis/messages.ftl

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,10 @@ hir_analysis_invalid_generic_receiver_ty_help =
241241
use a concrete type such as `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`)
242242
243243
hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}`
244-
.note = type of `self` must be `Self` or a type that dereferences to it
244+
.note = type of `self` must be `Self` or some type implementing Receiver
245245
246246
hir_analysis_invalid_receiver_ty_help =
247-
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`)
247+
consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
248248
249249
hir_analysis_invalid_union_field =
250250
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union

compiler/rustc_hir_analysis/src/autoderef.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ pub enum AutoderefKind {
1818
/// A type which must dispatch to a `Deref` implementation.
1919
Overloaded,
2020
}
21-
2221
struct AutoderefSnapshot<'tcx> {
2322
at_start: bool,
2423
reached_recursion_limit: bool,
@@ -27,6 +26,10 @@ struct AutoderefSnapshot<'tcx> {
2726
obligations: PredicateObligations<'tcx>,
2827
}
2928

29+
/// Recursively dereference a type, considering both built-in
30+
/// dereferences (`*`) and the `Deref` trait.
31+
/// Although called `Autoderef` it can be configured to use the
32+
/// `Receiver` trait instead of the `Deref` trait.
3033
pub struct Autoderef<'a, 'tcx> {
3134
// Meta infos:
3235
infcx: &'a InferCtxt<'tcx>,
@@ -39,6 +42,7 @@ pub struct Autoderef<'a, 'tcx> {
3942

4043
// Configurations:
4144
include_raw_pointers: bool,
45+
use_receiver_trait: bool,
4246
silence_errors: bool,
4347
}
4448

@@ -69,6 +73,10 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
6973
}
7074

7175
// Otherwise, deref if type is derefable:
76+
// NOTE: in the case of self.use_receiver_trait = true, you might think it would
77+
// be better to skip this clause and use the Overloaded case only, since &T
78+
// and &mut T implement Receiver. But built-in derefs apply equally to Receiver
79+
// and Deref, and this has benefits for const and the emitted MIR.
7280
let (kind, new_ty) =
7381
if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
7482
debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
@@ -111,7 +119,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
111119
body_def_id: LocalDefId,
112120
span: Span,
113121
base_ty: Ty<'tcx>,
114-
) -> Autoderef<'a, 'tcx> {
122+
) -> Self {
115123
Autoderef {
116124
infcx,
117125
span,
@@ -125,6 +133,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
125133
reached_recursion_limit: false,
126134
},
127135
include_raw_pointers: false,
136+
use_receiver_trait: false,
128137
silence_errors: false,
129138
}
130139
}
@@ -137,8 +146,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
137146
return None;
138147
}
139148

140-
// <ty as Deref>
141-
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
149+
// <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk.
150+
let (trait_def_id, trait_target_def_id) = if self.use_receiver_trait {
151+
(tcx.lang_items().receiver_trait()?, tcx.lang_items().receiver_target()?)
152+
} else {
153+
(tcx.lang_items().deref_trait()?, tcx.lang_items().deref_target()?)
154+
};
155+
let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]);
142156
let cause = traits::ObligationCause::misc(self.span, self.body_id);
143157
let obligation = traits::Obligation::new(
144158
tcx,
@@ -151,11 +165,8 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
151165
return None;
152166
}
153167

154-
let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(
155-
tcx,
156-
tcx.lang_items().deref_target()?,
157-
[ty],
158-
))?;
168+
let (normalized_ty, obligations) =
169+
self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
159170
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
160171
self.state.obligations.extend(obligations);
161172

@@ -234,6 +245,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
234245
self
235246
}
236247

248+
/// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as
249+
/// the trait and associated type to iterate, instead of
250+
/// `core::ops::Deref` and `core::ops::Deref::Target`
251+
pub fn use_receiver_trait(mut self) -> Self {
252+
self.use_receiver_trait = true;
253+
self
254+
}
255+
237256
pub fn silence_errors(mut self) -> Self {
238257
self.silence_errors = true;
239258
self

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -1808,13 +1808,18 @@ fn receiver_is_valid<'tcx>(
18081808

18091809
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
18101810

1811+
// The `arbitrary_self_types` feature allows custom smart pointer
1812+
// types to be method receivers, as identified by following the Receiver<Target=T>
1813+
// chain.
1814+
if arbitrary_self_types_enabled.is_some() {
1815+
autoderef = autoderef.use_receiver_trait();
1816+
}
1817+
18111818
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
18121819
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
18131820
autoderef = autoderef.include_raw_pointers();
18141821
}
18151822

1816-
let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
1817-
18181823
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
18191824
while let Some((potential_self_ty, _)) = autoderef.next() {
18201825
debug!(
@@ -1836,11 +1841,13 @@ fn receiver_is_valid<'tcx>(
18361841
}
18371842

18381843
// Without `feature(arbitrary_self_types)`, we require that each step in the
1839-
// deref chain implement `receiver`.
1844+
// deref chain implement `LegacyReceiver`.
18401845
if arbitrary_self_types_enabled.is_none() {
1841-
if !receiver_is_implemented(
1846+
let legacy_receiver_trait_def_id =
1847+
tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
1848+
if !legacy_receiver_is_implemented(
18421849
wfcx,
1843-
receiver_trait_def_id,
1850+
legacy_receiver_trait_def_id,
18441851
cause.clone(),
18451852
potential_self_ty,
18461853
) {
@@ -1853,7 +1860,7 @@ fn receiver_is_valid<'tcx>(
18531860
cause.clone(),
18541861
wfcx.param_env,
18551862
potential_self_ty,
1856-
receiver_trait_def_id,
1863+
legacy_receiver_trait_def_id,
18571864
);
18581865
}
18591866
}
@@ -1862,22 +1869,22 @@ fn receiver_is_valid<'tcx>(
18621869
Err(ReceiverValidityError::DoesNotDeref)
18631870
}
18641871

1865-
fn receiver_is_implemented<'tcx>(
1872+
fn legacy_receiver_is_implemented<'tcx>(
18661873
wfcx: &WfCheckingCtxt<'_, 'tcx>,
1867-
receiver_trait_def_id: DefId,
1874+
legacy_receiver_trait_def_id: DefId,
18681875
cause: ObligationCause<'tcx>,
18691876
receiver_ty: Ty<'tcx>,
18701877
) -> bool {
18711878
let tcx = wfcx.tcx();
1872-
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
1879+
let trait_ref = ty::TraitRef::new(tcx, legacy_receiver_trait_def_id, [receiver_ty]);
18731880

18741881
let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
18751882

18761883
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
18771884
true
18781885
} else {
18791886
debug!(
1880-
"receiver_is_implemented: type `{:?}` does not implement `Receiver` trait",
1887+
"receiver_is_implemented: type `{:?}` does not implement `LegacyReceiver` trait",
18811888
receiver_ty
18821889
);
18831890
false

compiler/rustc_hir_typeck/src/demand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
917917
[candidate] => format!(
918918
"the method of the same name on {} `{}`",
919919
match candidate.kind {
920-
probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for",
920+
probe::CandidateKind::InherentImplCandidate { .. } => "the inherent impl for",
921921
_ => "trait",
922922
},
923923
self.tcx.def_path_str(candidate.item.container_id(self.tcx))

0 commit comments

Comments
 (0)