Rollup merge of #134638 - compiler-errors:fx-item-bounds, r=lcnr
Fix effect predicates from item bounds in old solver r? lcnr
This commit is contained in:
commit
c2f44cd32c
13 changed files with 202 additions and 78 deletions
|
@ -1,13 +1,15 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
|
||||
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{self, TypingMode};
|
||||
use rustc_type_ir::elaborate::elaborate;
|
||||
use rustc_type_ir::solve::NoSolution;
|
||||
use thin_vec::ThinVec;
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use super::SelectionContext;
|
||||
use super::normalize::normalize_with_depth_to;
|
||||
|
||||
pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
|
||||
|
||||
|
@ -38,6 +40,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
|
|||
Err(EvaluationFailure::NoSolution) => {}
|
||||
}
|
||||
|
||||
match evaluate_host_effect_from_item_bounds(selcx, obligation) {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
||||
Err(EvaluationFailure::NoSolution) => {}
|
||||
}
|
||||
|
||||
match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
||||
|
@ -48,24 +56,45 @@ pub fn evaluate_host_effect_obligation<'tcx>(
|
|||
}
|
||||
|
||||
fn match_candidate<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
|
||||
candidate_is_unnormalized: bool,
|
||||
more_nested: impl FnOnce(&mut SelectionContext<'_, 'tcx>, &mut ThinVec<PredicateObligation<'tcx>>),
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
|
||||
if !candidate.skip_binder().constness.satisfies(obligation.predicate.constness) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let candidate = infcx.instantiate_binder_with_fresh_vars(
|
||||
let mut candidate = selcx.infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
candidate,
|
||||
);
|
||||
|
||||
let mut nested = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
|
||||
.into_obligations();
|
||||
let mut nested = thin_vec![];
|
||||
|
||||
// Unlike param-env bounds, item bounds may not be normalized.
|
||||
if candidate_is_unnormalized {
|
||||
candidate = normalize_with_depth_to(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth,
|
||||
candidate,
|
||||
&mut nested,
|
||||
);
|
||||
}
|
||||
|
||||
nested.extend(
|
||||
selcx
|
||||
.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
|
||||
.into_obligations(),
|
||||
);
|
||||
|
||||
more_nested(selcx, &mut nested);
|
||||
|
||||
for nested in &mut nested {
|
||||
nested.set_depth_from_parent(obligation.recursion_depth);
|
||||
|
@ -82,41 +111,121 @@ fn evaluate_host_effect_from_bounds<'tcx>(
|
|||
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
|
||||
let mut candidate = None;
|
||||
|
||||
for predicate in obligation.param_env.caller_bounds() {
|
||||
let bound_predicate = predicate.kind();
|
||||
if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
|
||||
let data = bound_predicate.rebind(data);
|
||||
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
||||
continue;
|
||||
}
|
||||
for clause in obligation.param_env.caller_bounds() {
|
||||
let bound_clause = clause.kind();
|
||||
let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
|
||||
continue;
|
||||
};
|
||||
let data = bound_clause.rebind(data);
|
||||
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !drcx.args_may_unify(
|
||||
obligation.predicate.trait_ref.args,
|
||||
data.skip_binder().trait_ref.args,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if !drcx
|
||||
.args_may_unify(obligation.predicate.trait_ref.args, data.skip_binder().trait_ref.args)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());
|
||||
let is_match =
|
||||
infcx.probe(|_| match_candidate(selcx, obligation, data, false, |_, _| {}).is_ok());
|
||||
|
||||
if is_match {
|
||||
if candidate.is_some() {
|
||||
return Err(EvaluationFailure::Ambiguous);
|
||||
} else {
|
||||
candidate = Some(data);
|
||||
}
|
||||
if is_match {
|
||||
if candidate.is_some() {
|
||||
return Err(EvaluationFailure::Ambiguous);
|
||||
} else {
|
||||
candidate = Some(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(data) = candidate {
|
||||
Ok(match_candidate(infcx, obligation, data)
|
||||
Ok(match_candidate(selcx, obligation, data, false, |_, _| {})
|
||||
.expect("candidate matched before, so it should match again"))
|
||||
} else {
|
||||
Err(EvaluationFailure::NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_host_effect_from_item_bounds<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||
let infcx = selcx.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
|
||||
let mut candidate = None;
|
||||
|
||||
let mut consider_ty = obligation.predicate.self_ty();
|
||||
while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
|
||||
if tcx.is_conditionally_const(alias_ty.def_id) {
|
||||
for clause in elaborate(
|
||||
tcx,
|
||||
tcx.explicit_implied_const_bounds(alias_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, alias_ty.args)
|
||||
.map(|(trait_ref, _)| {
|
||||
trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness)
|
||||
}),
|
||||
) {
|
||||
let bound_clause = clause.kind();
|
||||
let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
|
||||
unreachable!("should not elaborate non-HostEffect from HostEffect")
|
||||
};
|
||||
let data = bound_clause.rebind(data);
|
||||
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !drcx.args_may_unify(
|
||||
obligation.predicate.trait_ref.args,
|
||||
data.skip_binder().trait_ref.args,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_match = infcx
|
||||
.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
|
||||
|
||||
if is_match {
|
||||
if candidate.is_some() {
|
||||
return Err(EvaluationFailure::Ambiguous);
|
||||
} else {
|
||||
candidate = Some((data, alias_ty));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if kind != ty::Projection {
|
||||
break;
|
||||
}
|
||||
|
||||
consider_ty = alias_ty.self_ty();
|
||||
}
|
||||
|
||||
if let Some((data, alias_ty)) = candidate {
|
||||
Ok(match_candidate(selcx, obligation, data, true, |selcx, nested| {
|
||||
// An alias bound only holds if we also check the const conditions
|
||||
// of the alias, so we need to register those, too.
|
||||
let const_conditions = normalize_with_depth_to(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
obligation.cause.clone(),
|
||||
obligation.recursion_depth,
|
||||
tcx.const_conditions(alias_ty.def_id).instantiate(tcx, alias_ty.args),
|
||||
nested,
|
||||
);
|
||||
nested.extend(const_conditions.into_iter().map(|(trait_ref, _)| {
|
||||
obligation
|
||||
.with(tcx, trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness))
|
||||
}));
|
||||
})
|
||||
.expect("candidate matched before, so it should match again"))
|
||||
} else {
|
||||
Err(EvaluationFailure::NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_host_effect_from_selection_candiate<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue