move GAT inference prevention hack
This commit is contained in:
parent
95aeb46965
commit
15b02a94b1
4 changed files with 104 additions and 47 deletions
|
|
@ -1125,11 +1125,12 @@ where
|
|||
/// treat the alias as rigid.
|
||||
///
|
||||
/// See trait-system-refactor-initiative#124 for more details.
|
||||
#[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
|
||||
#[instrument(level = "debug", skip_all, fields(proven_via, goal), ret)]
|
||||
pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
|
||||
&mut self,
|
||||
proven_via: Option<TraitGoalProvenVia>,
|
||||
goal: Goal<I, G>,
|
||||
inject_forced_ambiguity_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> Option<QueryResult<I>>,
|
||||
inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
|
||||
) -> QueryResult<I> {
|
||||
let Some(proven_via) = proven_via else {
|
||||
|
|
@ -1149,15 +1150,24 @@ where
|
|||
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
|
||||
let (mut candidates, _) = self
|
||||
.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
|
||||
debug!(?candidates);
|
||||
|
||||
// If the trait goal has been proven by using the environment, we want to treat
|
||||
// aliases as rigid if there are no applicable projection bounds in the environment.
|
||||
if candidates.is_empty() {
|
||||
return inject_normalize_to_rigid_candidate(self);
|
||||
}
|
||||
|
||||
// If we're normalizing an GAT, we bail if using a where-bound would constrain
|
||||
// its generic arguments.
|
||||
if let Some(result) = inject_forced_ambiguity_candidate(self) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// We still need to prefer where-bounds over alias-bounds however.
|
||||
// See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
|
||||
if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
|
||||
candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_)));
|
||||
} else if candidates.is_empty() {
|
||||
// If the trait goal has been proven by using the environment, we want to treat
|
||||
// aliases as rigid if there are no applicable projection bounds in the environment.
|
||||
return inject_normalize_to_rigid_candidate(self);
|
||||
}
|
||||
|
||||
if let Some((response, _)) = self.try_merge_candidates(&candidates) {
|
||||
|
|
|
|||
|
|
@ -446,6 +446,6 @@ where
|
|||
goal.with(ecx.cx(), goal.predicate.trait_ref);
|
||||
ecx.compute_trait_goal(trait_goal)
|
||||
})?;
|
||||
self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
|
||||
self.assemble_and_merge_candidates(proven_via, goal, |_ecx| None, |_ecx| Err(NoSolution))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,15 +39,49 @@ where
|
|||
let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
|
||||
ecx.compute_trait_goal(trait_goal)
|
||||
})?;
|
||||
self.assemble_and_merge_candidates(proven_via, goal, |ecx| {
|
||||
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
|
||||
this.structurally_instantiate_normalizes_to_term(
|
||||
goal,
|
||||
goal.predicate.alias,
|
||||
);
|
||||
this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
})
|
||||
self.assemble_and_merge_candidates(
|
||||
proven_via,
|
||||
goal,
|
||||
|ecx| {
|
||||
// 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 a GAT argument is fully unconstrained.
|
||||
// This is quite arbitrary but fixing it causes some ambiguity, see #125196.
|
||||
for arg in goal.predicate.alias.own_args(cx).iter() {
|
||||
let Some(term) = arg.as_term() else {
|
||||
continue;
|
||||
};
|
||||
match ecx.structurally_normalize_term(goal.param_env, term) {
|
||||
Ok(term) => {
|
||||
if term.is_infer() {
|
||||
return Some(
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(NoSolution) => return Some(Err(NoSolution)),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
|ecx| {
|
||||
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
|
||||
this.structurally_instantiate_normalizes_to_term(
|
||||
goal,
|
||||
goal.predicate.alias,
|
||||
);
|
||||
this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
|
||||
self.normalize_inherent_associated_term(goal)
|
||||
|
|
@ -132,39 +166,7 @@ where
|
|||
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);
|
||||
ecx.eq(goal.param_env, goal.predicate.alias, assumption_projection_pred.projection_term)?;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue