Instantiate binders in supertrait_vtable_slot

This commit is contained in:
Michael Goulet 2024-09-29 17:51:38 -04:00
parent c3ce4e66a5
commit af3f212453
2 changed files with 38 additions and 17 deletions

View File

@ -2,6 +2,8 @@
use std::ops::ControlFlow; use std::ops::ControlFlow;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::util::PredicateSet;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
@ -13,7 +15,7 @@
use tracing::debug; use tracing::debug;
use crate::errors::DumpVTableEntries; use crate::errors::DumpVTableEntries;
use crate::traits::{impossible_predicates, is_vtable_safe_method}; use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum VtblSegment<'tcx> { pub enum VtblSegment<'tcx> {
@ -383,17 +385,37 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
let ty::Dynamic(target, _, _) = *target.kind() else { let ty::Dynamic(target, _, _) = *target.kind() else {
bug!(); bug!();
}; };
let target_principal = tcx let target_principal = target.principal()?.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal()?)
.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
// Given that we have a target principal, it is a bug for there not to be a source principal. // Given that we have a target principal, it is a bug for there not to be a source principal.
let ty::Dynamic(source, _, _) = *source.kind() else { let ty::Dynamic(source, _, _) = *source.kind() else {
bug!(); bug!();
}; };
let source_principal = tcx let source_principal =
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self);
.with_self_ty(tcx, tcx.types.trait_object_dummy_self);
let infcx = tcx.infer_ctxt().build();
let param_env = ty::ParamEnv::reveal_all();
let trait_refs_are_compatible =
|source: ty::PolyTraitRef<'tcx>, target: ty::PolyTraitRef<'tcx>| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new(&infcx);
let source = ocx.normalize(&ObligationCause::dummy(), param_env, source);
let target = ocx.normalize(&ObligationCause::dummy(), param_env, target);
infcx.enter_forall(target, |target| {
let source = infcx.instantiate_binder_with_fresh_vars(
DUMMY_SP,
BoundRegionConversionTime::HigherRankedType,
source,
);
let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, target, source)
else {
return false;
};
ocx.select_all_or_error().is_empty()
})
})
};
let vtable_segment_callback = { let vtable_segment_callback = {
let mut vptr_offset = 0; let mut vptr_offset = 0;
@ -404,9 +426,7 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
} }
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len();
if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref) if trait_refs_are_compatible(trait_ref, target_principal) {
== target_principal
{
if emit_vptr { if emit_vptr {
return ControlFlow::Break(Some(vptr_offset)); return ControlFlow::Break(Some(vptr_offset));
} else { } else {

View File

@ -1,21 +1,22 @@
//@ revisions: current next //@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions) //@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver //@[next] compile-flags: -Znext-solver
//@ check-pass //@ build-pass
// We should be able to instantiate a binder during trait upcasting. // Check that we are able to instantiate a binder during trait upcasting,
// This test could be `check-pass`, but we should make sure that we // and that it doesn't cause any issues with codegen either.
// do so in both trait solvers.
#![feature(trait_upcasting)] #![feature(trait_upcasting)]
trait Supertrait<'a, 'b> {} trait Supertrait<'a, 'b> {}
trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {} trait Subtrait<'a, 'b>: Supertrait<'a, 'b> {}
impl<'a> Supertrait<'a, 'a> for () {} impl Supertrait<'_, '_> for () {}
impl<'a> Subtrait<'a, 'a> for () {} impl Subtrait<'_, '_> for () {}
fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> { fn ok(x: &dyn for<'a, 'b> Subtrait<'a, 'b>) -> &dyn for<'a> Supertrait<'a, 'a> {
x x
} }
fn main() {} fn main() {
ok(&());
}