Rollup merge of #131699 - compiler-errors:better-errors-for-projections, r=lcnr
Try to improve error messages involving aliases in the solver 1. Treat aliases as rigid only if it may not be defined and it's well formed (i.e. for projections, its trait goal is satisfied). 2. Record goals that are related to alias normalization under a new `GoalKind`, so we can look into them in the `BestObligation` visitor. 3. Try to deduplicate errors due to self types of goals that are un-normalizable aliases. r? lcnr
This commit is contained in:
commit
aac91f75e3
34 changed files with 324 additions and 187 deletions
|
@ -14,7 +14,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
|
||||
use tracing::instrument;
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use super::Certainty;
|
||||
use super::delegate::SolverDelegate;
|
||||
|
@ -401,6 +401,7 @@ impl<'tcx> BestObligation<'tcx> {
|
|||
nested_goal.source(),
|
||||
GoalSource::ImplWhereBound
|
||||
| GoalSource::InstantiateHigherRanked
|
||||
| GoalSource::AliasWellFormed
|
||||
) && match self.consider_ambiguities {
|
||||
true => {
|
||||
matches!(
|
||||
|
@ -415,6 +416,13 @@ impl<'tcx> BestObligation<'tcx> {
|
|||
})
|
||||
});
|
||||
}
|
||||
|
||||
// Prefer a non-rigid candidate if there is one.
|
||||
if candidates.len() > 1 {
|
||||
candidates.retain(|candidate| {
|
||||
!matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. })
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,8 +437,11 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
|
|||
self.obligation.cause.span
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
|
||||
fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
|
||||
let candidates = self.non_trivial_candidates(goal);
|
||||
trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>());
|
||||
|
||||
let [candidate] = candidates.as_slice() else {
|
||||
return ControlFlow::Break(self.obligation.clone());
|
||||
};
|
||||
|
@ -464,17 +475,13 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
|
|||
polarity: ty::PredicatePolarity::Positive,
|
||||
}))
|
||||
}
|
||||
ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::WellFormed(_) | ty::ClauseKind::Projection(..),
|
||||
)
|
||||
| ty::PredicateKind::AliasRelate(..) => ChildMode::PassThrough,
|
||||
_ => {
|
||||
return ControlFlow::Break(self.obligation.clone());
|
||||
}
|
||||
_ => ChildMode::PassThrough,
|
||||
};
|
||||
|
||||
let mut impl_where_bound_count = 0;
|
||||
for nested_goal in candidate.instantiate_nested_goals(self.span()) {
|
||||
trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
|
||||
|
||||
let make_obligation = |cause| Obligation {
|
||||
cause,
|
||||
param_env: nested_goal.goal().param_env,
|
||||
|
@ -501,7 +508,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
|
|||
(_, GoalSource::InstantiateHigherRanked) => {
|
||||
obligation = self.obligation.clone();
|
||||
}
|
||||
(ChildMode::PassThrough, _) => {
|
||||
(ChildMode::PassThrough, _) | (_, GoalSource::AliasWellFormed) => {
|
||||
obligation = make_obligation(self.obligation.cause.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,7 +292,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||
| inspect::ProbeKind::Root { .. }
|
||||
| inspect::ProbeKind::TryNormalizeNonRigid { .. }
|
||||
| inspect::ProbeKind::TraitCandidate { .. }
|
||||
| inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => {
|
||||
| inspect::ProbeKind::OpaqueTypeStorageLookup { .. }
|
||||
| inspect::ProbeKind::RigidAlias { .. } => {
|
||||
// Nested probes have to prove goals added in their parent
|
||||
// but do not leak them, so we truncate the added goals
|
||||
// afterwards.
|
||||
|
@ -316,7 +317,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||
inspect::ProbeKind::Root { result }
|
||||
| inspect::ProbeKind::TryNormalizeNonRigid { result }
|
||||
| inspect::ProbeKind::TraitCandidate { source: _, result }
|
||||
| inspect::ProbeKind::OpaqueTypeStorageLookup { result } => {
|
||||
| inspect::ProbeKind::OpaqueTypeStorageLookup { result }
|
||||
| inspect::ProbeKind::RigidAlias { result } => {
|
||||
// We only add a candidate if `shallow_certainty` was set, which means
|
||||
// that we ended up calling `evaluate_added_goals_and_make_canonical_response`.
|
||||
if let Some(shallow_certainty) = shallow_certainty {
|
||||
|
|
|
@ -177,7 +177,8 @@ fn to_selection<'tcx>(
|
|||
| ProbeKind::UpcastProjectionCompatibility
|
||||
| ProbeKind::OpaqueTypeStorageLookup { result: _ }
|
||||
| ProbeKind::Root { result: _ }
|
||||
| ProbeKind::ShadowedEnvProbing => {
|
||||
| ProbeKind::ShadowedEnvProbing
|
||||
| ProbeKind::RigidAlias { result: _ } => {
|
||||
span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue