Fold vtable_trait_upcasting_coercion_new_vptr_slot
logic into obligation processing.
This commit is contained in:
parent
1e605023ec
commit
6b1c52ff25
11 changed files with 137 additions and 87 deletions
|
@ -28,6 +28,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
|||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc_middle::ty::{
|
||||
|
@ -759,48 +760,38 @@ fn vtable_trait_first_method_offset<'tcx>(
|
|||
pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: (
|
||||
ty::PolyTraitRef<'tcx>, // trait owning vtable
|
||||
ty::PolyTraitRef<'tcx>, // super trait ref
|
||||
Ty<'tcx>, // trait object type whose trait owning vtable
|
||||
Ty<'tcx>, // trait object for supertrait
|
||||
),
|
||||
) -> Option<usize> {
|
||||
let (trait_owning_vtable, super_trait_ref) = key;
|
||||
let super_trait_did = super_trait_ref.def_id();
|
||||
// FIXME: take substsref part into account here after upcasting coercion allows the same def_id occur
|
||||
// multiple times.
|
||||
let (source, target) = key;
|
||||
debug_assert!(matches!(&source.kind(), &ty::Dynamic(..)));
|
||||
debug_assert!(matches!(&target.kind(), &ty::Dynamic(..)));
|
||||
|
||||
let vtable_segment_callback = {
|
||||
let mut vptr_offset = 0;
|
||||
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);
|
||||
}
|
||||
}
|
||||
// this has been typecked-before, so diagnostics is not really needed.
|
||||
let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
|
||||
|
||||
if emit_vptr {
|
||||
vptr_offset += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
let trait_ref = ty::TraitRef {
|
||||
def_id: unsize_trait_did,
|
||||
substs: tcx.mk_substs_trait(source, &[target.into()]),
|
||||
};
|
||||
let obligation = Obligation::new(
|
||||
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) =
|
||||
prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
|
||||
{
|
||||
vptr_offset
|
||||
} else {
|
||||
bug!("Failed to find info for expected trait in vtable");
|
||||
}
|
||||
implsrc_traitcasting.vtable_vptr_slot
|
||||
}
|
||||
|
||||
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.
|
||||
false
|
||||
}
|
||||
super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
|
||||
super::ImplSource::AutoImpl(..)
|
||||
| super::ImplSource::Builtin(..)
|
||||
| super::ImplSource::TraitUpcasting(_) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.delay_span_bug(
|
||||
obligation.cause.span,
|
||||
|
@ -1554,6 +1556,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||
| super::ImplSource::AutoImpl(..)
|
||||
| super::ImplSource::Param(..)
|
||||
| super::ImplSource::Builtin(..)
|
||||
| super::ImplSource::TraitUpcasting(_)
|
||||
| super::ImplSource::TraitAlias(..) => {
|
||||
// we don't create Select candidates with this kind of resolution
|
||||
span_bug!(
|
||||
|
|
|
@ -26,12 +26,13 @@ use crate::traits::Normalized;
|
|||
use crate::traits::OutputTypeParameterMismatch;
|
||||
use crate::traits::Selection;
|
||||
use crate::traits::TraitNotObjectSafe;
|
||||
use crate::traits::VtblSegment;
|
||||
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
|
||||
use crate::traits::{
|
||||
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
|
||||
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
|
||||
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
|
||||
ImplSourceUserDefinedData,
|
||||
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
|
||||
};
|
||||
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
|
||||
use crate::traits::{Obligation, ObligationCause};
|
||||
|
@ -42,6 +43,7 @@ use super::SelectionCandidate::{self, *};
|
|||
use super::SelectionContext;
|
||||
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
@ -121,7 +123,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
TraitUpcastingUnsizeCandidate(idx) => {
|
||||
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
|
||||
Ok(ImplSource::Builtin(data))
|
||||
Ok(ImplSource::TraitUpcasting(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -694,7 +696,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
idx: usize,
|
||||
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
|
||||
|
@ -706,16 +709,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
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();
|
||||
let source_trait_ref = principal_a.with_self_ty(tcx, source);
|
||||
let target_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
|
||||
assert_eq!(data_b.principal_def_id(), Some(target_trait_ref.def_id()));
|
||||
let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
|
||||
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,
|
||||
))
|
||||
|
@ -762,7 +767,37 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
_ => bug!(),
|
||||
};
|
||||
|
||||
Ok(ImplSourceBuiltinData { nested })
|
||||
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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue