Equate types instead of using `Unsize`

This commit is contained in:
Maybe Lapkin 2024-07-05 22:35:14 +02:00
parent 56de9da1f8
commit 073f3a263b
6 changed files with 68 additions and 87 deletions

View File

@ -38,6 +38,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::DUMMY_SP;
use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@ -49,6 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::ResultsCursor;
use crate::renumber::RegionCtxt;
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
use crate::{ use crate::{
borrow_set::BorrowSet, borrow_set::BorrowSet,
@ -2335,51 +2337,39 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
&& src_tty.principal().is_some() && src_tty.principal().is_some()
&& dst_tty.principal().is_some() && dst_tty.principal().is_some()
{ {
// Erase trait object lifetimes, to allow casts like `*mut dyn FnOnce()` -> `*mut dyn FnOnce() + 'static` // Remove auto traits.
// and remove auto traits. // Auto trait checks are handled in `rustc_hir_typeck` as FCW.
let src_obj = tcx.mk_ty_from_kind(ty::Dynamic( let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
tcx.mk_poly_existential_predicates( tcx.mk_poly_existential_predicates(
&src_tty.without_auto_traits().collect::<Vec<_>>(), &src_tty.without_auto_traits().collect::<Vec<_>>(),
), ),
tcx.lifetimes.re_erased, tcx.lifetimes.re_static,
ty::Dyn, ty::Dyn,
)); ));
let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic( let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
tcx.mk_poly_existential_predicates( tcx.mk_poly_existential_predicates(
&dst_tty.without_auto_traits().collect::<Vec<_>>(), &dst_tty.without_auto_traits().collect::<Vec<_>>(),
), ),
tcx.lifetimes.re_erased, tcx.lifetimes.re_static,
ty::Dyn, ty::Dyn,
)); ));
// FIXME: // Replace trait object lifetimes with fresh vars, to allow casts like
// this currently does nothing, but once we make `ptr_cast_add_auto_to_object` // `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
// into a hard error, we can remove the above removal of auto traits and only let src_obj =
// keep this. freshen_single_trait_object_lifetime(self.infcx, src_obj);
let src_obj = erase_single_trait_object_lifetime(tcx, src_obj); let dst_obj =
let dst_obj = erase_single_trait_object_lifetime(tcx, dst_obj); freshen_single_trait_object_lifetime(self.infcx, dst_obj);
let trait_ref = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Unsize, Some(span)),
[src_obj, dst_obj],
);
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
self.prove_trait_ref( self.eq_types(
trait_ref, src_obj,
dst_obj,
location.to_locations(), location.to_locations(),
ConstraintCategory::Cast { ConstraintCategory::Cast { unsize_to: None },
unsize_to: Some(tcx.fold_regions(dst_obj, |r, _| { )
if let ty::ReVar(_) = r.kind() { .unwrap();
tcx.lifetimes.re_erased
} else {
r
}
})),
},
);
} }
} }
_ => { _ => {
@ -2905,14 +2895,15 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
} }
} }
fn erase_single_trait_object_lifetime<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { fn freshen_single_trait_object_lifetime<'tcx>(
let &ty::Dynamic(tty, region, dyn_kind @ ty::Dyn) = ty.kind() else { infcx: &BorrowckInferCtxt<'tcx>,
bug!("expected trait object") ty: Ty<'tcx>,
}; ) -> Ty<'tcx> {
let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") };
if region.is_erased() { let fresh = infcx
return ty; .next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || {
} RegionCtxt::Unknown
});
tcx.mk_ty_from_kind(ty::Dynamic(tty, tcx.lifetimes.re_erased, dyn_kind)) infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind))
} }

View File

@ -34,8 +34,7 @@ use crate::errors;
use crate::type_error_struct; use crate::type_error_struct;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed}; use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
use rustc_hir::{self as hir, ExprKind, LangItem}; use rustc_hir::{self as hir, ExprKind};
use rustc_infer::traits::Obligation;
use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::mir::Mutability; use rustc_middle::mir::Mutability;
@ -835,9 +834,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(Some(src_principal), Some(dst_principal)) => { (Some(src_principal), Some(dst_principal)) => {
let tcx = fcx.tcx; let tcx = fcx.tcx;
// Check that the traits are actually the same // Check that the traits are actually the same.
// (this is required as the `Unsize` check below would allow upcasting, etc) // The `dyn Src = dyn Dst` check below would suffice,
// N.B.: this is only correct as long as we don't support `trait A<T>: A<()>`. // but this may produce a better diagnostic.
// //
// Note that trait upcasting goes through a different mechanism (`coerce_unsized`) // Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
// and is unaffected by this check. // and is unaffected by this check.
@ -867,20 +866,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
ty::Dyn, ty::Dyn,
)); ));
// `dyn Src: Unsize<dyn Dst>`, this checks for matching generics // `dyn Src = dyn Dst`, this checks for matching traits/generics
let cause = fcx.misc(self.span); fcx.demand_eqtype(self.span, src_obj, dst_obj);
let obligation = Obligation::new(
tcx,
cause,
fcx.param_env,
ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Unsize, Some(self.span)),
[src_obj, dst_obj],
),
);
fcx.register_predicate(obligation);
// Check that `SrcAuto` is a superset of `DstAuto`. // Check that `SrcAuto` is a superset of `DstAuto`.
// Emit an FCW otherwise. // Emit an FCW otherwise.

View File

@ -18,14 +18,14 @@ fn main() {
let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
let x: *const dyn Trait<X> = &(); let x: *const dyn Trait<X> = &();
let y: *const dyn Trait<Y> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied let y: *const dyn Trait<Y> = x as _; //~ error: mismatched types
_ = (b, y); _ = (b, y);
} }
fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) { fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
let _: *const dyn Trait<T> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied let _: *const dyn Trait<T> = x as _; //~ error: mismatched types
let _: *const dyn Trait<X> = t as _; //~ error: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied let _: *const dyn Trait<X> = t as _; //~ error: mismatched types
} }
trait Assocked { trait Assocked {
@ -33,5 +33,5 @@ trait Assocked {
} }
fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> { fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
x as _ //~ error: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied x as _ //~ error: mismatched types
} }

View File

@ -6,47 +6,48 @@ LL | let b: *const dyn B = a as _;
| |
= note: vtable kinds may not match = note: vtable kinds may not match
error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied error[E0308]: mismatched types
--> $DIR/ptr-to-trait-obj-different-args.rs:21:34 --> $DIR/ptr-to-trait-obj-different-args.rs:21:34
| |
LL | let y: *const dyn Trait<Y> = x as _; LL | let y: *const dyn Trait<Y> = x as _;
| ^^^^^^ the trait `Unsize<dyn Trait<Y>>` is not implemented for `dyn Trait<X>` | ^^^^^^ expected `X`, found `Y`
| |
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: expected trait object `dyn Trait<X>`
found trait object `dyn Trait<Y>`
error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied error[E0308]: mismatched types
--> $DIR/ptr-to-trait-obj-different-args.rs:27:34 --> $DIR/ptr-to-trait-obj-different-args.rs:27:34
| |
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
| - found this type parameter
LL | let _: *const dyn Trait<T> = x as _; LL | let _: *const dyn Trait<T> = x as _;
| ^^^^^^ the trait `Unsize<dyn Trait<T>>` is not implemented for `dyn Trait<X>` | ^^^^^^ expected `X`, found type parameter `T`
| |
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: expected trait object `dyn Trait<X>`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement found trait object `dyn Trait<T>`
|
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<X>: Unsize<dyn Trait<T>> {
| ++++++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied error[E0308]: mismatched types
--> $DIR/ptr-to-trait-obj-different-args.rs:28:34 --> $DIR/ptr-to-trait-obj-different-args.rs:28:34
| |
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
| - expected this type parameter
LL | let _: *const dyn Trait<T> = x as _;
LL | let _: *const dyn Trait<X> = t as _; LL | let _: *const dyn Trait<X> = t as _;
| ^^^^^^ the trait `Unsize<dyn Trait<X>>` is not implemented for `dyn Trait<T>` | ^^^^^^ expected type parameter `T`, found `X`
| |
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: expected trait object `dyn Trait<T>`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement found trait object `dyn Trait<X>`
|
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<T>: Unsize<dyn Trait<X>> {
| ++++++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied error[E0308]: mismatched types
--> $DIR/ptr-to-trait-obj-different-args.rs:36:5 --> $DIR/ptr-to-trait-obj-different-args.rs:36:5
| |
LL | x as _ LL | x as _
| ^^^^^^ the trait `Unsize<dyn Assocked<Assoc = u32>>` is not implemented for `dyn Assocked<Assoc = u8>` | ^^^^^^ expected `u8`, found `u32`
| |
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: expected trait object `dyn Assocked<Assoc = u8>`
found trait object `dyn Assocked<Assoc = u32>`
error: aborting due to 5 previous errors error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0606. Some errors have detailed explanations: E0308, E0606.
For more information about an error, try `rustc --explain E0277`. For more information about an error, try `rustc --explain E0308`.

View File

@ -57,7 +57,7 @@ pub fn user2() -> &'static dyn Trait<u8, u16> {
fn main() { fn main() {
let p: *const dyn Trait<u8, u8> = &(); let p: *const dyn Trait<u8, u8> = &();
let p = p as *const dyn Trait<u8, u16>; // <- this is bad! let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
//~^ error: the trait bound `dyn Trait<u8, u8>: Unsize<dyn Trait<u8, u16>>` is not satisfied //~^ error: mismatched types
let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry
// accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)', // accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)',
// thus reading 'null pointer for missing_method' // thus reading 'null pointer for missing_method'

View File

@ -1,11 +1,13 @@
error[E0277]: the trait bound `dyn Trait<u8, u8>: Unsize<dyn Trait<u8, u16>>` is not satisfied error[E0308]: mismatched types
--> $DIR/upcast_soundness_bug.rs:59:13 --> $DIR/upcast_soundness_bug.rs:59:13
| |
LL | let p = p as *const dyn Trait<u8, u16>; // <- this is bad! LL | let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<dyn Trait<u8, u16>>` is not implemented for `dyn Trait<u8, u8>` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
| |
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information = note: expected trait object `dyn Trait<u8, u8>`
found trait object `dyn Trait<u8, u16>`
= help: `dyn Trait<u8, u16>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
error: aborting due to 1 previous error error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0308`.