Rollup merge of #140712 - lcnr:normalization-gat-args, r=compiler-errors
normalization: avoid incompletely constraining GAT args We need to copy the behavior of #125214 in the new solver. This fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/202 which seems to be the cause of the regression in `deptypes`. r? ```@compiler-errors```
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
pub(super) mod structural_traits;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use derive_where::derive_where;
|
||||
@@ -117,24 +118,24 @@ where
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
Self::fast_reject_assumption(ecx, goal, assumption)?;
|
||||
|
||||
ecx.probe(|candidate: &Result<Candidate<I>, NoSolution>| match candidate {
|
||||
Ok(candidate) => inspect::ProbeKind::TraitCandidate {
|
||||
source: candidate.source,
|
||||
result: Ok(candidate.result),
|
||||
},
|
||||
Err(NoSolution) => inspect::ProbeKind::TraitCandidate {
|
||||
source: CandidateSource::ParamEnv(ParamEnvSource::Global),
|
||||
result: Err(NoSolution),
|
||||
},
|
||||
// Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
|
||||
// check whether the candidate is global while considering normalization.
|
||||
//
|
||||
// We need to write into `source` inside of `match_assumption`, but need to access it
|
||||
// in `probe` even if the candidate does not apply before we get there. We handle this
|
||||
// by using a `Cell` here. We only ever write into it inside of `match_assumption`.
|
||||
let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global));
|
||||
ecx.probe(|result: &QueryResult<I>| inspect::ProbeKind::TraitCandidate {
|
||||
source: source.get(),
|
||||
result: *result,
|
||||
})
|
||||
.enter(|ecx| {
|
||||
Self::match_assumption(ecx, goal, assumption)?;
|
||||
let source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?;
|
||||
Ok(Candidate {
|
||||
source,
|
||||
result: ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?,
|
||||
Self::match_assumption(ecx, goal, assumption, |ecx| {
|
||||
source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
})
|
||||
.map(|result| Candidate { source: source.get(), result })
|
||||
}
|
||||
|
||||
/// Try equating an assumption predicate against a goal's predicate. If it
|
||||
@@ -150,10 +151,8 @@ where
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
Self::fast_reject_assumption(ecx, goal, assumption)?;
|
||||
|
||||
ecx.probe_trait_candidate(source).enter(|ecx| {
|
||||
Self::match_assumption(ecx, goal, assumption)?;
|
||||
then(ecx)
|
||||
})
|
||||
ecx.probe_trait_candidate(source)
|
||||
.enter(|ecx| Self::match_assumption(ecx, goal, assumption, then))
|
||||
}
|
||||
|
||||
/// Try to reject the assumption based off of simple heuristics, such as [`ty::ClauseKind`]
|
||||
@@ -169,7 +168,8 @@ where
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
) -> Result<(), NoSolution>;
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
|
||||
) -> QueryResult<I>;
|
||||
|
||||
fn consider_impl_candidate(
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
|
||||
@@ -61,13 +61,14 @@ where
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
) -> Result<(), NoSolution> {
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
|
||||
) -> QueryResult<I> {
|
||||
let host_clause = assumption.as_host_effect_clause().unwrap();
|
||||
|
||||
let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
|
||||
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
|
||||
|
||||
Ok(())
|
||||
then(ecx)
|
||||
}
|
||||
|
||||
/// Register additional assumptions for aliases corresponding to `~const` item bounds.
|
||||
|
||||
@@ -129,7 +129,40 @@ where
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
) -> Result<(), NoSolution> {
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
|
||||
) -> QueryResult<I> {
|
||||
let cx = ecx.cx();
|
||||
// FIXME(generic_associated_types): Addresses aggressive inference in #92917.
|
||||
//
|
||||
// If this type is a GAT with currently unconstrained arguments, we do not
|
||||
// want to normalize it via a candidate which only applies for a specific
|
||||
// instantiation. We could otherwise keep the GAT as rigid and succeed this way.
|
||||
// See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs.
|
||||
//
|
||||
// This only avoids normalization if the GAT arguments are fully unconstrained.
|
||||
// This is quite arbitrary but fixing it causes some ambiguity, see #125196.
|
||||
match goal.predicate.alias.kind(cx) {
|
||||
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
|
||||
for arg in goal.predicate.alias.own_args(cx).iter() {
|
||||
let Some(term) = arg.as_term() else {
|
||||
continue;
|
||||
};
|
||||
let term = ecx.structurally_normalize_term(goal.param_env, term)?;
|
||||
if term.is_infer() {
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::AliasTermKind::OpaqueTy
|
||||
| ty::AliasTermKind::InherentTy
|
||||
| ty::AliasTermKind::InherentConst
|
||||
| ty::AliasTermKind::FreeTy
|
||||
| ty::AliasTermKind::FreeConst
|
||||
| ty::AliasTermKind::UnevaluatedConst => {}
|
||||
}
|
||||
|
||||
let projection_pred = assumption.as_projection_clause().unwrap();
|
||||
|
||||
let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred);
|
||||
@@ -139,7 +172,6 @@ where
|
||||
|
||||
// Add GAT where clauses from the trait's definition
|
||||
// FIXME: We don't need these, since these are the type's own WF obligations.
|
||||
let cx = ecx.cx();
|
||||
ecx.add_goals(
|
||||
GoalSource::AliasWellFormed,
|
||||
cx.own_predicates_of(goal.predicate.def_id())
|
||||
@@ -147,7 +179,7 @@ where
|
||||
.map(|pred| goal.with(cx, pred)),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
then(ecx)
|
||||
}
|
||||
|
||||
fn consider_additional_alias_assumptions(
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidates
|
||||
use crate::solve::inspect::ProbeKind;
|
||||
use crate::solve::{
|
||||
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
|
||||
NoSolution, ParamEnvSource,
|
||||
NoSolution, ParamEnvSource, QueryResult,
|
||||
};
|
||||
|
||||
impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
|
||||
@@ -150,13 +150,14 @@ where
|
||||
ecx: &mut EvalCtxt<'_, D>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
) -> Result<(), NoSolution> {
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
|
||||
) -> QueryResult<I> {
|
||||
let trait_clause = assumption.as_trait_clause().unwrap();
|
||||
|
||||
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
|
||||
ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
|
||||
|
||||
Ok(())
|
||||
then(ecx)
|
||||
}
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
|
||||
Reference in New Issue
Block a user