Skip to content

Commit 4067bd8

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 8b2dbc9 commit 4067bd8

7 files changed

Lines changed: 200 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
@@ -359,6 +359,8 @@ declare_features! (
359359
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
360360
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
361361
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
362+
/// Enforce agreement between `Receiver::Target` and `Deref::Target`
363+
(unstable, arbitrary_self_types_split_chains, "1.23.0", Some(44874)),
362364
/// Target features on arm.
363365
(unstable, arm_target_feature, "1.27.0", Some(150246)),
364366
/// Enables experimental inline assembly support for additional architectures.

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;
@@ -49,6 +50,7 @@ pub(super) fn check_trait<'tcx>(
4950
lang_items.coerce_pointee_validated_trait(),
5051
visit_implementation_of_coerce_pointee_validity,
5152
)?;
53+
checker.check(lang_items.receiver_trait(), visit_implementation_of_receiver)?;
5254
Ok(())
5355
}
5456

@@ -792,3 +794,55 @@ fn visit_implementation_of_coerce_pointee_validity(
792794
}
793795
Ok(())
794796
}
797+
798+
fn visit_implementation_of_receiver(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
799+
let tcx = checker.tcx;
800+
if tcx.features().arbitrary_self_types_split_chains() {
801+
return Ok(());
802+
}
803+
let impl_did = checker.impl_def_id;
804+
let span = tcx.def_span(impl_did);
805+
let deref_target_did = tcx.require_lang_item(LangItem::DerefTarget, span);
806+
let receiver_target_did = tcx.require_lang_item(LangItem::ReceiverTarget, span);
807+
let self_ty = tcx.impl_trait_ref(impl_did).instantiate_identity().self_ty();
808+
let param_env = tcx.param_env(impl_did);
809+
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
810+
let ocx = ObligationCtxt::new(&infcx);
811+
let cause = ObligationCause::misc(span, impl_did);
812+
ocx.register_obligation(Obligation::new(
813+
tcx,
814+
cause.clone(),
815+
param_env,
816+
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Deref, span), [self_ty]),
817+
));
818+
if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() {
819+
// We cannot enforce Deref::Target == Receiver::Target because we cannot find `impl Deref`
820+
return Ok(());
821+
}
822+
let infer::InferOk { value: deref_target_ty, .. } = infcx.at(&cause, param_env).normalize(
823+
Ty::new_projection_from_args(tcx, deref_target_did, tcx.mk_args(&[self_ty.into()])),
824+
);
825+
let infer::InferOk { value: receiver_target_ty, .. } = infcx.at(&cause, param_env).normalize(
826+
Ty::new_projection_from_args(tcx, receiver_target_did, tcx.mk_args(&[self_ty.into()])),
827+
);
828+
if let Err(_) = infcx.at(&cause, param_env).eq(
829+
infer::DefineOpaqueTypes::No,
830+
deref_target_ty,
831+
receiver_target_ty,
832+
) {
833+
feature_err(
834+
tcx.sess,
835+
sym::arbitrary_self_types_split_chains,
836+
span,
837+
"`Receiver::Target` diverging from `Deref::Target` is not supported; we look forward to your feedback",
838+
)
839+
.emit();
840+
Err(tcx.dcx().emit_err(errors::DerefReceiverTargetDiverge {
841+
span,
842+
deref_ty: deref_target_ty,
843+
recv_ty: receiver_target_ty,
844+
}))
845+
} else {
846+
Ok(())
847+
}
848+
}

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,17 @@ pub(crate) struct CoercePointeeNoField {
12161216
pub span: Span,
12171217
}
12181218

1219+
#[derive(Diagnostic)]
1220+
#[diag("`Deref::Target` does not agree with `Receiver::Target`", code = E0390)]
1221+
#[note("`Deref::Target` is `{$deref_ty}` but `Receiver::Target` is `{$recv_ty}`")]
1222+
#[note("`#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence")]
1223+
pub(crate) struct DerefReceiverTargetDiverge<'a> {
1224+
#[primary_span]
1225+
pub span: Span,
1226+
pub deref_ty: Ty<'a>,
1227+
pub recv_ty: Ty<'a>,
1228+
}
1229+
12191230
#[derive(Diagnostic)]
12201231
#[diag("cannot define inherent `impl` for a type outside of the crate where the type is defined", code = E0390)]
12211232
#[help("consider moving this inherent impl into the crate defining the type if possible")]

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ symbols! {
404404
arbitrary_enum_discriminant,
405405
arbitrary_self_types,
406406
arbitrary_self_types_pointers,
407+
arbitrary_self_types_split_chains,
407408
areg,
408409
args,
409410
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: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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[E0390]: `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+
| ^^^^^^^^^^^^^^^^^^^
16+
|
17+
= note: `Deref::Target` is `u8` but `Receiver::Target` is `u32`
18+
= note: `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
19+
20+
error[E0658]: `Receiver::Target` diverging from `Deref::Target` is not supported; we look forward to your feedback
21+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
22+
|
23+
LL | impl<'a, T> Receiver for B<'a, T> {
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
25+
|
26+
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
27+
= help: add `#![feature(arbitrary_self_types_split_chains)]` to the crate attributes to enable
28+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
29+
30+
error[E0390]: `Deref::Target` does not agree with `Receiver::Target`
31+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
32+
|
33+
LL | impl<'a, T> Receiver for B<'a, T> {
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
|
36+
= note: `Deref::Target` is `T` but `Receiver::Target` is `Box<T>`
37+
= note: `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
38+
39+
error: aborting due to 4 previous errors
40+
41+
Some errors have detailed explanations: E0390, E0658.
42+
For more information about an error, try `rustc --explain E0390`.
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)