Rollup merge of #113625 - compiler-errors:structurally-norm-in-selection, r=lcnr
Structurally normalize in selection We need to do this because of the fact that we're checking the `Ty::kind` on a type during selection, but goals passed into select are not necessarily normalized. Right now, we're (kinda) unnecessarily normalizing the RHS of a trait upcasting goal, which is broken for different reasons (#113393). But I'm waiting for this PR to land before discussing that one. r? `@lcnr`
This commit is contained in:
commit
da18cf8572
2 changed files with 51 additions and 6 deletions
|
@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||||
use rustc_infer::traits::util::supertraits;
|
use rustc_infer::traits::util::supertraits;
|
||||||
use rustc_infer::traits::{
|
use rustc_infer::traits::{
|
||||||
Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult,
|
Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
|
||||||
};
|
};
|
||||||
use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
|
use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
|
||||||
use rustc_middle::traits::{
|
use rustc_middle::traits::{
|
||||||
|
@ -20,6 +20,8 @@ use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
|
||||||
use crate::solve::inspect::ProofTreeBuilder;
|
use crate::solve::inspect::ProofTreeBuilder;
|
||||||
use crate::solve::search_graph::OverflowHandler;
|
use crate::solve::search_graph::OverflowHandler;
|
||||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||||
|
use crate::traits::StructurallyNormalizeExt;
|
||||||
|
use crate::traits::TraitEngineExt;
|
||||||
|
|
||||||
pub trait InferCtxtSelectExt<'tcx> {
|
pub trait InferCtxtSelectExt<'tcx> {
|
||||||
fn select_in_new_trait_solver(
|
fn select_in_new_trait_solver(
|
||||||
|
@ -228,18 +230,24 @@ fn rematch_object<'tcx>(
|
||||||
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
||||||
mut nested: Vec<PredicateObligation<'tcx>>,
|
mut nested: Vec<PredicateObligation<'tcx>>,
|
||||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
|
||||||
let ty::Dynamic(data, _, source_kind) = *self_ty.kind() else { bug!() };
|
let ty::Dynamic(data, _, source_kind) = *a_ty.kind() else { bug!() };
|
||||||
let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, self_ty);
|
let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, a_ty);
|
||||||
|
|
||||||
let (is_upcasting, target_trait_ref_unnormalized) =
|
let (is_upcasting, target_trait_ref_unnormalized) =
|
||||||
if Some(goal.predicate.def_id()) == infcx.tcx.lang_items().unsize_trait() {
|
if Some(goal.predicate.def_id()) == infcx.tcx.lang_items().unsize_trait() {
|
||||||
assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*");
|
assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*");
|
||||||
if let ty::Dynamic(data, _, ty::Dyn) = goal.predicate.trait_ref.args.type_at(1).kind() {
|
let b_ty = structurally_normalize(
|
||||||
|
goal.predicate.trait_ref.args.type_at(1),
|
||||||
|
infcx,
|
||||||
|
goal.param_env,
|
||||||
|
&mut nested,
|
||||||
|
);
|
||||||
|
if let ty::Dynamic(data, _, ty::Dyn) = *b_ty.kind() {
|
||||||
// FIXME: We also need to ensure that the source lifetime outlives the
|
// FIXME: We also need to ensure that the source lifetime outlives the
|
||||||
// target lifetime. This doesn't matter for codegen, though, and only
|
// target lifetime. This doesn't matter for codegen, though, and only
|
||||||
// *really* matters if the goal's certainty is ambiguous.
|
// *really* matters if the goal's certainty is ambiguous.
|
||||||
(true, data.principal().unwrap().with_self_ty(infcx.tcx, self_ty))
|
(true, data.principal().unwrap().with_self_ty(infcx.tcx, a_ty))
|
||||||
} else {
|
} else {
|
||||||
bug!()
|
bug!()
|
||||||
}
|
}
|
||||||
|
@ -447,3 +455,22 @@ fn rematch_unsize<'tcx>(
|
||||||
|
|
||||||
Ok(Some(ImplSource::Builtin(nested)))
|
Ok(Some(ImplSource::Builtin(nested)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn structurally_normalize<'tcx>(
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
infcx: &InferCtxt<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
nested: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
if matches!(ty.kind(), ty::Alias(..)) {
|
||||||
|
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx);
|
||||||
|
let normalized_ty = infcx
|
||||||
|
.at(&ObligationCause::dummy(), param_env)
|
||||||
|
.structurally_normalize(ty, &mut *engine)
|
||||||
|
.expect("normalization shouldn't fail if we got to here");
|
||||||
|
nested.extend(engine.pending_obligations());
|
||||||
|
normalized_ty
|
||||||
|
} else {
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// check-pass
|
||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
|
||||||
|
pub trait A {}
|
||||||
|
pub trait B: A {}
|
||||||
|
|
||||||
|
pub trait Mirror {
|
||||||
|
type Assoc: ?Sized;
|
||||||
|
}
|
||||||
|
impl<T: ?Sized> Mirror for T {
|
||||||
|
type Assoc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foo<'a>(x: &'a <dyn B + 'static as Mirror>::Assoc) -> &'a (dyn A + 'static) {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue