Skip to content

Arbitrary self types v2: stabilize #135881

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
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Adapted from rustc run-pass test suite

#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
#![feature(unsize, coerce_unsized, dispatch_from_dyn)]

use std::marker::Unsize;
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn};
7 changes: 0 additions & 7 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
@@ -47,13 +47,6 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}

#[lang = "legacy_receiver"]
pub trait LegacyReceiver {}

impl<T: ?Sized> LegacyReceiver for &T {}
impl<T: ?Sized> LegacyReceiver for &mut T {}
impl<T: ?Sized> LegacyReceiver for Box<T> {}

#[lang = "copy"]
pub trait Copy {}

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Adapted from rustc run-pass test suite

#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
#![feature(unsize, coerce_unsized, dispatch_from_dyn)]
#![feature(rustc_attrs)]
#![allow(internal_features)]

7 changes: 0 additions & 7 deletions compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
@@ -44,13 +44,6 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}

#[lang = "legacy_receiver"]
pub trait LegacyReceiver {}

impl<T: ?Sized> LegacyReceiver for &T {}
impl<T: ?Sized> LegacyReceiver for &mut T {}
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}

#[lang = "copy"]
pub trait Copy {}

2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
@@ -60,6 +60,8 @@ declare_features! (
(accepted, adx_target_feature, "1.61.0", Some(44839)),
/// Allows explicit discriminants on non-unit enum variants.
(accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553)),
/// Allows inherent and trait methods with arbitrary self types.
(accepted, arbitrary_self_types, "CURRENT_RUSTC_VERSION", Some(44874)),
/// Allows using `const` operands in inline assembly.
(accepted, asm_const, "1.82.0", Some(93332)),
/// Allows using `sym` operands in inline assembly.
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
@@ -364,8 +364,6 @@ declare_features! (
(unstable, adt_const_params, "1.56.0", Some(95174)),
/// Allows defining an `#[alloc_error_handler]`.
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
/// Allows inherent and trait methods with arbitrary self types.
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
/// Enables experimental inline assembly support for additional architectures.
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
@@ -242,7 +242,6 @@ language_item_table! {
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
ReceiverTarget, sym::receiver_target, receiver_target, Target::AssocTy, GenericRequirement::None;
LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None;

Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
6 changes: 0 additions & 6 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
@@ -256,18 +256,12 @@ hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty
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`)

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`

hir_analysis_invalid_receiver_ty_help_weak_note =
`Weak` does not implement `Receiver` because it has methods that may shadow the referent; consider wrapping your `Weak` in a newtype wrapper for which you implement `Receiver`

hir_analysis_invalid_receiver_ty_no_arbitrary_self_types = invalid `self` parameter type: `{$receiver_ty}`
.note = type of `self` must be `Self` or a type that dereferences to it

hir_analysis_invalid_union_field =
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
.note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
147 changes: 22 additions & 125 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -29,7 +29,6 @@ use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuil
use rustc_trait_selection::traits::misc::{
ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,
};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
WellFormedLoc,
@@ -1698,13 +1697,6 @@ fn check_sized_if_body<'tcx>(
}
}

/// The `arbitrary_self_types_pointers` feature implies `arbitrary_self_types`.
#[derive(Clone, Copy, PartialEq)]
enum ArbitrarySelfTypesLevel {
Basic, // just arbitrary_self_types
WithPointers, // both arbitrary_self_types and arbitrary_self_types_pointers
}

#[instrument(level = "debug", skip(wfcx))]
fn check_method_receiver<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
@@ -1737,55 +1729,21 @@ fn check_method_receiver<'tcx>(
return Ok(());
}

let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers() {
Some(ArbitrarySelfTypesLevel::WithPointers)
} else if tcx.features().arbitrary_self_types() {
Some(ArbitrarySelfTypesLevel::Basic)
} else {
None
};
let generics = tcx.generics_of(method.def_id);

let receiver_validity =
receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics);
let arbitrary_self_types_pointers_enabled = tcx.features().arbitrary_self_types_pointers();
let receiver_validity = receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
arbitrary_self_types_pointers_enabled,
generics,
);
if let Err(receiver_validity_err) = receiver_validity {
return Err(match arbitrary_self_types_level {
// Wherever possible, emit a message advising folks that the features
// `arbitrary_self_types` or `arbitrary_self_types_pointers` might
// have helped.
None if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::Basic),
generics,
)
.is_ok() =>
{
// Report error; would have worked with `arbitrary_self_types`.
feature_err(
&tcx.sess,
sym::arbitrary_self_types,
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
None | Some(ArbitrarySelfTypesLevel::Basic)
if receiver_is_valid(
wfcx,
span,
receiver_ty,
self_ty,
Some(ArbitrarySelfTypesLevel::WithPointers),
generics,
)
.is_ok() =>
return Err(
if !arbitrary_self_types_pointers_enabled
&& receiver_is_valid(wfcx, span, receiver_ty, self_ty, true, generics).is_ok()
{
// Report error; would have worked with `arbitrary_self_types_pointers`.
feature_err(
@@ -1794,17 +1752,15 @@ fn check_method_receiver<'tcx>(
span,
format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types_pointers` feature",
the `arbitrary_self_types_pointers` feature",
),
)
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
.emit()
}
_ =>
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
{
} else {
// 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::DoesNotDeref => {
let hint = match receiver_ty
.builtin_deref(false)
.unwrap_or(receiver_ty)
@@ -1818,18 +1774,12 @@ fn check_method_receiver<'tcx>(

tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty, hint })
}
ReceiverValidityError::DoesNotDeref => {
tcx.dcx().emit_err(errors::InvalidReceiverTyNoArbitrarySelfTypes {
span,
receiver_ty,
})
}
ReceiverValidityError::MethodGenericParamUsed => {
tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty })
}
}
}
});
},
);
}
Ok(())
}
@@ -1873,11 +1823,10 @@ fn receiver_is_valid<'tcx>(
span: Span,
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
arbitrary_self_types_pointers_enabled: bool,
method_generics: &ty::Generics,
) -> Result<(), ReceiverValidityError> {
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
let cause =
ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver);

@@ -1892,17 +1841,11 @@ fn receiver_is_valid<'tcx>(

confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?;

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>
// chain.
if arbitrary_self_types_enabled.is_some() {
autoderef = autoderef.use_receiver_trait();
}
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty)
.use_receiver_trait();

// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
if arbitrary_self_types_pointers_enabled {
autoderef = autoderef.include_raw_pointers();
}

@@ -1925,58 +1868,12 @@ fn receiver_is_valid<'tcx>(
wfcx.register_obligations(autoderef.into_obligations());
return Ok(());
}

// Without `feature(arbitrary_self_types)`, we require that each step in the
// deref chain implement `LegacyReceiver`.
if arbitrary_self_types_enabled.is_none() {
let legacy_receiver_trait_def_id =
tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
if !legacy_receiver_is_implemented(
wfcx,
legacy_receiver_trait_def_id,
cause.clone(),
potential_self_ty,
) {
// We cannot proceed.
break;
}

// Register the bound, in case it has any region side-effects.
wfcx.register_bound(
cause.clone(),
wfcx.param_env,
potential_self_ty,
legacy_receiver_trait_def_id,
);
}
}

debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
Err(ReceiverValidityError::DoesNotDeref)
}

fn legacy_receiver_is_implemented<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
legacy_receiver_trait_def_id: DefId,
cause: ObligationCause<'tcx>,
receiver_ty: Ty<'tcx>,
) -> bool {
let tcx = wfcx.tcx();
let trait_ref = ty::TraitRef::new(tcx, legacy_receiver_trait_def_id, [receiver_ty]);

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

if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
true
} else {
debug!(
"receiver_is_implemented: type `{:?}` does not implement `LegacyReceiver` trait",
receiver_ty
);
false
}
}

fn check_variances_for_type_defn<'tcx>(
tcx: TyCtxt<'tcx>,
item: &'tcx hir::Item<'tcx>,
10 changes: 0 additions & 10 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1610,16 +1610,6 @@ pub(crate) enum InvalidReceiverTyHint {
NonNull,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_invalid_receiver_ty_no_arbitrary_self_types, code = E0307)]
#[note]
#[help(hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types)]
pub(crate) struct InvalidReceiverTyNoArbitrarySelfTypes<'tcx> {
#[primary_span]
pub span: Span,
pub receiver_ty: Ty<'tcx>,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_invalid_receiver_ty, code = E0307)]
#[note]
31 changes: 4 additions & 27 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
@@ -352,15 +352,7 @@ 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);

// 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 autoderef = self.fcx.autoderef(self.span, self_ty).use_receiver_trait();

autoderef
.include_raw_pointers()
@@ -540,24 +532,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.register_predicates(obligations);
}
Err(terr) => {
if self.tcx.features().arbitrary_self_types() {
self.err_ctxt()
.report_mismatched_types(
&cause,
self.param_env,
method_self_ty,
self_ty,
terr,
)
.emit();
} else {
// This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions
// may run before wfcheck if the function is used in const eval.
self.dcx().span_delayed_bug(
cause.span,
format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
);
}
self.err_ctxt()
.report_mismatched_types(&cause, self.param_env, method_self_ty, self_ty, terr)
.emit();
}
}
}
Loading