Arbitrary self types v2: simulated stabilization, do not merge by adetaylor · Pull Request #133570 · rust-lang/rust (original) (raw)

Expand Up

@@ -18,7 +18,6 @@ pub enum AutoderefKind {

/// A type which must dispatch to a `Deref` implementation.

Overloaded,

}

struct AutoderefSnapshot<'tcx> {

at_start: bool,

reached_recursion_limit: bool,

Expand All

@@ -27,6 +26,10 @@ struct AutoderefSnapshot<'tcx> {

obligations: PredicateObligations<'tcx>,

}

/// Recursively dereference a type, considering both built-in

/// dereferences (`*`) and the `Deref` trait.

/// Although called `Autoderef` it can be configured to use the

/// `Receiver` trait instead of the `Deref` trait.

pub struct Autoderef<'a, 'tcx> {

// Meta infos:

infcx: &'a InferCtxt<'tcx>,

Expand All

@@ -39,6 +42,7 @@ pub struct Autoderef<'a, 'tcx> {

// Configurations:

include_raw_pointers: bool,

use_receiver_trait: bool,

silence_errors: bool,

}

Expand Down Expand Up

@@ -69,6 +73,10 @@ 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.

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));

Expand Down Expand Up

@@ -111,7 +119,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {

body_def_id: LocalDefId,

span: Span,

base_ty: Ty<'tcx>,

) -> Autoderef<'a, 'tcx> {

) -> Self {

Autoderef {

infcx,

span,

Expand All

@@ -125,6 +133,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {

reached_recursion_limit: false,

},

include_raw_pointers: false,

use_receiver_trait: false,

silence_errors: false,

}

}

Expand All

@@ -137,8 +146,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {

return None;

}

//

let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);

// , or whatever the equivalent trait is that we've been asked to walk.

let (trait_def_id, trait_target_def_id) = if self.use_receiver_trait {

(tcx.lang_items().receiver_trait()?, tcx.lang_items().receiver_target()?)

} else {

(tcx.lang_items().deref_trait()?, tcx.lang_items().deref_target()?)

};

let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]);

let cause = traits::ObligationCause::misc(self.span, self.body_id);

let obligation = traits::Obligation::new(

tcx,

Expand All

@@ -151,11 +165,8 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {

return None;

}

let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(

tcx,

tcx.lang_items().deref_target()?,

[ty],

))?;

let (normalized_ty, obligations) =

self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?;

debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);

self.state.obligations.extend(obligations);

Expand Down Expand Up

@@ -234,6 +245,14 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {

self

}

/// 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 {

self.use_receiver_trait = true;

self

}

pub fn silence_errors(mut self) -> Self {

self.silence_errors = true;

self

Expand Down