Skip to content

Commit

Permalink
require principal to be equal
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukas Markeffsky committed Jan 22, 2024
1 parent 1a52fae commit 38bf3b6
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 66 deletions.
14 changes: 9 additions & 5 deletions compiler/rustc_middle/src/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,8 @@ pub enum SelectionCandidate<'tcx> {
has_nested: bool,
},

/// Implementation of the `MetadataCast<T>` trait.
MetadataCastCandidate {
/// Whether we should check for `Self == T`.
require_eq: bool,
},
/// Implementation of the `MetadataCast` trait.
MetadataCastCandidate(MetadataCastKind<'tcx>),

/// Implementation of transmutability trait.
TransmutabilityCandidate,
Expand Down Expand Up @@ -182,6 +179,13 @@ pub enum SelectionCandidate<'tcx> {
ConstDestructCandidate(Option<DefId>),
}

#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
pub enum MetadataCastKind<'tcx> {
Unconditional,
Subtype,
Dyn(ty::PolyExistentialTraitRef<'tcx>, ty::PolyExistentialTraitRef<'tcx>),
}

/// The result of trait evaluation. The order is important
/// here as the evaluation of a list is the maximum of the
/// evaluations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use hir::def_id::DefId;
use hir::LangItem;
use rustc_hir as hir;
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
use rustc_middle::traits::select::MetadataCastKind;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};

Expand Down Expand Up @@ -1121,13 +1122,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ty::Tuple(tys) = target.kind()
&& tys.is_empty()
{
candidates.vec.push(MetadataCastCandidate { require_eq: false });
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Unconditional));
return;
}

let source = obligation.self_ty().skip_binder();
let source = self.infcx.shallow_resolve(source);

if source.has_non_region_infer() || target.has_non_region_infer() {
candidates.ambiguous = true;
return;
}

if let ty::Adt(src_def, src_args) = source.kind()
&& let ty::Adt(tgt_def, tgt_args) = target.kind()
&& src_def == tgt_def
Expand All @@ -1136,21 +1142,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let src_dyn = src_args.type_at(0);
let tgt_dyn = tgt_args.type_at(0);

// We could theoretically allow casting the principal away, but `as` casts
// don't allow that, so neither does `MetadataCast` for now.
if let ty::Dynamic(src_pred, _, ty::Dyn) = src_dyn.kind()
&& let ty::Dynamic(tgt_pred, _, ty::Dyn) = tgt_dyn.kind()
&& src_pred.principal_def_id() == tgt_pred.principal_def_id()
if let ty::Dynamic(src_preds, _, ty::Dyn) = src_dyn.kind()
&& let ty::Dynamic(tgt_preds, _, ty::Dyn) = tgt_dyn.kind()
{
candidates.vec.push(MetadataCastCandidate { require_eq: false });
if let Some(src_principal) = src_preds.principal() {
if let Some(tgt_principal) = tgt_preds.principal() {
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Dyn(
src_principal,
tgt_principal,
)));
} else {
// We could theoretically allow casting the principal away, but `as` casts
// don't allow that, so neither does `MetadataCast` for now.
}
} else if tgt_preds.principal().is_none() {
// Casting between auto-trait-only trait objects is always allowed.
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Unconditional));
}
return;
}
}

if source.has_non_region_infer() || target.has_non_region_infer() {
candidates.ambiguous = true;
} else if self.infcx.can_eq(obligation.param_env, source, target) {
candidates.vec.push(MetadataCastCandidate { require_eq: true });
}
candidates.vec.push(MetadataCastCandidate(MetadataCastKind::Subtype));
}
}
50 changes: 34 additions & 16 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::traits::select::MetadataCastKind;
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
use rustc_middle::ty::{
self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
Expand Down Expand Up @@ -51,22 +52,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}

MetadataCastCandidate { require_eq } => {
let data = if require_eq {
let source = obligation.self_ty().skip_binder();
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);

let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
.sub(DefineOpaqueTypes::No, source, target)
.map_err(|_| Unimplemented)?;

obligations
} else {
Vec::new()
};

MetadataCastCandidate(kind) => {
let data = self.confirm_metadata_cast_candidate(obligation, kind)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}

Expand Down Expand Up @@ -291,6 +278,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations
}

fn confirm_metadata_cast_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
kind: MetadataCastKind<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
match kind {
MetadataCastKind::Unconditional => Ok(Vec::new()),
MetadataCastKind::Subtype => {
let source = obligation.self_ty().skip_binder();
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);

let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
.sub(DefineOpaqueTypes::No, source, target)
.map_err(|_| Unimplemented)?;

Ok(obligations)
}
MetadataCastKind::Dyn(source, target) => {
let InferOk { obligations, .. } = self
.infcx
.at(&obligation.cause, obligation.param_env)
.eq(DefineOpaqueTypes::No, source, target)
.map_err(|_| Unimplemented)?;

Ok(obligations)
}
}
}

#[instrument(level = "debug", skip(self))]
fn confirm_transmutability_candidate(
&mut self,
Expand Down
16 changes: 8 additions & 8 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1833,14 +1833,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
(
BuiltinCandidate { has_nested: false }
| ConstDestructCandidate(_)
| MetadataCastCandidate { require_eq: false },
| MetadataCastCandidate(MetadataCastKind::Unconditional),
_,
) => DropVictim::Yes,
(
_,
BuiltinCandidate { has_nested: false }
| ConstDestructCandidate(_)
| MetadataCastCandidate { require_eq: false },
| MetadataCastCandidate(MetadataCastKind::Unconditional),
) => DropVictim::No,

(ParamCandidate(other), ParamCandidate(victim)) => {
Expand Down Expand Up @@ -1879,7 +1879,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| MetadataCastCandidate { .. }
| MetadataCastCandidate(_)
| TraitAliasCandidate
| ObjectCandidate(_)
| ProjectionCandidate(_),
Expand Down Expand Up @@ -1910,7 +1910,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| MetadataCastCandidate { require_eq: true }
| MetadataCastCandidate(MetadataCastKind::Subtype | MetadataCastKind::Dyn(..))
| TraitAliasCandidate,
ParamCandidate(ref victim_cand),
) => {
Expand Down Expand Up @@ -1947,7 +1947,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| MetadataCastCandidate { .. }
| MetadataCastCandidate(_)
| TraitAliasCandidate,
) => DropVictim::Yes,

Expand All @@ -1964,7 +1964,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| MetadataCastCandidate { .. }
| MetadataCastCandidate(_)
| TraitAliasCandidate,
ObjectCandidate(_) | ProjectionCandidate(_),
) => DropVictim::No,
Expand Down Expand Up @@ -2073,7 +2073,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| MetadataCastCandidate { require_eq: true }
| MetadataCastCandidate(MetadataCastKind::Subtype | MetadataCastKind::Dyn(..))
| TraitAliasCandidate,
ImplCandidate(_)
| ClosureCandidate { .. }
Expand All @@ -2086,7 +2086,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| BuiltinUnsizeCandidate
| TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| MetadataCastCandidate { require_eq: true }
| MetadataCastCandidate(MetadataCastKind::Subtype | MetadataCastKind::Dyn(..))
| TraitAliasCandidate,
) => DropVictim::No,
}
Expand Down
24 changes: 0 additions & 24 deletions tests/ui/cast/cast-rfc0401-vtable-kinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,6 @@

#![feature(unsized_tuple_coercion)]

trait Foo<T> {
fn foo(&self, _: T) -> u32 { 42 }
}

trait Bar {
fn bar(&self) { println!("Bar!"); }
}

impl<T> Foo<T> for () {}
impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
impl Bar for () {}

unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo<u32>+'a)) -> u32 {
let foo_e : *const dyn Foo<u16> = t as *const _;
let r_1 = foo_e as *mut dyn Foo<u32>;

(&*r_1).foo(0)
}

#[repr(C)]
struct FooS<T:?Sized>(T);
#[repr(C)]
Expand All @@ -38,11 +19,6 @@ fn tuple_i32_to_u32<T:?Sized>(u: *const (i32, T)) -> *const (u32, T) {


fn main() {
let x = 4u32;
let y : &dyn Foo<u32> = &x;
let fl = unsafe { round_trip_and_call(y as *const dyn Foo<u32>) };
assert_eq!(fl, (43+4));

let s = FooS([0,1,2]);
let u: &FooS<[u32]> = &s;
let u: *const FooS<[u32]> = u;
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/cast/fat-ptr-cast-borrowck.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
trait LifetimeParam<'a> {}
fn lifetime_param<'a, 'b>(ptr: *const dyn LifetimeParam<'a>) -> *const dyn LifetimeParam<'b> {
ptr as _
//~^ ERROR lifetime may not live long enough
//~| ERROR lifetime may not live long enough
}

fn main() {}
28 changes: 28 additions & 0 deletions tests/ui/cast/fat-ptr-cast-borrowck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
error: lifetime may not live long enough
--> $DIR/fat-ptr-cast-borrowck.rs:3:5
|
LL | fn lifetime_param<'a, 'b>(ptr: *const dyn LifetimeParam<'a>) -> *const dyn LifetimeParam<'b> {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | ptr as _
| ^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
|
= help: consider adding the following bound: `'b: 'a`

error: lifetime may not live long enough
--> $DIR/fat-ptr-cast-borrowck.rs:3:5
|
LL | fn lifetime_param<'a, 'b>(ptr: *const dyn LifetimeParam<'a>) -> *const dyn LifetimeParam<'b> {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | ptr as _
| ^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
|
= help: consider adding the following bound: `'a: 'b`

help: `'b` and `'a` must be the same: replace one with the other

error: aborting due to 2 previous errors

5 changes: 5 additions & 0 deletions tests/ui/cast/fat-ptr-cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,8 @@ fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
{
u as *const str //~ ERROR is invalid
}

trait TypeParam<T> {}
fn type_param<T, U>(ptr: *const dyn TypeParam<T>) -> *const dyn TypeParam<U> {
ptr as _ //~ ERROR is invalid
}
10 changes: 9 additions & 1 deletion tests/ui/cast/fat-ptr-cast.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,15 @@ LL | u as *const str
|
= note: vtable kinds may not match

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

error: aborting due to 47 previous errors

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

0 comments on commit 38bf3b6

Please sign in to comment.