mirror of https://github.com/rust-lang/rust.git
Auto merge of #88135 - crlf0710:trait_upcasting_part_3, r=nikomatsakis
Trait upcasting coercion (part 3) By using separate candidates for each possible choice, this fixes type-checking issues in previous commits. r? `@nikomatsakis`
This commit is contained in:
commit
d3e2578c31
|
@ -31,21 +31,10 @@ pub(crate) fn unsized_info<'tcx>(
|
||||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||||
return old_info;
|
return old_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trait upcasting coercion
|
// trait upcasting coercion
|
||||||
|
let vptr_entry_idx =
|
||||||
// if both of the two `principal`s are `None`, this function would have returned early above.
|
fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
|
||||||
// and if one of the two `principal`s is `None`, typechecking would have rejected this case.
|
|
||||||
let principal_a = data_a
|
|
||||||
.principal()
|
|
||||||
.expect("unsized_info: missing principal trait for trait upcasting coercion");
|
|
||||||
let principal_b = data_b
|
|
||||||
.principal()
|
|
||||||
.expect("unsized_info: missing principal trait for trait upcasting coercion");
|
|
||||||
|
|
||||||
let vptr_entry_idx = fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
|
|
||||||
principal_a.with_self_ty(fx.tcx, source),
|
|
||||||
principal_b.with_self_ty(fx.tcx, source),
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(entry_idx) = vptr_entry_idx {
|
if let Some(entry_idx) = vptr_entry_idx {
|
||||||
let entry_idx = u32::try_from(entry_idx).unwrap();
|
let entry_idx = u32::try_from(entry_idx).unwrap();
|
||||||
|
|
|
@ -150,19 +150,8 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
|
|
||||||
// trait upcasting coercion
|
// trait upcasting coercion
|
||||||
|
|
||||||
// if both of the two `principal`s are `None`, this function would have returned early above.
|
let vptr_entry_idx =
|
||||||
// and if one of the two `principal`s is `None`, typechecking would have rejected this case.
|
cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
|
||||||
let principal_a = data_a
|
|
||||||
.principal()
|
|
||||||
.expect("unsized_info: missing principal trait for trait upcasting coercion");
|
|
||||||
let principal_b = data_b
|
|
||||||
.principal()
|
|
||||||
.expect("unsized_info: missing principal trait for trait upcasting coercion");
|
|
||||||
|
|
||||||
let vptr_entry_idx = cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((
|
|
||||||
principal_a.with_self_ty(cx.tcx(), source),
|
|
||||||
principal_b.with_self_ty(cx.tcx(), source),
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(entry_idx) = vptr_entry_idx {
|
if let Some(entry_idx) = vptr_entry_idx {
|
||||||
let ptr_ty = cx.type_i8p();
|
let ptr_ty = cx.type_i8p();
|
||||||
|
|
|
@ -987,9 +987,9 @@ rustc_queries! {
|
||||||
desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
|
desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>)) -> Option<usize> {
|
query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
|
||||||
desc { |tcx| "finding the slot within vtable for trait {} vtable ptr during trait upcasting coercion from {} vtable",
|
desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
|
||||||
tcx.def_path_str(key.1.def_id()), tcx.def_path_str(key.0.def_id()) }
|
key.1, key.0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
query codegen_fulfill_obligation(
|
query codegen_fulfill_obligation(
|
||||||
|
|
|
@ -505,6 +505,9 @@ pub enum ImplSource<'tcx, N> {
|
||||||
/// Successful resolution for a builtin trait.
|
/// Successful resolution for a builtin trait.
|
||||||
Builtin(ImplSourceBuiltinData<N>),
|
Builtin(ImplSourceBuiltinData<N>),
|
||||||
|
|
||||||
|
/// ImplSource for trait upcasting coercion
|
||||||
|
TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
|
||||||
|
|
||||||
/// ImplSource automatically generated for a closure. The `DefId` is the ID
|
/// ImplSource automatically generated for a closure. The `DefId` is the ID
|
||||||
/// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the
|
/// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the
|
||||||
/// impl is generated by the compiler and does not appear in the source.
|
/// impl is generated by the compiler and does not appear in the source.
|
||||||
|
@ -540,6 +543,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
|
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
|
||||||
ImplSource::TraitAlias(d) => d.nested,
|
ImplSource::TraitAlias(d) => d.nested,
|
||||||
|
ImplSource::TraitUpcasting(d) => d.nested,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,6 +560,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
|
||||||
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
|
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
|
||||||
ImplSource::TraitAlias(d) => &d.nested[..],
|
ImplSource::TraitAlias(d) => &d.nested[..],
|
||||||
|
ImplSource::TraitUpcasting(d) => &d.nested[..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,6 +612,13 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||||
substs: d.substs,
|
substs: d.substs,
|
||||||
nested: d.nested.into_iter().map(f).collect(),
|
nested: d.nested.into_iter().map(f).collect(),
|
||||||
}),
|
}),
|
||||||
|
ImplSource::TraitUpcasting(d) => {
|
||||||
|
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
|
||||||
|
upcast_trait_ref: d.upcast_trait_ref,
|
||||||
|
vtable_vptr_slot: d.vtable_vptr_slot,
|
||||||
|
nested: d.nested.into_iter().map(f).collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,6 +664,20 @@ pub struct ImplSourceAutoImplData<N> {
|
||||||
pub nested: Vec<N>,
|
pub nested: Vec<N>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
||||||
|
pub struct ImplSourceTraitUpcastingData<'tcx, N> {
|
||||||
|
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
|
||||||
|
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
|
|
||||||
|
/// The vtable is formed by concatenating together the method lists of
|
||||||
|
/// the base object trait and all supertraits, pointers to supertrait vtable will
|
||||||
|
/// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
|
||||||
|
/// within that vtable.
|
||||||
|
pub vtable_vptr_slot: Option<usize>,
|
||||||
|
|
||||||
|
pub nested: Vec<N>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
|
||||||
pub struct ImplSourceBuiltinData<N> {
|
pub struct ImplSourceBuiltinData<N> {
|
||||||
pub nested: Vec<N>,
|
pub nested: Vec<N>,
|
||||||
|
@ -663,8 +689,9 @@ pub struct ImplSourceObjectData<'tcx, N> {
|
||||||
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
|
|
||||||
/// The vtable is formed by concatenating together the method lists of
|
/// The vtable is formed by concatenating together the method lists of
|
||||||
/// the base object trait and all supertraits; this is the start of
|
/// the base object trait and all supertraits, pointers to supertrait vtable will
|
||||||
/// `upcast_trait_ref`'s methods in that vtable.
|
/// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
|
||||||
|
/// in that vtable.
|
||||||
pub vtable_base: usize,
|
pub vtable_base: usize,
|
||||||
|
|
||||||
pub nested: Vec<N>,
|
pub nested: Vec<N>,
|
||||||
|
|
|
@ -135,6 +135,11 @@ pub enum SelectionCandidate<'tcx> {
|
||||||
/// `rustc_infer::traits::util::supertraits`.
|
/// `rustc_infer::traits::util::supertraits`.
|
||||||
ObjectCandidate(usize),
|
ObjectCandidate(usize),
|
||||||
|
|
||||||
|
/// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
|
||||||
|
/// The index is the position in the iterator returned by
|
||||||
|
/// `rustc_infer::traits::util::supertraits`.
|
||||||
|
TraitUpcastingUnsizeCandidate(usize),
|
||||||
|
|
||||||
BuiltinObjectCandidate,
|
BuiltinObjectCandidate,
|
||||||
|
|
||||||
BuiltinUnsizeCandidate,
|
BuiltinUnsizeCandidate,
|
||||||
|
|
|
@ -30,6 +30,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
|
||||||
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
|
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
|
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
|
||||||
|
|
||||||
|
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +72,16 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceBuiltinData<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
|
||||||
|
self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
|
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|
|
@ -275,16 +275,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
return self.write_immediate(*val, dest);
|
return self.write_immediate(*val, dest);
|
||||||
}
|
}
|
||||||
// trait upcasting coercion
|
// trait upcasting coercion
|
||||||
let principal_a = data_a.principal().expect(
|
|
||||||
"unsize_into_ptr: missing principal trait for trait upcasting coercion",
|
|
||||||
);
|
|
||||||
let principal_b = data_b.principal().expect(
|
|
||||||
"unsize_into_ptr: missing principal trait for trait upcasting coercion",
|
|
||||||
);
|
|
||||||
|
|
||||||
let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
|
let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
|
||||||
principal_a.with_self_ty(*self.tcx, src_pointee_ty),
|
src_pointee_ty,
|
||||||
principal_b.with_self_ty(*self.tcx, src_pointee_ty),
|
dest_pointee_ty,
|
||||||
));
|
));
|
||||||
|
|
||||||
if let Some(entry_idx) = vptr_entry_idx {
|
if let Some(entry_idx) = vptr_entry_idx {
|
||||||
|
|
|
@ -332,6 +332,16 @@ impl<'tcx> Key for Ty<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
|
||||||
|
#[inline(always)]
|
||||||
|
fn query_crate_is_local(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||||
|
DUMMY_SP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
|
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn query_crate_is_local(&self) -> bool {
|
fn query_crate_is_local(&self) -> bool {
|
||||||
|
|
|
@ -28,6 +28,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
|
@ -759,48 +760,38 @@ fn vtable_trait_first_method_offset<'tcx>(
|
||||||
pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
|
pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
key: (
|
key: (
|
||||||
ty::PolyTraitRef<'tcx>, // trait owning vtable
|
Ty<'tcx>, // trait object type whose trait owning vtable
|
||||||
ty::PolyTraitRef<'tcx>, // super trait ref
|
Ty<'tcx>, // trait object for supertrait
|
||||||
),
|
),
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
let (trait_owning_vtable, super_trait_ref) = key;
|
let (source, target) = key;
|
||||||
let super_trait_did = super_trait_ref.def_id();
|
assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
|
||||||
// FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur
|
assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
|
||||||
// multiple times.
|
|
||||||
|
|
||||||
let vtable_segment_callback = {
|
// this has been typecked-before, so diagnostics is not really needed.
|
||||||
let mut vptr_offset = 0;
|
let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
|
||||||
move |segment| {
|
|
||||||
match segment {
|
|
||||||
VtblSegment::MetadataDSA => {
|
|
||||||
vptr_offset += COMMON_VTABLE_ENTRIES.len();
|
|
||||||
}
|
|
||||||
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
|
|
||||||
vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
|
|
||||||
if trait_ref.def_id() == super_trait_did {
|
|
||||||
if emit_vptr {
|
|
||||||
return ControlFlow::Break(Some(vptr_offset));
|
|
||||||
} else {
|
|
||||||
return ControlFlow::Break(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if emit_vptr {
|
let trait_ref = ty::TraitRef {
|
||||||
vptr_offset += 1;
|
def_id: unsize_trait_did,
|
||||||
}
|
substs: tcx.mk_substs_trait(source, &[target.into()]),
|
||||||
}
|
};
|
||||||
}
|
let obligation = Obligation::new(
|
||||||
ControlFlow::Continue(())
|
ObligationCause::dummy(),
|
||||||
}
|
ty::ParamEnv::reveal_all(),
|
||||||
|
ty::Binder::dummy(ty::TraitPredicate { trait_ref, constness: hir::Constness::NotConst }),
|
||||||
|
);
|
||||||
|
|
||||||
|
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||||
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
|
selcx.select(&obligation).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let implsrc_traitcasting = match implsrc {
|
||||||
|
Some(ImplSource::TraitUpcasting(data)) => data,
|
||||||
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(vptr_offset) =
|
implsrc_traitcasting.vtable_vptr_slot
|
||||||
prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
|
|
||||||
{
|
|
||||||
vptr_offset
|
|
||||||
} else {
|
|
||||||
bug!("Failed to find info for expected trait in vtable");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut ty::query::Providers) {
|
pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
|
|
|
@ -1483,7 +1483,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
// why we special case object types.
|
// why we special case object types.
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
|
super::ImplSource::AutoImpl(..)
|
||||||
|
| super::ImplSource::Builtin(..)
|
||||||
|
| super::ImplSource::TraitUpcasting(_) => {
|
||||||
// These traits have no associated types.
|
// These traits have no associated types.
|
||||||
selcx.tcx().sess.delay_span_bug(
|
selcx.tcx().sess.delay_span_bug(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
|
@ -1554,6 +1556,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||||
| super::ImplSource::AutoImpl(..)
|
| super::ImplSource::AutoImpl(..)
|
||||||
| super::ImplSource::Param(..)
|
| super::ImplSource::Param(..)
|
||||||
| super::ImplSource::Builtin(..)
|
| super::ImplSource::Builtin(..)
|
||||||
|
| super::ImplSource::TraitUpcasting(_)
|
||||||
| super::ImplSource::TraitAlias(..) => {
|
| super::ImplSource::TraitAlias(..) => {
|
||||||
// we don't create Select candidates with this kind of resolution
|
// we don't create Select candidates with this kind of resolution
|
||||||
span_bug!(
|
span_bug!(
|
||||||
|
|
|
@ -690,19 +690,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
debug!(?source, ?target, "assemble_candidates_for_unsizing");
|
debug!(?source, ?target, "assemble_candidates_for_unsizing");
|
||||||
|
|
||||||
let may_apply = match (source.kind(), target.kind()) {
|
match (source.kind(), target.kind()) {
|
||||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||||
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
|
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
|
||||||
// See `confirm_builtin_unsize_candidate` for more info.
|
// Upcast coercions permit several things:
|
||||||
|
//
|
||||||
|
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
||||||
|
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
|
||||||
|
// 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
|
||||||
|
//
|
||||||
|
// Note that neither of the first two of these changes requires any
|
||||||
|
// change at runtime. The third needs to change pointer metadata at runtime.
|
||||||
|
//
|
||||||
|
// We always perform upcasting coercions when we can because of reason
|
||||||
|
// #2 (region bounds).
|
||||||
let auto_traits_compatible = data_b
|
let auto_traits_compatible = data_b
|
||||||
.auto_traits()
|
.auto_traits()
|
||||||
// All of a's auto traits need to be in b's auto traits.
|
// All of a's auto traits need to be in b's auto traits.
|
||||||
.all(|b| data_a.auto_traits().any(|a| a == b));
|
.all(|b| data_a.auto_traits().any(|a| a == b));
|
||||||
auto_traits_compatible
|
if auto_traits_compatible {
|
||||||
|
let principal_def_id_a = data_a.principal_def_id();
|
||||||
|
let principal_def_id_b = data_b.principal_def_id();
|
||||||
|
if principal_def_id_a == principal_def_id_b {
|
||||||
|
// no cyclic
|
||||||
|
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||||
|
} else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
|
||||||
|
// not casual unsizing, now check whether this is trait upcasting coercion.
|
||||||
|
let principal_a = data_a.principal().unwrap();
|
||||||
|
let target_trait_did = principal_def_id_b.unwrap();
|
||||||
|
let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
|
||||||
|
for (idx, upcast_trait_ref) in
|
||||||
|
util::supertraits(self.tcx(), source_trait_ref).enumerate()
|
||||||
|
{
|
||||||
|
if upcast_trait_ref.def_id() == target_trait_did {
|
||||||
|
candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `T` -> `Trait`
|
// `T` -> `Trait`
|
||||||
(_, &ty::Dynamic(..)) => true,
|
(_, &ty::Dynamic(..)) => {
|
||||||
|
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||||
|
}
|
||||||
|
|
||||||
// Ambiguous handling is below `T` -> `Trait`, because inference
|
// Ambiguous handling is below `T` -> `Trait`, because inference
|
||||||
// variables can still implement `Unsize<Trait>` and nested
|
// variables can still implement `Unsize<Trait>` and nested
|
||||||
|
@ -710,26 +741,29 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
(&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
|
(&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
|
||||||
debug!("assemble_candidates_for_unsizing: ambiguous");
|
debug!("assemble_candidates_for_unsizing: ambiguous");
|
||||||
candidates.ambiguous = true;
|
candidates.ambiguous = true;
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `[T; n]` -> `[T]`
|
// `[T; n]` -> `[T]`
|
||||||
(&ty::Array(..), &ty::Slice(_)) => true,
|
(&ty::Array(..), &ty::Slice(_)) => {
|
||||||
|
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||||
|
}
|
||||||
|
|
||||||
// `Struct<T>` -> `Struct<U>`
|
// `Struct<T>` -> `Struct<U>`
|
||||||
(&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
|
(&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
|
||||||
def_id_a == def_id_b
|
if def_id_a == def_id_b {
|
||||||
|
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `(.., T)` -> `(.., U)`
|
// `(.., T)` -> `(.., U)`
|
||||||
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
|
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
|
||||||
|
if tys_a.len() == tys_b.len() {
|
||||||
|
candidates.vec.push(BuiltinUnsizeCandidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => false,
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
if may_apply {
|
|
||||||
candidates.vec.push(BuiltinUnsizeCandidate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assemble_candidates_for_trait_alias(
|
fn assemble_candidates_for_trait_alias(
|
||||||
|
|
|
@ -26,12 +26,13 @@ use crate::traits::Normalized;
|
||||||
use crate::traits::OutputTypeParameterMismatch;
|
use crate::traits::OutputTypeParameterMismatch;
|
||||||
use crate::traits::Selection;
|
use crate::traits::Selection;
|
||||||
use crate::traits::TraitNotObjectSafe;
|
use crate::traits::TraitNotObjectSafe;
|
||||||
|
use crate::traits::VtblSegment;
|
||||||
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
||||||
use crate::traits::{
|
use crate::traits::{
|
||||||
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
||||||
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
||||||
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
||||||
ImplSourceUserDefinedData,
|
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
|
||||||
};
|
};
|
||||||
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
|
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
|
||||||
use crate::traits::{Obligation, ObligationCause};
|
use crate::traits::{Obligation, ObligationCause};
|
||||||
|
@ -42,6 +43,7 @@ use super::SelectionCandidate::{self, *};
|
||||||
use super::SelectionContext;
|
use super::SelectionContext;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
|
@ -118,6 +120,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let data = self.confirm_builtin_unsize_candidate(obligation)?;
|
let data = self.confirm_builtin_unsize_candidate(obligation)?;
|
||||||
Ok(ImplSource::Builtin(data))
|
Ok(ImplSource::Builtin(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TraitUpcastingUnsizeCandidate(idx) => {
|
||||||
|
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
|
||||||
|
Ok(ImplSource::TraitUpcasting(data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,6 +692,114 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
|
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn confirm_trait_upcasting_unsize_candidate(
|
||||||
|
&mut self,
|
||||||
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
idx: usize,
|
||||||
|
) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
||||||
|
{
|
||||||
|
let tcx = self.tcx();
|
||||||
|
|
||||||
|
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
|
||||||
|
// regions here. See the comment there for more details.
|
||||||
|
let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
|
||||||
|
let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
|
||||||
|
let target = self.infcx.shallow_resolve(target);
|
||||||
|
|
||||||
|
debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
|
||||||
|
|
||||||
|
let mut nested = vec![];
|
||||||
|
let source_trait_ref;
|
||||||
|
let upcast_trait_ref;
|
||||||
|
match (source.kind(), target.kind()) {
|
||||||
|
// TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
|
||||||
|
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
||||||
|
// See `assemble_candidates_for_unsizing` for more info.
|
||||||
|
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
|
||||||
|
let principal_a = data_a.principal().unwrap();
|
||||||
|
source_trait_ref = principal_a.with_self_ty(tcx, source);
|
||||||
|
upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
|
||||||
|
assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id()));
|
||||||
|
let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| {
|
||||||
|
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
|
||||||
|
tcx, trait_ref,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let iter = Some(existential_predicate)
|
||||||
|
.into_iter()
|
||||||
|
.chain(
|
||||||
|
data_a
|
||||||
|
.projection_bounds()
|
||||||
|
.map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
|
||||||
|
)
|
||||||
|
.chain(
|
||||||
|
data_b
|
||||||
|
.auto_traits()
|
||||||
|
.map(ty::ExistentialPredicate::AutoTrait)
|
||||||
|
.map(ty::Binder::dummy),
|
||||||
|
);
|
||||||
|
let existential_predicates = tcx.mk_poly_existential_predicates(iter);
|
||||||
|
let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
|
||||||
|
|
||||||
|
// Require that the traits involved in this upcast are **equal**;
|
||||||
|
// only the **lifetime bound** is changed.
|
||||||
|
let InferOk { obligations, .. } = self
|
||||||
|
.infcx
|
||||||
|
.at(&obligation.cause, obligation.param_env)
|
||||||
|
.sup(target, source_trait)
|
||||||
|
.map_err(|_| Unimplemented)?;
|
||||||
|
nested.extend(obligations);
|
||||||
|
|
||||||
|
// Register one obligation for 'a: 'b.
|
||||||
|
let cause = ObligationCause::new(
|
||||||
|
obligation.cause.span,
|
||||||
|
obligation.cause.body_id,
|
||||||
|
ObjectCastObligation(target),
|
||||||
|
);
|
||||||
|
let outlives = ty::OutlivesPredicate(r_a, r_b);
|
||||||
|
nested.push(Obligation::with_depth(
|
||||||
|
cause,
|
||||||
|
obligation.recursion_depth + 1,
|
||||||
|
obligation.param_env,
|
||||||
|
obligation.predicate.rebind(outlives).to_predicate(tcx),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => bug!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let vtable_segment_callback = {
|
||||||
|
let mut vptr_offset = 0;
|
||||||
|
move |segment| {
|
||||||
|
match segment {
|
||||||
|
VtblSegment::MetadataDSA => {
|
||||||
|
vptr_offset += ty::COMMON_VTABLE_ENTRIES.len();
|
||||||
|
}
|
||||||
|
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
|
||||||
|
vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
|
||||||
|
if trait_ref == upcast_trait_ref {
|
||||||
|
if emit_vptr {
|
||||||
|
return ControlFlow::Break(Some(vptr_offset));
|
||||||
|
} else {
|
||||||
|
return ControlFlow::Break(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if emit_vptr {
|
||||||
|
vptr_offset += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let vtable_vptr_slot =
|
||||||
|
super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
|
||||||
|
}
|
||||||
|
|
||||||
fn confirm_builtin_unsize_candidate(
|
fn confirm_builtin_unsize_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
@ -701,58 +816,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
let mut nested = vec![];
|
let mut nested = vec![];
|
||||||
match (source.kind(), target.kind()) {
|
match (source.kind(), target.kind()) {
|
||||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
// Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
|
||||||
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
||||||
// Upcast coercions permit several things:
|
// See `assemble_candidates_for_unsizing` for more info.
|
||||||
//
|
|
||||||
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
|
||||||
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
|
|
||||||
// 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
|
|
||||||
//
|
|
||||||
// Note that neither of the first two of these changes requires any
|
|
||||||
// change at runtime. The third needs to change pointer metadata at runtime.
|
|
||||||
//
|
|
||||||
// We always perform upcasting coercions when we can because of reason
|
|
||||||
// #2 (region bounds).
|
|
||||||
|
|
||||||
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
|
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
|
||||||
|
let iter = data_a
|
||||||
let principal_a = data_a.principal();
|
.principal()
|
||||||
let principal_def_id_b = data_b.principal_def_id();
|
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
|
||||||
|
|
||||||
let existential_predicate = if let Some(principal_a) = principal_a {
|
|
||||||
let source_trait_ref = principal_a.with_self_ty(tcx, source);
|
|
||||||
let target_trait_did = principal_def_id_b.ok_or_else(|| Unimplemented)?;
|
|
||||||
let upcast_idx = util::supertraits(tcx, source_trait_ref)
|
|
||||||
.position(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
|
|
||||||
.ok_or_else(|| Unimplemented)?;
|
|
||||||
// FIXME(crlf0710): This is less than ideal, for example,
|
|
||||||
// if the trait is defined as `trait Foo: Bar<u32> + Bar<i32>`,
|
|
||||||
// the coercion from Box<Foo> to Box<dyn Bar<_>> is actually ambiguous.
|
|
||||||
// We currently make this coercion fail for now.
|
|
||||||
//
|
|
||||||
// see #65991 for more information.
|
|
||||||
if util::supertraits(tcx, source_trait_ref)
|
|
||||||
.skip(upcast_idx + 1)
|
|
||||||
.any(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
|
|
||||||
{
|
|
||||||
return Err(Unimplemented);
|
|
||||||
}
|
|
||||||
let target_trait_ref =
|
|
||||||
util::supertraits(tcx, source_trait_ref).nth(upcast_idx).unwrap();
|
|
||||||
let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
|
|
||||||
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
|
|
||||||
tcx, trait_ref,
|
|
||||||
))
|
|
||||||
});
|
|
||||||
Some(existential_predicate)
|
|
||||||
} else if principal_def_id_b.is_none() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
return Err(Unimplemented);
|
|
||||||
};
|
|
||||||
|
|
||||||
let iter = existential_predicate
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(
|
.chain(
|
||||||
data_a
|
data_a
|
||||||
|
|
|
@ -1516,6 +1516,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate(..)
|
| TraitAliasCandidate(..)
|
||||||
| ObjectCandidate(_)
|
| ObjectCandidate(_)
|
||||||
|
@ -1533,6 +1534,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { has_nested: true }
|
| BuiltinCandidate { has_nested: true }
|
||||||
| TraitAliasCandidate(..),
|
| TraitAliasCandidate(..),
|
||||||
ParamCandidate(ref cand),
|
ParamCandidate(ref cand),
|
||||||
|
@ -1562,6 +1564,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate(..),
|
| TraitAliasCandidate(..),
|
||||||
) => true,
|
) => true,
|
||||||
|
@ -1573,6 +1576,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { .. }
|
| BuiltinCandidate { .. }
|
||||||
| TraitAliasCandidate(..),
|
| TraitAliasCandidate(..),
|
||||||
ObjectCandidate(_) | ProjectionCandidate(_),
|
ObjectCandidate(_) | ProjectionCandidate(_),
|
||||||
|
@ -1646,6 +1650,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { has_nested: true }
|
| BuiltinCandidate { has_nested: true }
|
||||||
| TraitAliasCandidate(..),
|
| TraitAliasCandidate(..),
|
||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
|
@ -1654,6 +1659,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
| BuiltinCandidate { has_nested: true }
|
| BuiltinCandidate { has_nested: true }
|
||||||
| TraitAliasCandidate(..),
|
| TraitAliasCandidate(..),
|
||||||
) => false,
|
) => false,
|
||||||
|
|
|
@ -381,7 +381,8 @@ fn resolve_associated_item<'tcx>(
|
||||||
| traits::ImplSource::Param(..)
|
| traits::ImplSource::Param(..)
|
||||||
| traits::ImplSource::TraitAlias(..)
|
| traits::ImplSource::TraitAlias(..)
|
||||||
| traits::ImplSource::DiscriminantKind(..)
|
| traits::ImplSource::DiscriminantKind(..)
|
||||||
| traits::ImplSource::Pointee(..) => None,
|
| traits::ImplSource::Pointee(..)
|
||||||
|
| traits::ImplSource::TraitUpcasting(_) => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
// run-pass
|
||||||
|
#![feature(trait_upcasting)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
trait Foo<T: Default + ToString>: Bar<i32> + Bar<T> {}
|
||||||
|
trait Bar<T: Default + ToString> {
|
||||||
|
fn bar(&self) -> String {
|
||||||
|
T::default().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S1;
|
||||||
|
|
||||||
|
impl Bar<i32> for S1 {}
|
||||||
|
impl Foo<i32> for S1 {}
|
||||||
|
|
||||||
|
struct S2;
|
||||||
|
impl Bar<i32> for S2 {}
|
||||||
|
impl Bar<bool> for S2 {}
|
||||||
|
impl Foo<bool> for S2 {}
|
||||||
|
|
||||||
|
fn test1(x: &dyn Foo<i32>) {
|
||||||
|
let s = x as &dyn Bar<i32>;
|
||||||
|
assert_eq!("0", &s.bar().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test2(x: &dyn Foo<bool>) {
|
||||||
|
let p = x as &dyn Bar<i32>;
|
||||||
|
assert_eq!("0", &p.bar().to_string());
|
||||||
|
let q = x as &dyn Bar<bool>;
|
||||||
|
assert_eq!("false", &q.bar().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s1 = S1;
|
||||||
|
test1(&s1);
|
||||||
|
let s2 = S2;
|
||||||
|
test2(&s2);
|
||||||
|
}
|
|
@ -9,12 +9,8 @@ trait Bar<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_specific(x: &dyn Foo) {
|
fn test_specific(x: &dyn Foo) {
|
||||||
let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
let _ = x as &dyn Bar<i32>; // OK
|
||||||
//~^ ERROR non-primitive cast
|
let _ = x as &dyn Bar<u32>; // OK
|
||||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<i32>` is not satisfied
|
|
||||||
let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
|
||||||
//~^ ERROR non-primitive cast
|
|
||||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_unknown_version(x: &dyn Foo) {
|
fn test_unknown_version(x: &dyn Foo) {
|
||||||
|
@ -24,9 +20,7 @@ fn test_unknown_version(x: &dyn Foo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_infer_version(x: &dyn Foo) {
|
fn test_infer_version(x: &dyn Foo) {
|
||||||
let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
let a = x as &dyn Bar<_>; // OK
|
||||||
//~^ ERROR non-primitive cast
|
|
||||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
|
||||||
let _: Option<u32> = a.bar();
|
let _: Option<u32> = a.bar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,5 @@
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<i32>`
|
|
||||||
--> $DIR/type-checking-test-1.rs:12:13
|
|
||||||
|
|
|
||||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
|
||||||
|
|
|
||||||
help: consider borrowing the value
|
|
||||||
|
|
|
||||||
LL | let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
|
|
||||||
| +
|
|
||||||
|
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
|
|
||||||
--> $DIR/type-checking-test-1.rs:15:13
|
|
||||||
|
|
|
||||||
LL | let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
|
||||||
|
|
|
||||||
help: consider borrowing the value
|
|
||||||
|
|
|
||||||
LL | let _ = &x as &dyn Bar<u32>; // FIXME: OK, eventually
|
|
||||||
| +
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo: Bar<i32>` is not satisfied
|
|
||||||
--> $DIR/type-checking-test-1.rs:12:13
|
|
||||||
|
|
|
||||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
|
||||||
| ^ the trait `Bar<i32>` is not implemented for `&dyn Foo`
|
|
||||||
|
|
|
||||||
= note: required for the cast to the object type `dyn Bar<i32>`
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
|
||||||
--> $DIR/type-checking-test-1.rs:15:13
|
|
||||||
|
|
|
||||||
LL | let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
|
||||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
|
|
||||||
|
|
|
||||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
|
||||||
|
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
|
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
|
||||||
--> $DIR/type-checking-test-1.rs:21:13
|
--> $DIR/type-checking-test-1.rs:17:13
|
||||||
|
|
|
|
||||||
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
||||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||||
|
@ -48,33 +10,14 @@ LL | let _ = &x as &dyn Bar<_>; // Ambiguous
|
||||||
| +
|
| +
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
|
error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
|
||||||
--> $DIR/type-checking-test-1.rs:21:13
|
--> $DIR/type-checking-test-1.rs:17:13
|
||||||
|
|
|
|
||||||
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
||||||
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
|
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
|
||||||
|
|
|
|
||||||
= note: required for the cast to the object type `dyn Bar<_>`
|
= note: required for the cast to the object type `dyn Bar<_>`
|
||||||
|
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/type-checking-test-1.rs:27:13
|
|
||||||
|
|
|
||||||
LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
|
||||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
|
||||||
|
|
|
||||||
help: consider borrowing the value
|
|
||||||
|
|
|
||||||
LL | let a = &x as &dyn Bar<_>; // FIXME: OK, eventually
|
|
||||||
| +
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
|
||||||
--> $DIR/type-checking-test-1.rs:27:13
|
|
||||||
|
|
|
||||||
LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
|
||||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
|
|
||||||
|
|
|
||||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0605.
|
Some errors have detailed explanations: E0277, E0605.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -13,9 +13,7 @@ fn test_specific(x: &dyn Foo<i32>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_specific2(x: &dyn Foo<u32>) {
|
fn test_specific2(x: &dyn Foo<u32>) {
|
||||||
let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
let _ = x as &dyn Bar<i32>; // OK
|
||||||
//~^ ERROR non-primitive cast
|
|
||||||
//~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_specific3(x: &dyn Foo<i32>) {
|
fn test_specific3(x: &dyn Foo<i32>) {
|
||||||
|
|
|
@ -1,24 +1,5 @@
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<i32>`
|
|
||||||
--> $DIR/type-checking-test-2.rs:16:13
|
|
||||||
|
|
|
||||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
|
||||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
|
||||||
|
|
|
||||||
help: consider borrowing the value
|
|
||||||
|
|
|
||||||
LL | let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
|
|
||||||
| +
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
|
|
||||||
--> $DIR/type-checking-test-2.rs:16:13
|
|
||||||
|
|
|
||||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
|
||||||
| ^ the trait `Bar<i32>` is not implemented for `&dyn Foo<u32>`
|
|
||||||
|
|
|
||||||
= note: required for the cast to the object type `dyn Bar<i32>`
|
|
||||||
|
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
|
error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
|
||||||
--> $DIR/type-checking-test-2.rs:22:13
|
--> $DIR/type-checking-test-2.rs:20:13
|
||||||
|
|
|
|
||||||
LL | let _ = x as &dyn Bar<u32>; // Error
|
LL | let _ = x as &dyn Bar<u32>; // Error
|
||||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||||
|
@ -29,7 +10,7 @@ LL | let _ = &x as &dyn Bar<u32>; // Error
|
||||||
| +
|
| +
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
|
error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
|
||||||
--> $DIR/type-checking-test-2.rs:22:13
|
--> $DIR/type-checking-test-2.rs:20:13
|
||||||
|
|
|
|
||||||
LL | let _ = x as &dyn Bar<u32>; // Error
|
LL | let _ = x as &dyn Bar<u32>; // Error
|
||||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
|
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
|
||||||
|
@ -37,7 +18,7 @@ LL | let _ = x as &dyn Bar<u32>; // Error
|
||||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||||
|
|
||||||
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
|
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
|
||||||
--> $DIR/type-checking-test-2.rs:28:13
|
--> $DIR/type-checking-test-2.rs:26:13
|
||||||
|
|
|
|
||||||
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
||||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||||
|
@ -48,14 +29,14 @@ LL | let a = &x as &dyn Bar<_>; // Ambiguous
|
||||||
| +
|
| +
|
||||||
|
|
||||||
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
|
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
|
||||||
--> $DIR/type-checking-test-2.rs:28:13
|
--> $DIR/type-checking-test-2.rs:26:13
|
||||||
|
|
|
|
||||||
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
||||||
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
|
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
|
||||||
|
|
|
|
||||||
= note: required for the cast to the object type `dyn Bar<_>`
|
= note: required for the cast to the object type `dyn Bar<_>`
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0605.
|
Some errors have detailed explanations: E0277, E0605.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
|
Loading…
Reference in New Issue