Skip to content

Commit d190c3f

Browse files
Skip PhantomData in Unsize checks
This patch proposes relaxation on the type unsizing condition. `PhantomData` has been in the current type system exempted from being treated as carrying any data, including dropck, virtual call dispatch by `DispatchFromDyn` and unsizing container by `CoerceUnsize`. `PhantomData` is a special 1-ZST that really carries no "data" of the types it captures. I propose that we should also extend this interpretation to `Unsize`. Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
1 parent a2bc948 commit d190c3f

6 files changed

Lines changed: 83 additions & 9 deletions

File tree

compiler/rustc_traits/src/normalize_erasing_regions.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_middle::traits::query::NoSolution;
44
use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeFoldable, TypeVisitableExt};
55
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
66
use rustc_trait_selection::traits::{Normalized, ObligationCause};
7-
use tracing::debug;
7+
use tracing::{debug, instrument};
88

99
pub(crate) fn provide(p: &mut Providers) {
1010
*p = Providers {
@@ -17,6 +17,7 @@ pub(crate) fn provide(p: &mut Providers) {
1717
};
1818
}
1919

20+
#[instrument(level = "debug", skip(tcx))]
2021
fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy>(
2122
tcx: TyCtxt<'tcx>,
2223
goal: PseudoCanonicalInput<'tcx, T>,

compiler/rustc_ty_utils/src/ty.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ use rustc_infer::infer::TyCtxtInferExt;
66
use rustc_middle::bug;
77
use rustc_middle::query::Providers;
88
use rustc_middle::ty::{
9-
self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
10-
fold_regions,
9+
self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingEnv,
10+
Upcast, fold_regions,
1111
};
1212
use rustc_span::DUMMY_SP;
1313
use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
1414
use rustc_trait_selection::traits;
15-
use tracing::instrument;
15+
use tracing::{debug, instrument};
1616

1717
/// If `ty` implements the given `sizedness` trait, returns `None`. Otherwise, returns the type
1818
/// that must implement the given `sizedness` for `ty` to implement it.
@@ -298,6 +298,7 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness {
298298
})
299299
}
300300

301+
#[instrument(level = "debug", skip(tcx))]
301302
fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSet<u32> {
302303
let def = tcx.adt_def(def_id);
303304
let num_params = tcx.generics_of(def_id).count();
@@ -332,7 +333,16 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSe
332333
// Ensure none of the other fields mention the parameters used
333334
// in unsizing.
334335
for field in prefix_fields {
335-
for arg in tcx.type_of(field.did).instantiate_identity().walk() {
336+
let field_ty = tcx.type_of(field.did).instantiate_identity();
337+
let field_ty = tcx
338+
.try_normalize_erasing_regions(TypingEnv::non_body_analysis(tcx, def_id), field_ty)
339+
.inspect(|r| debug!(?r))
340+
.unwrap_or(field_ty);
341+
debug!(?field_ty);
342+
if field_ty.is_phantom_data() {
343+
continue;
344+
}
345+
for arg in field_ty.walk() {
336346
if let Some(i) = maybe_unsizing_param_idx(arg) {
337347
unsizing_params.remove(i);
338348
}

library/core/src/marker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ pub trait PointeeSized {
218218
/// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize<Foo<..., U1, ..., Un, ...>>`
219219
/// where any number of (type and const) parameters may be changed if all of these conditions
220220
/// are met:
221-
/// - Only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`.
221+
/// - Other than `PhantomData<_>` fields, only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`.
222222
/// - All other parameters of the struct are equal.
223223
/// - `Field<T1, ..., Tn>: Unsize<Field<U1, ..., Un>>`, where `Field<...>` stands for the actual
224224
/// type of the struct's last field.

tests/ui/traits/dispatch-from-dyn-invalid-impls.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,16 @@ where
6868
{
6969
}
7070

71+
struct Ptr<T: ?Sized>(Box<T>);
72+
73+
impl<'a, T: ?Sized, U: ?Sized> DispatchFromDyn<&'a Ptr<U>> for &'a Ptr<T> {}
74+
//~^ ERROR conflicting implementations of trait `DispatchFromDyn<&Ptr<_>>` for type `&Ptr<_>`
75+
76+
struct Inner<T: ?Sized>(T);
77+
#[repr(transparent)]
78+
struct Outer<T: ?Sized>(PhantomData<T>, Inner<T>);
79+
80+
impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<&'a Outer<U>> for &'a Outer<T> {}
81+
//~^ ERROR conflicting implementations of trait `DispatchFromDyn<&Outer<_>>` for type `&Outer<_>`
82+
7183
fn main() {}

tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
error[E0119]: conflicting implementations of trait `DispatchFromDyn<&Ptr<_>>` for type `&Ptr<_>`
2+
--> $DIR/dispatch-from-dyn-invalid-impls.rs:73:1
3+
|
4+
LL | impl<'a, T: ?Sized, U: ?Sized> DispatchFromDyn<&'a Ptr<U>> for &'a Ptr<T> {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: conflicting implementation in crate `core`:
8+
- impl<'a, T, U> DispatchFromDyn<&'a U> for &'a T
9+
where T: Unsize<U>, T: ?Sized, U: ?Sized;
10+
= note: downstream crates may implement trait `std::marker::Unsize<std::boxed::Box<_>>` for type `std::boxed::Box<_>`
11+
12+
error[E0119]: conflicting implementations of trait `DispatchFromDyn<&Outer<_>>` for type `&Outer<_>`
13+
--> $DIR/dispatch-from-dyn-invalid-impls.rs:80:1
14+
|
15+
LL | impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<&'a Outer<U>> for &'a Outer<T> {}
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
|
18+
= note: conflicting implementation in crate `core`:
19+
- impl<'a, T, U> DispatchFromDyn<&'a U> for &'a T
20+
where T: Unsize<U>, T: ?Sized, U: ?Sized;
21+
122
error[E0378]: 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
223
--> $DIR/dispatch-from-dyn-invalid-impls.rs:19:1
324
|
@@ -54,7 +75,7 @@ LL | | T: Unsize<U>
5475
|
5576
= note: extra field `1` of type `OverAlignedZst` is not allowed
5677

57-
error: aborting due to 5 previous errors
78+
error: aborting due to 7 previous errors
5879

59-
Some errors have detailed explanations: E0374, E0375, E0378.
60-
For more information about an error, try `rustc --explain E0374`.
80+
Some errors have detailed explanations: E0119, E0374, E0375, E0378.
81+
For more information about an error, try `rustc --explain E0119`.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
4+
//@ check-pass
5+
6+
#![feature(unsize)]
7+
8+
use std::marker::{PhantomData, Unsize};
9+
10+
fn assert<A, B: ?Sized>()
11+
where
12+
A: Unsize<B>,
13+
{
14+
}
15+
16+
struct Ptr<A: ?Sized>(PhantomData<A>, A);
17+
18+
trait ToPhantom {
19+
type T;
20+
}
21+
impl<T: ?Sized> ToPhantom for T {
22+
type T = PhantomData<fn() -> Self>;
23+
}
24+
25+
struct Ptr2<A: ?Sized>(<A as ToPhantom>::T, A);
26+
27+
fn main() {
28+
assert::<Ptr<[u8; 4]>, Ptr<[u8]>>();
29+
assert::<Ptr2<[u8; 4]>, Ptr2<[u8]>>();
30+
}

0 commit comments

Comments
 (0)