Skip to main content

rustc_trait_selection/traits/
structural_normalize.rs

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