Skip to content

Commit 915e7eb

Browse files
committed
Auto merge of rust-lang#132961 - adetaylor:arbitrary-self-types-the-big-bit, r=compiler-errors,wesleywiser
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 d4025ee + 337af8a commit 915e7eb

File tree

50 files changed

+1745
-198
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

+1745
-198
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
@@ -1821,13 +1821,18 @@ fn receiver_is_valid<'tcx>(
18211821

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

1824+
// The `arbitrary_self_types` feature allows custom smart pointer
1825+
// types to be method receivers, as identified by following the Receiver<Target=T>
1826+
// chain.
1827+
if arbitrary_self_types_enabled.is_some() {
1828+
autoderef = autoderef.use_receiver_trait();
1829+
}
1830+
18241831
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
18251832
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
18261833
autoderef = autoderef.include_raw_pointers();
18271834
}
18281835

1829-
let receiver_trait_def_id = tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
1830-
18311836
// Keep dereferencing `receiver_ty` until we get to `self_ty`.
18321837
while let Some((potential_self_ty, _)) = autoderef.next() {
18331838
debug!(
@@ -1849,11 +1854,13 @@ fn receiver_is_valid<'tcx>(
18491854
}
18501855

18511856
// Without `feature(arbitrary_self_types)`, we require that each step in the
1852-
// deref chain implement `receiver`.
1857+
// deref chain implement `LegacyReceiver`.
18531858
if arbitrary_self_types_enabled.is_none() {
1854-
if !receiver_is_implemented(
1859+
let legacy_receiver_trait_def_id =
1860+
tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
1861+
if !legacy_receiver_is_implemented(
18551862
wfcx,
1856-
receiver_trait_def_id,
1863+
legacy_receiver_trait_def_id,
18571864
cause.clone(),
18581865
potential_self_ty,
18591866
) {
@@ -1866,7 +1873,7 @@ fn receiver_is_valid<'tcx>(
18661873
cause.clone(),
18671874
wfcx.param_env,
18681875
potential_self_ty,
1869-
receiver_trait_def_id,
1876+
legacy_receiver_trait_def_id,
18701877
);
18711878
}
18721879
}
@@ -1875,22 +1882,22 @@ fn receiver_is_valid<'tcx>(
18751882
Err(ReceiverValidityError::DoesNotDeref)
18761883
}
18771884

1878-
fn receiver_is_implemented<'tcx>(
1885+
fn legacy_receiver_is_implemented<'tcx>(
18791886
wfcx: &WfCheckingCtxt<'_, 'tcx>,
1880-
receiver_trait_def_id: DefId,
1887+
legacy_receiver_trait_def_id: DefId,
18811888
cause: ObligationCause<'tcx>,
18821889
receiver_ty: Ty<'tcx>,
18831890
) -> bool {
18841891
let tcx = wfcx.tcx();
1885-
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
1892+
let trait_ref = ty::TraitRef::new(tcx, legacy_receiver_trait_def_id, [receiver_ty]);
18861893

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

18891896
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
18901897
true
18911898
} else {
18921899
debug!(
1893-
"receiver_is_implemented: type `{:?}` does not implement `Receiver` trait",
1900+
"receiver_is_implemented: type `{:?}` does not implement `LegacyReceiver` trait",
18941901
receiver_ty
18951902
);
18961903
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)