Skip to content
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

Arbitrary self types v2: stabilize #135881

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
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};
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand Down
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)]

Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,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.
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -246,18 +246,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<...>`
Expand Down
147 changes: 22 additions & 125 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use rustc_trait_selection::traits::misc::{
ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,
};
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
WellFormedLoc,
Expand Down Expand Up @@ -1642,13 +1641,6 @@ fn check_fn_or_method<'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>,
Expand Down Expand Up @@ -1681,55 +1673,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(
Expand All @@ -1738,17 +1696,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)
Expand All @@ -1762,18 +1718,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(())
}
Expand Down Expand Up @@ -1817,11 +1767,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);

Expand All @@ -1836,17 +1785,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();
}

Expand All @@ -1869,58 +1812,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>,
Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1620,16 +1620,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]
Expand Down
21 changes: 3 additions & 18 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,24 +529,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();
}
}
}
Expand Down
Loading
Loading