Skip to content

Commit fbee011

Browse files
author
Lukas Markeffsky
committed
require principal to be equal
1 parent 77d6647 commit fbee011

File tree

9 files changed

+121
-63
lines changed

9 files changed

+121
-63
lines changed

compiler/rustc_middle/src/traits/select.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,8 @@ pub enum SelectionCandidate<'tcx> {
116116
has_nested: bool,
117117
},
118118

119-
/// Implementation of the `MetadataCast<T>` trait.
120-
MetadataCastCandidate {
121-
/// Whether we should check for `Self == T`.
122-
require_eq: bool,
123-
},
119+
/// Implementation of the `MetadataCast` trait.
120+
MetadataCastCandidate(MetadataCastKind<'tcx>),
124121

125122
/// Implementation of transmutability trait.
126123
TransmutabilityCandidate,
@@ -182,6 +179,13 @@ pub enum SelectionCandidate<'tcx> {
182179
ConstDestructCandidate(Option<DefId>),
183180
}
184181

182+
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
183+
pub enum MetadataCastKind<'tcx> {
184+
Unconditional,
185+
Subtype,
186+
Dyn(ty::PolyExistentialTraitRef<'tcx>, ty::PolyExistentialTraitRef<'tcx>),
187+
}
188+
185189
/// The result of trait evaluation. The order is important
186190
/// here as the evaluation of a list is the maximum of the
187191
/// evaluations.

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+20-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use hir::def_id::DefId;
1010
use hir::LangItem;
1111
use rustc_hir as hir;
1212
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
13+
use rustc_middle::traits::select::MetadataCastKind;
1314
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
1415
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
1516

@@ -1121,7 +1122,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11211122
if let ty::Tuple(tys) = target.kind()
11221123
&& tys.is_empty()
11231124
{
1124-
candidates.vec.push(MetadataCastCandidate { require_eq: false });
1125+
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Unconditional));
11251126
return;
11261127
}
11271128

@@ -1136,21 +1137,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11361137
let src_dyn = src_args.type_at(0);
11371138
let tgt_dyn = tgt_args.type_at(0);
11381139

1139-
// We could theoretically allow casting the principal away, but `as` casts
1140-
// don't allow that, so neither does `MetadataCast` for now.
1141-
if let ty::Dynamic(src_pred, _, ty::Dyn) = src_dyn.kind()
1142-
&& let ty::Dynamic(tgt_pred, _, ty::Dyn) = tgt_dyn.kind()
1143-
&& src_pred.principal_def_id() == tgt_pred.principal_def_id()
1140+
if let ty::Dynamic(src_preds, _, ty::Dyn) = src_dyn.kind()
1141+
&& let ty::Dynamic(tgt_preds, _, ty::Dyn) = tgt_dyn.kind()
11441142
{
1145-
candidates.vec.push(MetadataCastCandidate { require_eq: false });
1143+
if let Some(src_principal) = src_preds.principal() {
1144+
if let Some(tgt_principal) = tgt_preds.principal() {
1145+
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Dyn(
1146+
src_principal,
1147+
tgt_principal,
1148+
)));
1149+
} else {
1150+
// We could theoretically allow casting the principal away, but `as` casts
1151+
// don't allow that, so neither does `MetadataCast` for now.
1152+
}
1153+
} else if tgt_preds.principal().is_none() {
1154+
// Casting between auto-trait-only trait objects is always allowed.
1155+
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Unconditional));
1156+
}
11461157
return;
11471158
}
11481159
}
11491160

11501161
if source.has_non_region_infer() || target.has_non_region_infer() {
11511162
candidates.ambiguous = true;
1152-
} else if self.infcx.can_eq(obligation.param_env, source, target) {
1153-
candidates.vec.push(MetadataCastCandidate { require_eq: true });
1163+
} else {
1164+
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Subtype));
11541165
}
11551166
}
11561167
}

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+34-16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
1111
use rustc_hir::lang_items::LangItem;
1212
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
1313
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
14+
use rustc_middle::traits::select::MetadataCastKind;
1415
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
1516
use rustc_middle::ty::{
1617
self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
@@ -51,22 +52,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
5152
ImplSource::Builtin(BuiltinImplSource::Misc, data)
5253
}
5354

54-
MetadataCastCandidate { require_eq } => {
55-
let data = if require_eq {
56-
let source = obligation.self_ty().skip_binder();
57-
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
58-
59-
let InferOk { obligations, .. } = self
60-
.infcx
61-
.at(&obligation.cause, obligation.param_env)
62-
.sub(DefineOpaqueTypes::No, source, target)
63-
.map_err(|_| Unimplemented)?;
64-
65-
obligations
66-
} else {
67-
Vec::new()
68-
};
69-
55+
MetadataCastCandidate(kind) => {
56+
let data = self.confirm_metadata_cast_candidate(obligation, kind)?;
7057
ImplSource::Builtin(BuiltinImplSource::Misc, data)
7158
}
7259

@@ -291,6 +278,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
291278
obligations
292279
}
293280

281+
fn confirm_metadata_cast_candidate(
282+
&mut self,
283+
obligation: &PolyTraitObligation<'tcx>,
284+
kind: MetadataCastKind<'tcx>,
285+
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
286+
match kind {
287+
MetadataCastKind::Unconditional => Ok(Vec::new()),
288+
MetadataCastKind::Subtype => {
289+
let source = obligation.self_ty().skip_binder();
290+
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
291+
292+
let InferOk { obligations, .. } = self
293+
.infcx
294+
.at(&obligation.cause, obligation.param_env)
295+
.sub(DefineOpaqueTypes::No, source, target)
296+
.map_err(|_| Unimplemented)?;
297+
298+
Ok(obligations)
299+
}
300+
MetadataCastKind::Dyn(source, target) => {
301+
let InferOk { obligations, .. } = self
302+
.infcx
303+
.at(&obligation.cause, obligation.param_env)
304+
.eq(DefineOpaqueTypes::No, source, target)
305+
.map_err(|_| Unimplemented)?;
306+
307+
Ok(obligations)
308+
}
309+
}
310+
}
311+
294312
#[instrument(level = "debug", skip(self))]
295313
fn confirm_transmutability_candidate(
296314
&mut self,

compiler/rustc_trait_selection/src/traits/select/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1833,14 +1833,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18331833
(
18341834
BuiltinCandidate { has_nested: false }
18351835
| ConstDestructCandidate(_)
1836-
| MetadataCastCandidate { require_eq: false },
1836+
| MetadataCastCandidate(MetadataCastKind::Unconditional),
18371837
_,
18381838
) => DropVictim::Yes,
18391839
(
18401840
_,
18411841
BuiltinCandidate { has_nested: false }
18421842
| ConstDestructCandidate(_)
1843-
| MetadataCastCandidate { require_eq: false },
1843+
| MetadataCastCandidate(MetadataCastKind::Unconditional),
18441844
) => DropVictim::No,
18451845

18461846
(ParamCandidate(other), ParamCandidate(victim)) => {
@@ -1879,7 +1879,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18791879
| BuiltinUnsizeCandidate
18801880
| TraitUpcastingUnsizeCandidate(_)
18811881
| BuiltinCandidate { .. }
1882-
| MetadataCastCandidate { .. }
1882+
| MetadataCastCandidate(_)
18831883
| TraitAliasCandidate
18841884
| ObjectCandidate(_)
18851885
| ProjectionCandidate(_),
@@ -1910,7 +1910,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19101910
| BuiltinUnsizeCandidate
19111911
| TraitUpcastingUnsizeCandidate(_)
19121912
| BuiltinCandidate { has_nested: true }
1913-
| MetadataCastCandidate { require_eq: true }
1913+
| MetadataCastCandidate(MetadataCastKind::Subtype | MetadataCastKind::Dyn(..))
19141914
| TraitAliasCandidate,
19151915
ParamCandidate(ref victim_cand),
19161916
) => {
@@ -1947,7 +1947,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19471947
| BuiltinUnsizeCandidate
19481948
| TraitUpcastingUnsizeCandidate(_)
19491949
| BuiltinCandidate { .. }
1950-
| MetadataCastCandidate { .. }
1950+
| MetadataCastCandidate(_)
19511951
| TraitAliasCandidate,
19521952
) => DropVictim::Yes,
19531953

@@ -1964,7 +1964,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19641964
| BuiltinUnsizeCandidate
19651965
| TraitUpcastingUnsizeCandidate(_)
19661966
| BuiltinCandidate { .. }
1967-
| MetadataCastCandidate { .. }
1967+
| MetadataCastCandidate(_)
19681968
| TraitAliasCandidate,
19691969
ObjectCandidate(_) | ProjectionCandidate(_),
19701970
) => DropVictim::No,
@@ -2073,7 +2073,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20732073
| BuiltinUnsizeCandidate
20742074
| TraitUpcastingUnsizeCandidate(_)
20752075
| BuiltinCandidate { has_nested: true }
2076-
| MetadataCastCandidate { require_eq: true }
2076+
| MetadataCastCandidate(MetadataCastKind::Subtype | MetadataCastKind::Dyn(..))
20772077
| TraitAliasCandidate,
20782078
ImplCandidate(_)
20792079
| ClosureCandidate { .. }
@@ -2086,7 +2086,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20862086
| BuiltinUnsizeCandidate
20872087
| TraitUpcastingUnsizeCandidate(_)
20882088
| BuiltinCandidate { has_nested: true }
2089-
| MetadataCastCandidate { require_eq: true }
2089+
| MetadataCastCandidate(MetadataCastKind::Subtype | MetadataCastKind::Dyn(..))
20902090
| TraitAliasCandidate,
20912091
) => DropVictim::No,
20922092
}

tests/ui/cast/cast-rfc0401-vtable-kinds.rs

-24
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,6 @@
44

55
#![feature(unsized_tuple_coercion)]
66

7-
trait Foo<T> {
8-
fn foo(&self, _: T) -> u32 { 42 }
9-
}
10-
11-
trait Bar {
12-
fn bar(&self) { println!("Bar!"); }
13-
}
14-
15-
impl<T> Foo<T> for () {}
16-
impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
17-
impl Bar for () {}
18-
19-
unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32>+'a)) -> u32 {
20-
let foo_e : *const dyn Foo<u16> = t as *const _;
21-
let r_1 = foo_e as *mut dyn Foo<u32>;
22-
23-
(&*r_1).foo(0)
24-
}
25-
267
#[repr(C)]
278
struct FooS<T:?Sized>(T);
289
#[repr(C)]
@@ -38,11 +19,6 @@ fn tuple_i32_to_u32<T:?Sized>(u: *const (i32, T)) -> *const (u32, T) {
3819

3920

4021
fn main() {
41-
let x = 4u32;
42-
let y : &dyn Foo<u32> = &x;
43-
let fl = unsafe { round_trip_and_call(y as *const dyn Foo<u32>) };
44-
assert_eq!(fl, (43+4));
45-
4622
let s = FooS([0,1,2]);
4723
let u: &FooS<[u32]> = &s;
4824
let u: *const FooS<[u32]> = u;
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait LifetimeParam<'a> {}
2+
fn lifetime_param<'a, 'b>(ptr: *const dyn LifetimeParam<'a>) -> *const dyn LifetimeParam<'b> {
3+
ptr as _
4+
//~^ ERROR lifetime may not live long enough
5+
//~| ERROR lifetime may not live long enough
6+
}
7+
8+
fn main() {}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/fat-ptr-cast-borrowck.rs:3:5
3+
|
4+
LL | fn lifetime_param<'a, 'b>(ptr: *const dyn LifetimeParam<'a>) -> *const dyn LifetimeParam<'b> {
5+
| -- -- lifetime `'b` defined here
6+
| |
7+
| lifetime `'a` defined here
8+
LL | ptr as _
9+
| ^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
10+
|
11+
= help: consider adding the following bound: `'b: 'a`
12+
13+
error: lifetime may not live long enough
14+
--> $DIR/fat-ptr-cast-borrowck.rs:3:5
15+
|
16+
LL | fn lifetime_param<'a, 'b>(ptr: *const dyn LifetimeParam<'a>) -> *const dyn LifetimeParam<'b> {
17+
| -- -- lifetime `'b` defined here
18+
| |
19+
| lifetime `'a` defined here
20+
LL | ptr as _
21+
| ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
22+
|
23+
= help: consider adding the following bound: `'a: 'b`
24+
25+
help: `'b` and `'a` must be the same: replace one with the other
26+
27+
error: aborting due to 2 previous errors
28+

tests/ui/cast/fat-ptr-cast.rs

+5
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,8 @@ fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
101101
{
102102
u as *const str //~ ERROR is invalid
103103
}
104+
105+
trait TypeParam<T> {}
106+
fn type_param<T, U>(ptr: *const dyn TypeParam<T>) -> *const dyn TypeParam<U> {
107+
ptr as _ //~ ERROR is invalid
108+
}

tests/ui/cast/fat-ptr-cast.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,15 @@ LL | u as *const str
339339
|
340340
= note: vtable kinds may not match
341341

342-
error: aborting due to 46 previous errors
342+
error[E0606]: casting `*const (dyn TypeParam<T> + 'static)` as `*const dyn TypeParam<U>` is invalid
343+
--> $DIR/fat-ptr-cast.rs:107:5
344+
|
345+
LL | ptr as _
346+
| ^^^^^^^^
347+
|
348+
= note: vtable kinds may not match
349+
350+
error: aborting due to 47 previous errors
343351

344352
Some errors have detailed explanations: E0054, E0277, E0604, E0605, E0606, E0607, E0609.
345353
For more information about an error, try `rustc --explain E0054`.

0 commit comments

Comments
 (0)