rustc_trait_selection/solve/
select.rs1use std::ops::ControlFlow;
2
3use rustc_infer::infer::InferCtxt;
4use rustc_infer::traits::solve::inspect::ProbeKind;
5use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal, ParamEnvSource};
6use rustc_infer::traits::{
7 BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause,
8 PolyTraitObligation, Selection, SelectionError, SelectionResult,
9};
10use rustc_macros::extension;
11use rustc_span::{Span, bug, span_bug};
12use thin_vec::thin_vec;
13
14use crate::solve::inspect::{self, InferCtxtProofTreeExt};
15
16pub trait InferCtxtSelectExt<'tcx> {
#[doc =
" Do not use this directly. This is called from [`crate::traits::SelectionContext::poly_select`]."]
fn select_in_new_trait_solver(&self,
obligation: &PolyTraitObligation<'tcx>)
-> SelectionResult<'tcx, Selection<'tcx>>;
}
impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
#[doc =
" Do not use this directly. This is called from [`crate::traits::SelectionContext::poly_select`]."]
fn select_in_new_trait_solver(&self,
obligation: &PolyTraitObligation<'tcx>)
-> SelectionResult<'tcx, Selection<'tcx>> {
if !self.next_trait_solver() {
::core::panicking::panic("assertion failed: self.next_trait_solver()")
};
self.visit_proof_tree(Goal::new(self.tcx, obligation.param_env,
obligation.predicate),
&mut Select {
span: obligation.cause.span,
}).break_value().unwrap()
}
}#[extension(pub trait InferCtxtSelectExt<'tcx>)]
17impl<'tcx> InferCtxt<'tcx> {
18 fn select_in_new_trait_solver(
20 &self,
21 obligation: &PolyTraitObligation<'tcx>,
22 ) -> SelectionResult<'tcx, Selection<'tcx>> {
23 assert!(self.next_trait_solver());
24
25 self.visit_proof_tree(
26 Goal::new(self.tcx, obligation.param_env, obligation.predicate),
27 &mut Select { span: obligation.cause.span },
28 )
29 .break_value()
30 .unwrap()
31 }
32}
33
34struct Select {
35 span: Span,
36}
37
38impl<'tcx> inspect::ProofTreeVisitor<'tcx> for Select {
39 type Result = ControlFlow<SelectionResult<'tcx, Selection<'tcx>>>;
40
41 fn span(&self) -> Span {
42 self.span
43 }
44
45 fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
46 let mut candidates = goal.candidates();
47 candidates.retain(|cand| cand.result().is_ok());
48
49 if candidates.is_empty() {
51 return ControlFlow::Break(Err(SelectionError::Unimplemented));
52 }
53
54 if candidates.len() == 1 {
56 return ControlFlow::Break(Ok(to_selection(
57 self.span,
58 candidates.into_iter().next().unwrap(),
59 )));
60 }
61
62 if #[allow(non_exhaustive_omitted_patterns)] match goal.result().unwrap() {
Certainty::Maybe(_) => true,
_ => false,
}matches!(goal.result().unwrap(), Certainty::Maybe(_)) {
65 return ControlFlow::Break(Ok(None));
66 }
67
68 let mut i = 0;
70 while i < candidates.len() {
71 let should_drop_i = (0..candidates.len())
72 .filter(|&j| i != j)
73 .any(|j| candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]));
74 if should_drop_i {
75 candidates.swap_remove(i);
76 } else {
77 i += 1;
78 if i > 1 {
79 return ControlFlow::Break(Ok(None));
80 }
81 }
82 }
83
84 ControlFlow::Break(Ok(to_selection(self.span, candidates.into_iter().next().unwrap())))
85 }
86}
87
88fn candidate_should_be_dropped_in_favor_of<'tcx>(
92 victim: &inspect::InspectCandidate<'_, 'tcx>,
93 other: &inspect::InspectCandidate<'_, 'tcx>,
94) -> bool {
95 if #[allow(non_exhaustive_omitted_patterns)] match other.result().unwrap() {
Certainty::Maybe(_) => true,
_ => false,
}matches!(other.result().unwrap(), Certainty::Maybe(_)) {
98 return false;
99 }
100
101 let inspect::ProbeKind::TraitCandidate { source: victim_source, result: _ } = victim.kind()
102 else {
103 return false;
104 };
105 let inspect::ProbeKind::TraitCandidate { source: other_source, result: _ } = other.kind()
106 else {
107 return false;
108 };
109
110 match (victim_source, other_source) {
111 (_, CandidateSource::CoherenceUnknowable) | (CandidateSource::CoherenceUnknowable, _) => {
112 ::rustc_span::macros::bug_impl(None,
format_args!("should not have assembled a CoherenceUnknowable candidate"),
Location::caller())bug!("should not have assembled a CoherenceUnknowable candidate")
113 }
114
115 (
118 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)),
119 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)),
120 ) => a >= b,
121 (
122 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(a)),
123 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(b)),
124 ) => a >= b,
125 (
128 CandidateSource::Impl(_)
129 | CandidateSource::ParamEnv(_)
130 | CandidateSource::AliasBound(_),
131 CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
132 ) => true,
133
134 (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
136 victim.goal().infcx().tcx.specializes((other_def_id, victim_def_id))
137 }
138
139 (
144 CandidateSource::ParamEnv(ParamEnvSource::Global),
145 CandidateSource::Impl(_) | CandidateSource::BuiltinImpl(_),
146 ) => true,
147
148 _ => false,
149 }
150}
151
152fn to_selection<'tcx>(
153 span: Span,
154 cand: inspect::InspectCandidate<'_, 'tcx>,
155) -> Option<Selection<'tcx>> {
156 if let Certainty::Maybe(_) = cand.shallow_certainty() {
157 return None;
158 }
159
160 let nested = match cand.result().expect("expected positive result") {
161 Certainty::Yes => ::thin_vec::ThinVec::new()thin_vec![],
162 Certainty::Maybe(_) => cand
163 .instantiate_nested_goals(span)
164 .into_iter()
165 .map(|nested| {
166 Obligation::new(
167 nested.infcx().tcx,
168 ObligationCause::dummy_with_span(span),
169 nested.goal().param_env,
170 nested.goal().predicate,
171 )
172 })
173 .collect(),
174 };
175
176 Some(match cand.kind() {
177 ProbeKind::TraitCandidate { source, result: _ } => match source {
178 CandidateSource::Impl(impl_def_id) => {
179 ImplSource::UserDefined(ImplSourceUserDefinedData {
182 impl_def_id,
183 args: cand.instantiate_impl_args(span),
184 nested,
185 })
186 }
187 CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
188 CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => {
189 ImplSource::Param(nested)
190 }
191 CandidateSource::CoherenceUnknowable => {
192 ::rustc_span::macros::bug_impl(Some(span),
format_args!("didn\'t expect to select an unknowable candidate"),
Location::caller())span_bug!(span, "didn't expect to select an unknowable candidate")
193 }
194 },
195 ProbeKind::NormalizedSelfTyAssembly
196 | ProbeKind::UnsizeAssembly
197 | ProbeKind::ProjectionCompatibility
198 | ProbeKind::OpaqueTypeStorageLookup { result: _ }
199 | ProbeKind::Root { result: _ }
200 | ProbeKind::ShadowedEnvProbing
201 | ProbeKind::RigidAlias { result: _ } => {
202 ::rustc_span::macros::bug_impl(Some(span),
format_args!("didn\'t expect to assemble trait candidate from {0:#?}",
cand.kind()), Location::caller())span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
203 }
204 })
205}