Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 150ca15

Browse files
committedMar 12, 2025
Only prefer Sized candidates, and only if they certainly hold
1 parent 26dd1b8 commit 150ca15

File tree

5 files changed

+43
-23
lines changed

5 files changed

+43
-23
lines changed
 

‎compiler/rustc_middle/src/traits/select.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,11 @@ pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>),
9595
/// parameter environment.
9696
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
9797
pub enum SelectionCandidate<'tcx> {
98-
/// UwU
99-
SizedCandidate,
98+
/// A built-in implementation for the `Sized` trait. This is preferred
99+
/// over all other candidates.
100+
SizedCandidate {
101+
has_nested: bool,
102+
},
100103

101104
/// A builtin implementation for some specific traits, used in cases
102105
/// where we cannot rely an ordinary library implementations.

‎compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1062,8 +1062,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10621062
candidates: &mut SelectionCandidateSet<'tcx>,
10631063
) {
10641064
match self.sized_conditions(obligation) {
1065-
BuiltinImplConditions::Where(_) => {
1066-
candidates.vec.push(SizedCandidate);
1065+
BuiltinImplConditions::Where(nested) => {
1066+
candidates
1067+
.vec
1068+
.push(SizedCandidate { has_nested: !nested.skip_binder().is_empty() });
10671069
}
10681070
BuiltinImplConditions::None => {}
10691071
BuiltinImplConditions::Ambiguous => {

‎compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
4040
candidate: SelectionCandidate<'tcx>,
4141
) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
4242
let mut impl_src = match candidate {
43-
SizedCandidate => {
44-
let data = self.confirm_builtin_candidate(obligation, true);
43+
SizedCandidate { has_nested } => {
44+
let data = self.confirm_builtin_candidate(obligation, has_nested);
4545
ImplSource::Builtin(BuiltinImplSource::Misc, data)
4646
}
4747

‎compiler/rustc_trait_selection/src/traits/select/mod.rs

+11-17
Original file line numberDiff line numberDiff line change
@@ -1803,25 +1803,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18031803

18041804
// We prefer `Sized` candidates over everything.
18051805
let mut sized_candidates =
1806-
candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate));
1807-
if let Some(_sized_candidate) = sized_candidates.next() {
1806+
candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate { has_nested: _ }));
1807+
if let Some(sized_candidate) = sized_candidates.next() {
18081808
// There should only ever be a single sized candidate
18091809
// as they would otherwise overlap.
18101810
debug_assert_eq!(sized_candidates.next(), None);
1811-
return Some(SizedCandidate);
1812-
}
1813-
1814-
// We prefer trivial builtin candidates, i.e. builtin impls without any nested
1815-
// requirements, over all others. This is a fix for #53123 and prevents winnowing
1816-
// from accidentally extending the lifetime of a variable.
1817-
let mut trivial_builtin = candidates
1818-
.iter()
1819-
.filter(|c| matches!(c.candidate, BuiltinCandidate { has_nested: false }));
1820-
if let Some(_trivial) = trivial_builtin.next() {
1821-
// There should only ever be a single trivial builtin candidate
1822-
// as they would otherwise overlap.
1823-
debug_assert_eq!(trivial_builtin.next(), None);
1824-
return Some(BuiltinCandidate { has_nested: false });
1811+
// Only prefer the built-in `Sized` candidate if its nested goals are certain.
1812+
// Otherwise, we may encounter failure later on if inference causes this candidate
1813+
// to not hold, but a where clause would've applied instead.
1814+
if sized_candidate.evaluation.must_apply_modulo_regions() {
1815+
return Some(sized_candidate.candidate.clone());
1816+
} else {
1817+
return None;
1818+
}
18251819
}
18261820

18271821
// Before we consider where-bounds, we have to deduplicate them here and also
@@ -1950,7 +1944,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19501944
// Don't use impl candidates which overlap with other candidates.
19511945
// This should pretty much only ever happen with malformed impls.
19521946
if candidates.iter().all(|c| match c.candidate {
1953-
SizedCandidate
1947+
SizedCandidate { has_nested: _ }
19541948
| BuiltinCandidate { has_nested: _ }
19551949
| TransmutabilityCandidate
19561950
| AutoImplCandidate
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ check-pass
2+
//@ revisions: current next
3+
//@ ignore-compare-mode-next-solver (explicit revisions)
4+
//@[next] compile-flags: -Znext-solver
5+
6+
struct W<T: ?Sized>(T);
7+
8+
fn is_sized<T: Sized>(x: *const T) {}
9+
10+
fn dummy<T: ?Sized>() -> *const T { todo!() }
11+
12+
fn non_param_where_bound<T: ?Sized>()
13+
where
14+
W<T>: Sized,
15+
{
16+
let x: *const W<_> = dummy();
17+
is_sized::<W<_>>(x);
18+
let _: *const W<T> = x;
19+
}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)
Failed to load comments.