Skip to content

Commit 42641c5

Browse files
Pull non-wf alias detection into sub-functions
1 parent fd0f8f6 commit 42641c5

File tree

1 file changed

+54
-33
lines changed

1 file changed

+54
-33
lines changed

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,59 @@ impl<'tcx> BestObligation<'tcx> {
290290
ControlFlow::Continue(())
291291
}
292292
}
293+
294+
/// It is likely that `NormalizesTo` failed without any applicable candidates
295+
/// because the alias is not well-formed.
296+
///
297+
/// As we only enter `RigidAlias` candidates if the trait bound of the associated type
298+
/// holds, we discard these candidates in `non_trivial_candidates` and always manually
299+
/// check this here.
300+
fn detect_non_well_formed_assoc_item(
301+
&mut self,
302+
goal: &inspect::InspectGoal<'_, 'tcx>,
303+
alias: ty::AliasTerm<'tcx>,
304+
) -> ControlFlow<PredicateObligation<'tcx>> {
305+
let tcx = goal.infcx().tcx;
306+
let obligation = Obligation::new(
307+
tcx,
308+
self.obligation.cause.clone(),
309+
goal.goal().param_env,
310+
alias.trait_ref(tcx),
311+
);
312+
self.with_derived_obligation(obligation, |this| {
313+
goal.infcx().visit_proof_tree_at_depth(
314+
goal.goal().with(tcx, alias.trait_ref(tcx)),
315+
goal.depth() + 1,
316+
this,
317+
)
318+
})
319+
}
320+
321+
/// If we have no candidates, then it's likely that we a non-well-formed alias
322+
/// in the goal.
323+
fn detect_error_from_empty_candidates(
324+
&mut self,
325+
goal: &inspect::InspectGoal<'_, 'tcx>,
326+
) -> ControlFlow<PredicateObligation<'tcx>> {
327+
let tcx = goal.infcx().tcx;
328+
let pred_kind = goal.goal().predicate.kind();
329+
330+
match pred_kind.no_bound_vars() {
331+
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
332+
self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
333+
}
334+
Some(ty::PredicateKind::NormalizesTo(pred))
335+
if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst =
336+
pred.alias.kind(tcx) =>
337+
{
338+
self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
339+
self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
340+
}
341+
Some(_) | None => {}
342+
}
343+
344+
ControlFlow::Break(self.obligation.clone())
345+
}
293346
}
294347

295348
impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -311,40 +364,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
311364

312365
let candidates = self.non_trivial_candidates(goal);
313366
let candidate = match candidates.as_slice() {
314-
[] => {
315-
match pred_kind.no_bound_vars() {
316-
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
317-
self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
318-
}
319-
Some(ty::PredicateKind::NormalizesTo(pred))
320-
if let ty::AliasTermKind::ProjectionTy
321-
| ty::AliasTermKind::ProjectionConst = pred.alias.kind(tcx) =>
322-
{
323-
self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
324-
// It is likely that `NormalizesTo` failed because the alias is not well-formed.
325-
// As we only enter `RigidAlias` candidates if the trait bound of the associated type
326-
// holds, we discard these candidates in `non_trivial_candidates` and always manually
327-
// check this here.
328-
let obligation = Obligation::new(
329-
tcx,
330-
self.obligation.cause.clone(),
331-
goal.goal().param_env,
332-
pred.alias.trait_ref(tcx),
333-
);
334-
self.with_derived_obligation(obligation, |this| {
335-
goal.infcx().visit_proof_tree_at_depth(
336-
goal.goal().with(tcx, pred.alias.trait_ref(tcx)),
337-
goal.depth() + 1,
338-
this,
339-
)
340-
})?;
341-
}
342-
Some(_) | None => {}
343-
}
344-
345-
return ControlFlow::Break(self.obligation.clone());
346-
}
347367
[candidate] => candidate,
368+
[] => return self.detect_error_from_empty_candidates(goal),
348369
_ => return ControlFlow::Break(self.obligation.clone()),
349370
};
350371

0 commit comments

Comments
 (0)