Rollup merge of #135866 - BoxyUwU:dont_pick_fnptr_nested_goals, r=lcnr

Don't pick `T: FnPtr` nested goals as the leaf goal in diagnostics for new solver

r? `@lcnr`

See `tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs` for a minimized example of what code this affects the diagnostics off. The output of running nightly `-Znext-solver` on that test is the following:
```
error[E0277]: the trait bound `Foo: Trait` is not satisfied
  --> src/lib.rs:14:20
   |
14 |     requires_trait(Foo);
   |     -------------- ^^^ the trait `FnPtr` is not implemented for `Foo`
   |     |
   |     required by a bound introduced by this call
   |
note: required for `Foo` to implement `Trait`
  --> src/lib.rs:7:16
   |
7  | impl<T: FnPtr> Trait for T {}
   |         -----  ^^^^^     ^
   |         |
   |         unsatisfied trait bound introduced here
note: required by a bound in `requires_trait`
  --> src/lib.rs:11:22
   |
11 | fn requires_trait<T: Trait>(_: T) {}
   |                      ^^^^^ required by this bound in `requires_trait`
```

Part of rust-lang/trait-system-refactor-initiative#148
This commit is contained in:
Matthias Krüger 2025-01-22 19:29:43 +01:00 committed by GitHub
commit 318466aec0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 389 additions and 69 deletions

View file

@ -513,8 +513,27 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
_ => ChildMode::PassThrough,
};
let nested_goals = candidate.instantiate_nested_goals(self.span());
// If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as
// an actual candidate, instead we should treat them as if the impl was never considered to
// have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written
// instead of `impl<T: FnPtr> Trait for T`.
//
// We do this as a separate loop so that we do not choose to tell the user about some nested
// goal before we encounter a `T: FnPtr` nested goal.
for nested_goal in &nested_goals {
if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
&& let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
&& poly_trait_pred.def_id() == fn_ptr_trait
&& let Err(NoSolution) = nested_goal.result()
{
return ControlFlow::Break(self.obligation.clone());
}
}
let mut impl_where_bound_count = 0;
for nested_goal in candidate.instantiate_nested_goals(self.span()) {
for nested_goal in nested_goals {
trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
let make_obligation = |cause| Obligation {
@ -605,7 +624,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
}
}
#[derive(Copy, Clone)]
#[derive(Debug, Copy, Clone)]
enum ChildMode<'tcx> {
// Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
// and skip all `GoalSource::Misc`, which represent useless obligations