Skip to content

Commit 4f716f1

Browse files
Enable experimentation with split/merged chains
To allow use of Receiver with Target diverging from Deref::Target, one must now enable an unstable feature flag arbitrary-self-types-split-chains. Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
1 parent c7aaca6 commit 4f716f1

8 files changed

Lines changed: 210 additions & 1 deletion

File tree

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ declare_features! (
351351
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
352352
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
353353
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
354+
/// Enforce agreement between `Receiver::Target` and `Deref::Target`
355+
(unstable, arbitrary_self_types_split_chains, "1.23.0", Some(44874)),
354356
/// Target features on arm.
355357
(unstable, arm_target_feature, "1.27.0", Some(150246)),
356358
/// Enables experimental inline assembly support for additional architectures.

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `
149149
hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate
150150
.label = can't implement cross-crate trait for type in another crate
151151
152+
hir_analysis_deref_receiver_target_diverge = `Deref::Target` does not agree with `Receiver::Target`
153+
.label = `Deref::Target` is `{$deref_ty}` but `Receiver::Target` is `{$recv_ty}`
154+
.note = `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
155+
hir_analysis_deref_receiver_target_diverge_feature = `Receiver::Target` diverging from `Deref::Target` is not supported, we look forward to your feedback
156+
152157
hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
153158
154159
hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else

compiler/rustc_hir_analysis/src/coherence/builtin.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ use rustc_middle::ty::print::PrintTraitRefExt as _;
1616
use rustc_middle::ty::{
1717
self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
1818
};
19+
use rustc_session::parse::feature_err;
1920
use rustc_span::{DUMMY_SP, Span, sym};
2021
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
2122
use rustc_trait_selection::traits::misc::{
2223
ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
2324
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
2425
};
25-
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
26+
use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCause, ObligationCtxt};
2627
use tracing::debug;
2728

2829
use crate::errors;
@@ -48,6 +49,7 @@ pub(super) fn check_trait<'tcx>(
4849
lang_items.coerce_pointee_validated_trait(),
4950
visit_implementation_of_coerce_pointee_validity,
5051
)?;
52+
checker.check(lang_items.receiver_trait(), visit_implementation_of_receiver)?;
5153
Ok(())
5254
}
5355

@@ -755,3 +757,55 @@ fn visit_implementation_of_coerce_pointee_validity(
755757
}
756758
Ok(())
757759
}
760+
761+
fn visit_implementation_of_receiver(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
762+
let tcx = checker.tcx;
763+
if tcx.features().arbitrary_self_types_split_chains() {
764+
return Ok(());
765+
}
766+
let impl_did = checker.impl_def_id;
767+
let span = tcx.def_span(impl_did);
768+
let deref_target_did = tcx.require_lang_item(LangItem::DerefTarget, span);
769+
let receiver_target_did = tcx.require_lang_item(LangItem::ReceiverTarget, span);
770+
let self_ty = tcx.impl_trait_ref(impl_did).instantiate_identity().self_ty();
771+
let param_env = tcx.param_env(impl_did);
772+
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
773+
let ocx = ObligationCtxt::new(&infcx);
774+
let cause = ObligationCause::misc(span, impl_did);
775+
ocx.register_obligation(Obligation::new(
776+
tcx,
777+
cause.clone(),
778+
param_env,
779+
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Deref, span), [self_ty]),
780+
));
781+
if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
782+
// We cannot enforce Deref::Target == Receiver::Target because we cannot find `impl Deref`
783+
return Ok(());
784+
}
785+
let infer::InferOk { value: deref_target_ty, .. } = infcx.at(&cause, param_env).normalize(
786+
Ty::new_projection_from_args(tcx, deref_target_did, tcx.mk_args(&[self_ty.into()])),
787+
);
788+
let infer::InferOk { value: receiver_target_ty, .. } = infcx.at(&cause, param_env).normalize(
789+
Ty::new_projection_from_args(tcx, receiver_target_did, tcx.mk_args(&[self_ty.into()])),
790+
);
791+
if let Err(_) = infcx.at(&cause, param_env).eq(
792+
infer::DefineOpaqueTypes::No,
793+
deref_target_ty,
794+
receiver_target_ty,
795+
) {
796+
feature_err(
797+
tcx.sess,
798+
sym::arbitrary_self_types_split_chains,
799+
span,
800+
crate::fluent_generated::hir_analysis_deref_receiver_target_diverge_feature,
801+
)
802+
.emit();
803+
Err(tcx.dcx().emit_err(errors::DerefReceiverTargetDiverge {
804+
span,
805+
deref_ty: deref_target_ty,
806+
recv_ty: receiver_target_ty,
807+
}))
808+
} else {
809+
Ok(())
810+
}
811+
}

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,17 @@ pub(crate) struct CoercePointeeNoField {
10751075
pub span: Span,
10761076
}
10771077

1078+
#[derive(Diagnostic)]
1079+
#[diag(hir_analysis_deref_receiver_target_diverge)]
1080+
pub(crate) struct DerefReceiverTargetDiverge<'a> {
1081+
#[primary_span]
1082+
#[label]
1083+
#[note]
1084+
pub span: Span,
1085+
pub deref_ty: Ty<'a>,
1086+
pub recv_ty: Ty<'a>,
1087+
}
1088+
10781089
#[derive(Diagnostic)]
10791090
#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)]
10801091
#[help]

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ symbols! {
477477
arbitrary_enum_discriminant,
478478
arbitrary_self_types,
479479
arbitrary_self_types_pointers,
480+
arbitrary_self_types_split_chains,
480481
areg,
481482
args,
482483
arith_offset,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// gate-test-arbitrary_self_types_split_chains
2+
3+
#![feature(arbitrary_self_types)]
4+
5+
use std::marker::PhantomData;
6+
use std::ops::{Deref, Receiver};
7+
8+
struct A;
9+
impl Deref for A {
10+
type Target = u8;
11+
fn deref(&self) -> &u8 {
12+
&0
13+
}
14+
}
15+
impl Receiver for A {
16+
//~^ ERROR `Deref::Target` does not agree with `Receiver::Target`
17+
//~| ERROR `Receiver::Target` diverging from `Deref::Target` is not supported
18+
type Target = u32;
19+
}
20+
21+
struct B<'a, T>(&'a T);
22+
impl<'a, T> Deref for B<'a, T> {
23+
type Target = T;
24+
fn deref(&self) -> &T {
25+
&*self.0
26+
}
27+
}
28+
impl<'a, T> Receiver for B<'a, T> {
29+
//~^ ERROR `Deref::Target` does not agree with `Receiver::Target`
30+
//~| ERROR `Receiver::Target` diverging from `Deref::Target` is not supported
31+
type Target = Box<T>;
32+
}
33+
34+
struct C<'a, T>(&'a T);
35+
impl<'a, T> Deref for C<'a, T> {
36+
type Target = Self;
37+
fn deref(&self) -> &Self {
38+
self
39+
}
40+
}
41+
impl<'b, T> Receiver for C<'b, T> {
42+
type Target = Self; // OK
43+
}
44+
45+
struct D<T>(PhantomData<fn() -> T>);
46+
trait Trait {
47+
type Output;
48+
}
49+
impl<T: Trait<Output = T>> Deref for D<T> {
50+
type Target = T::Output;
51+
fn deref(&self) -> &T {
52+
unimplemented!()
53+
}
54+
}
55+
impl<T> Receiver for D<T> {
56+
type Target = T; // OK
57+
}
58+
59+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0658]: `Receiver::Target` diverging from `Deref::Target` is not supported, we look forward to your feedback
2+
--> $DIR/arbitrary-self-types-merge-chains.rs:15:1
3+
|
4+
LL | impl Receiver for A {
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
8+
= help: add `#![feature(arbitrary_self_types_split_chains)]` to the crate attributes to enable
9+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10+
11+
error: `Deref::Target` does not agree with `Receiver::Target`
12+
--> $DIR/arbitrary-self-types-merge-chains.rs:15:1
13+
|
14+
LL | impl Receiver for A {
15+
| ^^^^^^^^^^^^^^^^^^^ `Deref::Target` is `u8` but `Receiver::Target` is `u32`
16+
|
17+
note: `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
18+
--> $DIR/arbitrary-self-types-merge-chains.rs:15:1
19+
|
20+
LL | impl Receiver for A {
21+
| ^^^^^^^^^^^^^^^^^^^
22+
23+
error[E0658]: `Receiver::Target` diverging from `Deref::Target` is not supported, we look forward to your feedback
24+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
25+
|
26+
LL | impl<'a, T> Receiver for B<'a, T> {
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
|
29+
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
30+
= help: add `#![feature(arbitrary_self_types_split_chains)]` to the crate attributes to enable
31+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
32+
33+
error: `Deref::Target` does not agree with `Receiver::Target`
34+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
35+
|
36+
LL | impl<'a, T> Receiver for B<'a, T> {
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Deref::Target` is `T` but `Receiver::Target` is `Box<T>`
38+
|
39+
note: `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
40+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
41+
|
42+
LL | impl<'a, T> Receiver for B<'a, T> {
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44+
45+
error: aborting due to 4 previous errors
46+
47+
For more information about this error, try `rustc --explain E0658`.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ check-pass
2+
3+
#![feature(arbitrary_self_types)]
4+
#![feature(arbitrary_self_types_split_chains)]
5+
6+
use std::ops::{Deref, Receiver};
7+
8+
struct A;
9+
impl Deref for A {
10+
type Target = u8;
11+
fn deref(&self) -> &u8 {
12+
&0
13+
}
14+
}
15+
impl Receiver for A {
16+
type Target = u32;
17+
}
18+
19+
struct B<'a, T>(&'a T);
20+
impl<'a, T> Deref for B<'a, T> {
21+
type Target = T;
22+
fn deref(&self) -> &T {
23+
&*self.0
24+
}
25+
}
26+
impl<'a, T> Receiver for B<'a, T> {
27+
type Target = Box<T>;
28+
}
29+
30+
fn main() {}

0 commit comments

Comments
 (0)