1#![expect(dead_code, reason = "this is used by rustc")]
2
3use std::ops::ControlFlow;
4
5use hir_def::TraitId;
6use macros::{TypeFoldable, TypeVisitable};
7use rustc_type_ir::{
8 Interner,
9 solve::{BuiltinImplSource, CandidateSource, Certainty, inspect::ProbeKind},
10};
11
12use crate::{
13 Span,
14 db::InternedOpaqueTyId,
15 next_solver::{
16 AnyImplId, Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError,
17 infer::{
18 InferCtxt,
19 select::EvaluationResult::*,
20 traits::{Obligation, ObligationCause, PredicateObligation, TraitObligation},
21 },
22 inspect::{InspectCandidate, InspectGoal, ProofTreeVisitor},
23 },
24};
25
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub enum SelectionError<'db> {
28 Unimplemented,
30 SignatureMismatch(Box<SignatureMismatchData<'db>>),
34 TraitDynIncompatible(TraitId),
36 NotConstEvaluatable(NotConstEvaluatable),
38 Overflow(OverflowError),
40 OpaqueTypeAutoTraitLeakageUnknown(InternedOpaqueTyId<'db>),
44 ConstArgHasWrongType { ct: Const<'db>, ct_ty: Ty<'db>, expected_ty: Ty<'db> },
46}
47
48#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
49pub enum NotConstEvaluatable {
50 Error(ErrorGuaranteed),
51 MentionsInfer,
52 MentionsParam,
53}
54
55#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
67pub enum EvaluationResult {
68 EvaluatedToOk,
70 EvaluatedToOkModuloRegions,
72 EvaluatedToOkModuloOpaqueTypes,
76 EvaluatedToAmbig,
83 EvaluatedToAmbigStackDependent,
90 EvaluatedToErr,
92}
93
94impl EvaluationResult {
95 pub(crate) fn must_apply_considering_regions(self) -> bool {
98 self == EvaluatedToOk
99 }
100
101 pub(crate) fn must_apply_modulo_regions(self) -> bool {
104 self <= EvaluatedToOkModuloRegions
105 }
106
107 pub(crate) fn may_apply(self) -> bool {
108 match self {
109 EvaluatedToOkModuloOpaqueTypes
110 | EvaluatedToOk
111 | EvaluatedToOkModuloRegions
112 | EvaluatedToAmbig
113 | EvaluatedToAmbigStackDependent => true,
114
115 EvaluatedToErr => false,
116 }
117 }
118
119 pub(crate) fn is_stack_dependent(self) -> bool {
120 match self {
121 EvaluatedToAmbigStackDependent => true,
122
123 EvaluatedToOkModuloOpaqueTypes
124 | EvaluatedToOk
125 | EvaluatedToOkModuloRegions
126 | EvaluatedToAmbig
127 | EvaluatedToErr => false,
128 }
129 }
130}
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
134pub enum OverflowError {
135 Error(ErrorGuaranteed),
136 Canonical,
137}
138
139#[derive(Clone, Debug, PartialEq, Eq)]
140pub struct SignatureMismatchData<'db> {
141 pub(crate) found_trait_ref: TraitRef<'db>,
142 pub(crate) expected_trait_ref: TraitRef<'db>,
143 pub(crate) terr: TypeError<'db>,
144}
145
146pub(crate) type SelectionResult<'db, T> = Result<Option<T>, SelectionError<'db>>;
154
155#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
185pub(crate) enum ImplSource<'db, N> {
186 UserDefined(ImplSourceUserDefinedData<'db, N>),
188
189 Param(Vec<N>),
194
195 Builtin(BuiltinImplSource, Vec<N>),
197}
198
199impl<'db, N> ImplSource<'db, N> {
200 pub(crate) fn nested_obligations(self) -> Vec<N> {
201 match self {
202 ImplSource::UserDefined(i) => i.nested,
203 ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
204 }
205 }
206
207 pub(crate) fn borrow_nested_obligations(&self) -> &[N] {
208 match self {
209 ImplSource::UserDefined(i) => &i.nested,
210 ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
211 }
212 }
213
214 pub(crate) fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
215 match self {
216 ImplSource::UserDefined(i) => &mut i.nested,
217 ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
218 }
219 }
220
221 pub(crate) fn map<M, F>(self, f: F) -> ImplSource<'db, M>
222 where
223 F: FnMut(N) -> M,
224 {
225 match self {
226 ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData {
227 impl_def_id: i.impl_def_id,
228 args: i.args,
229 nested: i.nested.into_iter().map(f).collect(),
230 }),
231 ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()),
232 ImplSource::Builtin(source, n) => {
233 ImplSource::Builtin(source, n.into_iter().map(f).collect())
234 }
235 }
236 }
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
250pub(crate) struct ImplSourceUserDefinedData<'db, N> {
251 #[type_visitable(ignore)]
252 #[type_foldable(identity)]
253 pub(crate) impl_def_id: AnyImplId,
254 pub(crate) args: GenericArgs<'db>,
255 pub(crate) nested: Vec<N>,
256}
257
258pub(crate) type Selection<'db> = ImplSource<'db, PredicateObligation<'db>>;
259
260impl<'db> InferCtxt<'db> {
261 pub(crate) fn select(
262 &self,
263 obligation: &TraitObligation<'db>,
264 ) -> SelectionResult<'db, Selection<'db>> {
265 self.visit_proof_tree(
266 Goal::new(self.interner, obligation.param_env, obligation.predicate),
267 &mut Select { span: obligation.cause.span() },
268 )
269 .break_value()
270 .unwrap()
271 }
272}
273
274struct Select {
275 span: Span,
276}
277
278impl<'db> ProofTreeVisitor<'db> for Select {
279 type Result = ControlFlow<SelectionResult<'db, Selection<'db>>>;
280
281 fn span(&self) -> Span {
282 self.span
283 }
284
285 fn visit_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> Self::Result {
286 let mut candidates = goal.candidates();
287 candidates.retain(|cand| cand.result().is_ok());
288
289 if candidates.is_empty() {
291 return ControlFlow::Break(Err(SelectionError::Unimplemented));
292 }
293
294 if candidates.len() == 1 {
296 return ControlFlow::Break(Ok(to_selection(
297 self.span,
298 candidates.into_iter().next().unwrap(),
299 )));
300 }
301
302 if matches!(goal.result().unwrap(), Certainty::Maybe { .. }) {
305 return ControlFlow::Break(Ok(None));
306 }
307
308 let mut i = 0;
310 while i < candidates.len() {
311 let should_drop_i = (0..candidates.len())
312 .filter(|&j| i != j)
313 .any(|j| candidate_should_be_dropped_in_favor_of(&candidates[i], &candidates[j]));
314 if should_drop_i {
315 candidates.swap_remove(i);
316 } else {
317 i += 1;
318 if i > 1 {
319 return ControlFlow::Break(Ok(None));
320 }
321 }
322 }
323
324 ControlFlow::Break(Ok(to_selection(self.span, candidates.into_iter().next().unwrap())))
325 }
326}
327
328fn candidate_should_be_dropped_in_favor_of<'db>(
332 victim: &InspectCandidate<'_, 'db>,
333 other: &InspectCandidate<'_, 'db>,
334) -> bool {
335 if matches!(other.result().unwrap(), Certainty::Maybe { .. }) {
338 return false;
339 }
340
341 let ProbeKind::TraitCandidate { source: victim_source, result: _ } = victim.kind() else {
342 return false;
343 };
344 let ProbeKind::TraitCandidate { source: other_source, result: _ } = other.kind() else {
345 return false;
346 };
347
348 match (victim_source, other_source) {
349 (_, CandidateSource::CoherenceUnknowable) | (CandidateSource::CoherenceUnknowable, _) => {
350 panic!("should not have assembled a CoherenceUnknowable candidate")
351 }
352
353 (
356 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(a)),
357 CandidateSource::BuiltinImpl(BuiltinImplSource::Object(b)),
358 ) => a >= b,
359 (
360 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(a)),
361 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(b)),
362 ) => a >= b,
363 (
366 CandidateSource::Impl(_)
367 | CandidateSource::ParamEnv(_)
368 | CandidateSource::AliasBound(_),
369 CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
370 ) => true,
371
372 (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
374 victim.goal().infcx().interner.impl_specializes(other_def_id, victim_def_id)
375 }
376
377 _ => false,
378 }
379}
380
381fn to_selection<'db>(span: Span, cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>> {
382 if let Certainty::Maybe { .. } = cand.shallow_certainty() {
383 return None;
384 }
385
386 let nested = match cand.result().expect("expected positive result") {
387 Certainty::Yes => Vec::new(),
388 Certainty::Maybe { .. } => cand
389 .instantiate_nested_goals(span)
390 .into_iter()
391 .map(|nested| {
392 Obligation::new(
393 nested.infcx().interner,
394 ObligationCause::dummy(),
395 nested.goal().param_env,
396 nested.goal().predicate,
397 )
398 })
399 .collect(),
400 };
401
402 Some(match cand.kind() {
403 ProbeKind::TraitCandidate { source, result: _ } => match source {
404 CandidateSource::Impl(impl_def_id) => {
405 ImplSource::UserDefined(ImplSourceUserDefinedData {
408 impl_def_id,
409 args: cand.instantiate_impl_args(span),
410 nested,
411 })
412 }
413 CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested),
414 CandidateSource::ParamEnv(_) | CandidateSource::AliasBound(_) => {
415 ImplSource::Param(nested)
416 }
417 CandidateSource::CoherenceUnknowable => {
418 panic!("didn't expect to select an unknowable candidate")
419 }
420 },
421 ProbeKind::NormalizedSelfTyAssembly
422 | ProbeKind::UnsizeAssembly
423 | ProbeKind::ProjectionCompatibility
424 | ProbeKind::OpaqueTypeStorageLookup { result: _ }
425 | ProbeKind::Root { result: _ }
426 | ProbeKind::ShadowedEnvProbing
427 | ProbeKind::RigidAlias { result: _ } => {
428 panic!("didn't expect to assemble trait candidate from {:#?}", cand.kind())
429 }
430 })
431}