Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions compiler/rustc_trait_selection/src/solve/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::ops::ControlFlow;

use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::solve::inspect::ProbeKind;
use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal};
use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal, ParamEnvSource};
use rustc_infer::traits::{
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause,
PolyTraitObligation, Selection, SelectionError, SelectionResult,
Expand Down Expand Up @@ -93,8 +93,8 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
victim: &inspect::InspectCandidate<'_, 'tcx>,
other: &inspect::InspectCandidate<'_, 'tcx>,
) -> bool {
// Don't winnow until `Certainty::Yes` -- we don't need to winnow until
// codegen, and only on the good path.
// Don't winnow until `Certainty::Yes` -- we don't need to winnow until constant evaluation or
// codegen.
Comment on lines -96 to +97

@dianne dianne Sep 11, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not totally sure what to do with this comment, but seeing as it was wrong before, I'd like to update it in some way

View changes since the review

if matches!(other.result().unwrap(), Certainty::Maybe(_)) {
return false;
}
Expand Down Expand Up @@ -137,6 +137,15 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
victim.goal().infcx().tcx.specializes((other_def_id, victim_def_id))
}

// Prefer impl candidates over global where clause candidates. Unless `generic_const_args`
// is enabled, we currently don't use an empty environment when resolving and evaluating
// constants to lower them to patterns. If we don't drop where clause candidates here, we
// can fail to select impl candidates (#162331).
(
CandidateSource::ParamEnv(ParamEnvSource::Global),
CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_),
) => true,
Comment on lines +144 to +147

@dianne dianne Sep 11, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this could be more aggressive? I'm not sure what else would be needed, so I'm treating this as a targeted fix. so far, I haven't been able to find any examples that would still fail without this if const-to-pat resolved and evaluated consts in a clean environment (e.g. as it does when full gca is enabled)

View changes since the review


_ => false,
}
}
Expand Down
48 changes: 48 additions & 0 deletions tests/ui/trait-bounds/ignore-where-clauses-in-const-pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/162331>
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
Comment on lines +2 to +4

@dianne dianne Sep 11, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could maybe get rid of the current-solver revision but I figured I'd include it as a sanity check

View changes since the review

//@ check-pass

#![feature(const_trait_impl)]
#![feature(const_clone)]
Comment on lines +7 to +8

@dianne dianne Sep 11, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is for testing the preference for builtin impls over global where-clause candidates. I haven't found a way to do that without unstable features

View changes since the review


// At the time of writing, when resolving an instance for `<u8 as Trait>::N`, the environment
// contains `f`'s `u8: Trait` clause. The old solver dropped the where clause candidate in favor of
// the `impl Trait for u8` candidate, but the new solver didn't, which resulted in ambiguity.

pub trait Trait {
const N: usize;
}

impl Trait for u8 {
const N: usize = 0;
}

pub fn f()
where
u8: Trait,
{
match 0 {
<u8 as Trait>::N => {}
_ => {}
}
}

// At the time of writing, `ZERO` is evaluated in an environment containing `g`'s `(u8,): Clone`
// clause. This wasn't dropped in favor of the built-in `(u8,): Clone` impl when resolving an
// instance for `<(u8,) as Clone>::clone`, which resulted in ambiguity.

const ZERO: (u8,) = (0,).clone();

fn g()
where
(u8,): Clone
{
match (0,) {
ZERO => {}
_ => {}
}
}

fn main() {}
Loading