Skip to content

Commit d87e0ca

Browse files
Extract trait_refs_are_compatible, make it instantiate binders
1 parent af3f212 commit d87e0ca

File tree

2 files changed

+64
-28
lines changed

2 files changed

+64
-28
lines changed

compiler/rustc_trait_selection/src/traits/engine.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{
99
Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
1010
};
1111
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
12-
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError};
12+
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace};
1313
use rustc_macros::extension;
1414
use rustc_middle::arena::ArenaAllocatable;
1515
use rustc_middle::traits::query::NoSolution;
1616
use rustc_middle::ty::error::TypeError;
1717
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance};
18+
use rustc_type_ir::relate::Relate;
1819

1920
use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine};
2021
use crate::error_reporting::InferCtxtErrorExt;
@@ -133,6 +134,20 @@ where
133134
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
134135
}
135136

137+
pub fn eq_trace<T: Relate<TyCtxt<'tcx>>>(
138+
&self,
139+
cause: &ObligationCause<'tcx>,
140+
param_env: ty::ParamEnv<'tcx>,
141+
trace: TypeTrace<'tcx>,
142+
expected: T,
143+
actual: T,
144+
) -> Result<(), TypeError<'tcx>> {
145+
self.infcx
146+
.at(cause, param_env)
147+
.eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual)
148+
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
149+
}
150+
136151
/// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
137152
pub fn sub<T: ToTrace<'tcx>>(
138153
&self,

compiler/rustc_trait_selection/src/traits/vtable.rs

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::fmt::Debug;
22
use std::ops::ControlFlow;
33

44
use rustc_hir::def_id::DefId;
5+
use rustc_infer::infer::at::ToTrace;
56
use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
67
use rustc_infer::traits::ObligationCause;
78
use rustc_infer::traits::util::PredicateSet;
@@ -24,6 +25,8 @@ pub enum VtblSegment<'tcx> {
2425
}
2526

2627
/// Prepare the segments for a vtable
28+
// FIXME: This should take a `PolyExistentialTraitRef`, since we don't care
29+
// about our `Self` type here.
2730
pub fn prepare_vtable_segments<'tcx, T>(
2831
tcx: TyCtxt<'tcx>,
2932
trait_ref: ty::PolyTraitRef<'tcx>,
@@ -385,7 +388,7 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
385388
let ty::Dynamic(target, _, _) = *target.kind() else {
386389
bug!();
387390
};
388-
let target_principal = target.principal()?.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
391+
let target_principal = target.principal()?;
389392

390393
// Given that we have a target principal, it is a bug for there not to be a source principal.
391394
let ty::Dynamic(source, _, _) = *source.kind() else {
@@ -394,39 +397,22 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
394397
let source_principal =
395398
source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
396399

397-
let infcx = tcx.infer_ctxt().build();
398-
let param_env = ty::ParamEnv::reveal_all();
399-
let trait_refs_are_compatible =
400-
|source: ty::PolyTraitRef<'tcx>, target: ty::PolyTraitRef<'tcx>| {
401-
infcx.probe(|_| {
402-
let ocx = ObligationCtxt::new(&infcx);
403-
let source = ocx.normalize(&ObligationCause::dummy(), param_env, source);
404-
let target = ocx.normalize(&ObligationCause::dummy(), param_env, target);
405-
infcx.enter_forall(target, |target| {
406-
let source = infcx.instantiate_binder_with_fresh_vars(
407-
DUMMY_SP,
408-
BoundRegionConversionTime::HigherRankedType,
409-
source,
410-
);
411-
let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target, source)
412-
else {
413-
return false;
414-
};
415-
ocx.select_all_or_error().is_empty()
416-
})
417-
})
418-
};
419-
420400
let vtable_segment_callback = {
421401
let mut vptr_offset = 0;
422402
move |segment| {
423403
match segment {
424404
VtblSegment::MetadataDSA => {
425405
vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
426406
}
427-
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
428-
vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
429-
if trait_refs_are_compatible(trait_ref, target_principal) {
407+
VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => {
408+
vptr_offset +=
409+
tcx.own_existential_vtable_entries(vtable_principal.def_id()).len();
410+
if trait_refs_are_compatible(
411+
tcx,
412+
vtable_principal
413+
.map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)),
414+
target_principal,
415+
) {
430416
if emit_vptr {
431417
return ControlFlow::Break(Some(vptr_offset));
432418
} else {
@@ -446,6 +432,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
446432
prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap()
447433
}
448434

435+
fn trait_refs_are_compatible<'tcx>(
436+
tcx: TyCtxt<'tcx>,
437+
hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>,
438+
hr_target_principal: ty::PolyExistentialTraitRef<'tcx>,
439+
) -> bool {
440+
if hr_vtable_principal.def_id() != hr_target_principal.def_id() {
441+
return false;
442+
}
443+
444+
let infcx = tcx.infer_ctxt().build();
445+
let param_env = ty::ParamEnv::reveal_all();
446+
let ocx = ObligationCtxt::new(&infcx);
447+
let hr_source_principal =
448+
ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal);
449+
let hr_target_principal =
450+
ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal);
451+
infcx.enter_forall(hr_target_principal, |target_principal| {
452+
let source_principal = infcx.instantiate_binder_with_fresh_vars(
453+
DUMMY_SP,
454+
BoundRegionConversionTime::HigherRankedType,
455+
hr_source_principal,
456+
);
457+
let Ok(()) = ocx.eq_trace(
458+
&ObligationCause::dummy(),
459+
param_env,
460+
ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal),
461+
target_principal,
462+
source_principal,
463+
) else {
464+
return false;
465+
};
466+
ocx.select_all_or_error().is_empty()
467+
})
468+
}
469+
449470
pub(super) fn provide(providers: &mut Providers) {
450471
*providers = Providers {
451472
own_existential_vtable_entries,

0 commit comments

Comments
 (0)