Skip to content

Commit 2304ec9

Browse files
enable experimentation with merged chains
1 parent 7c93ba8 commit 2304ec9

File tree

7 files changed

+149
-1
lines changed

7 files changed

+149
-1
lines changed

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,8 @@ declare_features! (
380380
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
381381
/// Allows inherent and trait methods with arbitrary self types.
382382
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
383+
/// Enforce agreement between `Receiver::Target` and `Deref::Target`
384+
(unstable, arbitrary_self_types_merge_chains, "1.23.0", Some(44874)),
383385
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
384386
(unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)),
385387
/// Allows #[cfg(...)] on inline assembly templates and operands.

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ 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+
152156
hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
153157
154158
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: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_trait_selection::traits::misc::{
2222
ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
2323
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
2424
};
25-
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
25+
use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCause, ObligationCtxt};
2626
use tracing::debug;
2727

2828
use crate::errors;
@@ -48,6 +48,7 @@ pub(super) fn check_trait<'tcx>(
4848
lang_items.coerce_pointee_validated_trait(),
4949
visit_implementation_of_coerce_pointee_validity,
5050
)?;
51+
checker.check(lang_items.receiver_trait(), visit_implementation_of_receiver)?;
5152
Ok(())
5253
}
5354

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

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,17 @@ pub(crate) struct CoercePointeeNoField {
11561156
pub span: Span,
11571157
}
11581158

1159+
#[derive(Diagnostic)]
1160+
#[diag(hir_analysis_deref_receiver_target_diverge)]
1161+
pub(crate) struct DerefReceiverTargetDiverge<'a> {
1162+
#[primary_span]
1163+
#[label]
1164+
#[note]
1165+
pub span: Span,
1166+
pub deref_ty: Ty<'a>,
1167+
pub recv_ty: Ty<'a>,
1168+
}
1169+
11591170
#[derive(Diagnostic)]
11601171
#[diag(hir_analysis_inherent_ty_outside_relevant, code = E0390)]
11611172
#[help]

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ symbols! {
463463
apx_target_feature,
464464
arbitrary_enum_discriminant,
465465
arbitrary_self_types,
466+
arbitrary_self_types_merge_chains,
466467
arbitrary_self_types_pointers,
467468
areg,
468469
args,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// gate-test-arbitrary_self_types_merge_chains
2+
3+
#![feature(arbitrary_self_types)]
4+
#![feature(arbitrary_self_types_merge_chains)]
5+
6+
use std::marker::PhantomData;
7+
use std::ops::{Deref, Receiver};
8+
9+
struct A;
10+
impl Deref for A {
11+
type Target = u8;
12+
fn deref(&self) -> &u8 {
13+
&0
14+
}
15+
}
16+
impl Receiver for A {
17+
//~^ ERROR `Deref::Target` does not agree with `Receiver::Target`
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+
type Target = Box<T>;
31+
}
32+
33+
struct C<'a, T>(&'a T);
34+
impl<'a, T> Deref for C<'a, T> {
35+
type Target = Self;
36+
fn deref(&self) -> &Self {
37+
self
38+
}
39+
}
40+
impl<'b, T> Receiver for C<'b, T> {
41+
type Target = Self; // OK
42+
}
43+
44+
struct D<T>(PhantomData<fn() -> T>);
45+
trait Trait {
46+
type Output;
47+
}
48+
impl<T: Trait<Output = T>> Deref for D<T> {
49+
type Target = T::Output;
50+
fn deref(&self) -> &T {
51+
unimplemented!()
52+
}
53+
}
54+
impl<T> Receiver for D<T> {
55+
type Target = T; // OK
56+
}
57+
58+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: `Deref::Target` does not agree with `Receiver::Target`
2+
--> $DIR/arbitrary-self-types-merge-chains.rs:16:1
3+
|
4+
LL | impl Receiver for A {
5+
| ^^^^^^^^^^^^^^^^^^^ `Deref::Target` is `u8` but `Receiver::Target` is `u32`
6+
|
7+
note: `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
8+
--> $DIR/arbitrary-self-types-merge-chains.rs:16:1
9+
|
10+
LL | impl Receiver for A {
11+
| ^^^^^^^^^^^^^^^^^^^
12+
13+
error: `Deref::Target` does not agree with `Receiver::Target`
14+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
15+
|
16+
LL | impl<'a, T> Receiver for B<'a, T> {
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Deref::Target` is `T` but `Receiver::Target` is `Box<T>`
18+
|
19+
note: `#![feature(arbitrary_self_types_merge_chains)]` rejects this kind of divergence
20+
--> $DIR/arbitrary-self-types-merge-chains.rs:28:1
21+
|
22+
LL | impl<'a, T> Receiver for B<'a, T> {
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error: aborting due to 2 previous errors
26+

0 commit comments

Comments
 (0)