Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Open
dingxiangfei2009 wants to merge 1 commit into rust-lang:master
base: master
Choose a base branch
Loading
from dingxiangfei2009:autoderef-split
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
#![feature(rustc_attrs)]
#![allow(internal_features)]

use std::{
ops::{Deref, CoerceUnsized, DispatchFromDyn},
marker::Unsize,
};
use std::marker::Unsize;
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};

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

Expand All @@ -18,6 +16,9 @@ impl<T: ?Sized> Deref for Ptr<T> {
&*self.0
}
}
impl<T: ?Sized> Receiver for Ptr<T> {
type Target = T;
}

impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
Expand All @@ -31,11 +32,13 @@ impl<T: ?Sized> Deref for Wrapper<T> {
&self.0
}
}
impl<T: ?Sized> Receiver for Wrapper<T> {
type Target = T;
}

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


trait Trait {
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
Expand Down
10 changes: 2 additions & 8 deletions compiler/rustc_error_codes/src/error_codes/E0307.md
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,16 @@ impl Trait for Foo {
The nightly feature [Arbitrary self types][AST] extends the accepted
set of receiver types to also include any type that implements the
`Receiver` trait and can follow its chain of `Target` types to `Self`.
There's a blanket implementation of `Receiver` for `T: Deref`, so any
type which dereferences to `Self` can be used.

```
#![feature(arbitrary_self_types)]
struct Foo;
struct Bar;
// Because you can dereference `Bar` into `Foo`...
impl std::ops::Deref for Bar {
// Because you can set `Bar` as method receiver for `Foo`...
impl std::ops::Receiver for Bar {
type Target = Foo;
fn deref(&self) -> &Foo {
&Foo
}
}
impl Foo {
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_hir_analysis/src/autoderef.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,19 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
}

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

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

if ty.references_error() {
Expand All @@ -161,13 +164,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
ty::Binder::dummy(trait_ref),
);
if !self.infcx.next_trait_solver() && !self.infcx.predicate_may_hold(&obligation) {
debug!("overloaded_deref_ty: cannot match obligation");
debug!("cannot match obligation");
return None;
}

let (normalized_ty, obligations) =
self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
debug!(?ty, ?normalized_ty, ?obligations);
self.state.obligations.extend(obligations);

Some(self.infcx.resolve_vars_if_possible(normalized_ty))
Expand Down Expand Up @@ -244,11 +247,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
/// Use `core::ops::Receiver` and `core::ops::Receiver::Target` as
/// the trait and associated type to iterate, instead of
/// `core::ops::Deref` and `core::ops::Deref::Target`
pub fn use_receiver_trait(mut self) -> Self {
pub fn follow_receiver_chain(mut self) -> Self {
self.use_receiver_trait = true;
self
}

pub fn silence_errors(mut self) -> Self {
self.silence_errors = true;
self
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -1734,7 +1734,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)
Expand All @@ -1748,7 +1750,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,
Expand All @@ -1770,7 +1772,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,
}
Expand Down Expand Up @@ -1828,7 +1830,9 @@ fn receiver_is_valid<'tcx>(
// 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();
}

// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
Expand Down Expand Up @@ -1882,7 +1886,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>(
Expand Down
32 changes: 26 additions & 6 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
View file Open in desktop
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;
Expand Down Expand Up @@ -352,18 +353,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>),
}
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)
} else {
EitherIter::B([(ty, derefs)].into_iter(), PhantomData)
}
})
.find_map(|(ty, _)| match ty.kind() {
ty::Dynamic(data, ..) => Some(closure(
self,
Expand Down
Loading
Loading

AltStyle によって変換されたページ (->オリジナル) /