Skip to content

Commit 073f3a2

Browse files
committed
Equate types instead of using Unsize
1 parent 56de9da commit 073f3a2

File tree

6 files changed

+68
-87
lines changed

6 files changed

+68
-87
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+28-37
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
3838
use rustc_span::source_map::Spanned;
3939
use rustc_span::symbol::sym;
4040
use rustc_span::Span;
41+
use rustc_span::DUMMY_SP;
4142
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
4243
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
4344
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -49,6 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
4950
use rustc_mir_dataflow::move_paths::MoveData;
5051
use rustc_mir_dataflow::ResultsCursor;
5152

53+
use crate::renumber::RegionCtxt;
5254
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
5355
use crate::{
5456
borrow_set::BorrowSet,
@@ -2335,51 +2337,39 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23352337
&& src_tty.principal().is_some()
23362338
&& dst_tty.principal().is_some()
23372339
{
2338-
// Erase trait object lifetimes, to allow casts like `*mut dyn FnOnce()` -> `*mut dyn FnOnce() + 'static`
2339-
// and remove auto traits.
2340+
// Remove auto traits.
2341+
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
23402342
let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
23412343
tcx.mk_poly_existential_predicates(
23422344
&src_tty.without_auto_traits().collect::<Vec<_>>(),
23432345
),
2344-
tcx.lifetimes.re_erased,
2346+
tcx.lifetimes.re_static,
23452347
ty::Dyn,
23462348
));
23472349
let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
23482350
tcx.mk_poly_existential_predicates(
23492351
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
23502352
),
2351-
tcx.lifetimes.re_erased,
2353+
tcx.lifetimes.re_static,
23522354
ty::Dyn,
23532355
));
23542356

2355-
// FIXME:
2356-
// this currently does nothing, but once we make `ptr_cast_add_auto_to_object`
2357-
// into a hard error, we can remove the above removal of auto traits and only
2358-
// keep this.
2359-
let src_obj = erase_single_trait_object_lifetime(tcx, src_obj);
2360-
let dst_obj = erase_single_trait_object_lifetime(tcx, dst_obj);
2361-
2362-
let trait_ref = ty::TraitRef::new(
2363-
tcx,
2364-
tcx.require_lang_item(LangItem::Unsize, Some(span)),
2365-
[src_obj, dst_obj],
2366-
);
2357+
// Replace trait object lifetimes with fresh vars, to allow casts like
2358+
// `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
2359+
let src_obj =
2360+
freshen_single_trait_object_lifetime(self.infcx, src_obj);
2361+
let dst_obj =
2362+
freshen_single_trait_object_lifetime(self.infcx, dst_obj);
23672363

23682364
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
23692365

2370-
self.prove_trait_ref(
2371-
trait_ref,
2366+
self.eq_types(
2367+
src_obj,
2368+
dst_obj,
23722369
location.to_locations(),
2373-
ConstraintCategory::Cast {
2374-
unsize_to: Some(tcx.fold_regions(dst_obj, |r, _| {
2375-
if let ty::ReVar(_) = r.kind() {
2376-
tcx.lifetimes.re_erased
2377-
} else {
2378-
r
2379-
}
2380-
})),
2381-
},
2382-
);
2370+
ConstraintCategory::Cast { unsize_to: None },
2371+
)
2372+
.unwrap();
23832373
}
23842374
}
23852375
_ => {
@@ -2905,14 +2895,15 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
29052895
}
29062896
}
29072897

2908-
fn erase_single_trait_object_lifetime<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
2909-
let &ty::Dynamic(tty, region, dyn_kind @ ty::Dyn) = ty.kind() else {
2910-
bug!("expected trait object")
2911-
};
2912-
2913-
if region.is_erased() {
2914-
return ty;
2915-
}
2898+
fn freshen_single_trait_object_lifetime<'tcx>(
2899+
infcx: &BorrowckInferCtxt<'tcx>,
2900+
ty: Ty<'tcx>,
2901+
) -> Ty<'tcx> {
2902+
let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") };
29162903

2917-
tcx.mk_ty_from_kind(ty::Dynamic(tty, tcx.lifetimes.re_erased, dyn_kind))
2904+
let fresh = infcx
2905+
.next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || {
2906+
RegionCtxt::Unknown
2907+
});
2908+
infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind))
29182909
}

compiler/rustc_hir_typeck/src/cast.rs

+6-19
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ use crate::errors;
3434
use crate::type_error_struct;
3535
use rustc_data_structures::fx::FxHashSet;
3636
use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
37-
use rustc_hir::{self as hir, ExprKind, LangItem};
38-
use rustc_infer::traits::Obligation;
37+
use rustc_hir::{self as hir, ExprKind};
3938
use rustc_macros::{TypeFoldable, TypeVisitable};
4039
use rustc_middle::bug;
4140
use rustc_middle::mir::Mutability;
@@ -835,9 +834,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
835834
(Some(src_principal), Some(dst_principal)) => {
836835
let tcx = fcx.tcx;
837836

838-
// Check that the traits are actually the same
839-
// (this is required as the `Unsize` check below would allow upcasting, etc)
840-
// N.B.: this is only correct as long as we don't support `trait A<T>: A<()>`.
837+
// Check that the traits are actually the same.
838+
// The `dyn Src = dyn Dst` check below would suffice,
839+
// but this may produce a better diagnostic.
841840
//
842841
// Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
843842
// and is unaffected by this check.
@@ -867,20 +866,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
867866
ty::Dyn,
868867
));
869868

870-
// `dyn Src: Unsize<dyn Dst>`, this checks for matching generics
871-
let cause = fcx.misc(self.span);
872-
let obligation = Obligation::new(
873-
tcx,
874-
cause,
875-
fcx.param_env,
876-
ty::TraitRef::new(
877-
tcx,
878-
tcx.require_lang_item(LangItem::Unsize, Some(self.span)),
879-
[src_obj, dst_obj],
880-
),
881-
);
882-
883-
fcx.register_predicate(obligation);
869+
// `dyn Src = dyn Dst`, this checks for matching traits/generics
870+
fcx.demand_eqtype(self.span, src_obj, dst_obj);
884871

885872
// Check that `SrcAuto` is a superset of `DstAuto`.
886873
// Emit an FCW otherwise.

tests/ui/cast/ptr-to-trait-obj-different-args.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@ fn main() {
1818
let b: *const dyn B = a as _; //~ error: casting `*const dyn A` as `*const dyn B` is invalid
1919

2020
let x: *const dyn Trait<X> = &();
21-
let y: *const dyn Trait<Y> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
21+
let y: *const dyn Trait<Y> = x as _; //~ error: mismatched types
2222

2323
_ = (b, y);
2424
}
2525

2626
fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
27-
let _: *const dyn Trait<T> = x as _; //~ error: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied
28-
let _: *const dyn Trait<X> = t as _; //~ error: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied
27+
let _: *const dyn Trait<T> = x as _; //~ error: mismatched types
28+
let _: *const dyn Trait<X> = t as _; //~ error: mismatched types
2929
}
3030

3131
trait Assocked {
3232
type Assoc: ?Sized;
3333
}
3434

3535
fn change_assoc(x: *mut dyn Assocked<Assoc = u8>) -> *mut dyn Assocked<Assoc = u32> {
36-
x as _ //~ error: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied
36+
x as _ //~ error: mismatched types
3737
}

tests/ui/cast/ptr-to-trait-obj-different-args.stderr

+23-22
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,48 @@ LL | let b: *const dyn B = a as _;
66
|
77
= note: vtable kinds may not match
88

9-
error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<Y>>` is not satisfied
9+
error[E0308]: mismatched types
1010
--> $DIR/ptr-to-trait-obj-different-args.rs:21:34
1111
|
1212
LL | let y: *const dyn Trait<Y> = x as _;
13-
| ^^^^^^ the trait `Unsize<dyn Trait<Y>>` is not implemented for `dyn Trait<X>`
13+
| ^^^^^^ expected `X`, found `Y`
1414
|
15-
= 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
15+
= note: expected trait object `dyn Trait<X>`
16+
found trait object `dyn Trait<Y>`
1617

17-
error[E0277]: the trait bound `dyn Trait<X>: Unsize<dyn Trait<T>>` is not satisfied
18+
error[E0308]: mismatched types
1819
--> $DIR/ptr-to-trait-obj-different-args.rs:27:34
1920
|
21+
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
22+
| - found this type parameter
2023
LL | let _: *const dyn Trait<T> = x as _;
21-
| ^^^^^^ the trait `Unsize<dyn Trait<T>>` is not implemented for `dyn Trait<X>`
24+
| ^^^^^^ expected `X`, found type parameter `T`
2225
|
23-
= 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
24-
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
25-
|
26-
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<X>: Unsize<dyn Trait<T>> {
27-
| ++++++++++++++++++++++++++++++++++++++++
26+
= note: expected trait object `dyn Trait<X>`
27+
found trait object `dyn Trait<T>`
2828

29-
error[E0277]: the trait bound `dyn Trait<T>: Unsize<dyn Trait<X>>` is not satisfied
29+
error[E0308]: mismatched types
3030
--> $DIR/ptr-to-trait-obj-different-args.rs:28:34
3131
|
32+
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) {
33+
| - expected this type parameter
34+
LL | let _: *const dyn Trait<T> = x as _;
3235
LL | let _: *const dyn Trait<X> = t as _;
33-
| ^^^^^^ the trait `Unsize<dyn Trait<X>>` is not implemented for `dyn Trait<T>`
34-
|
35-
= 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
36-
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
36+
| ^^^^^^ expected type parameter `T`, found `X`
3737
|
38-
LL | fn generic<T>(x: *const dyn Trait<X>, t: *const dyn Trait<T>) where dyn Trait<T>: Unsize<dyn Trait<X>> {
39-
| ++++++++++++++++++++++++++++++++++++++++
38+
= note: expected trait object `dyn Trait<T>`
39+
found trait object `dyn Trait<X>`
4040

41-
error[E0277]: the trait bound `dyn Assocked<Assoc = u8>: Unsize<dyn Assocked<Assoc = u32>>` is not satisfied
41+
error[E0308]: mismatched types
4242
--> $DIR/ptr-to-trait-obj-different-args.rs:36:5
4343
|
4444
LL | x as _
45-
| ^^^^^^ the trait `Unsize<dyn Assocked<Assoc = u32>>` is not implemented for `dyn Assocked<Assoc = u8>`
45+
| ^^^^^^ expected `u8`, found `u32`
4646
|
47-
= 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
47+
= note: expected trait object `dyn Assocked<Assoc = u8>`
48+
found trait object `dyn Assocked<Assoc = u32>`
4849

4950
error: aborting due to 5 previous errors
5051

51-
Some errors have detailed explanations: E0277, E0606.
52-
For more information about an error, try `rustc --explain E0277`.
52+
Some errors have detailed explanations: E0308, E0606.
53+
For more information about an error, try `rustc --explain E0308`.

tests/ui/traits/upcast_soundness_bug.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub fn user2() -> &'static dyn Trait<u8, u16> {
5757
fn main() {
5858
let p: *const dyn Trait<u8, u8> = &();
5959
let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
60-
//~^ error: the trait bound `dyn Trait<u8, u8>: Unsize<dyn Trait<u8, u16>>` is not satisfied
60+
//~^ error: mismatched types
6161
let p = p as *const dyn Super<u16>; // <- this upcast accesses improper vtable entry
6262
// accessing from L__unnamed_2 the position for the 'Super<u16> vtable (pointer)',
6363
// thus reading 'null pointer for missing_method'
+6-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
error[E0277]: the trait bound `dyn Trait<u8, u8>: Unsize<dyn Trait<u8, u16>>` is not satisfied
1+
error[E0308]: mismatched types
22
--> $DIR/upcast_soundness_bug.rs:59:13
33
|
44
LL | let p = p as *const dyn Trait<u8, u16>; // <- this is bad!
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<dyn Trait<u8, u16>>` is not implemented for `dyn Trait<u8, u8>`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
66
|
7-
= 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
7+
= note: expected trait object `dyn Trait<u8, u8>`
8+
found trait object `dyn Trait<u8, u16>`
9+
= 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
810

911
error: aborting due to 1 previous error
1012

11-
For more information about this error, try `rustc --explain E0277`.
13+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)