hax_frontend_exporter/traits/
resolution.rs

1//! Trait resolution: given a trait reference, we track which local clause caused it to be true.
2//! This module is independent from the rest of hax, in particular it doesn't use its
3//! state-tracking machinery.
4
5use hax_frontend_exporter_options::BoundsOptions;
6use itertools::Itertools;
7use std::collections::{HashMap, hash_map::Entry};
8
9use rustc_hir::def::DefKind;
10use rustc_hir::def_id::DefId;
11use rustc_middle::traits::CodegenObligationError;
12use rustc_middle::ty::{self, *};
13use rustc_trait_selection::traits::ImplSource;
14
15use crate::{self_predicate, traits::utils::erase_and_norm};
16
17use super::utils::{ToPolyTraitRef, implied_predicates, normalize_bound_val, required_predicates};
18
19#[derive(Debug, Clone)]
20pub enum PathChunk<'tcx> {
21    AssocItem {
22        item: AssocItem,
23        /// The arguments provided to the item (for GATs).
24        generic_args: GenericArgsRef<'tcx>,
25        /// The impl exprs that must be satisfied to apply the given arguments to the item. E.g.
26        /// `T: Clone` in the following example:
27        /// ```ignore
28        /// trait Foo {
29        ///     type Type<T: Clone>: Debug;
30        /// }
31        /// ```
32        impl_exprs: Vec<ImplExpr<'tcx>>,
33        /// The implemented predicate.
34        predicate: PolyTraitPredicate<'tcx>,
35        /// The index of this predicate in the list returned by `implied_predicates`.
36        index: usize,
37    },
38    Parent {
39        /// The implemented predicate.
40        predicate: PolyTraitPredicate<'tcx>,
41        /// The index of this predicate in the list returned by `implied_predicates`.
42        index: usize,
43    },
44}
45pub type Path<'tcx> = Vec<PathChunk<'tcx>>;
46
47#[derive(Debug, Clone)]
48pub enum ImplExprAtom<'tcx> {
49    /// A concrete `impl Trait for Type {}` item.
50    Concrete {
51        def_id: DefId,
52        generics: GenericArgsRef<'tcx>,
53        /// The impl exprs that prove the clauses on the impl.
54        impl_exprs: Vec<ImplExpr<'tcx>>,
55    },
56    /// A context-bound clause like `where T: Trait`.
57    LocalBound {
58        predicate: Predicate<'tcx>,
59        /// The nth (non-self) predicate found for this item. We use predicates from
60        /// `required_predicates` starting from the parentmost item.
61        index: usize,
62        r#trait: PolyTraitRef<'tcx>,
63        path: Path<'tcx>,
64    },
65    /// The automatic clause `Self: Trait` present inside a `impl Trait for Type {}` item.
66    SelfImpl {
67        r#trait: PolyTraitRef<'tcx>,
68        path: Path<'tcx>,
69    },
70    /// `dyn Trait` is a wrapped value with a virtual table for trait
71    /// `Trait`.  In other words, a value `dyn Trait` is a dependent
72    /// triple that gathers a type τ, a value of type τ and an
73    /// instance of type `Trait`.
74    /// `dyn Trait` implements `Trait` using a built-in implementation; this refers to that
75    /// built-in implementation.
76    Dyn,
77    /// A virtual `Drop` implementation.
78    /// `Drop` doesn't work like a real trait but we want to pretend it does. If a type has a
79    /// user-defined `impl Drop for X` we just use the `Concrete` variant, but if it doesn't we use
80    /// this variant to supply the data needed to know what code will run on drop.
81    Drop(DropData<'tcx>),
82    /// A built-in trait whose implementation is computed by the compiler, such as `FnMut`. This
83    /// morally points to an invisible `impl` block; as such it contains the information we may
84    /// need from one.
85    Builtin {
86        r#trait: PolyTraitRef<'tcx>,
87        /// The `ImplExpr`s required to satisfy the implied predicates on the trait declaration.
88        /// E.g. since `FnMut: FnOnce`, a built-in `T: FnMut` impl would have an `ImplExpr` for `T:
89        /// FnOnce`.
90        impl_exprs: Vec<ImplExpr<'tcx>>,
91        /// The values of the associated types for this trait.
92        types: Vec<(DefId, Ty<'tcx>)>,
93    },
94    /// An error happened while resolving traits.
95    Error(String),
96}
97
98#[derive(Debug, Clone)]
99pub enum DropData<'tcx> {
100    /// A drop that does nothing, e.g. for scalars and pointers.
101    Noop,
102    /// An implicit `Drop` local clause, if the `resolve_drop_bounds` option is `false`. If that
103    /// option is `true`, we'll add `Drop` bounds to every type param, and use that to resolve
104    /// `Drop` impls of generics. If it's `false`, we use this variant to indicate that the drop
105    /// clause comes from a generic or associated type.
106    Implicit,
107    /// The implicit `Drop` impl that exists for every type without an explicit `Drop` impl. The
108    /// virtual impl is considered to have one `T: Drop` bound for each generic argument of the
109    /// target type; it then simply drops each field in order.
110    Glue {
111        /// The type we're generating glue for.
112        ty: Ty<'tcx>,
113        /// The `ImplExpr`s for the `T: Drop` bounds of the virtual impl. There is one for each
114        /// generic argument, in order.
115        impl_exprs: Vec<ImplExpr<'tcx>>,
116    },
117}
118
119#[derive(Clone, Debug)]
120pub struct ImplExpr<'tcx> {
121    /// The trait this is an impl for.
122    pub r#trait: PolyTraitRef<'tcx>,
123    /// The kind of implemention of the root of the tree.
124    pub r#impl: ImplExprAtom<'tcx>,
125}
126
127/// Items have various predicates in scope. `path_to` uses them as a starting point for trait
128/// resolution. This tracks where each of them comes from.
129#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
130pub enum BoundPredicateOrigin {
131    /// The `Self: Trait` predicate implicitly present within trait declarations (note: we
132    /// don't add it for trait implementations, should we?).
133    SelfPred,
134    /// The nth (non-self) predicate found for this item. We use predicates from
135    /// `required_predicates` starting from the parentmost item.
136    Item(usize),
137}
138
139#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
140pub struct AnnotatedTraitPred<'tcx> {
141    pub origin: BoundPredicateOrigin,
142    pub clause: PolyTraitPredicate<'tcx>,
143}
144
145/// The predicates to use as a starting point for resolving trait references within this item. This
146/// includes the "self" predicate if applicable and the `required_predicates` of this item and all
147/// its parents, numbered starting from the parents.
148fn initial_search_predicates<'tcx>(
149    tcx: TyCtxt<'tcx>,
150    def_id: rustc_span::def_id::DefId,
151    options: BoundsOptions,
152) -> Vec<AnnotatedTraitPred<'tcx>> {
153    fn acc_predicates<'tcx>(
154        tcx: TyCtxt<'tcx>,
155        def_id: rustc_span::def_id::DefId,
156        options: BoundsOptions,
157        predicates: &mut Vec<AnnotatedTraitPred<'tcx>>,
158        pred_id: &mut usize,
159    ) {
160        let next_item_origin = |pred_id: &mut usize| {
161            let origin = BoundPredicateOrigin::Item(*pred_id);
162            *pred_id += 1;
163            origin
164        };
165        use DefKind::*;
166        match tcx.def_kind(def_id) {
167            // These inherit some predicates from their parent.
168            AssocTy | AssocFn | AssocConst | Closure | Ctor(..) | Variant => {
169                let parent = tcx.parent(def_id);
170                acc_predicates(tcx, parent, options, predicates, pred_id);
171            }
172            Trait | TraitAlias => {
173                let self_pred = self_predicate(tcx, def_id).upcast(tcx);
174                predicates.push(AnnotatedTraitPred {
175                    origin: BoundPredicateOrigin::SelfPred,
176                    clause: self_pred,
177                })
178            }
179            _ => {}
180        }
181        predicates.extend(
182            required_predicates(tcx, def_id, options)
183                .predicates
184                .iter()
185                .map(|(clause, _span)| *clause)
186                .filter_map(|clause| {
187                    clause.as_trait_clause().map(|clause| AnnotatedTraitPred {
188                        origin: next_item_origin(pred_id),
189                        clause,
190                    })
191                }),
192        );
193    }
194
195    let mut predicates = vec![];
196    acc_predicates(tcx, def_id, options, &mut predicates, &mut 0);
197    predicates
198}
199
200#[tracing::instrument(level = "trace", skip(tcx))]
201fn parents_trait_predicates<'tcx>(
202    tcx: TyCtxt<'tcx>,
203    pred: PolyTraitPredicate<'tcx>,
204    options: BoundsOptions,
205) -> Vec<PolyTraitPredicate<'tcx>> {
206    let self_trait_ref = pred.to_poly_trait_ref();
207    implied_predicates(tcx, pred.def_id(), options)
208        .predicates
209        .iter()
210        .map(|(clause, _span)| *clause)
211        // Substitute with the `self` args so that the clause makes sense in the
212        // outside context.
213        .map(|clause| clause.instantiate_supertrait(tcx, self_trait_ref))
214        .filter_map(|pred| pred.as_trait_clause())
215        .collect()
216}
217
218/// A candidate projects `self` along a path reaching some predicate. A candidate is
219/// selected when its predicate is the one expected, aka `target`.
220#[derive(Debug, Clone)]
221struct Candidate<'tcx> {
222    path: Path<'tcx>,
223    pred: PolyTraitPredicate<'tcx>,
224    origin: AnnotatedTraitPred<'tcx>,
225}
226
227impl<'tcx> Candidate<'tcx> {
228    fn into_impl_expr(self, tcx: TyCtxt<'tcx>) -> ImplExprAtom<'tcx> {
229        let path = self.path;
230        let r#trait = self.origin.clause.to_poly_trait_ref();
231        match self.origin.origin {
232            BoundPredicateOrigin::SelfPred => ImplExprAtom::SelfImpl { r#trait, path },
233            BoundPredicateOrigin::Item(index) => ImplExprAtom::LocalBound {
234                predicate: self.origin.clause.upcast(tcx),
235                index,
236                r#trait,
237                path,
238            },
239        }
240    }
241}
242
243/// Stores a set of predicates along with where they came from.
244pub struct PredicateSearcher<'tcx> {
245    tcx: TyCtxt<'tcx>,
246    typing_env: rustc_middle::ty::TypingEnv<'tcx>,
247    /// Local clauses available in the current context.
248    candidates: HashMap<PolyTraitPredicate<'tcx>, Candidate<'tcx>>,
249    options: BoundsOptions,
250}
251
252impl<'tcx> PredicateSearcher<'tcx> {
253    /// Initialize the elaborator with the predicates accessible within this item.
254    pub fn new_for_owner(tcx: TyCtxt<'tcx>, owner_id: DefId, options: BoundsOptions) -> Self {
255        let mut out = Self {
256            tcx,
257            typing_env: TypingEnv {
258                param_env: tcx.param_env(owner_id),
259                typing_mode: TypingMode::PostAnalysis,
260            },
261            candidates: Default::default(),
262            options,
263        };
264        out.extend(
265            initial_search_predicates(tcx, owner_id, options)
266                .into_iter()
267                .map(|clause| Candidate {
268                    path: vec![],
269                    pred: clause.clause,
270                    origin: clause,
271                }),
272        );
273        out
274    }
275
276    /// Insert new candidates and all their parent predicates. This deduplicates predicates
277    /// to avoid divergence.
278    fn extend(&mut self, candidates: impl IntoIterator<Item = Candidate<'tcx>>) {
279        let tcx = self.tcx;
280        // Filter out duplicated candidates.
281        let mut new_candidates = Vec::new();
282        for mut candidate in candidates {
283            // Normalize and erase all lifetimes.
284            candidate.pred = normalize_bound_val(tcx, self.typing_env, candidate.pred);
285            if let Entry::Vacant(entry) = self.candidates.entry(candidate.pred) {
286                entry.insert(candidate.clone());
287                new_candidates.push(candidate);
288            }
289        }
290        if !new_candidates.is_empty() {
291            self.extend_parents(new_candidates);
292        }
293    }
294
295    /// Add the parents of these candidates. This is a separate function to avoid
296    /// polymorphic recursion due to the closures capturing the type parameters of this
297    /// function.
298    fn extend_parents(&mut self, new_candidates: Vec<Candidate<'tcx>>) {
299        let tcx = self.tcx;
300        // Then recursively add their parents. This way ensures a breadth-first order,
301        // which means we select the shortest path when looking up predicates.
302        let options = self.options;
303        self.extend(new_candidates.into_iter().flat_map(|candidate| {
304            parents_trait_predicates(tcx, candidate.pred, options)
305                .into_iter()
306                .enumerate()
307                .map(move |(index, parent_pred)| {
308                    let mut parent_candidate = Candidate {
309                        pred: parent_pred,
310                        path: candidate.path.clone(),
311                        origin: candidate.origin,
312                    };
313                    parent_candidate.path.push(PathChunk::Parent {
314                        predicate: parent_pred,
315                        index,
316                    });
317                    parent_candidate
318                })
319        }));
320    }
321
322    /// If the type is a trait associated type, we add any relevant bounds to our context.
323    fn add_associated_type_refs(
324        &mut self,
325        ty: Binder<'tcx, Ty<'tcx>>,
326        // Call back into hax-related code to display a nice warning.
327        warn: &impl Fn(&str),
328    ) -> Result<(), String> {
329        let tcx = self.tcx;
330        // Note: We skip a binder but rebind it just after.
331        let TyKind::Alias(AliasTyKind::Projection, alias_ty) = ty.skip_binder().kind() else {
332            return Ok(());
333        };
334        let (trait_ref, item_args) = alias_ty.trait_ref_and_own_args(tcx);
335        let item_args = tcx.mk_args(item_args);
336        let trait_ref = ty.rebind(trait_ref).upcast(tcx);
337
338        // The predicate we're looking for is is `<T as Trait>::Type: OtherTrait`. We look up `T as
339        // Trait` in the current context and add all the bounds on `Trait::Type` to our context.
340        let Some(trait_candidate) = self.resolve_local(trait_ref, warn)? else {
341            return Ok(());
342        };
343
344        // The bounds that hold on the associated type.
345        let item_bounds = implied_predicates(tcx, alias_ty.def_id, self.options)
346            .predicates
347            .iter()
348            .map(|(clause, _span)| *clause)
349            .filter_map(|pred| pred.as_trait_clause())
350            // Substitute the item generics
351            .map(|pred| EarlyBinder::bind(pred).instantiate(tcx, alias_ty.args))
352            .enumerate();
353
354        // Resolve predicates required to mention the item.
355        let nested_impl_exprs =
356            self.resolve_item_required_predicates(alias_ty.def_id, alias_ty.args, warn)?;
357
358        // Add all the bounds on the corresponding associated item.
359        self.extend(item_bounds.map(|(index, pred)| {
360            let mut candidate = Candidate {
361                path: trait_candidate.path.clone(),
362                pred,
363                origin: trait_candidate.origin,
364            };
365            candidate.path.push(PathChunk::AssocItem {
366                item: tcx.associated_item(alias_ty.def_id),
367                generic_args: item_args,
368                impl_exprs: nested_impl_exprs.clone(),
369                predicate: pred,
370                index,
371            });
372            candidate
373        }));
374
375        Ok(())
376    }
377
378    /// Resolve a local clause by looking it up in this set. If the predicate applies to an
379    /// associated type, we add the relevant implied associated type bounds to the set as well.
380    fn resolve_local(
381        &mut self,
382        target: PolyTraitPredicate<'tcx>,
383        // Call back into hax-related code to display a nice warning.
384        warn: &impl Fn(&str),
385    ) -> Result<Option<Candidate<'tcx>>, String> {
386        tracing::trace!("Looking for {target:?}");
387
388        // Look up the predicate
389        let ret = self.candidates.get(&target).cloned();
390        if ret.is_some() {
391            return Ok(ret);
392        }
393
394        // Add clauses related to associated type in the `Self` type of the predicate.
395        self.add_associated_type_refs(target.self_ty(), warn)?;
396
397        let ret = self.candidates.get(&target).cloned();
398        if ret.is_none() {
399            tracing::trace!(
400                "Couldn't find {target:?} in: [\n{}]",
401                self.candidates
402                    .iter()
403                    .map(|(_, c)| format!("  - {:?}\n", c.pred))
404                    .join("")
405            );
406        }
407        Ok(ret)
408    }
409
410    /// Resolve the given trait reference in the local context.
411    #[tracing::instrument(level = "trace", skip(self, warn))]
412    pub fn resolve(
413        &mut self,
414        tref: &PolyTraitRef<'tcx>,
415        // Call back into hax-related code to display a nice warning.
416        warn: &impl Fn(&str),
417    ) -> Result<ImplExpr<'tcx>, String> {
418        use rustc_trait_selection::traits::{
419            BuiltinImplSource, ImplSource, ImplSourceUserDefinedData,
420        };
421        let tcx = self.tcx;
422        let drop_trait = tcx.lang_items().drop_trait().unwrap();
423
424        let erased_tref = normalize_bound_val(self.tcx, self.typing_env, *tref);
425        let trait_def_id = erased_tref.skip_binder().def_id;
426
427        let impl_source = shallow_resolve_trait_ref(tcx, self.typing_env.param_env, erased_tref);
428        let atom = match impl_source {
429            Ok(ImplSource::UserDefined(ImplSourceUserDefinedData {
430                impl_def_id,
431                args: generics,
432                ..
433            })) => {
434                // Resolve the predicates required by the impl.
435                let impl_exprs =
436                    self.resolve_item_required_predicates(impl_def_id, generics, warn)?;
437                ImplExprAtom::Concrete {
438                    def_id: impl_def_id,
439                    generics,
440                    impl_exprs,
441                }
442            }
443            Ok(ImplSource::Param(_)) => {
444                match self.resolve_local(erased_tref.upcast(self.tcx), warn)? {
445                    Some(candidate) => candidate.into_impl_expr(tcx),
446                    None => {
447                        let msg = format!(
448                            "Could not find a clause for `{tref:?}` in the item parameters"
449                        );
450                        warn(&msg);
451                        ImplExprAtom::Error(msg)
452                    }
453                }
454            }
455            Ok(ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)) => ImplExprAtom::Dyn,
456            Ok(ImplSource::Builtin(_, _)) => {
457                // Resolve the predicates implied by the trait.
458                // If we wanted to not skip this binder, we'd have to instantiate the bound
459                // regions, solve, then wrap the result in a binder. And track higher-kinded
460                // clauses better all over.
461                let impl_exprs = self.resolve_item_implied_predicates(
462                    trait_def_id,
463                    erased_tref.skip_binder().args,
464                    warn,
465                )?;
466                let types = tcx
467                    .associated_items(trait_def_id)
468                    .in_definition_order()
469                    .filter(|assoc| matches!(assoc.kind, AssocKind::Type { .. }))
470                    .filter_map(|assoc| {
471                        let ty =
472                            Ty::new_projection(tcx, assoc.def_id, erased_tref.skip_binder().args);
473                        let ty = erase_and_norm(tcx, self.typing_env, ty);
474                        if let TyKind::Alias(_, alias_ty) = ty.kind() {
475                            if alias_ty.def_id == assoc.def_id {
476                                // Couldn't normalize the type to anything different than itself;
477                                // this must be a built-in associated type such as
478                                // `DiscriminantKind::Discriminant`.
479                                // We can't return the unnormalized associated type as that would
480                                // make the trait ref contain itself, which would make hax's
481                                // `sinto` infrastructure loop. That's ok because we can't provide
482                                // a value for this type other than the associate type alias
483                                // itself.
484                                return None;
485                            }
486                        }
487                        Some((assoc.def_id, ty))
488                    })
489                    .collect();
490                ImplExprAtom::Builtin {
491                    r#trait: *tref,
492                    impl_exprs,
493                    types,
494                }
495            }
496            // Resolve `Drop` trait impls by adding virtual impls when a real one can't be found.
497            Err(CodegenObligationError::Unimplemented)
498                if erased_tref.skip_binder().def_id == drop_trait =>
499            {
500                // If we wanted to not skip this binder, we'd have to instantiate the bound
501                // regions, solve, then wrap the result in a binder. And track higher-kinded
502                // clauses better all over.
503                let mut resolve_drop = |ty: Ty<'tcx>| {
504                    let tref = ty::Binder::dummy(ty::TraitRef::new(tcx, drop_trait, [ty]));
505                    self.resolve(&tref, warn)
506                };
507                let find_drop_impl = |ty: Ty<'tcx>| {
508                    let mut dtor = None;
509                    tcx.for_each_relevant_impl(drop_trait, ty, |impl_did| {
510                        dtor = Some(impl_did);
511                    });
512                    dtor
513                };
514                // TODO: how to check if there is a real drop impl?????
515                let ty = erased_tref.skip_binder().args[0].as_type().unwrap();
516                // Source of truth are `ty::needs_drop_components` and `tcx.needs_drop_raw`.
517                match ty.kind() {
518                    // TODO: Does `UnsafeBinder` drop its contents?
519                    ty::Bool
520                    | ty::Char
521                    | ty::Int(..)
522                    | ty::Uint(..)
523                    | ty::Float(..)
524                    | ty::Foreign(..)
525                    | ty::Str
526                    | ty::RawPtr(..)
527                    | ty::Ref(..)
528                    | ty::FnDef(..)
529                    | ty::FnPtr(..)
530                    | ty::UnsafeBinder(..)
531                    | ty::Never => ImplExprAtom::Drop(DropData::Noop),
532                    ty::Array(inner_ty, _) | ty::Pat(inner_ty, _) | ty::Slice(inner_ty) => {
533                        ImplExprAtom::Drop(DropData::Glue {
534                            ty,
535                            impl_exprs: vec![resolve_drop(*inner_ty)?],
536                        })
537                    }
538                    ty::Tuple(tys) => ImplExprAtom::Drop(DropData::Glue {
539                        ty,
540                        impl_exprs: tys.iter().map(resolve_drop).try_collect()?,
541                    }),
542                    ty::Adt(..) if let Some(_) = find_drop_impl(ty) => {
543                        // We should have been able to resolve the `T: Drop` clause above, if we
544                        // get here we don't know how to reconstruct the arguments to the impl.
545                        let msg = format!("Cannot resolve clause `{tref:?}`");
546                        warn(&msg);
547                        ImplExprAtom::Error(msg)
548                    }
549                    ty::Adt(_, args)
550                    | ty::Closure(_, args)
551                    | ty::Coroutine(_, args)
552                    | ty::CoroutineClosure(_, args)
553                    | ty::CoroutineWitness(_, args) => ImplExprAtom::Drop(DropData::Glue {
554                        ty,
555                        impl_exprs: args
556                            .iter()
557                            .filter_map(|arg| arg.as_type())
558                            .map(resolve_drop)
559                            .try_collect()?,
560                    }),
561                    // Every `dyn` has a `Drop` in its vtable, ergo we pretend that every `dyn` has
562                    // `Drop` in its list of traits.
563                    ty::Dynamic(..) => ImplExprAtom::Dyn,
564                    ty::Param(..) | ty::Alias(..) | ty::Bound(..) => {
565                        if self.options.resolve_drop {
566                            // We've added `Drop` impls on everything, we should be able to resolve
567                            // it.
568                            match self.resolve_local(erased_tref.upcast(self.tcx), warn)? {
569                                Some(candidate) => candidate.into_impl_expr(tcx),
570                                None => {
571                                    let msg =
572                                        format!("Cannot find virtual `Drop` clause: `{tref:?}`");
573                                    warn(&msg);
574                                    ImplExprAtom::Error(msg)
575                                }
576                            }
577                        } else {
578                            ImplExprAtom::Drop(DropData::Implicit)
579                        }
580                    }
581
582                    ty::Placeholder(..) | ty::Infer(..) | ty::Error(..) => {
583                        let msg = format!(
584                            "Cannot resolve clause `{tref:?}` \
585                                because of a type error"
586                        );
587                        warn(&msg);
588                        ImplExprAtom::Error(msg)
589                    }
590                }
591            }
592            Err(e) => {
593                let msg = format!(
594                    "Could not find a clause for `{tref:?}` \
595                    in the current context: `{e:?}`"
596                );
597                warn(&msg);
598                ImplExprAtom::Error(msg)
599            }
600        };
601
602        Ok(ImplExpr {
603            r#impl: atom,
604            r#trait: *tref,
605        })
606    }
607
608    /// Resolve the predicates required by the given item.
609    pub fn resolve_item_required_predicates(
610        &mut self,
611        def_id: DefId,
612        generics: GenericArgsRef<'tcx>,
613        // Call back into hax-related code to display a nice warning.
614        warn: &impl Fn(&str),
615    ) -> Result<Vec<ImplExpr<'tcx>>, String> {
616        let tcx = self.tcx;
617        self.resolve_predicates(
618            generics,
619            required_predicates(tcx, def_id, self.options),
620            warn,
621        )
622    }
623
624    /// Resolve the predicates implied by the given item.
625    pub fn resolve_item_implied_predicates(
626        &mut self,
627        def_id: DefId,
628        generics: GenericArgsRef<'tcx>,
629        // Call back into hax-related code to display a nice warning.
630        warn: &impl Fn(&str),
631    ) -> Result<Vec<ImplExpr<'tcx>>, String> {
632        let tcx = self.tcx;
633        self.resolve_predicates(
634            generics,
635            implied_predicates(tcx, def_id, self.options),
636            warn,
637        )
638    }
639
640    /// Apply the given generics to the provided clauses and resolve the trait references in the
641    /// current context.
642    pub fn resolve_predicates(
643        &mut self,
644        generics: GenericArgsRef<'tcx>,
645        predicates: GenericPredicates<'tcx>,
646        // Call back into hax-related code to display a nice warning.
647        warn: &impl Fn(&str),
648    ) -> Result<Vec<ImplExpr<'tcx>>, String> {
649        let tcx = self.tcx;
650        predicates
651            .predicates
652            .iter()
653            .map(|(clause, _span)| *clause)
654            .filter_map(|clause| clause.as_trait_clause())
655            .map(|trait_pred| trait_pred.map_bound(|p| p.trait_ref))
656            // Substitute the item generics
657            .map(|trait_ref| EarlyBinder::bind(trait_ref).instantiate(tcx, generics))
658            // Resolve
659            .map(|trait_ref| self.resolve(&trait_ref, warn))
660            .collect()
661    }
662}
663
664/// Attempts to resolve an obligation to an `ImplSource`. The result is a shallow `ImplSource`
665/// resolution, meaning that we do not resolve all nested obligations on the impl. Note that type
666/// check should guarantee to us that all nested obligations *could be* resolved if we wanted to.
667///
668/// This expects that `trait_ref` is fully normalized.
669///
670/// This is based on `rustc_traits::codegen::codegen_select_candidate` in rustc.
671pub fn shallow_resolve_trait_ref<'tcx>(
672    tcx: TyCtxt<'tcx>,
673    param_env: ParamEnv<'tcx>,
674    trait_ref: PolyTraitRef<'tcx>,
675) -> Result<ImplSource<'tcx, ()>, CodegenObligationError> {
676    use rustc_infer::infer::TyCtxtInferExt;
677    use rustc_middle::traits::CodegenObligationError;
678    use rustc_middle::ty::TypeVisitableExt;
679    use rustc_trait_selection::traits::{
680        Obligation, ObligationCause, ObligationCtxt, SelectionContext, SelectionError,
681    };
682    // Do the initial selection for the obligation. This yields the
683    // shallow result we are looking for -- that is, what specific impl.
684    let infcx = tcx
685        .infer_ctxt()
686        .ignoring_regions()
687        .build(TypingMode::PostAnalysis);
688    let mut selcx = SelectionContext::new(&infcx);
689
690    let obligation_cause = ObligationCause::dummy();
691    let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
692
693    let selection = match selcx.poly_select(&obligation) {
694        Ok(Some(selection)) => selection,
695        Ok(None) => return Err(CodegenObligationError::Ambiguity),
696        Err(SelectionError::Unimplemented) => return Err(CodegenObligationError::Unimplemented),
697        Err(_) => return Err(CodegenObligationError::Ambiguity),
698    };
699
700    // Currently, we use a fulfillment context to completely resolve
701    // all nested obligations. This is because they can inform the
702    // inference of the impl's type parameters.
703    // FIXME(-Znext-solver): Doesn't need diagnostics if new solver.
704    let ocx = ObligationCtxt::new(&infcx);
705    let impl_source = selection.map(|obligation| {
706        ocx.register_obligation(obligation.clone());
707        ()
708    });
709
710    let errors = ocx.select_all_or_error();
711    if !errors.is_empty() {
712        return Err(CodegenObligationError::Ambiguity);
713    }
714
715    let impl_source = infcx.resolve_vars_if_possible(impl_source);
716    let impl_source = tcx.erase_regions(impl_source);
717
718    if impl_source.has_infer() {
719        // Unused lifetimes on an impl get replaced with inference vars, but never resolved.
720        return Err(CodegenObligationError::Ambiguity);
721    }
722
723    Ok(impl_source)
724}