rustc_trait_selection/traits/
structural_normalize.rs

1use rustc_infer::infer::at::At;
2use rustc_infer::traits::TraitEngine;
3use rustc_macros::extension;
4use rustc_middle::ty::{self, Ty};
5
6use crate::traits::{NormalizeExt, Obligation};
7
8#[extension(pub trait StructurallyNormalizeExt<'tcx>)]
9impl<'tcx> At<'_, 'tcx> {
10    fn structurally_normalize_ty<E: 'tcx>(
11        &self,
12        ty: Ty<'tcx>,
13        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
14    ) -> Result<Ty<'tcx>, Vec<E>> {
15        self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type())
16    }
17
18    fn structurally_normalize_const<E: 'tcx>(
19        &self,
20        ct: ty::Const<'tcx>,
21        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
22    ) -> Result<ty::Const<'tcx>, Vec<E>> {
23        if self.infcx.tcx.features().generic_const_exprs() {
24            return Ok(super::evaluate_const(&self.infcx, ct, self.param_env));
25        }
26
27        self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const())
28    }
29
30    fn structurally_normalize_term<E: 'tcx>(
31        &self,
32        term: ty::Term<'tcx>,
33        fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
34    ) -> Result<ty::Term<'tcx>, Vec<E>> {
35        assert!(!term.is_infer(), "should have resolved vars before calling");
36
37        if self.infcx.next_trait_solver() {
38            if let None = term.to_alias_term() {
39                return Ok(term);
40            }
41
42            let new_infer = match term.unpack() {
43                ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(),
44                ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(),
45            };
46
47            // We simply emit an `alias-eq` goal here, since that will take care of
48            // normalizing the LHS of the projection until it is a rigid projection
49            // (or a not-yet-defined opaque in scope).
50            let obligation = Obligation::new(
51                self.infcx.tcx,
52                self.cause.clone(),
53                self.param_env,
54                ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate),
55            );
56
57            fulfill_cx.register_predicate_obligation(self.infcx, obligation);
58            let errors = fulfill_cx.select_where_possible(self.infcx);
59            if !errors.is_empty() {
60                return Err(errors);
61            }
62
63            Ok(self.infcx.resolve_vars_if_possible(new_infer))
64        } else {
65            Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx))
66        }
67    }
68}