Skip to content

Commit 8287fb0

Browse files
committed
trait_sel: prefer only nested alias bounds
1 parent c8c6716 commit 8287fb0

File tree

11 files changed

+138
-57
lines changed

11 files changed

+138
-57
lines changed

compiler/rustc_middle/src/traits/select.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_errors::ErrorGuaranteed;
66
use rustc_hir::def_id::DefId;
77
use rustc_macros::{HashStable, TypeVisitable};
88
use rustc_query_system::cache::Cache;
9+
use rustc_type_ir::solve::AliasBoundKind;
910

1011
use self::EvaluationResult::*;
1112
use super::{SelectionError, SelectionResult};
@@ -116,8 +117,13 @@ pub enum SelectionCandidate<'tcx> {
116117

117118
/// This is a trait matching with a projected type as `Self`, and we found
118119
/// an applicable bound in the trait definition. The `usize` is an index
119-
/// into the list returned by `tcx.item_bounds`.
120-
ProjectionCandidate(usize),
120+
/// into the list returned by `tcx.item_bounds` and the `AliasBoundKind`
121+
/// is whether this is candidate from recursion on the self type of a
122+
/// projection.
123+
ProjectionCandidate {
124+
idx: usize,
125+
kind: AliasBoundKind,
126+
},
121127

122128
/// Implementation of a `Fn`-family trait by one of the anonymous types
123129
/// generated for an `||` expression.

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use derive_where::derive_where;
99
use rustc_type_ir::inherent::*;
1010
use rustc_type_ir::lang_items::SolverTraitLangItem;
1111
use rustc_type_ir::search_graph::CandidateHeadUsages;
12-
use rustc_type_ir::solve::SizedTraitKind;
12+
use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind};
1313
use rustc_type_ir::{
1414
self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
1515
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
@@ -27,11 +27,6 @@ use crate::solve::{
2727
has_no_inference_or_external_constraints,
2828
};
2929

30-
enum AliasBoundKind {
31-
SelfBounds,
32-
NonSelfBounds,
33-
}
34-
3530
/// A candidate is a possible way to prove a goal.
3631
///
3732
/// It consists of both the `source`, which describes how that goal would be proven,
@@ -451,7 +446,7 @@ where
451446
matches!(
452447
c.source,
453448
CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
454-
| CandidateSource::AliasBound
449+
| CandidateSource::AliasBound(_)
455450
) && has_no_inference_or_external_constraints(c.result)
456451
})
457452
{
@@ -711,7 +706,7 @@ where
711706
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
712707
{
713708
candidates.push(Candidate {
714-
source: CandidateSource::AliasBound,
709+
source: CandidateSource::AliasBound(consider_self_bounds),
715710
result,
716711
head_usages: CandidateHeadUsages::default(),
717712
});
@@ -735,7 +730,7 @@ where
735730
{
736731
candidates.extend(G::probe_and_consider_implied_clause(
737732
self,
738-
CandidateSource::AliasBound,
733+
CandidateSource::AliasBound(consider_self_bounds),
739734
goal,
740735
assumption,
741736
[],
@@ -750,7 +745,7 @@ where
750745
{
751746
candidates.extend(G::probe_and_consider_implied_clause(
752747
self,
753-
CandidateSource::AliasBound,
748+
CandidateSource::AliasBound(consider_self_bounds),
754749
goal,
755750
assumption,
756751
[],
@@ -1030,7 +1025,7 @@ where
10301025
item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
10311026
candidates.extend(G::probe_and_match_goal_against_assumption(
10321027
self,
1033-
CandidateSource::AliasBound,
1028+
CandidateSource::AliasBound(AliasBoundKind::SelfBounds),
10341029
goal,
10351030
assumption,
10361031
|ecx| {

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
use rustc_type_ir::fast_reject::DeepRejectCtxt;
55
use rustc_type_ir::inherent::*;
66
use rustc_type_ir::lang_items::SolverTraitLangItem;
7-
use rustc_type_ir::solve::SizedTraitKind;
87
use rustc_type_ir::solve::inspect::ProbeKind;
8+
use rustc_type_ir::solve::{AliasBoundKind, SizedTraitKind};
99
use rustc_type_ir::{self as ty, Interner, TypingMode, elaborate};
1010
use tracing::instrument;
1111

@@ -96,7 +96,7 @@ where
9696
) {
9797
candidates.extend(Self::probe_and_match_goal_against_assumption(
9898
ecx,
99-
CandidateSource::AliasBound,
99+
CandidateSource::AliasBound(AliasBoundKind::SelfBounds),
100100
goal,
101101
clause,
102102
|ecx| {

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use rustc_type_ir::data_structures::IndexSet;
44
use rustc_type_ir::fast_reject::DeepRejectCtxt;
55
use rustc_type_ir::inherent::*;
66
use rustc_type_ir::lang_items::SolverTraitLangItem;
7-
use rustc_type_ir::solve::{CandidatePreferenceMode, CanonicalResponse, SizedTraitKind};
7+
use rustc_type_ir::solve::{
8+
AliasBoundKind, CandidatePreferenceMode, CanonicalResponse, SizedTraitKind,
9+
};
810
use rustc_type_ir::{
911
self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
1012
TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
@@ -1381,22 +1383,21 @@ where
13811383
return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
13821384
}
13831385

1384-
let potential_alias_bound_response =
1385-
candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)).then(|| {
1386-
let alias_bounds: Vec<_> = candidates
1387-
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound))
1388-
.collect();
1389-
if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1390-
(response, Some(TraitGoalProvenVia::AliasBound))
1391-
} else {
1392-
(self.bail_with_ambiguity(&alias_bounds), None)
1393-
}
1394-
});
1395-
1386+
// Extract non-nested alias bound candidates, will be preferred over where bounds if
1387+
// we're proving an auto-trait, sizedness trait or default trait.
13961388
if matches!(candidate_preference_mode, CandidatePreferenceMode::Marker)
1397-
&& let Some(alias_bound_response) = potential_alias_bound_response
1389+
&& candidates.iter().any(|c| {
1390+
matches!(c.source, CandidateSource::AliasBound(AliasBoundKind::SelfBounds))
1391+
})
13981392
{
1399-
return Ok(alias_bound_response);
1393+
let alias_bounds: Vec<_> = candidates
1394+
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound(..)))
1395+
.collect();
1396+
return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1397+
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1398+
} else {
1399+
Ok((self.bail_with_ambiguity(&alias_bounds), None))
1400+
};
14001401
}
14011402

14021403
// If there are non-global where-bounds, prefer where-bounds
@@ -1446,8 +1447,16 @@ where
14461447
};
14471448
}
14481449

1449-
if let Some(response) = potential_alias_bound_response {
1450-
return Ok(response);
1450+
// Next, prefer any alias bound (nested or otherwise).
1451+
if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound(_))) {
1452+
let alias_bounds: Vec<_> = candidates
1453+
.extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound(_)))
1454+
.collect();
1455+
return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1456+
Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1457+
} else {
1458+
Ok((self.bail_with_ambiguity(&alias_bounds), None))
1459+
};
14511460
}
14521461

14531462
self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);

compiler/rustc_trait_selection/src/solve/select.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
126126
// Prefer dyn candidates over non-dyn candidates. This is necessary to
127127
// handle the unsoundness between `impl<T: ?Sized> Any for T` and `dyn Any: Any`.
128128
(
129-
CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound,
129+
CandidateSource::Impl(_)
130+
| CandidateSource::ParamEnv(_)
131+
| CandidateSource::AliasBound(_),
130132
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
131133
) => true,
132134

@@ -175,7 +177,9 @@ fn to_selection<'tcx>(
175177
})
176178
}
177179
CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
178-
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested),
180+
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => {
181+
ImplSource::Param(nested)
182+
}
179183
CandidateSource::CoherenceUnknowable => {
180184
span_bug!(span, "didn't expect to select an unknowable candidate")
181185
}

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
741741
let mut ambiguous = false;
742742
let _ = selcx.for_each_item_bound(
743743
obligation.predicate.self_ty(),
744-
|selcx, clause, _| {
744+
|selcx, clause, _, _| {
745745
let Some(clause) = clause.as_projection_clause() else {
746746
return ControlFlow::Continue(());
747747
};

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
208208
let mut distinct_normalized_bounds = FxHashSet::default();
209209
let _ = self.for_each_item_bound::<!>(
210210
placeholder_trait_predicate.self_ty(),
211-
|selcx, bound, idx| {
211+
|selcx, bound, idx, alias_bound_kind| {
212212
let Some(bound) = bound.as_trait_clause() else {
213213
return ControlFlow::Continue(());
214214
};
@@ -230,12 +230,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
230230
bound.map_bound(|pred| pred.trait_ref),
231231
) {
232232
Ok(None) => {
233-
candidates.vec.push(ProjectionCandidate(idx));
233+
candidates
234+
.vec
235+
.push(ProjectionCandidate { idx, kind: alias_bound_kind });
234236
}
235237
Ok(Some(normalized_trait))
236238
if distinct_normalized_bounds.insert(normalized_trait) =>
237239
{
238-
candidates.vec.push(ProjectionCandidate(idx));
240+
candidates
241+
.vec
242+
.push(ProjectionCandidate { idx, kind: alias_bound_kind });
239243
}
240244
_ => {}
241245
}
@@ -825,7 +829,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
825829
}
826830

827831
ty::Alias(ty::Opaque, alias) => {
828-
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
832+
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate { .. })) {
829833
// We do not generate an auto impl candidate for `impl Trait`s which already
830834
// reference our auto trait.
831835
//

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
6767
ImplSource::Builtin(BuiltinImplSource::Misc, data)
6868
}
6969

70-
ProjectionCandidate(idx) => {
70+
ProjectionCandidate { idx, .. } => {
7171
let obligations = self.confirm_projection_candidate(obligation, idx)?;
7272
ImplSource::Param(obligations)
7373
}
@@ -150,7 +150,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
150150
let candidate_predicate = self
151151
.for_each_item_bound(
152152
placeholder_self_ty,
153-
|_, clause, clause_idx| {
153+
|_, clause, clause_idx, _| {
154154
if clause_idx == idx {
155155
ControlFlow::Break(clause)
156156
} else {

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

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use rustc_middle::ty::{
3232
SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
3333
may_use_unstable_feature,
3434
};
35+
use rustc_next_trait_solver::solve::AliasBoundKind;
3536
use rustc_span::{Symbol, sym};
3637
use tracing::{debug, instrument, trace};
3738

@@ -1628,11 +1629,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16281629
pub(super) fn for_each_item_bound<T>(
16291630
&mut self,
16301631
mut self_ty: Ty<'tcx>,
1631-
mut for_each: impl FnMut(&mut Self, ty::Clause<'tcx>, usize) -> ControlFlow<T, ()>,
1632+
mut for_each: impl FnMut(
1633+
&mut Self,
1634+
ty::Clause<'tcx>,
1635+
usize,
1636+
AliasBoundKind,
1637+
) -> ControlFlow<T, ()>,
16321638
on_ambiguity: impl FnOnce(),
16331639
) -> ControlFlow<T, ()> {
16341640
let mut idx = 0;
1635-
let mut in_parent_alias_type = false;
1641+
let mut alias_bound_kind = AliasBoundKind::SelfBounds;
16361642

16371643
loop {
16381644
let (kind, alias_ty) = match *self_ty.kind() {
@@ -1648,14 +1654,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16481654
// share the same type as `self_ty`. This is because for truly rigid
16491655
// projections, we will never be able to equate, e.g. `<T as Tr>::A`
16501656
// with `<<T as Tr>::A as Tr>::A`.
1651-
let relevant_bounds = if in_parent_alias_type {
1657+
let relevant_bounds = if matches!(alias_bound_kind, AliasBoundKind::NonSelfBounds) {
16521658
self.tcx().item_non_self_bounds(alias_ty.def_id)
16531659
} else {
16541660
self.tcx().item_self_bounds(alias_ty.def_id)
16551661
};
16561662

16571663
for bound in relevant_bounds.instantiate(self.tcx(), alias_ty.args) {
1658-
for_each(self, bound, idx)?;
1664+
for_each(self, bound, idx, alias_bound_kind)?;
16591665
idx += 1;
16601666
}
16611667

@@ -1665,7 +1671,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16651671
return ControlFlow::Continue(());
16661672
}
16671673

1668-
in_parent_alias_type = true;
1674+
alias_bound_kind = AliasBoundKind::NonSelfBounds;
16691675
}
16701676
}
16711677

@@ -1880,14 +1886,24 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
18801886
break;
18811887
}
18821888

1883-
let alias_bound = candidates
1884-
.iter()
1885-
.filter_map(|c| if let ProjectionCandidate(i) = c.candidate { Some(i) } else { None })
1886-
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) });
1887-
1889+
let mut alias_bounds = candidates.iter().filter_map(|c| {
1890+
if let ProjectionCandidate { idx, kind } = c.candidate {
1891+
Some((idx, kind))
1892+
} else {
1893+
None
1894+
}
1895+
});
1896+
// Extract non-nested alias bound candidates, will be preferred over where bounds if
1897+
// we're proving an auto-trait, sizedness trait or default trait.
18881898
if matches!(candidate_preference_mode, CandidatePreferenceMode::Marker) {
1889-
match alias_bound {
1890-
Some(Some(index)) => return Some(ProjectionCandidate(index)),
1899+
match alias_bounds
1900+
.clone()
1901+
.filter_map(|(idx, kind)| (kind == AliasBoundKind::SelfBounds).then_some(idx))
1902+
.try_reduce(|c1, c2| if has_non_region_infer { None } else { Some(c1.min(c2)) })
1903+
{
1904+
Some(Some(idx)) => {
1905+
return Some(ProjectionCandidate { idx, kind: AliasBoundKind::SelfBounds });
1906+
}
18911907
Some(None) => {}
18921908
None => return None,
18931909
}
@@ -1926,8 +1942,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19261942
// fairly arbitrary but once again necessary for backwards compatibility.
19271943
// If there are multiple applicable candidates which don't affect type inference,
19281944
// choose the one with the lowest index.
1929-
match alias_bound {
1930-
Some(Some(index)) => return Some(ProjectionCandidate(index)),
1945+
match alias_bounds.try_reduce(|(c1, k1), (c2, k2)| {
1946+
if has_non_region_infer {
1947+
None
1948+
} else if c1 < c2 {
1949+
Some((c1, k1))
1950+
} else {
1951+
Some((c2, k2))
1952+
}
1953+
}) {
1954+
Some(Some((idx, kind))) => return Some(ProjectionCandidate { idx, kind }),
19311955
Some(None) => {}
19321956
None => return None,
19331957
}
@@ -2016,7 +2040,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
20162040
// Non-global param candidates have already been handled, global
20172041
// where-bounds get ignored.
20182042
ParamCandidate(_) | ImplCandidate(_) => true,
2019-
ProjectionCandidate(_) | ObjectCandidate(_) => unreachable!(),
2043+
ProjectionCandidate { .. } | ObjectCandidate(_) => unreachable!(),
20202044
}) {
20212045
return Some(ImplCandidate(def_id));
20222046
} else {

compiler/rustc_type_ir/src/solve/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ pub enum CandidateSource<I: Interner> {
189189
/// let _y = x.clone();
190190
/// }
191191
/// ```
192-
AliasBound,
192+
AliasBound(AliasBoundKind),
193193
/// A candidate that is registered only during coherence to represent some
194194
/// yet-unknown impl that could be produced downstream without violating orphan
195195
/// rules.
@@ -207,6 +207,15 @@ pub enum ParamEnvSource {
207207
Global,
208208
}
209209

210+
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
211+
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
212+
pub enum AliasBoundKind {
213+
/// Alias bound from the self type of a projection
214+
SelfBounds,
215+
// Alias bound having recursed on the self type of a projection
216+
NonSelfBounds,
217+
}
218+
210219
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
211220
#[cfg_attr(
212221
feature = "nightly",

0 commit comments

Comments
 (0)