-
Couldn't load subscription status.
- Fork 13.9k
arbitrary_self_types: Split the Autoderef chain #146095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -264,7 +264,8 @@ hir_analysis_invalid_receiver_ty_help = | |
| consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>` | ||
|
|
||
| hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types = | ||
| 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`) | ||
| 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`); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised by this change. I would expect to only change the diagnostic when the feature is not enabled |
||
| alternatively, consider implement `Receiver` trait on the type of `self`, where applicable | ||
|
|
||
| hir_analysis_invalid_receiver_ty_help_nonnull_note = | ||
| `NonNull` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `NonNull` in a newtype wrapper for which you implement `Receiver` | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1722,7 +1722,9 @@ fn check_method_receiver<'tcx>( | |
| // Report error; would not have worked with `arbitrary_self_types[_pointers]`. | ||
| { | ||
| match receiver_validity_err { | ||
| ReceiverValidityError::DoesNotDeref if arbitrary_self_types_level.is_some() => { | ||
| ReceiverValidityError::DoesNotReceive | ||
| if arbitrary_self_types_level.is_some() => | ||
| { | ||
| let hint = match receiver_ty | ||
| .builtin_deref(false) | ||
| .unwrap_or(receiver_ty) | ||
|
|
@@ -1736,7 +1738,7 @@ fn check_method_receiver<'tcx>( | |
|
|
||
| tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint }) | ||
| } | ||
| ReceiverValidityError::DoesNotDeref => { | ||
| ReceiverValidityError::DoesNotReceive => { | ||
| tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes { | ||
| span, | ||
| receiver_ty, | ||
|
|
@@ -1758,7 +1760,7 @@ fn check_method_receiver<'tcx>( | |
| enum ReceiverValidityError { | ||
| /// The self type does not get to the receiver type by following the | ||
| /// autoderef chain. | ||
| DoesNotDeref, | ||
| DoesNotReceive, | ||
| /// A type was found which is a method type parameter, and that's not allowed. | ||
| MethodGenericParamUsed, | ||
| } | ||
|
|
@@ -1817,14 +1819,16 @@ fn receiver_is_valid<'tcx>( | |
| let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); | ||
|
|
||
| // The `arbitrary_self_types` feature allows custom smart pointer | ||
| // types to be method receivers, as identified by following the Receiver<Target=T> | ||
| // types to be method receivers, as identified by following the Receiver<Target = T> | ||
| // chain. | ||
| if arbitrary_self_types_enabled.is_some() { | ||
| autoderef = autoderef.use_receiver_trait(); | ||
| // We are in the wf check, so we would like to deref the references in the type head. | ||
| // However, we do not want to walk `Deref` chain. | ||
| autoderef = autoderef.follow_receiver_chain(); | ||
|
Comment on lines
+1825
to
+1827
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious why that is here? But in |
||
| } | ||
|
|
||
| // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`. | ||
| if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) { | ||
| if matches!(arbitrary_self_types_enabled, Some(ArbitrarySelfTypesLevel::WithPointers)) { | ||
| autoderef = autoderef.include_raw_pointers(); | ||
| } | ||
|
|
||
|
|
@@ -1878,7 +1882,7 @@ fn receiver_is_valid<'tcx>( | |
| } | ||
|
|
||
| debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); | ||
| Err(ReceiverValidityError::DoesNotDeref) | ||
| Err(ReceiverValidityError::DoesNotReceive) | ||
| } | ||
|
|
||
| fn legacy_receiver_is_implemented<'tcx>( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| use std::marker::PhantomData; | ||
| use std::ops::Deref; | ||
|
|
||
| use rustc_hir as hir; | ||
|
|
@@ -350,18 +351,37 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { | |
| // yield an object-type (e.g., `&Object` or `Box<Object>` | ||
| // etc). | ||
|
|
||
| let mut autoderef = self.fcx.autoderef(self.span, self_ty); | ||
| let fcx = self.fcx; | ||
| let span = self.span; | ||
| let autoderef = fcx.autoderef(span, self_ty); | ||
|
|
||
| // We don't need to gate this behind arbitrary self types | ||
| // per se, but it does make things a bit more gated. | ||
| if self.tcx.features().arbitrary_self_types() | ||
| || self.tcx.features().arbitrary_self_types_pointers() | ||
| { | ||
| autoderef = autoderef.use_receiver_trait(); | ||
| } | ||
| let follow_receiver_chain = self.tcx.features().arbitrary_self_types() | ||
| || self.tcx.features().arbitrary_self_types_pointers(); | ||
|
|
||
| autoderef | ||
| .include_raw_pointers() | ||
| .flat_map(|(ty, derefs)| { | ||
| enum EitherIter<A, B, C> { | ||
| A(A, PhantomData<fn() -> C>), | ||
| B(B, PhantomData<fn() -> C>), | ||
|
Comment on lines
+367
to
+368
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the extra |
||
| } | ||
| impl<A: Iterator<Item = C>, B: Iterator<Item = C>, C> Iterator for EitherIter<A, B, C> { | ||
| type Item = C; | ||
| fn next(&mut self) -> Option<Self::Item> { | ||
| match self { | ||
| EitherIter::A(a, _) => a.next(), | ||
| EitherIter::B(b, _) => b.next(), | ||
| } | ||
| } | ||
| } | ||
| if follow_receiver_chain { | ||
| EitherIter::A(fcx.autoderef(span, ty).follow_receiver_chain(), PhantomData) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, so if I'm understanding this correctly, for each step in I would really like to evaluate perf before and after this PR (when enabling arbitrary self types). |
||
| } else { | ||
| EitherIter::B([(ty, derefs)].into_iter(), PhantomData) | ||
| } | ||
| }) | ||
| .find_map(|(ty, _)| match ty.kind() { | ||
| ty::Dynamic(data, ..) => Some(closure( | ||
| self, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these impls required? I imagine this might be a consequence of my comment in
wfcheck?