Skip to main content

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